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 && 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: 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: 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: 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"