]> granicus.if.org Git - clang/commitdiff
clang-format: Fix formatting C++ namespaces with preceding 'inline' or 'export' specifier
authorSam McCall <sam.mccall@gmail.com>
Wed, 5 Sep 2018 07:44:02 +0000 (07:44 +0000)
committerSam McCall <sam.mccall@gmail.com>
Wed, 5 Sep 2018 07:44:02 +0000 (07:44 +0000)
This fixes formatting namespaces with preceding 'inline' and 'export' (Modules TS) specifiers.

This change fixes namespaces not being identified as such with preceding 'inline' or 'export' specifiers.

Motivation: I was experimenting with the Modules TS (-fmodules-ts) and found it would be useful if clang-format would correctly format 'export namespace'. While making the changes, I noticed that similar issues still exist with 'inline namespace', and addressed them as well.

Patch by Marco Elver!

Reviewers: klimek, djasper, owenpan, sammccall

Reviewed By: owenpan, sammccall

Subscribers: owenpan, cfe-commits

Differential Revision: https://reviews.llvm.org/D51036

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@341450 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Format/Format.cpp
lib/Format/FormatToken.h
lib/Format/NamespaceEndCommentsFixer.cpp
lib/Format/TokenAnnotator.h
lib/Format/UnwrappedLineFormatter.cpp
lib/Format/UnwrappedLineParser.cpp
unittests/Format/FormatTest.cpp

index 4a67cdeedf35692e59186e9e149e0a574731ecf3..0637f76f07c0bd901ae4290e1180f5dc4d012d07 100644 (file)
@@ -1309,8 +1309,7 @@ private:
     std::set<unsigned> DeletedLines;
     for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
       auto &Line = *AnnotatedLines[i];
-      if (Line.startsWith(tok::kw_namespace) ||
-          Line.startsWith(tok::kw_inline, tok::kw_namespace)) {
+      if (Line.startsWithNamespace()) {
         checkEmptyNamespace(AnnotatedLines, i, i, DeletedLines);
       }
     }
@@ -1347,9 +1346,7 @@ private:
       if (AnnotatedLines[CurrentLine]->startsWith(tok::r_brace))
         break;
 
-      if (AnnotatedLines[CurrentLine]->startsWith(tok::kw_namespace) ||
-          AnnotatedLines[CurrentLine]->startsWith(tok::kw_inline,
-                                                  tok::kw_namespace)) {
+      if (AnnotatedLines[CurrentLine]->startsWithNamespace()) {
         if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine,
                                  DeletedLines))
           return false;
index 9094e7689e1ded736d4c4b20654b82c65241bbf5..d9bff0112ccd92e5e62d976a64b02d73a8154bb4 100644 (file)
@@ -520,8 +520,8 @@ struct FormatToken {
     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))
+    // Detect "(inline|export)? namespace" in the beginning of a line.
+    if (NamespaceTok && NamespaceTok->isOneOf(tok::kw_inline, tok::kw_export))
       NamespaceTok = NamespaceTok->getNextNonComment();
     return NamespaceTok && NamespaceTok->is(tok::kw_namespace) ? NamespaceTok
                                                                : nullptr;
index 995b3219a1f4a291a8ad6f5a8e959323c1c28661..dd364866d1ceb4f2ba8dd3319b52b6ce716565ca 100644 (file)
@@ -125,12 +125,7 @@ getNamespaceToken(const AnnotatedLine *Line,
     if (StartLineIndex > 0)
       NamespaceTok = AnnotatedLines[StartLineIndex - 1]->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();
 }
 
 NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env,
index a3124fcb3d65bc15e66e51d538e41663097b3e46..e2f2c469d26756ea6066b17a00012a046d76bff4 100644 (file)
@@ -105,6 +105,13 @@ public:
     return !Last->isOneOf(tok::semi, tok::comment);
   }
 
+  /// \c true if this line starts a namespace definition.
+  bool startsWithNamespace() const {
+    return startsWith(tok::kw_namespace) ||
+           startsWith(tok::kw_inline, tok::kw_namespace) ||
+           startsWith(tok::kw_export, tok::kw_namespace);
+  }
+
   FormatToken *First;
   FormatToken *Last;
 
index 1b7daf67d90bb0107cd50445802603f9ab736190..f0d93a1f4f3b945c490599a8bdb95bc59fe25c8b 100644 (file)
@@ -535,7 +535,7 @@ private:
         Tok->SpacesRequiredBefore = 0;
         Tok->CanBreakBefore = true;
         return 1;
-      } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
+      } else if (Limit != 0 && !Line.startsWithNamespace() &&
                  !startsExternCBlock(Line)) {
         // We don't merge short records.
         FormatToken *RecordTok = Line.First;
@@ -1160,7 +1160,7 @@ void UnwrappedLineFormatter::formatFirstToken(
   // Remove empty lines after "{".
   if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
       PreviousLine->Last->is(tok::l_brace) &&
-      PreviousLine->First->isNot(tok::kw_namespace) &&
+      !PreviousLine->startsWithNamespace() &&
       !startsExternCBlock(*PreviousLine))
     Newlines = 1;
 
index 07109daf6f9526eabc29851349c5d564832415fe..752357c1affb39100e7fae8d77361f678765f882 100644 (file)
@@ -992,13 +992,6 @@ void UnwrappedLineParser::parseStructuralElement() {
   case tok::kw_namespace:
     parseNamespace();
     return;
-  case tok::kw_inline:
-    nextToken();
-    if (FormatTok->Tok.is(tok::kw_namespace)) {
-      parseNamespace();
-      return;
-    }
-    break;
   case tok::kw_public:
   case tok::kw_protected:
   case tok::kw_private:
@@ -1066,6 +1059,16 @@ void UnwrappedLineParser::parseStructuralElement() {
       parseJavaScriptEs6ImportExport();
       return;
     }
+    if (!Style.isCpp())
+      break;
+    // Handle C++ "(inline|export) namespace".
+    LLVM_FALLTHROUGH;
+  case tok::kw_inline:
+    nextToken();
+    if (FormatTok->Tok.is(tok::kw_namespace)) {
+      parseNamespace();
+      return;
+    }
     break;
   case tok::identifier:
     if (FormatTok->is(TT_ForEachMacro)) {
index 3dd9fc00f68f42b174088ba68829077fefd5c61a..e7c467547a12a7e1f16bf13e432dd962116613ff 100644 (file)
@@ -200,6 +200,42 @@ TEST_F(FormatTest, RemovesEmptyLines) {
                    "int    i;\n"
                    "}",
                    getGoogleStyle()));
+  EXPECT_EQ("/* something */ namespace N {\n"
+            "\n"
+            "int i;\n"
+            "}",
+            format("/* something */ namespace N {\n"
+                   "\n"
+                   "int    i;\n"
+                   "}",
+                   getGoogleStyle()));
+  EXPECT_EQ("inline namespace N {\n"
+            "\n"
+            "int i;\n"
+            "}",
+            format("inline namespace N {\n"
+                   "\n"
+                   "int    i;\n"
+                   "}",
+                   getGoogleStyle()));
+  EXPECT_EQ("/* something */ inline namespace N {\n"
+            "\n"
+            "int i;\n"
+            "}",
+            format("/* something */ inline namespace N {\n"
+                   "\n"
+                   "int    i;\n"
+                   "}",
+                   getGoogleStyle()));
+  EXPECT_EQ("export namespace N {\n"
+            "\n"
+            "int i;\n"
+            "}",
+            format("export namespace N {\n"
+                   "\n"
+                   "int    i;\n"
+                   "}",
+                   getGoogleStyle()));
   EXPECT_EQ("extern /**/ \"C\" /**/ {\n"
             "\n"
             "int i;\n"
@@ -1220,12 +1256,25 @@ TEST_F(FormatTest, UnderstandsAccessSpecifiers) {
                "private:\n"
                "  void f() {}\n"
                "};");
+  verifyFormat("export class A {\n"
+               "public:\n"
+               "public: // comment\n"
+               "protected:\n"
+               "private:\n"
+               "  void f() {}\n"
+               "};");
   verifyGoogleFormat("class A {\n"
                      " public:\n"
                      " protected:\n"
                      " private:\n"
                      "  void f() {}\n"
                      "};");
+  verifyGoogleFormat("export class A {\n"
+                     " public:\n"
+                     " protected:\n"
+                     " private:\n"
+                     "  void f() {}\n"
+                     "};");
   verifyFormat("class A {\n"
                "public slots:\n"
                "  void f1() {}\n"
@@ -1597,16 +1646,36 @@ TEST_F(FormatTest, FormatsNamespaces) {
                "void f() { f(); }\n"
                "}",
                LLVMWithNoNamespaceFix);
+  verifyFormat("/* something */ namespace some_namespace {\n"
+               "class A {};\n"
+               "void f() { f(); }\n"
+               "}",
+               LLVMWithNoNamespaceFix);
   verifyFormat("namespace {\n"
                "class A {};\n"
                "void f() { f(); }\n"
                "}",
                LLVMWithNoNamespaceFix);
+  verifyFormat("/* something */ namespace {\n"
+               "class A {};\n"
+               "void f() { f(); }\n"
+               "}",
+               LLVMWithNoNamespaceFix);
   verifyFormat("inline namespace X {\n"
                "class A {};\n"
                "void f() { f(); }\n"
                "}",
                LLVMWithNoNamespaceFix);
+  verifyFormat("/* something */ inline namespace X {\n"
+               "class A {};\n"
+               "void f() { f(); }\n"
+               "}",
+               LLVMWithNoNamespaceFix);
+  verifyFormat("export namespace X {\n"
+               "class A {};\n"
+               "void f() { f(); }\n"
+               "}",
+               LLVMWithNoNamespaceFix);
   verifyFormat("using namespace some_namespace;\n"
                "class A {};\n"
                "void f() { f(); }",
@@ -7602,6 +7671,12 @@ TEST_F(FormatTest, SplitEmptyNamespace) {
   verifyFormat("inline namespace Foo\n"
                "{};",
                Style);
+  verifyFormat("/* something */ inline namespace Foo\n"
+               "{};",
+               Style);
+  verifyFormat("export namespace Foo\n"
+               "{};",
+               Style);
   verifyFormat("namespace Foo\n"
                "{\n"
                "void Bar();\n"