[PATCH] D57184: [clang-format] Allow configuring list of function-like macros that resolve to a type
dextero created this revision. dextero added reviewers: Typz, krasimir, djasper. Herald added a subscriber: cfe-commits. 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). Repository: rC Clang https://reviews.llvm.org/D57184 Files: docs/ClangFormatStyleOptions.rst include/clang/Format/Format.h lib/Format/Format.cpp lib/Format/FormatToken.h lib/Format/FormatTokenLexer.cpp lib/Format/TokenAnnotator.cpp unittests/Format/FormatTest.cpp Index: unittests/Format/FormatTest.cpp === --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -12806,6 +12806,35 @@ guessLanguage("foo.h", "#define FOO ({ foo(); ({ NSString *s; }) })")); } +TEST_F(FormatTest, TypenameMacros) { + std::vector 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 Index: lib/Format/TokenAnnotator.cpp === --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -1134,8 +1134,9 @@ // 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_ForEachMacro, - TT_FunctionLBrace, TT_ImplicitStringLiteral, - TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, + TT_TypenameMacro, TT_FunctionLBrace, + TT_ImplicitStringLiteral, TT_InlineASMBrace, + TT_JsFatArrow, TT_LambdaArrow, TT_OverloadedOperator, TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral)) CurrentToken->Type = TT_Unknown; @@ -1354,6 +1355,7 @@ 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)) @@ -1604,7 +1606,8 @@ 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; } @@ -2455,7 +2458,8 @@ 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() || Index: lib/Format/FormatTokenLexer.cpp === --- lib/Format/FormatTokenLexer.cpp +++ lib/Format/FormatTokenLexer.cpp @@ -39,6 +39,8 @@ Macros.insert({&IdentTable.get(ForEachMacro), TT_ForEachMacro}); for (const std::string &StatementMacro : Style.StatementMacros)
[PATCH] D57184: [clang-format] Allow configuring list of function-like macros that resolve to a type
dextero updated this revision to Diff 201393. dextero marked an inline comment as done. dextero added a comment. - [clang-format] Make documentation a bit clearer - Rebased onto recent master @Typz: thank you for the review! I don't have push access to the repository though. Could you commit this diff, or point me to someone I should ask instead? Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57184/new/ https://reviews.llvm.org/D57184 Files: docs/ClangFormatStyleOptions.rst include/clang/Format/Format.h lib/Format/Format.cpp lib/Format/FormatToken.h lib/Format/FormatTokenLexer.cpp lib/Format/TokenAnnotator.cpp unittests/Format/FormatTest.cpp Index: unittests/Format/FormatTest.cpp === --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -13545,6 +13545,35 @@ guessLanguage("foo.h", "#define FOO ({ foo(); ({ NSString *s; }) })")); } +TEST_F(FormatTest, TypenameMacros) { + std::vector 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 Index: lib/Format/TokenAnnotator.cpp === --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -1194,11 +1194,12 @@ // 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 @@ 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 @@ 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 @@ 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() || Index: lib/Format/FormatTokenLexer.cpp === --- lib/Format/FormatTokenLexer.cpp +++ lib/Format/FormatTokenLexer.cpp @@ -39,6 +39,8 @@ Macros.insert({&IdentTable.get
[PATCH] D57184: [clang-format] Allow configuring list of function-like macros that resolve to a type
dextero updated this revision to Diff 201395. dextero added a comment. - [clang-format] Change "types" -> "type declarations" in Format.h Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57184/new/ https://reviews.llvm.org/D57184 Files: docs/ClangFormatStyleOptions.rst include/clang/Format/Format.h lib/Format/Format.cpp lib/Format/FormatToken.h lib/Format/FormatTokenLexer.cpp lib/Format/TokenAnnotator.cpp unittests/Format/FormatTest.cpp Index: unittests/Format/FormatTest.cpp === --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -13545,6 +13545,35 @@ guessLanguage("foo.h", "#define FOO ({ foo(); ({ NSString *s; }) })")); } +TEST_F(FormatTest, TypenameMacros) { + std::vector 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 Index: lib/Format/TokenAnnotator.cpp === --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -1194,11 +1194,12 @@ // 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 @@ 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 @@ 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 @@ 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() || Index: lib/Format/FormatTokenLexer.cpp === --- lib/Format/FormatTokenLexer.cpp +++ lib/Format/FormatTokenLexer.cpp @@ -39,6 +39,8 @@ 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 &TypenameMa