Typz updated this revision to Diff 103935.
Typz added a comment.
Complete refactor to make the processing much more generic
https://reviews.llvm.org/D33440
Files:
include/clang/Format/Format.h
lib/Format/Format.cpp
lib/Format/FormatToken.h
lib/Format/FormatTokenLexer.cpp
lib/Format/FormatTokenLexer.h
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
@@ -1356,9 +1356,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",
@@ -1372,6 +1480,14 @@
"} // namespace out",
Style));
+ EXPECT_EQ("namespace out { namespace in {\n"
+ "}} // namespace out::in",
+ format("namespace out {\n"
+ "namespace in {\n"
+ "} // namespace in\n"
+ "} // namespace out",
+ Style));
+
// Only namespaces which have both consecutive opening and end get compacted
EXPECT_EQ("namespace out {\n"
"namespace in1 {\n"
@@ -2172,6 +2288,26 @@
getLLVMStyleWithColumns(40)));
verifyFormat("MACRO(>)");
+
+ // Some macros contain an implicit semicolon
+ FormatStyle Style = getLLVMStyle();
+ Style.StatementMacros.push_back("FOO");
+ verifyFormat("FOO(a) int b = 0;");
+ verifyFormat("FOO(a)\n"
+ "int b = 0;",
+ Style);
+ verifyFormat("FOO(a);\n"
+ "int b = 0;",
+ Style);
+ verifyFormat("FOO(argc, argv, \"4.0.2\")\n"
+ "int b = 0;",
+ Style);
+ verifyFormat("FOO()\n"
+ "int b = 0;",
+ Style);
+ verifyFormat("FOO\n"
+ "int b = 0;",
+ Style);
}
TEST_F(FormatTest, LayoutMacroDefinitionsStatementsSpanningBlocks) {
@@ -9555,6 +9691,18 @@
CHECK_PARSE("ForEachMacros: [BOOST_FOREACH, Q_FOREACH]", ForEachMacros,
BoostAndQForeach);
+ Style.StatementMacros.clear();
+ CHECK_PARSE("StatementMacros: [QUNUSED]", StatementMacros,
+ std::vector<std::string>{"QUNUSED"});
+ 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
@@ -537,7 +537,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;
@@ -986,6 +986,19 @@
return;
}
}
+ if (Style.isCpp() && FormatTok->is(TT_StatementMacro)) {
+ nextToken();
+ if (FormatTok->is(tok::l_paren))
+ parseParens();
+ if (FormatTok->is(tok::semi))
+ nextToken();
+ addUnwrappedLine();
+ return;
+ }
+ if (Style.isCpp() && FormatTok->is(TT_NamespaceMacro)) {
+ parseNamespace();
+ return;
+ }
// In all other cases, parse the declaration.
break;
default:
@@ -1625,12 +1638,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,23 +134,29 @@
unsigned Indent = 0;
};
-bool isNamespaceDeclaration(const AnnotatedLine *Line) {
- const FormatToken *NamespaceTok = Line->First;
- // Detect "(inline)? namespace" in the beginning of a line.
- if (NamespaceTok->is(tok::kw_inline))
- NamespaceTok = NamespaceTok->getNextNonComment();
- return NamespaceTok && NamespaceTok->is(tok::kw_namespace);
-}
-
-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 {
@@ -230,10 +236,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--) {
@@ -245,10 +252,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
@@ -432,6 +441,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 =
@@ -1004,6 +1014,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
@@ -925,7 +925,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,52 @@
"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;
- Tok = Tok->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 ? Tok->getNextNonComment() : nullptr;
+ 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 += ")";
+ // close brace
if (AddNewline)
text += '\n';
return text;
@@ -64,22 +89,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 +143,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 +176,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 +198,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 +230,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.h
===================================================================
--- lib/Format/FormatTokenLexer.h
+++ lib/Format/FormatTokenLexer.h
@@ -97,7 +97,29 @@
// Index (in 'Tokens') of the last token that starts a new line.
unsigned FirstInLineIndex;
SmallVector<FormatToken *, 16> Tokens;
- SmallVector<IdentifierInfo *, 8> ForEachMacros;
+
+ struct MacroInfo {
+ MacroInfo() : Identifier(NULL), TokType(TT_Unknown) {}
+ MacroInfo(IdentifierInfo *Identifier, TokenType TokType)
+ : Identifier(Identifier), TokType(TokType) {}
+
+ IdentifierInfo *Identifier;
+ TokenType TokType;
+
+ bool operator==(const MacroInfo &Other) const {
+ return Identifier == Other.Identifier;
+ }
+ bool operator==(const IdentifierInfo *Other) const {
+ return Identifier == Other;
+ }
+ bool operator<(const MacroInfo &Other) const {
+ return Identifier < Other.Identifier;
+ }
+ bool operator<(const IdentifierInfo *Other) const {
+ return Identifier < Other;
+ }
+ };
+ SmallVector<MacroInfo, 8> Macros;
bool FormattingDisabled;
Index: lib/Format/FormatTokenLexer.cpp
===================================================================
--- lib/Format/FormatTokenLexer.cpp
+++ lib/Format/FormatTokenLexer.cpp
@@ -37,8 +37,12 @@
Lex->SetKeepWhitespaceMode(true);
for (const std::string &ForEachMacro : Style.ForEachMacros)
- ForEachMacros.push_back(&IdentTable.get(ForEachMacro));
- std::sort(ForEachMacros.begin(), ForEachMacros.end());
+ 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());
}
ArrayRef<FormatToken *> FormatTokenLexer::lex() {
@@ -605,12 +609,13 @@
}
if (Style.isCpp()) {
+ auto it = std::find(Macros.begin(), Macros.end(),
+ FormatTok->Tok.getIdentifierInfo());
if (!(Tokens.size() > 0 && Tokens.back()->Tok.getIdentifierInfo() &&
Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() ==
tok::pp_define) &&
- std::find(ForEachMacros.begin(), ForEachMacros.end(),
- FormatTok->Tok.getIdentifierInfo()) != ForEachMacros.end()) {
- FormatTok->Type = TT_ForEachMacro;
+ it != Macros.end()) {
+ FormatTok->Type = it->TokType;
} else if (FormatTok->is(tok::identifier)) {
if (MacroBlockBeginRegex.match(Text)) {
FormatTok->Type = TT_MacroBlockBegin;
Index: lib/Format/FormatToken.h
===================================================================
--- lib/Format/FormatToken.h
+++ lib/Format/FormatToken.h
@@ -67,6 +67,7 @@
TYPE(LineComment) \
TYPE(MacroBlockBegin) \
TYPE(MacroBlockEnd) \
+ TYPE(NamespaceMacro) \
TYPE(ObjCBlockLBrace) \
TYPE(ObjCBlockLParen) \
TYPE(ObjCDecl) \
@@ -83,6 +84,7 @@
TYPE(RegexLiteral) \
TYPE(SelectorName) \
TYPE(StartOfName) \
+ TYPE(StatementMacro) \
TYPE(TemplateCloser) \
TYPE(TemplateOpener) \
TYPE(TemplateString) \
@@ -475,6 +477,21 @@
return MatchingParen && MatchingParen->opensBlockOrBlockTypeList(Style);
}
+ /// \brief Return the actual namespace token, if this token starts a namespace
+ /// block.
+ const FormatToken *getNamespaceToken() const {
+ const FormatToken *NamespaceTok = this;
+ if (is(tok::comment))
+ NamespaceTok = NamespaceTok->getNextNonComment();
+ // Detect "(inline)? namespace" in the beginning of a line.
+ if (NamespaceTok && NamespaceTok->is(tok::kw_inline))
+ NamespaceTok = NamespaceTok->getNextNonComment();
+ return NamespaceTok &&
+ NamespaceTok->isOneOf(tok::kw_namespace, TT_NamespaceMacro)
+ ? NamespaceTok
+ : nullptr;
+ }
+
private:
// Disallow copying.
FormatToken(const FormatToken &) = delete;
Index: lib/Format/Format.cpp
===================================================================
--- lib/Format/Format.cpp
+++ lib/Format/Format.cpp
@@ -361,6 +361,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",
@@ -395,6 +396,7 @@
IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses);
IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
IO.mapOptional("Standard", Style.Standard);
+ IO.mapOptional("StatementMacros", Style.StatementMacros);
IO.mapOptional("TabWidth", Style.TabWidth);
IO.mapOptional("UseTab", Style.UseTab);
}
@@ -619,6 +621,8 @@
LLVMStyle.DisableFormat = false;
LLVMStyle.SortIncludes = true;
+ LLVMStyle.StatementMacros.push_back("Q_UNUSED");
+ LLVMStyle.StatementMacros.push_back("QT_REQUIRE_VERSION");
return LLVMStyle;
}
Index: include/clang/Format/Format.h
===================================================================
--- include/clang/Format/Format.h
+++ include/clang/Format/Format.h
@@ -935,6 +935,28 @@
/// For example: BOOST_FOREACH.
std::vector<std::string> ForEachMacros;
+ /// \brief A vector of macros that should be interpreted as complete
+ /// statements.
+ ///
+ /// Typical macros are expressions, and require a semi-colon to be
+ /// added; sometimes this is not the case, and this allows to make
+ /// clang-format aware of such cases.
+ ///
+ /// 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.
@@ -1492,11 +1514,11 @@
MacroBlockEnd == R.MacroBlockEnd &&
MaxEmptyLinesToKeep == R.MaxEmptyLinesToKeep &&
NamespaceIndentation == R.NamespaceIndentation &&
+ NamespaceMacros == R.NamespaceMacros &&
ObjCBlockIndentWidth == R.ObjCBlockIndentWidth &&
ObjCSpaceAfterProperty == R.ObjCSpaceAfterProperty &&
ObjCSpaceBeforeProtocolList == R.ObjCSpaceBeforeProtocolList &&
- PenaltyBreakAssignment ==
- R.PenaltyBreakAssignment &&
+ PenaltyBreakAssignment == R.PenaltyBreakAssignment &&
PenaltyBreakBeforeFirstCallParameter ==
R.PenaltyBreakBeforeFirstCallParameter &&
PenaltyBreakComment == R.PenaltyBreakComment &&
@@ -1517,7 +1539,7 @@
SpacesInParentheses == R.SpacesInParentheses &&
SpacesInSquareBrackets == R.SpacesInSquareBrackets &&
Standard == R.Standard && TabWidth == R.TabWidth &&
- UseTab == R.UseTab;
+ StatementMacros == R.StatementMacros && UseTab == R.UseTab;
}
};
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits