r269888 - Make clang-format cleaner remove redundant commas in list and redundant colon in constructor initializer.
Eric Liu via cfe-commits
cfe-commits at lists.llvm.org
Wed May 18 01:02:56 PDT 2016
Author: ioeric
Date: Wed May 18 03:02:56 2016
New Revision: 269888
URL: http://llvm.org/viewvc/llvm-project?rev=269888&view=rev
Log:
Make clang-format cleaner remove redundant commas in list and redundant colon in constructor initializer.
Summary: Make clang-format cleaner remove redundant commas/colons in constructor initializer list.
Reviewers: klimek, djasper
Subscribers: cfe-commits, klimek
Differential Revision: http://reviews.llvm.org/D19804
Modified:
cfe/trunk/lib/Format/Format.cpp
cfe/trunk/lib/Format/TokenAnnotator.cpp
cfe/trunk/unittests/Format/CleanupTest.cpp
Modified: cfe/trunk/lib/Format/Format.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=269888&r1=269887&r2=269888&view=diff
==============================================================================
--- cfe/trunk/lib/Format/Format.cpp (original)
+++ cfe/trunk/lib/Format/Format.cpp Wed May 18 03:02:56 2016
@@ -1765,6 +1765,15 @@ public:
checkEmptyNamespace(AnnotatedLines);
+ for (auto &Line : AnnotatedLines) {
+ if (Line->Affected) {
+ cleanupRight(Line->First, tok::comma, tok::comma);
+ cleanupRight(Line->First, TT_CtorInitializerColon, tok::comma);
+ cleanupLeft(Line->First, TT_CtorInitializerComma, tok::l_brace);
+ cleanupLeft(Line->First, TT_CtorInitializerColon, tok::l_brace);
+ }
+ }
+
return generateFixes();
}
@@ -1853,6 +1862,45 @@ private:
return true;
}
+ // Checks pairs {start, start->next},..., {end->previous, end} and deletes one
+ // of the token in the pair if the left token has \p LK token kind and the
+ // right token has \p RK token kind. If \p DeleteLeft is true, the left token
+ // is deleted on match; otherwise, the right token is deleted.
+ template <typename LeftKind, typename RightKind>
+ void cleanupPair(FormatToken *Start, LeftKind LK, RightKind RK,
+ bool DeleteLeft) {
+ auto NextNotDeleted = [this](const FormatToken &Tok) -> FormatToken * {
+ for (auto *Res = Tok.Next; Res; Res = Res->Next)
+ if (!Res->is(tok::comment) &&
+ DeletedTokens.find(Res) == DeletedTokens.end())
+ return Res;
+ return nullptr;
+ };
+ for (auto *Left = Start; Left;) {
+ auto *Right = NextNotDeleted(*Left);
+ if (!Right)
+ break;
+ if (Left->is(LK) && Right->is(RK)) {
+ deleteToken(DeleteLeft ? Left : Right);
+ // If the right token is deleted, we should keep the left token
+ // unchanged and pair it with the new right token.
+ if (!DeleteLeft)
+ continue;
+ }
+ Left = Right;
+ }
+ }
+
+ template <typename LeftKind, typename RightKind>
+ void cleanupLeft(FormatToken *Start, LeftKind LK, RightKind RK) {
+ cleanupPair(Start, LK, RK, /*DeleteLeft=*/true);
+ }
+
+ template <typename LeftKind, typename RightKind>
+ void cleanupRight(FormatToken *Start, LeftKind LK, RightKind RK) {
+ cleanupPair(Start, LK, RK, /*DeleteLeft=*/false);
+ }
+
// Delete the given token.
inline void deleteToken(FormatToken *Tok) {
if (Tok)
Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=269888&r1=269887&r2=269888&view=diff
==============================================================================
--- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp Wed May 18 03:02:56 2016
@@ -920,6 +920,10 @@ private:
Contexts.back().IsExpression = false;
} else if (Current.is(TT_LambdaArrow) || Current.is(Keywords.kw_assert)) {
Contexts.back().IsExpression = Style.Language == FormatStyle::LK_Java;
+ } else if (Current.Previous &&
+ Current.Previous->is(TT_CtorInitializerColon)) {
+ Contexts.back().IsExpression = true;
+ Contexts.back().InCtorInitializer = true;
} else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) {
for (FormatToken *Previous = Current.Previous;
Previous && Previous->isOneOf(tok::star, tok::amp);
@@ -927,10 +931,6 @@ private:
Previous->Type = TT_PointerOrReference;
if (Line.MustBeDeclaration && !Contexts.front().InCtorInitializer)
Contexts.back().IsExpression = false;
- } else if (Current.Previous &&
- Current.Previous->is(TT_CtorInitializerColon)) {
- Contexts.back().IsExpression = true;
- Contexts.back().InCtorInitializer = true;
} else if (Current.is(tok::kw_new)) {
Contexts.back().CanBeExpression = false;
} else if (Current.isOneOf(tok::semi, tok::exclaim)) {
Modified: cfe/trunk/unittests/Format/CleanupTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/CleanupTest.cpp?rev=269888&r1=269887&r2=269888&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/CleanupTest.cpp (original)
+++ cfe/trunk/unittests/Format/CleanupTest.cpp Wed May 18 03:02:56 2016
@@ -113,6 +113,133 @@ TEST_F(CleanupTest, EmptyNamespaceWithCo
EXPECT_EQ(Expected, Result);
}
+TEST_F(CleanupTest, CtorInitializationSimpleRedundantComma) {
+ std::string Code = "class A {\nA() : , {} };";
+ std::string Expected = "class A {\nA() {} };";
+ std::vector<tooling::Range> Ranges;
+ Ranges.push_back(tooling::Range(17, 0));
+ Ranges.push_back(tooling::Range(19, 0));
+ std::string Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+
+ Code = "class A {\nA() : x(1), {} };";
+ Expected = "class A {\nA() : x(1) {} };";
+ Ranges.clear();
+ Ranges.push_back(tooling::Range(23, 0));
+ Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+
+ Code = "class A {\nA() :,,,,{} };";
+ Expected = "class A {\nA() {} };";
+ Ranges.clear();
+ Ranges.push_back(tooling::Range(15, 0));
+ Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+}
+
+TEST_F(CleanupTest, ListSimpleRedundantComma) {
+ std::string Code = "void f() { std::vector<int> v = {1,2,,,3,{4,5}}; }";
+ std::string Expected = "void f() { std::vector<int> v = {1,2,3,{4,5}}; }";
+ std::vector<tooling::Range> Ranges;
+ Ranges.push_back(tooling::Range(40, 0));
+ std::string Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+
+ Code = "int main() { f(1,,2,3,,4);}";
+ Expected = "int main() { f(1,2,3,4);}";
+ Ranges.clear();
+ Ranges.push_back(tooling::Range(17, 0));
+ Ranges.push_back(tooling::Range(22, 0));
+ Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+}
+
+TEST_F(CleanupTest, CtorInitializationBracesInParens) {
+ std::string Code = "class A {\nA() : x({1}),, {} };";
+ std::string Expected = "class A {\nA() : x({1}) {} };";
+ std::vector<tooling::Range> Ranges;
+ Ranges.push_back(tooling::Range(24, 0));
+ Ranges.push_back(tooling::Range(26, 0));
+ std::string Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+}
+
+TEST_F(CleanupTest, RedundantCommaNotInAffectedRanges) {
+ std::string Code =
+ "class A {\nA() : x({1}), /* comment */, { int x = 0; } };";
+ std::string Expected =
+ "class A {\nA() : x({1}), /* comment */, { int x = 0; } };";
+ // Set the affected range to be "int x = 0", which does not intercept the
+ // constructor initialization list.
+ std::vector<tooling::Range> Ranges(1, tooling::Range(42, 9));
+ std::string Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+
+ Code = "class A {\nA() : x(1), {} };";
+ Expected = "class A {\nA() : x(1), {} };";
+ // No range. Fixer should do nothing.
+ Ranges.clear();
+ Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+}
+
+// FIXME: delete comments too.
+TEST_F(CleanupTest, CtorInitializationCommentAroundCommas) {
+ // Remove redundant commas around comment.
+ std::string Code = "class A {\nA() : x({1}), /* comment */, {} };";
+ std::string Expected = "class A {\nA() : x({1}) /* comment */ {} };";
+ std::vector<tooling::Range> Ranges;
+ Ranges.push_back(tooling::Range(25, 0));
+ Ranges.push_back(tooling::Range(40, 0));
+ std::string Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+
+ // Remove trailing comma and ignore comment.
+ Code = "class A {\nA() : x({1}), // comment\n{} };";
+ Expected = "class A {\nA() : x({1}) // comment\n{} };";
+ Ranges = std::vector<tooling::Range>(1, tooling::Range(25, 0));
+ Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+
+ // Remove trailing comma and ignore comment.
+ Code = "class A {\nA() : x({1}), // comment\n , y(1),{} };";
+ Expected = "class A {\nA() : x({1}), // comment\n y(1){} };";
+ Ranges = std::vector<tooling::Range>(1, tooling::Range(38, 0));
+ Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+
+ // Remove trailing comma and ignore comment.
+ Code = "class A {\nA() : x({1}), \n/* comment */, y(1),{} };";
+ Expected = "class A {\nA() : x({1}), \n/* comment */ y(1){} };";
+ Ranges = std::vector<tooling::Range>(1, tooling::Range(40, 0));
+ Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+
+ // Remove trailing comma and ignore comment.
+ Code = "class A {\nA() : , // comment\n y(1),{} };";
+ Expected = "class A {\nA() : // comment\n y(1){} };";
+ Ranges = std::vector<tooling::Range>(1, tooling::Range(17, 0));
+ Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+}
+
+TEST_F(CleanupTest, CtorInitializerInNamespace) {
+ std::string Code = "namespace A {\n"
+ "namespace B {\n" // missing r_brace
+ "} // namespace A\n\n"
+ "namespace C {\n"
+ "class A { A() : x(0),, {} };\n"
+ "inline namespace E { namespace { } }\n"
+ "}";
+ std::string Expected = "namespace A {\n"
+ "\n\n\nnamespace C {\n"
+ "class A { A() : x(0) {} };\n \n"
+ "}";
+ std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size()));
+ std::string Result = cleanup(Code, Ranges);
+ EXPECT_EQ(Expected, Result);
+}
+
} // end namespace
} // end namespace format
} // end namespace clang
More information about the cfe-commits
mailing list