From 1f3085d3b8993328b699d9b75460171a4cbdd231 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Tue, 7 Mar 2017 14:07:43 +0000 Subject: [PATCH] [clang-format] Support namespaces ending in semicolon Summary: This patch adds support for namespaces ending in semicolon to the namespace comment fixer. source: ``` namespace A { int i; int j; }; ``` clang-format before: ``` namespace A { int i; int j; } // namespace A; ``` clang-format after: ``` namespace A { int i; int j; }; // namespace A ``` Reviewers: djasper Reviewed By: djasper Subscribers: cfe-commits, klimek Differential Revision: https://reviews.llvm.org/D30688 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@297140 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Format/NamespaceEndCommentsFixer.cpp | 28 ++++-- .../Format/NamespaceEndCommentsFixerTest.cpp | 85 ++++++++++++++++++- 2 files changed, 105 insertions(+), 8 deletions(-) diff --git a/lib/Format/NamespaceEndCommentsFixer.cpp b/lib/Format/NamespaceEndCommentsFixer.cpp index d0b5919c9b..af751100ec 100644 --- a/lib/Format/NamespaceEndCommentsFixer.cpp +++ b/lib/Format/NamespaceEndCommentsFixer.cpp @@ -139,20 +139,34 @@ tooling::Replacements NamespaceEndCommentsFixer::analyze( if (RBraceTok->Finalized) continue; RBraceTok->Finalized = true; + const FormatToken *EndCommentPrevTok = RBraceTok; + // Namespaces often end with '};'. In that case, attach namespace end + // comments to the semicolon tokens. + if (RBraceTok->Next && RBraceTok->Next->is(tok::semi)) { + EndCommentPrevTok = RBraceTok->Next; + } + // The next token in the token stream after the place where the end comment + // token must be. This is either the next token on the current line or the + // first token on the next line. + const FormatToken *EndCommentNextTok = EndCommentPrevTok->Next; + if (EndCommentNextTok && EndCommentNextTok->is(tok::comment)) + EndCommentNextTok = EndCommentNextTok->Next; + if (!EndCommentNextTok && I + 1 < E) + EndCommentNextTok = AnnotatedLines[I + 1]->First; + bool AddNewline = EndCommentNextTok && + EndCommentNextTok->NewlinesBefore == 0 && + EndCommentNextTok->isNot(tok::eof); const std::string NamespaceName = computeName(NamespaceTok); - bool AddNewline = (I + 1 < E) && - AnnotatedLines[I + 1]->First->NewlinesBefore == 0 && - AnnotatedLines[I + 1]->First->isNot(tok::eof); const std::string EndCommentText = computeEndCommentText(NamespaceName, AddNewline); - if (!hasEndComment(RBraceTok)) { + if (!hasEndComment(EndCommentPrevTok)) { bool isShort = I - StartLineIndex <= kShortNamespaceMaxLines + 1; if (!isShort) - addEndComment(RBraceTok, EndCommentText, SourceMgr, &Fixes); + addEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes); continue; } - if (!validEndComment(RBraceTok, NamespaceName)) - updateEndComment(RBraceTok, EndCommentText, SourceMgr, &Fixes); + if (!validEndComment(EndCommentPrevTok, NamespaceName)) + updateEndComment(EndCommentPrevTok, EndCommentText, SourceMgr, &Fixes); } return Fixes; } diff --git a/unittests/Format/NamespaceEndCommentsFixerTest.cpp b/unittests/Format/NamespaceEndCommentsFixerTest.cpp index f0e67b39a3..48ecdb038e 100644 --- a/unittests/Format/NamespaceEndCommentsFixerTest.cpp +++ b/unittests/Format/NamespaceEndCommentsFixerTest.cpp @@ -184,6 +184,34 @@ TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) { "}\n" "}\n" "}")); + + // Adds an end comment after a semicolon. + EXPECT_EQ("namespace {\n" + " int i;\n" + " int j;\n" + "};// namespace", + fixNamespaceEndComments("namespace {\n" + " int i;\n" + " int j;\n" + "};")); + EXPECT_EQ("namespace A {\n" + " int i;\n" + " int j;\n" + "};// namespace A", + fixNamespaceEndComments("namespace A {\n" + " int i;\n" + " int j;\n" + "};")); + EXPECT_EQ("namespace A {\n" + " int i;\n" + " int j;\n" + "};// namespace A\n" + "// unrelated", + fixNamespaceEndComments("namespace A {\n" + " int i;\n" + " int j;\n" + "};\n" + "// unrelated")); } TEST_F(NamespaceEndCommentsFixerTest, AddsNewlineIfNeeded) { @@ -220,6 +248,24 @@ TEST_F(NamespaceEndCommentsFixerTest, AddsNewlineIfNeeded) { " int j;\n" " int k;\n" "}")); + EXPECT_EQ("namespace {\n" + " int i;\n" + " int j;\n" + "};// namespace\n" + "int k;", + fixNamespaceEndComments("namespace {\n" + " int i;\n" + " int j;\n" + "};int k;")); + EXPECT_EQ("namespace {\n" + " int i;\n" + " int j;\n" + "};// namespace\n" + ";", + fixNamespaceEndComments("namespace {\n" + " int i;\n" + " int j;\n" + "};;")); } TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddEndCommentForShortNamespace) { @@ -227,6 +273,8 @@ TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddEndCommentForShortNamespace) { EXPECT_EQ("namespace A {}", fixNamespaceEndComments("namespace A {}")); EXPECT_EQ("namespace A { a }", fixNamespaceEndComments("namespace A { a }")); + EXPECT_EQ("namespace A { a };", + fixNamespaceEndComments("namespace A { a };")); } TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddCommentAfterUnaffectedRBrace) { @@ -238,6 +286,14 @@ TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddCommentAfterUnaffectedRBrace) { "}", // The range (16, 3) spans the 'int' above. /*Ranges=*/{1, tooling::Range(16, 3)})); + EXPECT_EQ("namespace A {\n" + " int i;\n" + "};", + fixNamespaceEndComments("namespace A {\n" + " int i;\n" + "};", + // The range (16, 3) spans the 'int' above. + /*Ranges=*/{1, tooling::Range(16, 3)})); } TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddCommentAfterRBraceInPPDirective) { @@ -276,6 +332,18 @@ TEST_F(NamespaceEndCommentsFixerTest, KeepsValidEndComment) { fixNamespaceEndComments("namespace A::B {\n" " int i;\n" "} // end namespace A::B")); + EXPECT_EQ("namespace A {\n" + " int i;\n" + "}; // end namespace A", + fixNamespaceEndComments("namespace A {\n" + " int i;\n" + "}; // end namespace A")); + EXPECT_EQ("namespace {\n" + " int i;\n" + "}; /* unnamed namespace */", + fixNamespaceEndComments("namespace {\n" + " int i;\n" + "}; /* unnamed namespace */")); } TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndLineComment) { @@ -309,10 +377,17 @@ TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndLineComment) { fixNamespaceEndComments("namespace A {\n" " int i;\n" "} // banamespace A")); - + EXPECT_EQ("namespace A {\n" + " int i;\n" + "}; // namespace A", + fixNamespaceEndComments("namespace A {\n" + " int i;\n" + "}; // banamespace A")); // Updates invalid line comments even for short namespaces. EXPECT_EQ("namespace A {} // namespace A", fixNamespaceEndComments("namespace A {} // namespace")); + EXPECT_EQ("namespace A {}; // namespace A", + fixNamespaceEndComments("namespace A {}; // namespace")); } TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndBlockComment) { @@ -346,8 +421,16 @@ TEST_F(NamespaceEndCommentsFixerTest, UpdatesInvalidEndBlockComment) { fixNamespaceEndComments("namespace A {\n" " int i;\n" "} /* banamespace A */")); + EXPECT_EQ("namespace A {\n" + " int i;\n" + "}; // namespace A", + fixNamespaceEndComments("namespace A {\n" + " int i;\n" + "}; /* banamespace A */")); EXPECT_EQ("namespace A {} // namespace A", fixNamespaceEndComments("namespace A {} /**/")); + EXPECT_EQ("namespace A {}; // namespace A", + fixNamespaceEndComments("namespace A {}; /**/")); } TEST_F(NamespaceEndCommentsFixerTest, -- 2.40.0