Typz created this revision. Other macros are used to declare namespaces, and should thus be handled similarly. This is the case for crpcut's TESTSUITE macro, or for unittest-cpp's SUITE macro:
TESTSUITE(Foo) { TEST(MyFirstTest) { assert(0); } } // TESTSUITE(Foo) This patch deals with this cases by introducing a new option to specify lists of namespace macros. Internally, it re-uses the system already in place for foreach and statement macros, to ensure there is no impact on performance. https://reviews.llvm.org/D37813 Files: include/clang/Format/Format.h lib/Format/Format.cpp lib/Format/FormatToken.h lib/Format/FormatTokenLexer.cpp lib/Format/NamespaceEndCommentsFixer.cpp lib/Format/TokenAnnotator.cpp lib/Format/UnwrappedLineFormatter.cpp lib/Format/UnwrappedLineParser.cpp unittests/Format/FormatTest.cpp unittests/Format/NamespaceEndCommentsFixerTest.cpp
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" Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -1569,9 +1569,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", @@ -10211,6 +10319,12 @@ CHECK_PARSE("StatementMacros: [QUNUSED, QT_REQUIRE_VERSION]", StatementMacros, std::vector<std::string>({"QUNUSED", "QT_REQUIRE_VERSION"})); + Style.NamespaceMacros.clear(); + CHECK_PARSE("NamespaceMacros: [TESTSUITE]", NamespaceMacros, + std::vector<std::string>{"TESTSUITE"}); + CHECK_PARSE("NamespaceMacros: [TESTSUITE, SUITE]", NamespaceMacros, + std::vector<std::string>({"TESTSUITE", "SUITE"})); + Style.IncludeCategories.clear(); std::vector<FormatStyle::IncludeCategory> ExpectedCategories = {{"abc/.*", 2}, {".*", 1}}; Index: lib/Format/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -576,7 +576,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; @@ -1098,6 +1098,10 @@ addUnwrappedLine(); return; } + if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) { + parseNamespace(); + return; + } // In all other cases, parse the declaration. break; default: @@ -1761,12 +1765,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: lib/Format/UnwrappedLineFormatter.cpp =================================================================== --- lib/Format/UnwrappedLineFormatter.cpp +++ 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<AnnotatedLine *> &AnnotatedLines) { +const FormatToken *getMatchingNamespaceToken( + const AnnotatedLine *Line, + const SmallVectorImpl<AnnotatedLine *> &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<AnnotatedLine *> &AnnotatedLines) { + const FormatToken *NamespaceToken = + getMatchingNamespaceToken(Line, AnnotatedLines); + return NamespaceToken ? NamespaceToken->TokenText : StringRef(); } class LineJoiner { @@ -248,10 +257,11 @@ TheLine->Level != 0); if (Style.CompactNamespaces) { - if (isNamespaceDeclaration(TheLine)) { + if (auto nsToken = TheLine->First->getNamespaceToken()) { int i = 0; unsigned closingLine = TheLine->MatchingOpeningBlockLineIndex - 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]->MatchingOpeningBlockLineIndex && I[i + 1]->Last->TotalLength < Limit; i++, closingLine--) { @@ -263,10 +273,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 @@ -515,6 +527,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 = @@ -1111,6 +1124,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/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -974,7 +974,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/NamespaceEndCommentsFixer.cpp =================================================================== --- lib/Format/NamespaceEndCommentsFixer.cpp +++ lib/Format/NamespaceEndCommentsFixer.cpp @@ -34,27 +34,51 @@ "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$", llvm::Regex::IgnoreCase); +// Matches a valid namespace end comment. +// Valid namespace end comments don't need to be edited. +static llvm::Regex kNamespaceMacroCommentPattern = + llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" + "([a-zA-Z0-9_]+)\\(([a-zA-Z0-9:_]*)\\)\\.? *(\\*/)?$", + llvm::Regex::IgnoreCase); + // 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; @@ -64,22 +88,31 @@ 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; - SmallVector<StringRef, 7> Groups; - if (kNamespaceCommentPattern.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()) + SmallVector<StringRef, 8> Groups; + if (NamespaceTok->is(TT_NamespaceMacro) && + kNamespaceMacroCommentPattern.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) || + !kNamespaceCommentPattern.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, @@ -109,21 +142,23 @@ } const FormatToken * -getNamespaceToken(const AnnotatedLine *line, +getNamespaceToken(const AnnotatedLine *Line, const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) { - if (!line->Affected || line->InPPDirective || !line->startsWith(tok::r_brace)) + if (!Line->Affected || Line->InPPDirective || !Line->startsWith(tok::r_brace)) return nullptr; - size_t StartLineIndex = line->MatchingOpeningBlockLineIndex; + size_t StartLineIndex = Line->MatchingOpeningBlockLineIndex; if (StartLineIndex == UnwrappedLine::kInvalidIndex) return nullptr; assert(StartLineIndex < AnnotatedLines.size()); const FormatToken *NamespaceTok = AnnotatedLines[StartLineIndex]->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<AnnotatedLine *> &AnnotatedLines) { + const FormatToken *NamespaceTok = getNamespaceToken(Line, AnnotatedLines); + return NamespaceTok ? NamespaceTok->TokenText : StringRef(); } } // namespace @@ -140,6 +175,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]; @@ -161,8 +197,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) { @@ -190,12 +229,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/FormatTokenLexer.cpp =================================================================== --- lib/Format/FormatTokenLexer.cpp +++ lib/Format/FormatTokenLexer.cpp @@ -40,6 +40,8 @@ Macros.emplace_back(&IdentTable.get(ForEachMacro), TT_ForEachMacro); for (const std::string &StatementMacro : Style.StatementMacros) Macros.emplace_back(&IdentTable.get(StatementMacro), TT_StatementMacro); + for (const std::string &NamespaceMacro : Style.NamespaceMacros) + Macros.emplace_back(&IdentTable.get(NamespaceMacro), TT_NamespaceMacro); std::sort(Macros.begin(), Macros.end()); } Index: lib/Format/FormatToken.h =================================================================== --- lib/Format/FormatToken.h +++ lib/Format/FormatToken.h @@ -68,6 +68,7 @@ TYPE(LineComment) \ TYPE(MacroBlockBegin) \ TYPE(MacroBlockEnd) \ + TYPE(NamespaceMacro) \ TYPE(ObjCBlockLBrace) \ TYPE(ObjCBlockLParen) \ TYPE(ObjCDecl) \ @@ -489,8 +490,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/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -370,6 +370,7 @@ IO.mapOptional("MacroBlockEnd", Style.MacroBlockEnd); IO.mapOptional("MaxEmptyLinesToKeep", Style.MaxEmptyLinesToKeep); IO.mapOptional("NamespaceIndentation", Style.NamespaceIndentation); + IO.mapOptional("NamespaceMacros", Style.NamespaceMacros); IO.mapOptional("ObjCBlockIndentWidth", Style.ObjCBlockIndentWidth); IO.mapOptional("ObjCSpaceAfterProperty", Style.ObjCSpaceAfterProperty); IO.mapOptional("ObjCSpaceBeforeProtocolList", Index: include/clang/Format/Format.h =================================================================== --- include/clang/Format/Format.h +++ include/clang/Format/Format.h @@ -981,6 +981,18 @@ /// For example: Q_UNUSED std::vector<std::string> StatementMacros; + /// \brief A vector of macros which are used to open namespace blocks. + /// + /// These are expected to be macros of the form: + /// \code + /// NAMESPACE(<namespace-name>, ...) { + /// <namespace-content> + /// } + /// \endcode + /// + /// For example: TESTSUITE + std::vector<std::string> NamespaceMacros; + /// \brief See documentation of ``IncludeCategories``. struct IncludeCategory { /// \brief The regular expression that this category matches. @@ -1575,6 +1587,7 @@ MacroBlockEnd == R.MacroBlockEnd && MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep && NamespaceIndentation == R.NamespaceIndentation && + NamespaceMacros == R.NamespaceMacros && ObjCBlockIndentWidth == R.ObjCBlockIndentWidth && ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty && ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList &&
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits