Skip to content

[clang-format] Improve BlockIndent at ColumnLimit #93140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jul 25, 2024
38 changes: 35 additions & 3 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,37 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
return !Tok.Previous->isOneOf(TT_CastRParen, tok::kw_for, tok::kw_while,
tok::kw_switch);
};
auto IsFunctionCallParen = [](const FormatToken &Tok) {
return Tok.is(tok::l_paren) && Tok.ParameterCount > 0 && Tok.Previous &&
Tok.Previous->is(tok::identifier);
};
const auto IsInTemplateString = [this](const FormatToken &Tok) {
if (!Style.isJavaScript())
return false;
for (const auto *Prev = &Tok; Prev; Prev = Prev->Previous) {
if (Prev->is(TT_TemplateString) && Prev->opensScope())
return true;
if (Prev->is(TT_TemplateString) && Prev->closesScope())
break;
}
return false;
};
// Identifies simple (no expression) one-argument function calls.
const auto IsSimpleFunction = [&](const FormatToken &Tok) {
if (!Tok.FakeLParens.empty() && Tok.FakeLParens.back() > prec::Unknown)
return false;
const auto *Previous = Tok.Previous;
if (!Previous || (!Previous->isOneOf(TT_FunctionDeclarationLParen,
TT_LambdaDefinitionLParen) &&
!IsFunctionCallParen(*Previous))) {
return true;
}
if (IsOpeningBracket(Tok) || IsInTemplateString(Tok))
return true;
const auto *Next = Tok.Next;
return !Next || Next->isMemberAccess() ||
Next->is(TT_FunctionDeclarationLParen) || IsFunctionCallParen(*Next);
};
if ((Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak ||
Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) &&
IsOpeningBracket(Previous) && State.Column > getNewLineColumn(State) &&
Expand All @@ -813,10 +844,10 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
// caaaaaaaaaaaall(
// caaaaaaaaaaaall(
// caaaaaaaaaaaaaaaaaaaaaaall(aaaaaaaaaaaaaa, aaaaaaaaa))));
Current.FakeLParens.size() > 0 &&
Current.FakeLParens.back() > prec::Unknown) {
!IsSimpleFunction(Current)) {
CurrentState.NoLineBreak = true;
}

if (Previous.is(TT_TemplateString) && Previous.opensScope())
CurrentState.NoLineBreak = true;

Expand All @@ -831,7 +862,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
Previous.isNot(TT_TableGenDAGArgOpenerToBreak) &&
!(Current.MacroParent && Previous.MacroParent) &&
(Current.isNot(TT_LineComment) ||
Previous.isOneOf(BK_BracedInit, TT_VerilogMultiLineListLParen))) {
Previous.isOneOf(BK_BracedInit, TT_VerilogMultiLineListLParen)) &&
!IsInTemplateString(Current)) {
CurrentState.Indent = State.Column + Spaces;
CurrentState.IsAligned = true;
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ namespace format {
TYPE(JsTypeColon) \
TYPE(JsTypeOperator) \
TYPE(JsTypeOptionalQuestion) \
TYPE(LambdaDefinitionLParen) \
TYPE(LambdaLBrace) \
TYPE(LambdaLSquare) \
TYPE(LeadingJavaAnnotation) \
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ static bool canBeObjCSelectorComponent(const FormatToken &Tok) {

/// With `Left` being '(', check if we're at either `[...](` or
/// `[...]<...>(`, where the [ opens a lambda capture list.
// FIXME: this doesn't cover attributes/constraints before the l_paren.
static bool isLambdaParameterList(const FormatToken *Left) {
// Skip <...> if present.
if (Left->Previous && Left->Previous->is(tok::greater) &&
Expand Down Expand Up @@ -365,6 +366,7 @@ class AnnotatingParser {
Contexts.back().IsExpression = false;
} else if (isLambdaParameterList(&OpeningParen)) {
// This is a parameter list of a lambda expression.
OpeningParen.setType(TT_LambdaDefinitionLParen);
Contexts.back().IsExpression = false;
} else if (OpeningParen.is(TT_RequiresExpressionLParen)) {
Contexts.back().IsExpression = false;
Expand Down Expand Up @@ -6205,6 +6207,12 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return !(Previous && (Previous->is(tok::kw_for) || Previous->isIf()));
}

if (Left.isOneOf(tok::r_paren, TT_TrailingAnnotation) &&
Right.is(TT_TrailingAnnotation) &&
Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) {
return false;
}

// Allow breaking after a trailing annotation, e.g. after a method
// declaration.
if (Left.is(TT_TrailingAnnotation)) {
Expand Down
25 changes: 25 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9338,6 +9338,31 @@ TEST_F(FormatTest, AlignsAfterOpenBracket) {
" aaaaaaaaaaaaaaaa\n"
");",
Style);
verifyFormat("bool aaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
" const bool &aaaaaaaaa, const void *aaaaaaaaaa\n"
") const {\n"
" return true;\n"
"}",
Style);
verifyFormat("bool aaaaaaaaaaaaaaaaaaaaaaaa(\n"
" const bool &aaaaaaaaaa, const void *aaaaaaaaaa\n"
") const;",
Style);
verifyFormat("void aaaaaaaaa(\n"
" int aaaaaa, int bbbbbb, int cccccc, int dddddddddd\n"
") const noexcept -> std::vector<of_very_long_type>;",
Style);
verifyFormat(
"x = aaaaaaaaaaaaaaa(\n"
" \"a aaaaaaa aaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaaaaaaaa\"\n"
");",
Style);
Style.ColumnLimit = 60;
verifyFormat("auto lambda =\n"
" [&b](\n"
" auto aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" ) {};",
Style);
}

TEST_F(FormatTest, ParenthesesAndOperandAlignment) {
Expand Down
32 changes: 32 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1665,38 +1665,45 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
auto Tokens = annotate("[]() constexpr {}");
ASSERT_EQ(Tokens.size(), 8u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[5], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[]() consteval {}");
ASSERT_EQ(Tokens.size(), 8u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[5], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[]() mutable {}");
ASSERT_EQ(Tokens.size(), 8u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[5], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[]() static {}");
ASSERT_EQ(Tokens.size(), 8u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[5], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[]() -> auto {}");
ASSERT_EQ(Tokens.size(), 9u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[4], tok::arrow, TT_TrailingReturnArrow);
EXPECT_TOKEN(Tokens[6], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[]() -> auto & {}");
ASSERT_EQ(Tokens.size(), 10u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[4], tok::arrow, TT_TrailingReturnArrow);
EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[]() -> auto * {}");
ASSERT_EQ(Tokens.size(), 10u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[4], tok::arrow, TT_TrailingReturnArrow);
EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_LambdaLBrace);

Expand Down Expand Up @@ -1725,13 +1732,15 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
Tokens = annotate("foo([&](u32 bar) __attribute__((attr)) -> void {});");
ASSERT_EQ(Tokens.size(), 22u) << Tokens;
EXPECT_TOKEN(Tokens[2], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[5], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[15], tok::arrow, TT_TrailingReturnArrow);
EXPECT_TOKEN(Tokens[17], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[] <typename T> () {}");
ASSERT_EQ(Tokens.size(), 11u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[6], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[8], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[] <typename T> {}");
Expand All @@ -1744,6 +1753,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
ASSERT_EQ(Tokens.size(), 12u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[7], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[9], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[] <typename... T> {}");
Expand All @@ -1756,6 +1766,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
ASSERT_EQ(Tokens.size(), 12u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[7], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[9], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[] <int... T> {}");
Expand All @@ -1768,6 +1779,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
ASSERT_EQ(Tokens.size(), 12u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[7], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[9], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[] <Foo... T> {}");
Expand All @@ -1781,6 +1793,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
ASSERT_EQ(Tokens.size(), 18u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[6], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[10], tok::kw_requires, TT_RequiresClause);
EXPECT_TRUE(Tokens[14]->ClosesRequiresClause);
EXPECT_TOKEN(Tokens[15], tok::l_brace, TT_LambdaLBrace);
Expand All @@ -1789,6 +1802,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
ASSERT_EQ(Tokens.size(), 19u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[6], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[8], tok::ampamp, TT_PointerOrReference);
EXPECT_TOKEN(Tokens[11], tok::kw_requires, TT_RequiresClause);
EXPECT_TRUE(Tokens[15]->ClosesRequiresClause);
Expand All @@ -1798,6 +1812,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
ASSERT_EQ(Tokens.size(), 23u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[6], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[10], tok::kw_requires, TT_RequiresClause);
EXPECT_TRUE(Tokens[19]->ClosesRequiresClause);
EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_LambdaLBrace);
Expand All @@ -1806,6 +1821,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
ASSERT_EQ(Tokens.size(), 20u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[6], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[10], tok::arrow, TT_TrailingReturnArrow);
EXPECT_TOKEN(Tokens[12], tok::kw_requires, TT_RequiresClause);
EXPECT_TRUE(Tokens[16]->ClosesRequiresClause);
Expand All @@ -1817,6 +1833,8 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
EXPECT_TRUE(Tokens[10]->ClosesRequiresClause);
// FIXME:
// EXPECT_TOKEN(Tokens[11], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[15], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[] <typename T> requires Bar<T> (T &&t) {}");
Expand All @@ -1825,6 +1843,8 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
EXPECT_TRUE(Tokens[10]->ClosesRequiresClause);
// FIXME:
// EXPECT_TOKEN(Tokens[11], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[13], tok::ampamp, TT_PointerOrReference);
EXPECT_TOKEN(Tokens[16], tok::l_brace, TT_LambdaLBrace);

Expand All @@ -1834,6 +1854,8 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
EXPECT_TRUE(Tokens[15]->ClosesRequiresClause);
// FIXME:
// EXPECT_TOKEN(Tokens[16], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[] <typename T> requires true (T&& t) {}");
Expand All @@ -1842,6 +1864,8 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
EXPECT_TRUE(Tokens[7]->ClosesRequiresClause);
// FIXME:
// EXPECT_TOKEN(Tokens[8], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[10], tok::ampamp, TT_PointerOrReference);
EXPECT_TOKEN(Tokens[13], tok::l_brace, TT_LambdaLBrace);

Expand Down Expand Up @@ -1876,6 +1900,8 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[6], tok::kw_requires, TT_RequiresClause);
EXPECT_TRUE(Tokens[10]->ClosesRequiresClause);
// FIXME:
// EXPECT_TOKEN(Tokens[11], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[15], tok::kw_requires, TT_RequiresClause);
EXPECT_TRUE(Tokens[19]->ClosesRequiresClause);
EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_LambdaLBrace);
Expand All @@ -1885,20 +1911,23 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[7], tok::greater, TT_TemplateCloser);
EXPECT_TOKEN(Tokens[8], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[] <int I = 0> (T t) {}");
ASSERT_EQ(Tokens.size(), 15u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[7], tok::greater, TT_TemplateCloser);
EXPECT_TOKEN(Tokens[8], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[] <bool b = false> (T t) {}");
ASSERT_EQ(Tokens.size(), 15u) << Tokens;
EXPECT_TOKEN(Tokens[0], tok::l_square, TT_LambdaLSquare);
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[7], tok::greater, TT_TemplateCloser);
EXPECT_TOKEN(Tokens[8], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[12], tok::l_brace, TT_LambdaLBrace);

Tokens = annotate("[] <bool b = true && false> (T&& t) {}");
Expand All @@ -1907,6 +1936,7 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[7], tok::ampamp, TT_BinaryOperator);
EXPECT_TOKEN(Tokens[9], tok::greater, TT_TemplateCloser);
EXPECT_TOKEN(Tokens[10], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[12], tok::ampamp, TT_PointerOrReference);
EXPECT_TOKEN(Tokens[15], tok::l_brace, TT_LambdaLBrace);

Expand All @@ -1916,6 +1946,8 @@ TEST_F(TokenAnnotatorTest, UnderstandsLambdas) {
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[7], tok::greater, TT_TemplateCloser);
EXPECT_TOKEN(Tokens[8], tok::kw_requires, TT_RequiresClause);
// FIXME:
// EXPECT_TOKEN(Tokens[13], tok::l_paren, TT_LambdaDefinitionLParen);
EXPECT_TOKEN(Tokens[17], tok::l_brace, TT_LambdaLBrace);
}

Expand Down