Index: clang/lib/Format/FormatToken.h =================================================================== --- clang/lib/Format/FormatToken.h +++ clang/lib/Format/FormatToken.h @@ -98,7 +98,9 @@ TYPE(MacroBlockBegin) \ TYPE(MacroBlockEnd) \ TYPE(ModulePartitionColon) \ + TYPE(NamespaceLBrace) \ TYPE(NamespaceMacro) \ + TYPE(NamespaceRBrace) \ TYPE(NonNullAssertion) \ TYPE(NullCoalescingEqual) \ TYPE(NullCoalescingOperator) \ Index: clang/lib/Format/UnwrappedLineParser.cpp =================================================================== --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -2986,10 +2986,16 @@ if (ManageWhitesmithsBraces) ++Line->Level; + FormatToken *LBrace = FormatTok; + LBrace->setFinalizedType(TT_NamespaceLBrace); + parseBlock(/*MustBeDeclaration=*/true, AddLevels, /*MunchSemi=*/true, /*KeepBraces=*/nullptr, /*IfKind=*/nullptr, ManageWhitesmithsBraces); + if (LBrace->MatchingParen) + LBrace->MatchingParen->setFinalizedType(TT_NamespaceRBrace); + // Munch the semicolon after a namespace. This is more common than one would // think. Putting the semicolon into its own line is very ugly. if (FormatTok->is(tok::semi)) Index: clang/lib/Format/WhitespaceManager.cpp =================================================================== --- clang/lib/Format/WhitespaceManager.cpp +++ clang/lib/Format/WhitespaceManager.cpp @@ -985,11 +985,10 @@ if (i + 1 != e && Changes[i + 1].ContinuesPPDirective) ChangeMaxColumn -= 2; - // If this comment follows an } in column 0, it probably documents the - // closing of a namespace and we don't want to align it. - bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 && - Changes[i - 1].Tok->is(tok::r_brace) && - Changes[i - 1].StartOfTokenColumn == 0; + + // We don't want to align namespace end comments. + bool DontAlignThisComment = + i > 0 && Changes[i - 1].Tok->is(TT_NamespaceRBrace); bool WasAlignedWithStartOfNextLine = false; if (Changes[i].NewlinesBefore >= 1) { // A comment on its own line. unsigned CommentColumn = SourceMgr.getSpellingColumnNumber( @@ -1009,7 +1008,7 @@ } } if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Never || - FollowsRBraceInColumn0) { + DontAlignThisComment) { alignTrailingComments(StartOfSequence, i, MinColumn); MinColumn = ChangeMinColumn; MaxColumn = ChangeMinColumn; Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -19221,7 +19221,7 @@ " int x;\n" " };\n" " } // namespace b\n" - " } // namespace a", + " } // namespace a", WhitesmithsBraceStyle); verifyFormat("void f()\n" Index: clang/unittests/Format/FormatTestComments.cpp =================================================================== --- clang/unittests/Format/FormatTestComments.cpp +++ clang/unittests/Format/FormatTestComments.cpp @@ -68,6 +68,20 @@ EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); } + void verifyFormat(llvm::StringRef Expected, llvm::StringRef Code, + const FormatStyle &Style = getLLVMStyle()) { + EXPECT_EQ(Expected.str(), format(Expected, Style)) + << "Expected code is not stable"; + EXPECT_EQ(Expected.str(), format(test::messUp(Code), Style)); + } + + void verifyFormatWithoutMessUp(llvm::StringRef Expected, llvm::StringRef Code, + const FormatStyle &Style = getLLVMStyle()) { + EXPECT_EQ(Expected.str(), format(Expected, Style)) + << "Expected code is not stable"; + EXPECT_EQ(Expected.str(), format(Code, Style)); + } + void verifyGoogleFormat(llvm::StringRef Code) { verifyFormat(Code, getGoogleStyle()); } @@ -3076,6 +3090,55 @@ Style)); } +TEST_F(FormatTestComments, DontAlignNamespaceComments) { + FormatStyle Style = getLLVMStyle(); + Style.NamespaceIndentation = FormatStyle::NI_All; + Style.NamespaceMacros.push_back("TESTSUITE"); + Style.ShortNamespaceLines = 0; + + llvm::StringRef Input = "namespace A {\n" + " TESTSUITE(B) {\n" + " namespace C {\n" + " namespace D {} // namespace D\n" + " std::string Foo = Bar; // Comment\n" + " } // namespace C\n" + " }\n" + "} // NaMeSpAcE A"; + + EXPECT_EQ(Style.AlignTrailingComments.Kind, FormatStyle::TCAS_Always); + verifyFormat("namespace A {\n" + " TESTSUITE(B) {\n" + " namespace C {\n" + " namespace D {} // namespace D\n" + " std::string Foo = Bar; // Comment\n" + " } // namespace C\n" + " } // TESTSUITE(B)\n" + "} // NaMeSpAcE A", + Input, Style); + + Style.AlignTrailingComments.Kind = FormatStyle::TCAS_Never; + verifyFormat("namespace A {\n" + " TESTSUITE(B) {\n" + " namespace C {\n" + " namespace D {} // namespace D\n" + " std::string Foo = Bar; // Comment\n" + " } // namespace C\n" + " } // TESTSUITE(B)\n" + "} // NaMeSpAcE A", + Input, Style); + + Style.AlignTrailingComments.Kind = FormatStyle::TCAS_Leave; + verifyFormatWithoutMessUp("namespace A {\n" + " TESTSUITE(B) {\n" + " namespace C {\n" + " namespace D {} // namespace D\n" + " std::string Foo = Bar; // Comment\n" + " } // namespace C\n" + " }// TESTSUITE(B)\n" + "} // NaMeSpAcE A", + Input, Style); +} + TEST_F(FormatTestComments, AlignsBlockCommentDecorations) { EXPECT_EQ("/*\n" " */",