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

llvm-svn: 362740
This commit is contained in:
Francois Ferrand 2019-06-06 20:06:23 +00:00
parent f1d9b3180e
commit e8a301f87f
12 changed files with 531 additions and 50 deletions

View File

@ -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``.

View File

@ -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 &&

View File

@ -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);

View File

@ -71,6 +71,7 @@ namespace format {
TYPE(LineComment) \
TYPE(MacroBlockBegin) \
TYPE(MacroBlockEnd) \
TYPE(NamespaceMacro) \
TYPE(ObjCBlockLBrace) \
TYPE(ObjCBlockLParen) \
TYPE(ObjCDecl) \
@ -531,7 +532,9 @@ 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
return NamespaceTok &&
NamespaceTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro)
? NamespaceTok
: nullptr;
}

View File

@ -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() {

View File

@ -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();
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;
}
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,8 +84,23 @@ 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)) {
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;
} 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())
@ -78,8 +111,6 @@ bool validEndComment(const FormatToken *RBraceTok, StringRef NamespaceName) {
return false;
return NamespaceNameInComment == NamespaceName;
}
return false;
}
void addEndComment(const FormatToken *RBraceTok, StringRef EndCommentText,
const SourceManager &SourceMgr,
@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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 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

View File

@ -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();
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();

View File

@ -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}};

View File

@ -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"