Author: typz Date: Wed May 29 09:30:47 2019 New Revision: 361986 URL: http://llvm.org/viewvc/llvm-project?rev=361986&view=rev Log: [clang-format] Allow configuring list of function-like macros that resolve to a type
Summary: Adds a `TypenameMacros` configuration option that causes certain identifiers to be handled in a way similar to `typeof()`. This is enough to: - Prevent misinterpreting declarations of pointers to such types as expressions (`STACK_OF(int) * foo` -> `STACK_OF(int) *foo`), - Avoid surprising line breaks in variable/struct field declarations (`STACK_OF(int)\nfoo;` -> `STACK_OF(int) foo;`, see https://bugs.llvm.org/show_bug.cgi?id=30353). Reviewers: Typz, krasimir, djasper Reviewed By: Typz Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D57184 Modified: cfe/trunk/docs/ClangFormatStyleOptions.rst cfe/trunk/include/clang/Format/Format.h cfe/trunk/lib/Format/Format.cpp cfe/trunk/lib/Format/FormatToken.h cfe/trunk/lib/Format/FormatTokenLexer.cpp cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/unittests/Format/FormatTest.cpp Modified: cfe/trunk/docs/ClangFormatStyleOptions.rst URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ClangFormatStyleOptions.rst?rev=361986&r1=361985&r2=361986&view=diff ============================================================================== --- cfe/trunk/docs/ClangFormatStyleOptions.rst (original) +++ cfe/trunk/docs/ClangFormatStyleOptions.rst Wed May 29 09:30:47 2019 @@ -1367,6 +1367,24 @@ the configuration (without a prefix: ``A For example: BOOST_FOREACH. +**TypenameMacros** (``std::vector<std::string>``) + A vector of macros that should be interpreted as type declarations + instead of as function calls. + + These are expected to be macros of the form: + + .. code-block: c++ + + STACK_OF(...) + + In the .clang-format configuration file, this can be configured like: + + .. code-block: yaml + + TypenameMacros: ['STACK_OF', 'LIST'] + + For example: OpenSSL STACK_OF, BSD LIST_ENTRY. + **IncludeBlocks** (``IncludeBlocksStyle``) Dependent on the value, multiple ``#include`` blocks can be sorted as one and divided based on category. Modified: cfe/trunk/include/clang/Format/Format.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Format/Format.h?rev=361986&r1=361985&r2=361986&view=diff ============================================================================== --- cfe/trunk/include/clang/Format/Format.h (original) +++ cfe/trunk/include/clang/Format/Format.h Wed May 29 09:30:47 2019 @@ -1160,6 +1160,22 @@ struct FormatStyle { /// For example: BOOST_FOREACH. std::vector<std::string> ForEachMacros; + /// \brief A vector of macros that should be interpreted as type declarations + /// instead of as function calls. + /// + /// These are expected to be macros of the form: + /// \code + /// STACK_OF(...) + /// \endcode + /// + /// In the .clang-format configuration file, this can be configured like: + /// \code{.yaml} + /// TypenameMacros: ['STACK_OF', 'LIST'] + /// \endcode + /// + /// For example: OpenSSL STACK_OF, BSD LIST_ENTRY. + std::vector<std::string> TypenameMacros; + /// A vector of macros that should be interpreted as complete /// statements. /// @@ -1952,7 +1968,8 @@ struct FormatStyle { SpacesInParentheses == R.SpacesInParentheses && SpacesInSquareBrackets == R.SpacesInSquareBrackets && Standard == R.Standard && TabWidth == R.TabWidth && - StatementMacros == R.StatementMacros && UseTab == R.UseTab; + StatementMacros == R.StatementMacros && UseTab == R.UseTab && + TypenameMacros == R.TypenameMacros; } llvm::Optional<FormatStyle> GetLanguageStyle(LanguageKind Language) const; Modified: cfe/trunk/lib/Format/Format.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=361986&r1=361985&r2=361986&view=diff ============================================================================== --- cfe/trunk/lib/Format/Format.cpp (original) +++ cfe/trunk/lib/Format/Format.cpp Wed May 29 09:30:47 2019 @@ -505,6 +505,7 @@ template <> struct MappingTraits<FormatS IO.mapOptional("Standard", Style.Standard); IO.mapOptional("StatementMacros", Style.StatementMacros); IO.mapOptional("TabWidth", Style.TabWidth); + IO.mapOptional("TypenameMacros", Style.TypenameMacros); IO.mapOptional("UseTab", Style.UseTab); } }; Modified: cfe/trunk/lib/Format/FormatToken.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=361986&r1=361985&r2=361986&view=diff ============================================================================== --- cfe/trunk/lib/Format/FormatToken.h (original) +++ cfe/trunk/lib/Format/FormatToken.h Wed May 29 09:30:47 2019 @@ -96,6 +96,7 @@ namespace format { TYPE(TrailingAnnotation) \ TYPE(TrailingReturnArrow) \ TYPE(TrailingUnaryOperator) \ + TYPE(TypenameMacro) \ TYPE(UnaryOperator) \ TYPE(CSharpStringLiteral) \ TYPE(CSharpNullCoalescing) \ Modified: cfe/trunk/lib/Format/FormatTokenLexer.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatTokenLexer.cpp?rev=361986&r1=361985&r2=361986&view=diff ============================================================================== --- cfe/trunk/lib/Format/FormatTokenLexer.cpp (original) +++ cfe/trunk/lib/Format/FormatTokenLexer.cpp Wed May 29 09:30:47 2019 @@ -39,6 +39,8 @@ FormatTokenLexer::FormatTokenLexer(const Macros.insert({&IdentTable.get(ForEachMacro), TT_ForEachMacro}); for (const std::string &StatementMacro : Style.StatementMacros) Macros.insert({&IdentTable.get(StatementMacro), TT_StatementMacro}); + for (const std::string &TypenameMacro : Style.TypenameMacros) + Macros.insert({&IdentTable.get(TypenameMacro), TT_TypenameMacro}); } ArrayRef<FormatToken *> FormatTokenLexer::lex() { Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=361986&r1=361985&r2=361986&view=diff ============================================================================== --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Wed May 29 09:30:47 2019 @@ -1194,11 +1194,12 @@ private: // Reset token type in case we have already looked at it and then // recovered from an error (e.g. failure to find the matching >). - if (!CurrentToken->isOneOf( - TT_LambdaLSquare, TT_LambdaLBrace, TT_ForEachMacro, - TT_FunctionLBrace, TT_ImplicitStringLiteral, TT_InlineASMBrace, - TT_JsFatArrow, TT_LambdaArrow, TT_OverloadedOperator, - TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral)) + if (!CurrentToken->isOneOf(TT_LambdaLSquare, TT_LambdaLBrace, + TT_ForEachMacro, TT_TypenameMacro, + TT_FunctionLBrace, TT_ImplicitStringLiteral, + TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, + TT_OverloadedOperator, TT_RegexLiteral, + TT_TemplateString, TT_ObjCStringLiteral)) CurrentToken->Type = TT_Unknown; CurrentToken->Role.reset(); CurrentToken->MatchingParen = nullptr; @@ -1416,6 +1417,7 @@ private: if (AfterParen->Tok.isNot(tok::caret)) { if (FormatToken *BeforeParen = Current.MatchingParen->Previous) if (BeforeParen->is(tok::identifier) && + !BeforeParen->is(TT_TypenameMacro) && BeforeParen->TokenText == BeforeParen->TokenText.upper() && (!BeforeParen->Previous || BeforeParen->Previous->ClosesTemplateDeclaration)) @@ -1667,7 +1669,8 @@ private: FormatToken *TokenBeforeMatchingParen = PrevToken->MatchingParen->getPreviousNonComment(); if (TokenBeforeMatchingParen && - TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype)) + TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype, + TT_TypenameMacro)) return TT_PointerOrReference; } @@ -2527,7 +2530,8 @@ bool TokenAnnotator::spaceRequiredBetwee FormatToken *TokenBeforeMatchingParen = Left.MatchingParen->getPreviousNonComment(); if (!TokenBeforeMatchingParen || - !TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype)) + !TokenBeforeMatchingParen->isOneOf(tok::kw_typeof, tok::kw_decltype, + TT_TypenameMacro)) return true; } return (Left.Tok.isLiteral() || Modified: cfe/trunk/unittests/Format/FormatTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=361986&r1=361985&r2=361986&view=diff ============================================================================== --- cfe/trunk/unittests/Format/FormatTest.cpp (original) +++ cfe/trunk/unittests/Format/FormatTest.cpp Wed May 29 09:30:47 2019 @@ -13545,6 +13545,35 @@ TEST_F(FormatTest, GuessLanguageWithChil guessLanguage("foo.h", "#define FOO ({ foo(); ({ NSString *s; }) })")); } +TEST_F(FormatTest, TypenameMacros) { + std::vector<std::string> TypenameMacros = {"STACK_OF", "LIST", "TAILQ_ENTRY"}; + + // Test case reported in https://bugs.llvm.org/show_bug.cgi?id=30353 + FormatStyle Google = getGoogleStyleWithColumns(0); + Google.TypenameMacros = TypenameMacros; + verifyFormat("struct foo {\n" + " int bar;\n" + " TAILQ_ENTRY(a) bleh;\n" + "};", Google); + + FormatStyle Macros = getLLVMStyle(); + Macros.TypenameMacros = TypenameMacros; + + verifyFormat("STACK_OF(int) a;", Macros); + verifyFormat("STACK_OF(int) *a;", Macros); + verifyFormat("STACK_OF(int const *) *a;", Macros); + verifyFormat("STACK_OF(int *const) *a;", Macros); + verifyFormat("STACK_OF(int, string) a;", Macros); + verifyFormat("STACK_OF(LIST(int)) a;", Macros); + verifyFormat("STACK_OF(LIST(int)) a, b;", Macros); + verifyFormat("for (LIST(int) *a = NULL; a;) {\n}", Macros); + verifyFormat("STACK_OF(int) f(LIST(int) *arg);", Macros); + + Macros.PointerAlignment = FormatStyle::PAS_Left; + verifyFormat("STACK_OF(int)* a;", Macros); + verifyFormat("STACK_OF(int*)* a;", Macros); +} + } // end namespace } // end namespace format } // end namespace clang _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits