Index: cfe/trunk/docs/ClangFormatStyleOptions.rst =================================================================== --- cfe/trunk/docs/ClangFormatStyleOptions.rst +++ cfe/trunk/docs/ClangFormatStyleOptions.rst @@ -1782,6 +1782,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: cfe/trunk/include/clang/Format/Format.h =================================================================== --- cfe/trunk/include/clang/Format/Format.h +++ cfe/trunk/include/clang/Format/Format.h @@ -1195,6 +1195,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. @@ -1942,6 +1954,7 @@ MacroBlockEnd == R.MacroBlockEnd && MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep && NamespaceIndentation == R.NamespaceIndentation && + NamespaceMacros == R.NamespaceMacros && ObjCBinPackProtocolList == R.ObjCBinPackProtocolList && ObjCBlockIndentWidth == R.ObjCBlockIndentWidth && ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty && Index: cfe/trunk/lib/Format/Format.cpp =================================================================== --- cfe/trunk/lib/Format/Format.cpp +++ cfe/trunk/lib/Format/Format.cpp @@ -455,6 +455,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: cfe/trunk/lib/Format/FormatToken.h =================================================================== --- cfe/trunk/lib/Format/FormatToken.h +++ cfe/trunk/lib/Format/FormatToken.h @@ -71,6 +71,7 @@ TYPE(LineComment) \ TYPE(MacroBlockBegin) \ TYPE(MacroBlockEnd) \ + TYPE(NamespaceMacro) \ TYPE(ObjCBlockLBrace) \ TYPE(ObjCBlockLParen) \ TYPE(ObjCDecl) \ @@ -531,8 +532,10 @@ // 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; + return NamespaceTok && + NamespaceTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro) + ? NamespaceTok + : nullptr; } private: Index: cfe/trunk/lib/Format/FormatTokenLexer.cpp =================================================================== --- cfe/trunk/lib/Format/FormatTokenLexer.cpp +++ cfe/trunk/lib/Format/FormatTokenLexer.cpp @@ -41,6 +41,8 @@ Macros.insert({&IdentTable.get(StatementMacro), TT_StatementMacro}); for (const std::string &TypenameMacro : Style.TypenameMacros) Macros.insert({&IdentTable.get(TypenameMacro), TT_TypenameMacro}); + for (const std::string &NamespaceMacro : Style.NamespaceMacros) + Macros.insert({&IdentTable.get(NamespaceMacro), TT_NamespaceMacro}); } ArrayRef FormatTokenLexer::lex() { Index: cfe/trunk/lib/Format/NamespaceEndCommentsFixer.cpp =================================================================== --- cfe/trunk/lib/Format/NamespaceEndCommentsFixer.cpp +++ cfe/trunk/lib/Format/NamespaceEndCommentsFixer.cpp @@ -29,24 +29,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; @@ -56,7 +73,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; @@ -66,19 +84,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; - } - return false; + } else if (NamespaceTok->isNot(tok::kw_namespace) || + !NamespaceCommentPattern->match(Comment->TokenText, &Groups)) { + // Comment does not match regex. + 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, @@ -127,6 +158,13 @@ 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, const FormatStyle &Style) : TokenAnalyzer(Env, Style) {} @@ -139,6 +177,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]; @@ -160,8 +199,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) { @@ -189,12 +231,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: cfe/trunk/lib/Format/TokenAnnotator.h =================================================================== --- cfe/trunk/lib/Format/TokenAnnotator.h +++ cfe/trunk/lib/Format/TokenAnnotator.h @@ -115,6 +115,7 @@ /// \c true if this line starts a namespace definition. bool startsWithNamespace() const { return startsWith(tok::kw_namespace) || + startsWith(TT_NamespaceMacro) || startsWith(tok::kw_inline, tok::kw_namespace) || startsWith(tok::kw_export, tok::kw_namespace); } Index: cfe/trunk/lib/Format/TokenAnnotator.cpp =================================================================== --- cfe/trunk/lib/Format/TokenAnnotator.cpp +++ cfe/trunk/lib/Format/TokenAnnotator.cpp @@ -1194,12 +1194,12 @@ // Reset token type in case we have already looked at it and then // recovered from an error (e.g. failure to find the matching >). - if (!CurrentToken->isOneOf(TT_LambdaLSquare, TT_LambdaLBrace, - TT_ForEachMacro, TT_TypenameMacro, - TT_FunctionLBrace, TT_ImplicitStringLiteral, - TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, - TT_OverloadedOperator, TT_RegexLiteral, - TT_TemplateString, TT_ObjCStringLiteral)) + if (!CurrentToken->isOneOf( + TT_LambdaLSquare, TT_LambdaLBrace, TT_ForEachMacro, + TT_TypenameMacro, TT_FunctionLBrace, TT_ImplicitStringLiteral, + TT_InlineASMBrace, TT_JsFatArrow, TT_LambdaArrow, TT_NamespaceMacro, + TT_OverloadedOperator, TT_RegexLiteral, TT_TemplateString, + TT_ObjCStringLiteral)) CurrentToken->Type = TT_Unknown; CurrentToken->Role.reset(); CurrentToken->MatchingParen = nullptr; Index: cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp =================================================================== --- cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp +++ cfe/trunk/lib/Format/UnwrappedLineFormatter.cpp @@ -134,20 +134,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 { @@ -249,10 +258,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--) { @@ -264,10 +274,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 Index: cfe/trunk/lib/Format/UnwrappedLineParser.cpp =================================================================== --- cfe/trunk/lib/Format/UnwrappedLineParser.cpp +++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp @@ -630,7 +630,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; @@ -1122,6 +1122,10 @@ parseStatementMacro(); return; } + if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) { + parseNamespace(); + return; + } // In all other cases, parse the declaration. break; default: @@ -1860,12 +1864,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: cfe/trunk/unittests/Format/FormatTest.cpp =================================================================== --- cfe/trunk/unittests/Format/FormatTest.cpp +++ cfe/trunk/unittests/Format/FormatTest.cpp @@ -1870,9 +1870,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", @@ -11700,6 +11808,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: cfe/trunk/unittests/Format/NamespaceEndCommentsFixerTest.cpp =================================================================== --- cfe/trunk/unittests/Format/NamespaceEndCommentsFixerTest.cpp +++ cfe/trunk/unittests/Format/NamespaceEndCommentsFixerTest.cpp @@ -52,6 +52,7 @@ "int i;\n" "int j;\n" "}")); + EXPECT_EQ("namespace {\n" "int i;\n" "int j;\n" @@ -248,6 +249,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" @@ -380,6 +460,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" @@ -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"