Index: docs/ClangFormatStyleOptions.rst =================================================================== --- docs/ClangFormatStyleOptions.rst +++ docs/ClangFormatStyleOptions.rst @@ -1545,6 +1545,19 @@ +**NamespaceMacros** (``std::vector``) + A vector of macros which are used to open namespace blocks. + + These are expected to be macros of the form: + + .. code-block:: c++ + + NAMESPACE(, ...) { + + } + + For example: TESTSUITE + **ObjCBinPackProtocolList** (``BinPackStyle``) Controls bin-packing Objective-C protocol conformance list items into as few lines as possible when they go over ``ColumnLimit``. Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -1040,6 +1040,18 @@ /// For example: Q_UNUSED std::vector StatementMacros; + /// A vector of macros which are used to open namespace blocks. + /// + /// These are expected to be macros of the form: + /// \code + /// NAMESPACE(, ...) { + /// + /// } + /// \endcode + /// + /// For example: TESTSUITE + std::vector NamespaceMacros; + tooling::IncludeStyle IncludeStyle; /// Indent case labels one level from the switch statement. @@ -1710,6 +1722,7 @@ MacroBlockEnd == R.MacroBlockEnd && MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep && NamespaceIndentation == R.NamespaceIndentation && + NamespaceMacros == R.NamespaceMacros && ObjCBinPackProtocolList == R.ObjCBinPackProtocolList && ObjCBlockIndentWidth == R.ObjCBlockIndentWidth && ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty && Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -401,6 +401,7 @@ IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd); IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep); IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation); + IO.mapOptional("NamespaceMacros", Style.NamespaceMacros); IO.mapOptional("ObjCBinPackProtocolList", Style.ObjCBinPackProtocolList); IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth); IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty); Index: lib/Format/FormatToken.h =================================================================== --- lib/Format/FormatToken.h +++ lib/Format/FormatToken.h @@ -70,6 +70,7 @@ TYPE(LineComment) \ TYPE(MacroBlockBegin) \ TYPE(MacroBlockEnd) \ + TYPE(NamespaceMacro) \ TYPE(ObjCBlockLBrace) \ TYPE(ObjCBlockLParen) \ TYPE(ObjCDecl) \ @@ -518,8 +519,10 @@ // Detect "(inline)? namespace" in the beginning of a line. if (NamespaceTok && NamespaceTok->is(tok::kw_inline)) NamespaceTok = NamespaceTok->getNextNonComment(); - return NamespaceTok && NamespaceTok->is(tok::kw_namespace) ? NamespaceTok - : nullptr; + return NamespaceTok && + NamespaceTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro) + ? NamespaceTok + : nullptr; } private: Index: lib/Format/FormatTokenLexer.cpp =================================================================== --- lib/Format/FormatTokenLexer.cpp +++ lib/Format/FormatTokenLexer.cpp @@ -40,6 +40,8 @@ Macros.insert({&IdentTable.get(ForEachMacro), TT_ForEachMacro}); for (const std::string &StatementMacro : Style.StatementMacros) Macros.insert({&IdentTable.get(StatementMacro), TT_StatementMacro}); + for (const std::string &NamespaceMacro : Style.NamespaceMacros) + Macros.insert({&IdentTable.get(NamespaceMacro), TT_NamespaceMacro}); } ArrayRef FormatTokenLexer::lex() { Index: lib/Format/NamespaceEndCommentsFixer.cpp =================================================================== --- lib/Format/NamespaceEndCommentsFixer.cpp +++ lib/Format/NamespaceEndCommentsFixer.cpp @@ -30,24 +30,41 @@ // 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; + 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->getNextNonComment(); + 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 += ")"; if (AddNewline) text += '\n'; return text; @@ -57,7 +74,8 @@ 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; @@ -67,19 +85,32 @@ new llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$", llvm::Regex::IgnoreCase); - SmallVector Groups; - if (NamespaceCommentPattern->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()) + static llvm::Regex *const NamespaceMacroCommentPattern = + new llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" + "([a-zA-Z0-9_]+)\\(([a-zA-Z0-9:_]*)\\)\\.? *(\\*/)?$", + llvm::Regex::IgnoreCase); + + SmallVector Groups; + if (NamespaceTok->is(TT_NamespaceMacro) && + NamespaceMacroCommentPattern->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) || + !NamespaceCommentPattern->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, @@ -125,12 +156,14 @@ 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(); +} + +StringRef +getNamespaceTokenText(const AnnotatedLine *Line, + const SmallVectorImpl &AnnotatedLines) { + const FormatToken *NamespaceTok = getNamespaceToken(Line, AnnotatedLines); + return NamespaceTok ? NamespaceTok->TokenText : StringRef(); } NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env, @@ -145,6 +178,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]; @@ -166,8 +200,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) { @@ -195,12 +232,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/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -1112,7 +1112,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/UnwrappedLineFormatter.cpp =================================================================== --- lib/Format/UnwrappedLineFormatter.cpp +++ lib/Format/UnwrappedLineFormatter.cpp @@ -135,20 +135,29 @@ unsigned Indent = 0; }; -bool isNamespaceDeclaration(const AnnotatedLine *Line) { - const FormatToken *NamespaceTok = Line->First; - return NamespaceTok && NamespaceTok->getNamespaceToken(); -} - -bool isEndOfNamespace(const AnnotatedLine *Line, - const SmallVectorImpl &AnnotatedLines) { +const FormatToken *getMatchingNamespaceToken( + const AnnotatedLine *Line, + const SmallVectorImpl &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 &AnnotatedLines) { + const FormatToken *NamespaceToken = + getMatchingNamespaceToken(Line, AnnotatedLines); + return NamespaceToken ? NamespaceToken->TokenText : StringRef(); } class LineJoiner { @@ -250,10 +259,11 @@ TheLine->Level != 0); if (Style.CompactNamespaces) { - if (isNamespaceDeclaration(TheLine)) { + if (auto nsToken = TheLine->First->getNamespaceToken()) { int i = 0; unsigned closingLine = TheLine->MatchingClosingBlockLineIndex - 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]->MatchingClosingBlockLineIndex && I[i + 1]->Last->TotalLength < Limit; i++, closingLine--) { @@ -265,10 +275,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 @@ -530,6 +542,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 = Line.First; @@ -1155,6 +1168,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/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -618,7 +618,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; @@ -1106,6 +1106,10 @@ parseStatementMacro(); return; } + if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) { + parseNamespace(); + return; + } // In all other cases, parse the declaration. break; default: @@ -1790,12 +1794,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: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -1621,9 +1621,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", @@ -10773,6 +10881,12 @@ CHECK_PARSE("StatementMacros: [QUNUSED, QT_REQUIRE_VERSION]", StatementMacros, std::vector({"QUNUSED", "QT_REQUIRE_VERSION"})); + Style.NamespaceMacros.clear(); + CHECK_PARSE("NamespaceMacros: [TESTSUITE]", NamespaceMacros, + std::vector{"TESTSUITE"}); + CHECK_PARSE("NamespaceMacros: [TESTSUITE, SUITE]", NamespaceMacros, + std::vector({"TESTSUITE", "SUITE"})); + Style.IncludeStyle.IncludeCategories.clear(); std::vector ExpectedCategories = { {"abc/.*", 2}, {".*", 1}}; 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"