[PATCH] D57184: [clang-format] Allow configuring list of function-like macros that resolve to a type

2019-01-24 Thread Marcin Radomski via Phabricator via cfe-commits
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

2019-05-24 Thread Marcin Radomski via Phabricator via cfe-commits
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

2019-05-25 Thread Marcin Radomski via Phabricator via cfe-commits
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