aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam McCall <sam.mccall@gmail.com>2018-09-05 07:44:02 +0000
committerSam McCall <sam.mccall@gmail.com>2018-09-05 07:44:02 +0000
commit6f3778c3725e0f7de9e153e2f3b2b361cd7016f8 (patch)
treeda10bcdecf432b1b21d2078dfd77d0accbd11322
parentf592d281a72b19131e447a3695f5a4a114eaebff (diff)
downloadllvm-6f3778c3725e0f7de9e153e2f3b2b361cd7016f8.zip
llvm-6f3778c3725e0f7de9e153e2f3b2b361cd7016f8.tar.gz
llvm-6f3778c3725e0f7de9e153e2f3b2b361cd7016f8.tar.bz2
clang-format: Fix formatting C++ namespaces with preceding 'inline' or 'export' specifier
This fixes formatting namespaces with preceding 'inline' and 'export' (Modules TS) specifiers. This change fixes namespaces not being identified as such with preceding 'inline' or 'export' specifiers. Motivation: I was experimenting with the Modules TS (-fmodules-ts) and found it would be useful if clang-format would correctly format 'export namespace'. While making the changes, I noticed that similar issues still exist with 'inline namespace', and addressed them as well. Patch by Marco Elver! Reviewers: klimek, djasper, owenpan, sammccall Reviewed By: owenpan, sammccall Subscribers: owenpan, cfe-commits Differential Revision: https://reviews.llvm.org/D51036 llvm-svn: 341450
-rw-r--r--clang/lib/Format/Format.cpp7
-rw-r--r--clang/lib/Format/FormatToken.h4
-rw-r--r--clang/lib/Format/NamespaceEndCommentsFixer.cpp7
-rw-r--r--clang/lib/Format/TokenAnnotator.h7
-rw-r--r--clang/lib/Format/UnwrappedLineFormatter.cpp4
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp17
-rw-r--r--clang/unittests/Format/FormatTest.cpp75
7 files changed, 99 insertions, 22 deletions
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 4a67cde..0637f76 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1309,8 +1309,7 @@ private:
std::set<unsigned> DeletedLines;
for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
auto &Line = *AnnotatedLines[i];
- if (Line.startsWith(tok::kw_namespace) ||
- Line.startsWith(tok::kw_inline, tok::kw_namespace)) {
+ if (Line.startsWithNamespace()) {
checkEmptyNamespace(AnnotatedLines, i, i, DeletedLines);
}
}
@@ -1347,9 +1346,7 @@ private:
if (AnnotatedLines[CurrentLine]->startsWith(tok::r_brace))
break;
- if (AnnotatedLines[CurrentLine]->startsWith(tok::kw_namespace) ||
- AnnotatedLines[CurrentLine]->startsWith(tok::kw_inline,
- tok::kw_namespace)) {
+ if (AnnotatedLines[CurrentLine]->startsWithNamespace()) {
if (!checkEmptyNamespace(AnnotatedLines, CurrentLine, NewLine,
DeletedLines))
return false;
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index 9094e76..d9bff01 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -520,8 +520,8 @@ struct FormatToken {
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))
+ // 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;
diff --git a/clang/lib/Format/NamespaceEndCommentsFixer.cpp b/clang/lib/Format/NamespaceEndCommentsFixer.cpp
index 995b321..dd36486 100644
--- a/clang/lib/Format/NamespaceEndCommentsFixer.cpp
+++ b/clang/lib/Format/NamespaceEndCommentsFixer.cpp
@@ -125,12 +125,7 @@ getNamespaceToken(const AnnotatedLine *Line,
if (StartLineIndex > 0)
NamespaceTok = AnnotatedLines[StartLineIndex - 1]->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();
}
NamespaceEndCommentsFixer::NamespaceEndCommentsFixer(const Environment &Env,
diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h
index a3124fc..e2f2c46 100644
--- a/clang/lib/Format/TokenAnnotator.h
+++ b/clang/lib/Format/TokenAnnotator.h
@@ -105,6 +105,13 @@ public:
return !Last->isOneOf(tok::semi, tok::comment);
}
+ /// \c true if this line starts a namespace definition.
+ bool startsWithNamespace() const {
+ return startsWith(tok::kw_namespace) ||
+ startsWith(tok::kw_inline, tok::kw_namespace) ||
+ startsWith(tok::kw_export, tok::kw_namespace);
+ }
+
FormatToken *First;
FormatToken *Last;
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 1b7daf6..f0d93a1 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -535,7 +535,7 @@ private:
Tok->SpacesRequiredBefore = 0;
Tok->CanBreakBefore = true;
return 1;
- } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) &&
+ } else if (Limit != 0 && !Line.startsWithNamespace() &&
!startsExternCBlock(Line)) {
// We don't merge short records.
FormatToken *RecordTok = Line.First;
@@ -1160,7 +1160,7 @@ void UnwrappedLineFormatter::formatFirstToken(
// Remove empty lines after "{".
if (!Style.KeepEmptyLinesAtTheStartOfBlocks && PreviousLine &&
PreviousLine->Last->is(tok::l_brace) &&
- PreviousLine->First->isNot(tok::kw_namespace) &&
+ !PreviousLine->startsWithNamespace() &&
!startsExternCBlock(*PreviousLine))
Newlines = 1;
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 07109da..752357c 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -992,13 +992,6 @@ void UnwrappedLineParser::parseStructuralElement() {
case tok::kw_namespace:
parseNamespace();
return;
- case tok::kw_inline:
- nextToken();
- if (FormatTok->Tok.is(tok::kw_namespace)) {
- parseNamespace();
- return;
- }
- break;
case tok::kw_public:
case tok::kw_protected:
case tok::kw_private:
@@ -1066,6 +1059,16 @@ void UnwrappedLineParser::parseStructuralElement() {
parseJavaScriptEs6ImportExport();
return;
}
+ if (!Style.isCpp())
+ break;
+ // Handle C++ "(inline|export) namespace".
+ LLVM_FALLTHROUGH;
+ case tok::kw_inline:
+ nextToken();
+ if (FormatTok->Tok.is(tok::kw_namespace)) {
+ parseNamespace();
+ return;
+ }
break;
case tok::identifier:
if (FormatTok->is(TT_ForEachMacro)) {
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 3dd9fc0..e7c4675 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -200,6 +200,42 @@ TEST_F(FormatTest, RemovesEmptyLines) {
"int i;\n"
"}",
getGoogleStyle()));
+ EXPECT_EQ("/* something */ namespace N {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ format("/* something */ namespace N {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ getGoogleStyle()));
+ EXPECT_EQ("inline namespace N {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ format("inline namespace N {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ getGoogleStyle()));
+ EXPECT_EQ("/* something */ inline namespace N {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ format("/* something */ inline namespace N {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ getGoogleStyle()));
+ EXPECT_EQ("export namespace N {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ format("export namespace N {\n"
+ "\n"
+ "int i;\n"
+ "}",
+ getGoogleStyle()));
EXPECT_EQ("extern /**/ \"C\" /**/ {\n"
"\n"
"int i;\n"
@@ -1220,12 +1256,25 @@ TEST_F(FormatTest, UnderstandsAccessSpecifiers) {
"private:\n"
" void f() {}\n"
"};");
+ verifyFormat("export class A {\n"
+ "public:\n"
+ "public: // comment\n"
+ "protected:\n"
+ "private:\n"
+ " void f() {}\n"
+ "};");
verifyGoogleFormat("class A {\n"
" public:\n"
" protected:\n"
" private:\n"
" void f() {}\n"
"};");
+ verifyGoogleFormat("export class A {\n"
+ " public:\n"
+ " protected:\n"
+ " private:\n"
+ " void f() {}\n"
+ "};");
verifyFormat("class A {\n"
"public slots:\n"
" void f1() {}\n"
@@ -1597,16 +1646,36 @@ TEST_F(FormatTest, FormatsNamespaces) {
"void f() { f(); }\n"
"}",
LLVMWithNoNamespaceFix);
+ verifyFormat("/* something */ namespace some_namespace {\n"
+ "class A {};\n"
+ "void f() { f(); }\n"
+ "}",
+ LLVMWithNoNamespaceFix);
verifyFormat("namespace {\n"
"class A {};\n"
"void f() { f(); }\n"
"}",
LLVMWithNoNamespaceFix);
+ verifyFormat("/* something */ namespace {\n"
+ "class A {};\n"
+ "void f() { f(); }\n"
+ "}",
+ LLVMWithNoNamespaceFix);
verifyFormat("inline namespace X {\n"
"class A {};\n"
"void f() { f(); }\n"
"}",
LLVMWithNoNamespaceFix);
+ verifyFormat("/* something */ inline namespace X {\n"
+ "class A {};\n"
+ "void f() { f(); }\n"
+ "}",
+ LLVMWithNoNamespaceFix);
+ verifyFormat("export namespace X {\n"
+ "class A {};\n"
+ "void f() { f(); }\n"
+ "}",
+ LLVMWithNoNamespaceFix);
verifyFormat("using namespace some_namespace;\n"
"class A {};\n"
"void f() { f(); }",
@@ -7602,6 +7671,12 @@ TEST_F(FormatTest, SplitEmptyNamespace) {
verifyFormat("inline namespace Foo\n"
"{};",
Style);
+ verifyFormat("/* something */ inline namespace Foo\n"
+ "{};",
+ Style);
+ verifyFormat("export namespace Foo\n"
+ "{};",
+ Style);
verifyFormat("namespace Foo\n"
"{\n"
"void Bar();\n"