Typz updated this revision to Diff 103937.
Typz added a comment.

Fix typo


https://reviews.llvm.org/D33440

Files:
  include/clang/Format/Format.h
  lib/Format/Format.cpp
  lib/Format/FormatToken.h
  lib/Format/FormatTokenLexer.cpp
  lib/Format/FormatTokenLexer.h
  lib/Format/NamespaceEndCommentsFixer.cpp
  lib/Format/TokenAnnotator.cpp
  lib/Format/UnwrappedLineFormatter.cpp
  lib/Format/UnwrappedLineParser.cpp
  unittests/Format/FormatTest.cpp
  unittests/Format/NamespaceEndCommentsFixerTest.cpp

Index: unittests/Format/NamespaceEndCommentsFixerTest.cpp
===================================================================
--- unittests/Format/NamespaceEndCommentsFixerTest.cpp
+++ unittests/Format/NamespaceEndCommentsFixerTest.cpp
@@ -53,6 +53,7 @@
                                     "  int i;\n"
                                     "  int j;\n"
                                     "}"));
+
   EXPECT_EQ("namespace {\n"
             "  int i;\n"
             "  int j;\n"
@@ -249,6 +250,85 @@
                                     "// unrelated"));
 }
 
+TEST_F(NamespaceEndCommentsFixerTest, AddsMacroEndComment) {
+  FormatStyle Style = getLLVMStyle();
+  Style.NamespaceMacros.push_back("TESTSUITE");
+
+  EXPECT_EQ("TESTSUITE() {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// TESTSUITE()",
+            fixNamespaceEndComments("TESTSUITE() {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "}",
+                                    Style));
+
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "}",
+                                    Style));
+  EXPECT_EQ("inline TESTSUITE(A) {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// TESTSUITE(A)",
+            fixNamespaceEndComments("inline TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "}",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(::A) {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// TESTSUITE(::A)",
+            fixNamespaceEndComments("TESTSUITE(::A) {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "}",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(::A::B) {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// TESTSUITE(::A::B)",
+            fixNamespaceEndComments("TESTSUITE(::A::B) {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "}",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(/**/::/**/A/**/::/**/B/**/) {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// TESTSUITE(::A::B)",
+            fixNamespaceEndComments("TESTSUITE(/**/::/**/A/**/::/**/B/**/) {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "}",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A, B) {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A, B) {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "}",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(\"Test1\") {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// TESTSUITE(\"Test1\")",
+            fixNamespaceEndComments("TESTSUITE(\"Test1\") {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "}",
+                                    Style));
+}
+
 TEST_F(NamespaceEndCommentsFixerTest, AddsNewlineIfNeeded) {
   EXPECT_EQ("namespace A {\n"
             "  int i;\n"
@@ -381,6 +461,54 @@
                                     "}; /* unnamed namespace */"));
 }
 
+TEST_F(NamespaceEndCommentsFixerTest, KeepsValidMacroEndComment) {
+  FormatStyle Style = getLLVMStyle();
+  Style.NamespaceMacros.push_back("TESTSUITE");
+
+  EXPECT_EQ("TESTSUITE() {\n"
+            "  int i;\n"
+            "} // end anonymous TESTSUITE()",
+            fixNamespaceEndComments("TESTSUITE() {\n"
+                                    "  int i;\n"
+                                    "} // end anonymous TESTSUITE()",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "} /* end of TESTSUITE(A) */",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "} /* end of TESTSUITE(A) */",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "}   //   TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "}   //   TESTSUITE(A)",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A::B) {\n"
+            "  int i;\n"
+            "} // end TESTSUITE(A::B)",
+            fixNamespaceEndComments("TESTSUITE(A::B) {\n"
+                                    "  int i;\n"
+                                    "} // end TESTSUITE(A::B)",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "}; // end TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "}; // end TESTSUITE(A)",
+                                    Style));
+  EXPECT_EQ("TESTSUITE() {\n"
+            "  int i;\n"
+            "}; /* unnamed TESTSUITE() */",
+            fixNamespaceEndComments("TESTSUITE() {\n"
+                                    "  int i;\n"
+                                    "}; /* unnamed TESTSUITE() */",
+                                    Style));
+}
+
 TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndLineComment) {
   EXPECT_EQ("namespace {\n"
             "  int i;\n"
@@ -402,10 +530,10 @@
                                     "} //"));
   EXPECT_EQ("namespace A {\n"
             "  int i;\n"
-            "} // namespace A",
+            "}; // namespace A",
             fixNamespaceEndComments("namespace A {\n"
                                     "  int i;\n"
-                                    "} //"));
+                                    "}; //"));
   EXPECT_EQ("namespace A {\n"
             "  int i;\n"
             "} // namespace A",
@@ -446,6 +574,96 @@
                                     CompactNamespacesStyle));
 }
 
+TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidMacroEndLineComment) {
+  FormatStyle Style = getLLVMStyle();
+  Style.NamespaceMacros.push_back("TESTSUITE");
+
+  EXPECT_EQ("TESTSUITE() {\n"
+            "  int i;\n"
+            "} // TESTSUITE()",
+            fixNamespaceEndComments("TESTSUITE() {\n"
+                                    "  int i;\n"
+                                    "} // TESTSUITE(A)",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "} // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "} // TESTSUITE()",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "} // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "} //",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "}; // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "}; //",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "} // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "} // TESTSUITE A",
+                                    Style));
+  EXPECT_EQ("TESTSUITE() {\n"
+            "  int i;\n"
+            "} // TESTSUITE()",
+            fixNamespaceEndComments("TESTSUITE() {\n"
+                                    "  int i;\n"
+                                    "} // TESTSUITE",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "} // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "} // TOASTSUITE(A)",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "}; // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "}; // TOASTSUITE(A)",
+                                    Style));
+  // Updates invalid line comments even for short namespaces.
+  EXPECT_EQ("TESTSUITE(A) {} // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {} // TESTSUITE()", Style));
+  EXPECT_EQ("TESTSUITE(A) {}; // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {}; // TESTSUITE()", Style));
+
+  // Update invalid comments for compacted namespaces.
+  FormatStyle CompactNamespacesStyle = getLLVMStyle();
+  CompactNamespacesStyle.CompactNamespaces = true;
+  CompactNamespacesStyle.NamespaceMacros.push_back("TESTSUITE");
+
+  EXPECT_EQ("TESTSUITE(out) { TESTSUITE(in) {\n"
+            "}} // TESTSUITE(out::in)",
+            fixNamespaceEndComments("TESTSUITE(out) { TESTSUITE(in) {\n"
+                                    "}} // TESTSUITE(out)",
+                                    CompactNamespacesStyle));
+  EXPECT_EQ("TESTSUITE(out) { TESTSUITE(in) {\n"
+            "}} // TESTSUITE(out::in)",
+            fixNamespaceEndComments("TESTSUITE(out) { TESTSUITE(in) {\n"
+                                    "}} // TESTSUITE(in)",
+                                    CompactNamespacesStyle));
+  EXPECT_EQ("TESTSUITE(out) { TESTSUITE(in) {\n"
+            "}\n"
+            "} // TESTSUITE(out::in)",
+            fixNamespaceEndComments("TESTSUITE(out) { TESTSUITE(in) {\n"
+                                    "}// TAOSTSUITE(in)\n"
+                                    "} // TESTSUITE(out)",
+                                    CompactNamespacesStyle));
+}
+
 TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndBlockComment) {
   EXPECT_EQ("namespace {\n"
             "  int i;\n"
@@ -489,6 +707,58 @@
             fixNamespaceEndComments("namespace A {}; /**/"));
 }
 
+TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidMacroEndBlockComment) {
+  FormatStyle Style = getLLVMStyle();
+  Style.NamespaceMacros.push_back("TESTSUITE");
+
+  EXPECT_EQ("TESTSUITE() {\n"
+            "  int i;\n"
+            "} // TESTSUITE()",
+            fixNamespaceEndComments("TESTSUITE() {\n"
+                                    "  int i;\n"
+                                    "} /* TESTSUITE(A) */",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "}  // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "}  /* end TESTSUITE() */",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "} // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "} /**/",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "} // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "} /* end unnamed TESTSUITE() */",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "} // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "} /* TOASTSUITE(A) */",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {\n"
+            "  int i;\n"
+            "}; // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {\n"
+                                    "  int i;\n"
+                                    "}; /* TAOSTSUITE(A) */",
+                                    Style));
+  EXPECT_EQ("TESTSUITE(A) {} // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {} /**/", Style));
+  EXPECT_EQ("TESTSUITE(A) {}; // TESTSUITE(A)",
+            fixNamespaceEndComments("TESTSUITE(A) {}; /**/", Style));
+}
+
 TEST_F(NamespaceEndCommentsFixerTest,
        DoesNotAddEndCommentForNamespacesControlledByMacros) {
   EXPECT_EQ("#ifdef 1\n"
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -1356,9 +1356,117 @@
                    Style));
 }
 
+TEST_F(FormatTest, NamespaceMacros) {
+  FormatStyle Style = getLLVMStyle();
+  Style.NamespaceMacros.push_back("TESTSUITE");
+
+  verifyFormat("TESTSUITE(A) {\n"
+               "int foo();\n"
+               "} // TESTSUITE(A)",
+               Style);
+
+  verifyFormat("TESTSUITE(A, B) {\n"
+               "int foo();\n"
+               "} // TESTSUITE(A)",
+               Style);
+
+  // Properly indent according to NamespaceIndentation style
+  Style.NamespaceIndentation = FormatStyle::NI_All;
+  verifyFormat("TESTSUITE(A) {\n"
+               "  int foo();\n"
+               "} // TESTSUITE(A)",
+               Style);
+  verifyFormat("TESTSUITE(A) {\n"
+               "  namespace B {\n"
+               "    int foo();\n"
+               "  } // namespace B\n"
+               "} // TESTSUITE(A)",
+               Style);
+  verifyFormat("namespace A {\n"
+               "  TESTSUITE(B) {\n"
+               "    int foo();\n"
+               "  } // TESTSUITE(B)\n"
+               "} // namespace A",
+               Style);
+
+  Style.NamespaceIndentation = FormatStyle::NI_Inner;
+  verifyFormat("TESTSUITE(A) {\n"
+               "TESTSUITE(B) {\n"
+               "  int foo();\n"
+               "} // TESTSUITE(B)\n"
+               "} // TESTSUITE(A)",
+               Style);
+  verifyFormat("TESTSUITE(A) {\n"
+               "namespace B {\n"
+               "  int foo();\n"
+               "} // namespace B\n"
+               "} // TESTSUITE(A)",
+               Style);
+  verifyFormat("namespace A {\n"
+               "TESTSUITE(B) {\n"
+               "  int foo();\n"
+               "} // TESTSUITE(B)\n"
+               "} // namespace A",
+               Style);
+
+  // Properly merge namespace-macros blocks in CompactNamespaces mode
+  Style.NamespaceIndentation = FormatStyle::NI_None;
+  Style.CompactNamespaces = true;
+  verifyFormat("TESTSUITE(A) { TESTSUITE(B) {\n"
+               "}} // TESTSUITE(A::B)",
+               Style);
+
+  EXPECT_EQ("TESTSUITE(out) { TESTSUITE(in) {\n"
+            "}} // TESTSUITE(out::in)",
+            format("TESTSUITE(out) {\n"
+                   "TESTSUITE(in) {\n"
+                   "} // TESTSUITE(in)\n"
+                   "} // TESTSUITE(out)",
+                   Style));
+
+  EXPECT_EQ("TESTSUITE(out) { TESTSUITE(in) {\n"
+            "}} // TESTSUITE(out::in)",
+            format("TESTSUITE(out) {\n"
+                   "TESTSUITE(in) {\n"
+                   "} // TESTSUITE(in)\n"
+                   "} // TESTSUITE(out)",
+                   Style));
+
+  // Do not merge different namespaces/macros
+  EXPECT_EQ("namespace out {\n"
+            "TESTSUITE(in) {\n"
+            "} // TESTSUITE(in)\n"
+            "} // namespace out",
+            format("namespace out {\n"
+                   "TESTSUITE(in) {\n"
+                   "} // TESTSUITE(in)\n"
+                   "} // namespace out",
+                   Style));
+  EXPECT_EQ("TESTSUITE(out) {\n"
+            "namespace in {\n"
+            "} // namespace in\n"
+            "} // TESTSUITE(out)",
+            format("TESTSUITE(out) {\n"
+                   "namespace in {\n"
+                   "} // namespace in\n"
+                   "} // TESTSUITE(out)",
+                   Style));
+  Style.NamespaceMacros.push_back("FOOBAR");
+  EXPECT_EQ("TESTSUITE(out) {\n"
+            "FOOBAR(in) {\n"
+            "} // FOOBAR(in)\n"
+            "} // TESTSUITE(out)",
+            format("TESTSUITE(out) {\n"
+                   "FOOBAR(in) {\n"
+                   "} // FOOBAR(in)\n"
+                   "} // TESTSUITE(out)",
+                   Style));
+}
+
 TEST_F(FormatTest, FormatsCompactNamespaces) {
   FormatStyle Style = getLLVMStyle();
   Style.CompactNamespaces = true;
+  Style.NamespaceMacros.push_back("TESTSUITE");
 
   verifyFormat("namespace A { namespace B {\n"
 			   "}} // namespace A::B",
@@ -1372,6 +1480,14 @@
                    "} // namespace out",
                    Style));
 
+  EXPECT_EQ("namespace out { namespace in {\n"
+            "}} // namespace out::in",
+            format("namespace out {\n"
+                   "namespace in {\n"
+                   "} // namespace in\n"
+                   "} // namespace out",
+                   Style));
+
   // Only namespaces which have both consecutive opening and end get compacted
   EXPECT_EQ("namespace out {\n"
             "namespace in1 {\n"
@@ -2172,6 +2288,26 @@
                    getLLVMStyleWithColumns(40)));
 
   verifyFormat("MACRO(>)");
+
+  // Some macros contain an implicit semicolon
+  FormatStyle Style = getLLVMStyle();
+  Style.StatementMacros.push_back("FOO");
+  verifyFormat("FOO(a) int b = 0;");
+  verifyFormat("FOO(a)\n"
+               "int b = 0;",
+               Style);
+  verifyFormat("FOO(a);\n"
+               "int b = 0;",
+               Style);
+  verifyFormat("FOO(argc, argv, \"4.0.2\")\n"
+               "int b = 0;",
+               Style);
+  verifyFormat("FOO()\n"
+               "int b = 0;",
+               Style);
+  verifyFormat("FOO\n"
+               "int b = 0;",
+               Style);
 }
 
 TEST_F(FormatTest, LayoutMacroDefinitionsStatementsSpanningBlocks) {
@@ -9555,6 +9691,18 @@
   CHECK_PARSE("ForEachMacros: [BOOST_FOREACH, Q_FOREACH]", ForEachMacros,
               BoostAndQForeach);
 
+  Style.StatementMacros.clear();
+  CHECK_PARSE("StatementMacros: [QUNUSED]", StatementMacros,
+              std::vector<std::string>{"QUNUSED"});
+  CHECK_PARSE("StatementMacros: [QUNUSED, QT_REQUIRE_VERSION]", StatementMacros,
+              std::vector<std::string>({"QUNUSED", "QT_REQUIRE_VERSION"}));
+
+  Style.NamespaceMacros.clear();
+  CHECK_PARSE("NamespaceMacros: [TESTSUITE]", NamespaceMacros,
+              std::vector<std::string>{"TESTSUITE"});
+  CHECK_PARSE("NamespaceMacros: [TESTSUITE, SUITE]", NamespaceMacros,
+              std::vector<std::string>({"TESTSUITE", "SUITE"}));
+
   Style.IncludeCategories.clear();
   std::vector<FormatStyle::IncludeCategory> ExpectedCategories = {{"abc/.*", 2},
                                                                   {".*", 1}};
Index: lib/Format/UnwrappedLineParser.cpp
===================================================================
--- lib/Format/UnwrappedLineParser.cpp
+++ lib/Format/UnwrappedLineParser.cpp
@@ -537,7 +537,7 @@
 
 static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
                                    const FormatToken &InitialToken) {
-  if (InitialToken.is(tok::kw_namespace))
+  if (InitialToken.isOneOf(tok::kw_namespace, TT_NamespaceMacro))
     return Style.BraceWrapping.AfterNamespace;
   if (InitialToken.is(tok::kw_class))
     return Style.BraceWrapping.AfterClass;
@@ -986,6 +986,19 @@
         return;
       }
     }
+    if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
+      nextToken();
+      if (FormatTok->is(tok::l_paren))
+        parseParens();
+      if (FormatTok->is(tok::semi))
+        nextToken();
+      addUnwrappedLine();
+      return;
+    }
+    if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) {
+      parseNamespace();
+      return;
+    }
     // In all other cases, parse the declaration.
     break;
   default:
@@ -1625,12 +1638,17 @@
 }
 
 void UnwrappedLineParser::parseNamespace() {
-  assert(FormatTok->Tok.is(tok::kw_namespace) && "'namespace' expected");
+  assert(FormatTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro) &&
+         "'namespace' expected");
 
   const FormatToken &InitialToken = *FormatTok;
   nextToken();
-  while (FormatTok->isOneOf(tok::identifier, tok::coloncolon))
-    nextToken();
+  if (InitialToken.is(TT_NamespaceMacro)) {
+    parseParens();
+  } else {
+    while (FormatTok->isOneOf(tok::identifier, tok::coloncolon))
+      nextToken();
+  }
   if (FormatTok->Tok.is(tok::l_brace)) {
     if (ShouldBreakBeforeBrace(Style, InitialToken))
       addUnwrappedLine();
Index: lib/Format/UnwrappedLineFormatter.cpp
===================================================================
--- lib/Format/UnwrappedLineFormatter.cpp
+++ lib/Format/UnwrappedLineFormatter.cpp
@@ -134,23 +134,29 @@
   unsigned Indent = 0;
 };
 
-bool isNamespaceDeclaration(const AnnotatedLine *Line) {
-  const FormatToken *NamespaceTok = Line->First;
-  // Detect "(inline)? namespace" in the beginning of a line.
-  if (NamespaceTok->is(tok::kw_inline))
-    NamespaceTok = NamespaceTok->getNextNonComment();
-  return NamespaceTok && NamespaceTok->is(tok::kw_namespace);
-}
-
-bool isEndOfNamespace(const AnnotatedLine *Line,
-                      const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
+const FormatToken *getMatchingNamespaceToken(
+    const AnnotatedLine *Line,
+    const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
   if (!Line->startsWith(tok::r_brace))
-    return false;
+    return nullptr;
   size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex;
   if (StartLineIndex == UnwrappedLine::kInvalidIndex)
-    return false;
+    return nullptr;
   assert(StartLineIndex < AnnotatedLines.size());
-  return isNamespaceDeclaration(AnnotatedLines[StartLineIndex]);
+  return AnnotatedLines[StartLineIndex]->First->getNamespaceToken();
+}
+
+StringRef getNamespaceTokenText(const AnnotatedLine *Line) {
+  const FormatToken *NamespaceToken = Line->First->getNamespaceToken();
+  return NamespaceToken ? NamespaceToken->TokenText : StringRef();
+}
+
+StringRef getMatchingNamespaceTokenText(
+    const AnnotatedLine *Line,
+    const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
+  const FormatToken *NamespaceToken =
+      getMatchingNamespaceToken(Line, AnnotatedLines);
+  return NamespaceToken ? NamespaceToken->TokenText : StringRef();
 }
 
 class LineJoiner {
@@ -230,10 +236,11 @@
          TheLine->Level != 0);
 
     if (Style.CompactNamespaces) {
-      if (isNamespaceDeclaration(TheLine)) {
+      if (auto nsToken = TheLine->First->getNamespaceToken()) {
         int i = 0;
         unsigned closingLine = TheLine->MatchingOpeningBlockLineIndex - 1;
-        for (; I + 1 + i != E && isNamespaceDeclaration(I[i + 1]) &&
+        for (; I + 1 + i != E &&
+               nsToken->TokenText == getNamespaceTokenText(I[i + 1]) &&
                closingLine == I[i + 1]->MatchingOpeningBlockLineIndex &&
                I[i + 1]->Last->TotalLength < Limit;
              i++, closingLine--) {
@@ -245,10 +252,12 @@
         return i;
       }
 
-      if (isEndOfNamespace(TheLine, AnnotatedLines)) {
+      if (auto nsToken = getMatchingNamespaceToken(TheLine, AnnotatedLines)) {
         int i = 0;
         unsigned openingLine = TheLine->MatchingOpeningBlockLineIndex - 1;
-        for (; I + 1 + i != E && isEndOfNamespace(I[i + 1], AnnotatedLines) &&
+        for (; I + 1 + i != E &&
+               nsToken->TokenText ==
+                   getMatchingNamespaceTokenText(I[i + 1], AnnotatedLines) &&
                openingLine == I[i + 1]->MatchingOpeningBlockLineIndex;
              i++, openingLine--) {
           // No space between consecutive braces
@@ -432,6 +441,7 @@
       Tok->CanBreakBefore = true;
       return 1;
     } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
+               !Line.startsWith(TT_NamespaceMacro) &&
                !startsExternCBlock(Line)) {
       // We don't merge short records.
       FormatToken *RecordTok =
@@ -1004,6 +1014,7 @@
   if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
       PreviousLine->Last->is(tok::l_brace) &&
       PreviousLine->First->isNot(tok::kw_namespace) &&
+      PreviousLine->First->isNot(TT_NamespaceMacro) &&
       !startsExternCBlock(*PreviousLine))
     Newlines = 1;
 
Index: lib/Format/TokenAnnotator.cpp
===================================================================
--- lib/Format/TokenAnnotator.cpp
+++ lib/Format/TokenAnnotator.cpp
@@ -925,7 +925,8 @@
                                TT_FunctionLBrace, TT_ImplicitStringLiteral,
                                TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow,
                                TT_OverloadedOperator, TT_RegexLiteral,
-                               TT_TemplateString, TT_ObjCStringLiteral))
+                               TT_TemplateString, TT_ObjCStringLiteral,
+                               TT_NamespaceMacro))
       CurrentToken->Type = TT_Unknown;
     CurrentToken->Role.reset();
     CurrentToken->MatchingParen = nullptr;
Index: lib/Format/NamespaceEndCommentsFixer.cpp
===================================================================
--- lib/Format/NamespaceEndCommentsFixer.cpp
+++ lib/Format/NamespaceEndCommentsFixer.cpp
@@ -34,27 +34,52 @@
                 "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$",
                 llvm::Regex::IgnoreCase);
 
+// Matches a valid namespace end comment.
+// Valid namespace end comments don't need to be edited.
+static llvm::Regex kNamespaceMacroCommentPattern =
+    llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *"
+                "([a-zA-Z0-9_]+)\\(([a-zA-Z0-9:_]*)\\)\\.? *(\\*/)?$",
+                llvm::Regex::IgnoreCase);
+
 // Computes the name of a namespace given the namespace token.
 // Returns "" for anonymous namespace.
 std::string computeName(const FormatToken *NamespaceTok) {
-  assert(NamespaceTok && NamespaceTok->is(tok::kw_namespace) &&
+  assert(NamespaceTok &&
+         NamespaceTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro) &&
          "expecting a namespace token");
   std::string name = "";
-  // Collects all the non-comment tokens between 'namespace' and '{'.
   const FormatToken *Tok = NamespaceTok->getNextNonComment();
-  while (Tok && !Tok->is(tok::l_brace)) {
-    name += Tok->TokenText;
-    Tok = Tok->getNextNonComment();
+  if (NamespaceTok->is(TT_NamespaceMacro)) {
+    // Collects all the non-comment tokens between opening parenthesis
+    // and closing parenthesis or comma
+    assert(Tok && Tok->is(tok::l_paren) && "expected an opening parenthesis");
+    Tok = Tok ? Tok->getNextNonComment() : nullptr;
+    while (Tok && !Tok->isOneOf(tok::r_paren, tok::comma)) {
+      name += Tok->TokenText;
+      Tok = Tok->getNextNonComment();
+    }
+  } else {
+    // Collects all the non-comment tokens between 'namespace' and '{'.
+    while (Tok && !Tok->is(tok::l_brace)) {
+      name += Tok->TokenText;
+      Tok = Tok->getNextNonComment();
+    }
   }
   return name;
 }
 
-std::string computeEndCommentText(StringRef NamespaceName, bool AddNewline) {
-  std::string text = "// namespace";
-  if (!NamespaceName.empty()) {
+std::string computeEndCommentText(StringRef NamespaceName, bool AddNewline,
+                                  const FormatToken *NamespaceTok) {
+  std::string text = "// ";
+  text += NamespaceTok->TokenText;
+  if (NamespaceTok->is(TT_NamespaceMacro))
+    text += "(";
+  else if (!NamespaceName.empty())
     text += ' ';
-    text += NamespaceName;
-  }
+  text += NamespaceName;
+  if (NamespaceTok->is(TT_NamespaceMacro))
+    text += ")";
+  // close brace
   if (AddNewline)
     text += '\n';
   return text;
@@ -64,22 +89,31 @@
   return RBraceTok->Next && RBraceTok->Next->is(tok::comment);
 }
 
-bool validEndComment(const FormatToken *RBraceTok, StringRef NamespaceName) {
+bool validEndComment(const FormatToken *RBraceTok, StringRef NamespaceName,
+                     const FormatToken *NamespaceTok) {
   assert(hasEndComment(RBraceTok));
   const FormatToken *Comment = RBraceTok->Next;
-  SmallVector<StringRef, 7> Groups;
-  if (kNamespaceCommentPattern.match(Comment->TokenText, &Groups)) {
-    StringRef NamespaceNameInComment = Groups.size() > 5 ? Groups[5] : "";
-    // Anonymous namespace comments must not mention a namespace name.
-    if (NamespaceName.empty() && !NamespaceNameInComment.empty())
-      return false;
-    StringRef AnonymousInComment = Groups.size() > 3 ? Groups[3] : "";
-    // Named namespace comments must not mention anonymous namespace.
-    if (!NamespaceName.empty() && !AnonymousInComment.empty())
+  SmallVector<StringRef, 8> Groups;
+  if (NamespaceTok->is(TT_NamespaceMacro) &&
+      kNamespaceMacroCommentPattern.match(Comment->TokenText, &Groups)) {
+    StringRef NamespaceTokenText = Groups.size() > 4 ? Groups[4] : "";
+    // The name of the macro must be used
+    if (NamespaceTokenText != NamespaceTok->TokenText)
       return false;
-    return NamespaceNameInComment == NamespaceName;
+  } else if (NamespaceTok->isNot(tok::kw_namespace) ||
+             !kNamespaceCommentPattern.match(Comment->TokenText, &Groups)) {
+    // Comment does not match regex
+    return false;
   }
-  return false;
+  StringRef NamespaceNameInComment = Groups.size() > 5 ? Groups[5] : "";
+  // Anonymous namespace comments must not mention a namespace name.
+  if (NamespaceName.empty() && !NamespaceNameInComment.empty())
+    return false;
+  StringRef AnonymousInComment = Groups.size() > 3 ? Groups[3] : "";
+  // Named namespace comments must not mention anonymous namespace.
+  if (!NamespaceName.empty() && !AnonymousInComment.empty())
+    return false;
+  return NamespaceNameInComment == NamespaceName;
 }
 
 void addEndComment(const FormatToken *RBraceTok, StringRef EndCommentText,
@@ -109,21 +143,23 @@
 }
 
 const FormatToken *
-getNamespaceToken(const AnnotatedLine *line,
+getNamespaceToken(const AnnotatedLine *Line,
                   const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
-  if (!line->Affected || line->InPPDirective || !line->startsWith(tok::r_brace))
+  if (!Line->Affected || Line->InPPDirective || !Line->startsWith(tok::r_brace))
     return nullptr;
-  size_t StartLineIndex = line->MatchingOpeningBlockLineIndex;
+  size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex;
   if (StartLineIndex == UnwrappedLine::kInvalidIndex)
     return nullptr;
   assert(StartLineIndex < AnnotatedLines.size());
   const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->First;
-  // Detect "(inline)? namespace" in the beginning of a line.
-  if (NamespaceTok->is(tok::kw_inline))
-    NamespaceTok = NamespaceTok->getNextNonComment();
-  if (!NamespaceTok || NamespaceTok->isNot(tok::kw_namespace))
-    return nullptr;
-  return NamespaceTok;
+  return NamespaceTok->getNamespaceToken();
+}
+
+StringRef
+getNamespaceTokenText(const AnnotatedLine *Line,
+                      const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) {
+  const FormatToken *NamespaceTok = getNamespaceToken(Line, AnnotatedLines);
+  return NamespaceTok ? NamespaceTok->TokenText : StringRef();
 }
 } // namespace
 
@@ -140,6 +176,7 @@
   tooling::Replacements Fixes;
   std::string AllNamespaceNames = "";
   size_t StartLineIndex = SIZE_MAX;
+  StringRef NamespaceTokenText;
   unsigned int CompactedNamespacesCount = 0;
   for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) {
     const AnnotatedLine *EndLine = AnnotatedLines[I];
@@ -161,8 +198,11 @@
       StartLineIndex = EndLine->MatchingOpeningBlockLineIndex;
     std::string NamespaceName = computeName(NamespaceTok);
     if (Style.CompactNamespaces) {
+      if (CompactedNamespacesCount == 0)
+        NamespaceTokenText = NamespaceTok->TokenText;
       if ((I + 1 < E) &&
-          getNamespaceToken(AnnotatedLines[I + 1], AnnotatedLines) &&
+          NamespaceTokenText ==
+              getNamespaceTokenText(AnnotatedLines[I + 1], AnnotatedLines) &&
           StartLineIndex - CompactedNamespacesCount - 1 ==
               AnnotatedLines[I + 1]->MatchingOpeningBlockLineIndex &&
           !AnnotatedLines[I + 1]->First->Finalized) {
@@ -190,12 +230,13 @@
                       EndCommentNextTok->NewlinesBefore == 0 &&
                       EndCommentNextTok->isNot(tok::eof);
     const std::string EndCommentText =
-        computeEndCommentText(NamespaceName, AddNewline);
+        computeEndCommentText(NamespaceName, AddNewline, NamespaceTok);
     if (!hasEndComment(EndCommentPrevTok)) {
       bool isShort = I - StartLineIndex <= kShortNamespaceMaxLines + 1;
       if (!isShort)
         addEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
-    } else if (!validEndComment(EndCommentPrevTok, NamespaceName)) {
+    } else if (!validEndComment(EndCommentPrevTok, NamespaceName,
+                                NamespaceTok)) {
       updateEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes);
     }
     StartLineIndex = SIZE_MAX;
Index: lib/Format/FormatTokenLexer.h
===================================================================
--- lib/Format/FormatTokenLexer.h
+++ lib/Format/FormatTokenLexer.h
@@ -97,7 +97,29 @@
   // Index (in 'Tokens') of the last token that starts a new line.
   unsigned FirstInLineIndex;
   SmallVector<FormatToken *, 16> Tokens;
-  SmallVector<IdentifierInfo *, 8> ForEachMacros;
+
+  struct MacroInfo {
+    MacroInfo() : Identifier(NULL), TokType(TT_Unknown) {}
+    MacroInfo(IdentifierInfo *Identifier, TokenType TokType)
+        : Identifier(Identifier), TokType(TokType) {}
+
+    IdentifierInfo *Identifier;
+    TokenType TokType;
+
+    bool operator==(const MacroInfo &Other) const {
+      return Identifier == Other.Identifier;
+    }
+    bool operator==(const IdentifierInfo *Other) const {
+      return Identifier == Other;
+    }
+    bool operator<(const MacroInfo &Other) const {
+      return Identifier < Other.Identifier;
+    }
+    bool operator<(const IdentifierInfo *Other) const {
+      return Identifier < Other;
+    }
+  };
+  SmallVector<MacroInfo, 8> Macros;
 
   bool FormattingDisabled;
 
Index: lib/Format/FormatTokenLexer.cpp
===================================================================
--- lib/Format/FormatTokenLexer.cpp
+++ lib/Format/FormatTokenLexer.cpp
@@ -37,8 +37,12 @@
   Lex->SetKeepWhitespaceMode(true);
 
   for (const std::string &ForEachMacro : Style.ForEachMacros)
-    ForEachMacros.push_back(&IdentTable.get(ForEachMacro));
-  std::sort(ForEachMacros.begin(), ForEachMacros.end());
+    Macros.emplace_back(&IdentTable.get(ForEachMacro), TT_ForEachMacro);
+  for (const std::string &StatementMacro : Style.StatementMacros)
+    Macros.emplace_back(&IdentTable.get(StatementMacro), TT_StatementMacro);
+  for (const std::string &NamespaceMacro : Style.NamespaceMacros)
+    Macros.emplace_back(&IdentTable.get(NamespaceMacro), TT_NamespaceMacro);
+  std::sort(Macros.begin(), Macros.end());
 }
 
 ArrayRef<FormatToken *> FormatTokenLexer::lex() {
@@ -605,12 +609,13 @@
   }
 
   if (Style.isCpp()) {
+    auto it = std::find(Macros.begin(), Macros.end(),
+                        FormatTok->Tok.getIdentifierInfo());
     if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() &&
           Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() ==
               tok::pp_define) &&
-        std::find(ForEachMacros.begin(), ForEachMacros.end(),
-                  FormatTok->Tok.getIdentifierInfo()) != ForEachMacros.end()) {
-      FormatTok->Type = TT_ForEachMacro;
+        it != Macros.end()) {
+      FormatTok->Type = it->TokType;
     } else if (FormatTok->is(tok::identifier)) {
       if (MacroBlockBeginRegex.match(Text)) {
         FormatTok->Type = TT_MacroBlockBegin;
Index: lib/Format/FormatToken.h
===================================================================
--- lib/Format/FormatToken.h
+++ lib/Format/FormatToken.h
@@ -67,6 +67,7 @@
   TYPE(LineComment) \
   TYPE(MacroBlockBegin) \
   TYPE(MacroBlockEnd) \
+  TYPE(NamespaceMacro) \
   TYPE(ObjCBlockLBrace) \
   TYPE(ObjCBlockLParen) \
   TYPE(ObjCDecl) \
@@ -83,6 +84,7 @@
   TYPE(RegexLiteral) \
   TYPE(SelectorName) \
   TYPE(StartOfName) \
+  TYPE(StatementMacro) \
   TYPE(TemplateCloser) \
   TYPE(TemplateOpener) \
   TYPE(TemplateString) \
@@ -475,6 +477,21 @@
     return MatchingParen && MatchingParen->opensBlockOrBlockTypeList(Style);
   }
 
+  /// \brief Return the actual namespace token, if this token starts a namespace
+  /// block.
+  const FormatToken *getNamespaceToken() const {
+    const FormatToken *NamespaceTok = this;
+    if (is(tok::comment))
+      NamespaceTok = NamespaceTok->getNextNonComment();
+    // Detect "(inline)? namespace" in the beginning of a line.
+    if (NamespaceTok && NamespaceTok->is(tok::kw_inline))
+      NamespaceTok = NamespaceTok->getNextNonComment();
+    return NamespaceTok &&
+                   NamespaceTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro)
+               ? NamespaceTok
+               : nullptr;
+  }
+
 private:
   // Disallow copying.
   FormatToken(const FormatToken &) = delete;
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -361,6 +361,7 @@
     IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd);
     IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep);
     IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation);
+    IO.mapOptional("NamespaceMacros", Style.NamespaceMacros);
     IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth);
     IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty);
     IO.mapOptional("ObjCSpaceBeforeProtocolList",
@@ -395,6 +396,7 @@
     IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
     IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
     IO.mapOptional("Standard", Style.Standard);
+    IO.mapOptional("StatementMacros", Style.StatementMacros);
     IO.mapOptional("TabWidth", Style.TabWidth);
     IO.mapOptional("UseTab", Style.UseTab);
   }
@@ -619,6 +621,8 @@
 
   LLVMStyle.DisableFormat = false;
   LLVMStyle.SortIncludes = true;
+  LLVMStyle.StatementMacros.push_back("Q_UNUSED");
+  LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION");
 
   return LLVMStyle;
 }
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -935,6 +935,28 @@
   /// For example: BOOST_FOREACH.
   std::vector<std::string> ForEachMacros;
 
+  /// \brief A vector of macros that should be interpreted as complete
+  /// statements.
+  ///
+  /// Typical macros are expressions, and require a semi-colon to be
+  /// added; sometimes this is not the case, and this allows to make
+  /// clang-format aware of such cases.
+  ///
+  /// For example: Q_UNUSED
+  std::vector<std::string> StatementMacros;
+
+  /// \brief A vector of macros which are used to open namespace blocks.
+  ///
+  /// These are expected to be macros of the form:
+  /// \code
+  ///   NAMESPACE(<namespace-name>, ...) {
+  ///     <namespace-content>
+  ///   }
+  /// \endcode
+  ///
+  /// For example: TESTSUITE
+  std::vector<std::string> NamespaceMacros;
+
   /// \brief See documentation of ``IncludeCategories``.
   struct IncludeCategory {
     /// \brief The regular expression that this category matches.
@@ -1492,11 +1514,11 @@
            MacroBlockEnd == R.MacroBlockEnd &&
            MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
            NamespaceIndentation == R.NamespaceIndentation &&
+           NamespaceMacros == R.NamespaceMacros &&
            ObjCBlockIndentWidth == R.ObjCBlockIndentWidth &&
            ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty &&
            ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList &&
-           PenaltyBreakAssignment ==
-               R.PenaltyBreakAssignment &&
+           PenaltyBreakAssignment == R.PenaltyBreakAssignment &&
            PenaltyBreakBeforeFirstCallParameter ==
                R.PenaltyBreakBeforeFirstCallParameter &&
            PenaltyBreakComment == R.PenaltyBreakComment &&
@@ -1517,7 +1539,7 @@
            SpacesInParentheses == R.SpacesInParentheses &&
            SpacesInSquareBrackets == R.SpacesInSquareBrackets &&
            Standard == R.Standard && TabWidth == R.TabWidth &&
-           UseTab == R.UseTab;
+           StatementMacros == R.StatementMacros && UseTab == R.UseTab;
   }
 };
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to