diff options
author | Sam McCall <sam.mccall@gmail.com> | 2018-09-05 07:44:02 +0000 |
---|---|---|
committer | Sam McCall <sam.mccall@gmail.com> | 2018-09-05 07:44:02 +0000 |
commit | 6f3778c3725e0f7de9e153e2f3b2b361cd7016f8 (patch) | |
tree | da10bcdecf432b1b21d2078dfd77d0accbd11322 /clang | |
parent | f592d281a72b19131e447a3695f5a4a114eaebff (diff) | |
download | bcm5719-llvm-6f3778c3725e0f7de9e153e2f3b2b361cd7016f8.tar.gz bcm5719-llvm-6f3778c3725e0f7de9e153e2f3b2b361cd7016f8.zip |
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
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Format/Format.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Format/FormatToken.h | 4 | ||||
-rw-r--r-- | clang/lib/Format/NamespaceEndCommentsFixer.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Format/TokenAnnotator.h | 7 | ||||
-rw-r--r-- | clang/lib/Format/UnwrappedLineFormatter.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Format/UnwrappedLineParser.cpp | 17 | ||||
-rw-r--r-- | clang/unittests/Format/FormatTest.cpp | 75 |
7 files changed, 99 insertions, 22 deletions
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 4a67cdeedf3..0637f76f07c 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 9094e7689e1..d9bff0112cc 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 995b3219a1f..dd364866d1c 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 a3124fcb3d6..e2f2c469d26 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 1b7daf67d90..f0d93a1f4f3 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 07109daf6f9..752357c1aff 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 3dd9fc00f68..e7c467547a1 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" |