forked from OSchip/llvm-project
[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
This commit is contained in:
parent
8c6c357897
commit
c5243c63cd
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue