Typz created this revision.
Herald added a subscriber: klimek.

This option allows cleaning up namespace declaration, by removing the
extra semicolon after namespace closing brace.


https://reviews.llvm.org/D33314

Files:
  include/clang/Format/Format.h
  lib/Format/Format.cpp
  lib/Format/NamespaceEndCommentsFixer.cpp
  unittests/Format/FormatTest.cpp
  unittests/Format/NamespaceEndCommentsFixerTest.cpp

Index: unittests/Format/NamespaceEndCommentsFixerTest.cpp
===================================================================
--- unittests/Format/NamespaceEndCommentsFixerTest.cpp
+++ unittests/Format/NamespaceEndCommentsFixerTest.cpp
@@ -214,6 +214,51 @@
                                     "// unrelated"));
 }
 
+TEST_F(NamespaceEndCommentsFixerTest, RemoveSemicolon) {
+  FormatStyle LLVMStyleWithoutSemicolon = getLLVMStyle();
+  LLVMStyleWithoutSemicolon.AllowSemicolonAfterNamespace = false;
+
+  EXPECT_EQ("namespace {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// namespace",
+            fixNamespaceEndComments("namespace {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "};",
+                                    LLVMStyleWithoutSemicolon));
+  EXPECT_EQ("namespace A {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// namespace A",
+            fixNamespaceEndComments("namespace A {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "};",
+                                    LLVMStyleWithoutSemicolon));
+  EXPECT_EQ("namespace A {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// namespace A\n"
+            "// unrelated",
+            fixNamespaceEndComments("namespace A {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "};\n"
+                                    "// unrelated",
+                                    LLVMStyleWithoutSemicolon));
+  // case without semicolon is not affected
+  EXPECT_EQ("namespace A {\n"
+            "  int i;\n"
+            "  int j;\n"
+            "}// namespace A",
+            fixNamespaceEndComments("namespace A {\n"
+                                    "  int i;\n"
+                                    "  int j;\n"
+                                    "}",
+                                    LLVMStyleWithoutSemicolon));
+}
+
 TEST_F(NamespaceEndCommentsFixerTest, AddsNewlineIfNeeded) {
   EXPECT_EQ("namespace A {\n"
             "  int i;\n"
Index: unittests/Format/FormatTest.cpp
===================================================================
--- unittests/Format/FormatTest.cpp
+++ unittests/Format/FormatTest.cpp
@@ -8670,6 +8670,7 @@
   CHECK_PARSE_BOOL(AlignConsecutiveAssignments);
   CHECK_PARSE_BOOL(AlignConsecutiveDeclarations);
   CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);
+  CHECK_PARSE_BOOL(AllowSemicolonAfterNamespace);
   CHECK_PARSE_BOOL(AllowShortBlocksOnASingleLine);
   CHECK_PARSE_BOOL(AllowShortCaseLabelsOnASingleLine);
   CHECK_PARSE_BOOL(AllowShortIfStatementsOnASingleLine);
Index: lib/Format/NamespaceEndCommentsFixer.cpp
===================================================================
--- lib/Format/NamespaceEndCommentsFixer.cpp
+++ lib/Format/NamespaceEndCommentsFixer.cpp
@@ -107,6 +107,19 @@
                  << llvm::toString(std::move(Err)) << "\n";
   }
 }
+
+void removeTrailingSemicolon(const FormatToken *SemiColonTok,
+                             const SourceManager &SourceMgr,
+                             tooling::Replacements *Fixes) {
+  assert(SemiColonTok->is(tok::semi));
+  auto Range = CharSourceRange::getCharRange(SemiColonTok->Tok.getLocation(),
+                                             SemiColonTok->Tok.getEndLoc());
+  auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, StringRef()));
+  if (Err) {
+    llvm::errs() << "Error while removing trailing semicolon at end of namespace: "
+                 << llvm::toString(std::move(Err)) << "\n";
+  }
+}
 } // namespace
 
 NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env,
@@ -144,6 +157,8 @@
     // comments to the semicolon tokens.
     if (RBraceTok->Next && RBraceTok->Next->is(tok::semi)) {
       EndCommentPrevTok = RBraceTok->Next;
+      if (!Style.AllowSemicolonAfterNamespace)
+        removeTrailingSemicolon(RBraceTok->Next, SourceMgr, &Fixes);
     }
     // The next token in the token stream after the place where the end comment
     // token must be. This is either the next token on the current line or the
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -252,6 +252,7 @@
     IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
     IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
                    Style.AllowAllParametersOfDeclarationOnNextLine);
+    IO.mapOptional("AllowSemicolonAfterNamespace", Style.AllowSemicolonAfterNamespace);
     IO.mapOptional("AllowShortBlocksOnASingleLine",
                    Style.AllowShortBlocksOnASingleLine);
     IO.mapOptional("AllowShortCaseLabelsOnASingleLine",
@@ -505,6 +506,7 @@
   LLVMStyle.AlignConsecutiveAssignments = false;
   LLVMStyle.AlignConsecutiveDeclarations = false;
   LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
+  LLVMStyle.AllowSemicolonAfterNamespace = true;
   LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
   LLVMStyle.AllowShortBlocksOnASingleLine = false;
   LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -144,6 +144,14 @@
   /// \endcode
   bool AllowAllParametersOfDeclarationOnNextLine;
 
+  /// \brief If ``true``, clang-format removes semicolon at the end of namespace.
+  /// \code
+  ///    true:                                  false:
+  ///    namespace a {                  vs.     namespace a {
+  ///    }                                      };
+  /// \endcode
+  bool AllowSemicolonAfterNamespace;
+
   /// \brief Allows contracting simple braced statements to a single line.
   ///
   /// E.g., this allows ``if (a) { return; }`` to be put on a single line.
@@ -1352,6 +1360,7 @@
            AlignTrailingComments == R.AlignTrailingComments &&
            AllowAllParametersOfDeclarationOnNextLine ==
                R.AllowAllParametersOfDeclarationOnNextLine &&
+           AllowSemicolonAfterNamespace == R.AllowSemicolonAfterNamespace &&
            AllowShortBlocksOnASingleLine == R.AllowShortBlocksOnASingleLine &&
            AllowShortCaseLabelsOnASingleLine ==
                R.AllowShortCaseLabelsOnASingleLine &&
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to