[clang] c5243c6 - [clang-format] Fix aligning with linebreaks
Björn Schäpers via cfe-commits
cfe-commits at lists.llvm.org
Sun Mar 28 07:26:50 PDT 2021
Author: Björn Schäpers
Date: 2021-03-28T16:26:27+02:00
New Revision: c5243c63cda3c740d6e9c7e501f6518c21688da3
URL: https://github.com/llvm/llvm-project/commit/c5243c63cda3c740d6e9c7e501f6518c21688da3
DIFF: https://github.com/llvm/llvm-project/commit/c5243c63cda3c740d6e9c7e501f6518c21688da3.diff
LOG: [clang-format] Fix aligning with linebreaks
Breaking a string literal or a function calls arguments with
AlignConsecutiveDeclarations or AlignConsecutiveAssignments did misalign
the continued line. E.g.:
void foo() {
int myVar = 5;
double x = 3.14;
auto str = "Hello"
"World";
}
or
void foo() {
int myVar = 5;
double x = 3.14;
auto str = "Hello"
"World";
}
Differential Revision: https://reviews.llvm.org/D98214
Added:
Modified:
clang/lib/Format/WhitespaceManager.cpp
clang/unittests/Format/FormatTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp
index ac68fe0aa01af..6016f8d131c74 100644
--- a/clang/lib/Format/WhitespaceManager.cpp
+++ b/clang/lib/Format/WhitespaceManager.cpp
@@ -278,6 +278,14 @@ AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
// double z);
// In the above example, we need to take special care to ensure that
// 'double z' is indented along with it's owning function 'b'.
+ // The same holds for calling a function:
+ // double a = foo(x);
+ // int b = bar(foo(y),
+ // foor(z));
+ // Similar for broken string literals:
+ // double x = 3.14;
+ // auto s = "Hello"
+ // "World";
// Special handling is required for 'nested' ternary operators.
SmallVector<unsigned, 16> ScopeStack;
@@ -298,8 +306,12 @@ AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
ScopeStack.push_back(i);
bool InsideNestedScope = ScopeStack.size() != 0;
+ bool ContinuedStringLiteral = i > Start &&
+ Changes[i].Tok->is(tok::string_literal) &&
+ Changes[i - 1].Tok->is(tok::string_literal);
+ bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral;
- if (Changes[i].NewlinesBefore > 0 && !InsideNestedScope) {
+ if (Changes[i].NewlinesBefore > 0 && !SkipMatchCheck) {
Shift = 0;
FoundMatchOnLine = false;
}
@@ -307,7 +319,7 @@ AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
// If this is the first matching token to be aligned, remember by how many
// spaces it has to be shifted, so the rest of the changes on the line are
// shifted by the same amount
- if (!FoundMatchOnLine && !InsideNestedScope && Matches(Changes[i])) {
+ if (!FoundMatchOnLine && !SkipMatchCheck && Matches(Changes[i])) {
FoundMatchOnLine = true;
Shift = Column - Changes[i].StartOfTokenColumn;
Changes[i].Spaces += Shift;
@@ -317,15 +329,41 @@ AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
// as mentioned in the ScopeStack comment.
if (InsideNestedScope && Changes[i].NewlinesBefore > 0) {
unsigned ScopeStart = ScopeStack.back();
- if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName) ||
- (ScopeStart > Start + 1 &&
- Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) ||
- Changes[i].Tok->is(TT_ConditionalExpr) ||
- (Changes[i].Tok->Previous &&
- Changes[i].Tok->Previous->is(TT_ConditionalExpr)))
+ auto ShouldShiftBeAdded = [&] {
+ // Function declaration
+ if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName))
+ return true;
+
+ // Continued function declaration
+ if (ScopeStart > Start + 1 &&
+ Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName))
+ return true;
+
+ // Continued function call
+ if (ScopeStart > Start + 1 &&
+ Changes[ScopeStart - 2].Tok->is(tok::identifier) &&
+ Changes[ScopeStart - 1].Tok->is(tok::l_paren))
+ return true;
+
+ // Ternary operator
+ if (Changes[i].Tok->is(TT_ConditionalExpr))
+ return true;
+
+ // Continued ternary operator
+ if (Changes[i].Tok->Previous &&
+ Changes[i].Tok->Previous->is(TT_ConditionalExpr))
+ return true;
+
+ return false;
+ };
+
+ if (ShouldShiftBeAdded())
Changes[i].Spaces += Shift;
}
+ if (ContinuedStringLiteral)
+ Changes[i].Spaces += Shift;
+
assert(Shift >= 0);
Changes[i].StartOfTokenColumn += Shift;
if (i + 1 != Changes.size())
@@ -434,7 +472,10 @@ static unsigned AlignTokens(
AlignCurrentSequence();
// A new line starts, re-initialize line status tracking bools.
- FoundMatchOnLine = false;
+ // Keep the match state if a string literal is continued on this line.
+ if (i == 0 || !Changes[i].Tok->is(tok::string_literal) ||
+ !Changes[i - 1].Tok->is(tok::string_literal))
+ FoundMatchOnLine = false;
LineIsComment = true;
}
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 429621e0ca1c6..1dd287f71ce1c 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -14297,6 +14297,102 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) {
Alignment);
}
+TEST_F(FormatTest, AlignWithLineBreaks) {
+ auto Style = getLLVMStyleWithColumns(120);
+
+ EXPECT_EQ(Style.AlignConsecutiveAssignments, FormatStyle::ACS_None);
+ EXPECT_EQ(Style.AlignConsecutiveDeclarations, FormatStyle::ACS_None);
+ verifyFormat("void foo() {\n"
+ " int myVar = 5;\n"
+ " double x = 3.14;\n"
+ " auto str = \"Hello \"\n"
+ " \"World\";\n"
+ " auto s = \"Hello \"\n"
+ " \"Again\";\n"
+ "}",
+ Style);
+
+ // clang-format off
+ verifyFormat("void foo() {\n"
+ " const int capacityBefore = Entries.capacity();\n"
+ " const auto newEntry = Entries.emplaceHint(std::piecewise_construct, std::forward_as_tuple(uniqueId),\n"
+ " std::forward_as_tuple(id, uniqueId, name, threadCreation));\n"
+ " const X newEntry2 = Entries.emplaceHint(std::piecewise_construct, std::forward_as_tuple(uniqueId),\n"
+ " std::forward_as_tuple(id, uniqueId, name, threadCreation));\n"
+ "}",
+ Style);
+ // clang-format on
+
+ Style.AlignConsecutiveAssignments = FormatStyle::ACS_Consecutive;
+ verifyFormat("void foo() {\n"
+ " int myVar = 5;\n"
+ " double x = 3.14;\n"
+ " auto str = \"Hello \"\n"
+ " \"World\";\n"
+ " auto s = \"Hello \"\n"
+ " \"Again\";\n"
+ "}",
+ Style);
+
+ // clang-format off
+ verifyFormat("void foo() {\n"
+ " const int capacityBefore = Entries.capacity();\n"
+ " const auto newEntry = Entries.emplaceHint(std::piecewise_construct, std::forward_as_tuple(uniqueId),\n"
+ " std::forward_as_tuple(id, uniqueId, name, threadCreation));\n"
+ " const X newEntry2 = Entries.emplaceHint(std::piecewise_construct, std::forward_as_tuple(uniqueId),\n"
+ " std::forward_as_tuple(id, uniqueId, name, threadCreation));\n"
+ "}",
+ Style);
+ // clang-format on
+
+ Style.AlignConsecutiveAssignments = FormatStyle::ACS_None;
+ Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive;
+ verifyFormat("void foo() {\n"
+ " int myVar = 5;\n"
+ " double x = 3.14;\n"
+ " auto str = \"Hello \"\n"
+ " \"World\";\n"
+ " auto s = \"Hello \"\n"
+ " \"Again\";\n"
+ "}",
+ Style);
+
+ // clang-format off
+ verifyFormat("void foo() {\n"
+ " const int capacityBefore = Entries.capacity();\n"
+ " const auto newEntry = Entries.emplaceHint(std::piecewise_construct, std::forward_as_tuple(uniqueId),\n"
+ " std::forward_as_tuple(id, uniqueId, name, threadCreation));\n"
+ " const X newEntry2 = Entries.emplaceHint(std::piecewise_construct, std::forward_as_tuple(uniqueId),\n"
+ " std::forward_as_tuple(id, uniqueId, name, threadCreation));\n"
+ "}",
+ Style);
+ // clang-format on
+
+ Style.AlignConsecutiveAssignments = FormatStyle::ACS_Consecutive;
+ Style.AlignConsecutiveDeclarations = FormatStyle::ACS_Consecutive;
+
+ verifyFormat("void foo() {\n"
+ " int myVar = 5;\n"
+ " double x = 3.14;\n"
+ " auto str = \"Hello \"\n"
+ " \"World\";\n"
+ " auto s = \"Hello \"\n"
+ " \"Again\";\n"
+ "}",
+ Style);
+
+ // clang-format off
+ verifyFormat("void foo() {\n"
+ " const int capacityBefore = Entries.capacity();\n"
+ " const auto newEntry = Entries.emplaceHint(std::piecewise_construct, std::forward_as_tuple(uniqueId),\n"
+ " std::forward_as_tuple(id, uniqueId, name, threadCreation));\n"
+ " const X newEntry2 = Entries.emplaceHint(std::piecewise_construct, std::forward_as_tuple(uniqueId),\n"
+ " std::forward_as_tuple(id, uniqueId, name, threadCreation));\n"
+ "}",
+ Style);
+ // clang-format on
+}
+
TEST_F(FormatTest, LinuxBraceBreaking) {
FormatStyle LinuxBraceStyle = getLLVMStyle();
LinuxBraceStyle.BreakBeforeBraces = FormatStyle::BS_Linux;
More information about the cfe-commits
mailing list