diff options
author | Francois Ferrand <thetypz@gmail.com> | 2019-06-06 20:06:23 +0000 |
---|---|---|
committer | Francois Ferrand <thetypz@gmail.com> | 2019-06-06 20:06:23 +0000 |
commit | c65fb39b929fc1a0ed7bbb93bab40fe53086cbd7 (patch) | |
tree | 3443e9ba621f7893289f7ab5bf1fddfec5de094b | |
parent | 5175654bee59d5b608d7d244aaeba455b1500be8 (diff) | |
download | clang-c65fb39b929fc1a0ed7bbb93bab40fe53086cbd7.tar.gz |
clang-format: better handle namespace macros
Summary:
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.
Reviewers: krasimir, djasper, klimek
Reviewed By: klimek
Subscribers: acoomans, cfe-commits, klimek
Tags: #clang
Differential Revision: https://reviews.llvm.org/D37813
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@362740 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | docs/ClangFormatStyleOptions.rst | 13 | ||||
-rw-r--r-- | include/clang/Format/Format.h | 13 | ||||
-rw-r--r-- | lib/Format/Format.cpp | 1 | ||||
-rw-r--r-- | lib/Format/FormatToken.h | 7 | ||||
-rw-r--r-- | lib/Format/FormatTokenLexer.cpp | 2 | ||||
-rw-r--r-- | lib/Format/NamespaceEndCommentsFixer.cpp | 91 | ||||
-rw-r--r-- | lib/Format/TokenAnnotator.cpp | 12 | ||||
-rw-r--r-- | lib/Format/TokenAnnotator.h | 1 | ||||
-rw-r--r-- | lib/Format/UnwrappedLineFormatter.cpp | 40 | ||||
-rw-r--r-- | lib/Format/UnwrappedLineParser.cpp | 17 | ||||
-rw-r--r-- | unittests/Format/FormatTest.cpp | 114 | ||||
-rw-r--r-- | unittests/Format/NamespaceEndCommentsFixerTest.cpp | 270 |
12 files changed, 531 insertions, 50 deletions
diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst index 8bd0e9c8f7..1276a41acb 100644 --- a/docs/ClangFormatStyleOptions.rst +++ b/docs/ClangFormatStyleOptions.rst @@ -1782,6 +1782,19 @@ the configuration (without a prefix: ``Auto``). +**NamespaceMacros** (``std::vector<std::string>``) + A vector of macros which are used to open namespace blocks. + + These are expected to be macros of the form: + + .. code-block:: c++ + + NAMESPACE(<namespace-name>, ...) { + <namespace-content> + } + + 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``. diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index 0aae75276f..c5034db71a 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -1195,6 +1195,18 @@ struct FormatStyle { /// For example: Q_UNUSED std::vector<std::string> StatementMacros; + /// 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; + tooling::IncludeStyle IncludeStyle; /// Indent case labels one level from the switch statement. @@ -1942,6 +1954,7 @@ struct FormatStyle { MacroBlockEnd == R.MacroBlockEnd && MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep && NamespaceIndentation == R.NamespaceIndentation && + NamespaceMacros == R.NamespaceMacros && ObjCBinPackProtocolList == R.ObjCBinPackProtocolList && ObjCBlockIndentWidth == R.ObjCBlockIndentWidth && ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty && diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index d775ca14a7..31442b5124 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -455,6 +455,7 @@ template <> struct MappingTraits<FormatStyle> { 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); diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index e8b737f00b..df74937420 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -71,6 +71,7 @@ namespace format { TYPE(LineComment) \ TYPE(MacroBlockBegin) \ TYPE(MacroBlockEnd) \ + TYPE(NamespaceMacro) \ TYPE(ObjCBlockLBrace) \ TYPE(ObjCBlockLParen) \ TYPE(ObjCDecl) \ @@ -531,8 +532,10 @@ struct FormatToken { // 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: diff --git a/lib/Format/FormatTokenLexer.cpp b/lib/Format/FormatTokenLexer.cpp index 4438756579..009b884975 100644 --- a/lib/Format/FormatTokenLexer.cpp +++ b/lib/Format/FormatTokenLexer.cpp @@ -41,6 +41,8 @@ FormatTokenLexer::FormatTokenLexer(const SourceManager &SourceMgr, FileID ID, 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<FormatToken *> FormatTokenLexer::lex() { diff --git a/lib/Format/NamespaceEndCommentsFixer.cpp b/lib/Format/NamespaceEndCommentsFixer.cpp index 53542000a1..d04fc8f115 100644 --- a/lib/Format/NamespaceEndCommentsFixer.cpp +++ b/lib/Format/NamespaceEndCommentsFixer.cpp @@ -29,24 +29,41 @@ static const int kShortNamespaceMaxLines = 1; // 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 @@ bool hasEndComment(const FormatToken *RBraceTok) { 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 @@ bool validEndComment(const FormatToken *RBraceTok, StringRef NamespaceName) { new llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$", llvm::Regex::IgnoreCase); - SmallVector<StringRef, 7> 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<StringRef, 8> 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, @@ -127,6 +158,13 @@ getNamespaceToken(const AnnotatedLine *Line, return NamespaceTok->getNamespaceToken(); } +StringRef +getNamespaceTokenText(const AnnotatedLine *Line, + const SmallVectorImpl<AnnotatedLine *> &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 @@ std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::analyze( 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 @@ std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::analyze( 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 @@ std::pair<tooling::Replacements, unsigned> NamespaceEndCommentsFixer::analyze( 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; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 1dca764eae..6b698e24b5 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -1194,12 +1194,12 @@ private: // 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; diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h index d21df4938b..702ac6c0d7 100644 --- a/lib/Format/TokenAnnotator.h +++ b/lib/Format/TokenAnnotator.h @@ -115,6 +115,7 @@ public: /// \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); } diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp index 4e633c203c..36a18de017 100644 --- a/lib/Format/UnwrappedLineFormatter.cpp +++ b/lib/Format/UnwrappedLineFormatter.cpp @@ -134,20 +134,29 @@ private: 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 { @@ -249,10 +258,11 @@ private: 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 @@ private: 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 diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index 7acf33a968..a35e98ae55 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -630,7 +630,7 @@ static bool isIIFE(const UnwrappedLine &Line, 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 @@ void UnwrappedLineParser::parseStructuralElement() { 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::parseTryCatch() { } 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(); diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 87405bccef..885aac0830 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -1870,9 +1870,117 @@ TEST_F(FormatTest, FormatsNamespaces) { 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 @@ TEST_F(FormatTest, ParsesConfiguration) { 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.IncludeStyle.IncludeCategories.clear(); std::vector<tooling::IncludeStyle::IncludeCategory> ExpectedCategories = { {"abc/.*", 2}, {".*", 1}}; diff --git a/unittests/Format/NamespaceEndCommentsFixerTest.cpp b/unittests/Format/NamespaceEndCommentsFixerTest.cpp index d4c16c82e1..44cb4ef653 100644 --- a/unittests/Format/NamespaceEndCommentsFixerTest.cpp +++ b/unittests/Format/NamespaceEndCommentsFixerTest.cpp @@ -52,6 +52,7 @@ TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) { "int i;\n" "int j;\n" "}")); + EXPECT_EQ("namespace {\n" "int i;\n" "int j;\n" @@ -248,6 +249,85 @@ TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) { "// 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 @@ TEST_F(NamespaceEndCommentsFixerTest, KeepsValidEndComment) { "}; /* 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 @@ TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndLineComment) { 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 @@ TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndBlockComment) { 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" |