summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancois Ferrand <thetypz@gmail.com>2019-06-06 20:06:23 +0000
committerFrancois Ferrand <thetypz@gmail.com>2019-06-06 20:06:23 +0000
commitc65fb39b929fc1a0ed7bbb93bab40fe53086cbd7 (patch)
tree3443e9ba621f7893289f7ab5bf1fddfec5de094b
parent5175654bee59d5b608d7d244aaeba455b1500be8 (diff)
downloadclang-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.rst13
-rw-r--r--include/clang/Format/Format.h13
-rw-r--r--lib/Format/Format.cpp1
-rw-r--r--lib/Format/FormatToken.h7
-rw-r--r--lib/Format/FormatTokenLexer.cpp2
-rw-r--r--lib/Format/NamespaceEndCommentsFixer.cpp91
-rw-r--r--lib/Format/TokenAnnotator.cpp12
-rw-r--r--lib/Format/TokenAnnotator.h1
-rw-r--r--lib/Format/UnwrappedLineFormatter.cpp40
-rw-r--r--lib/Format/UnwrappedLineParser.cpp17
-rw-r--r--unittests/Format/FormatTest.cpp114
-rw-r--r--unittests/Format/NamespaceEndCommentsFixerTest.cpp270
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"