Skip to content

Commit 14e26d9

Browse files
committed
[clang-format] Add LT_RequiresExpression and LT_SimpleRequirement
The new line types help to annotate */&/&& in simple requirements as binary operators. Fixes #121675.
1 parent 0093450 commit 14e26d9

File tree

3 files changed

+36
-17
lines changed

3 files changed

+36
-17
lines changed

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,7 +1582,10 @@ class AnnotatingParser {
15821582
return false;
15831583
break;
15841584
case tok::l_brace:
1585-
if (Style.Language == FormatStyle::LK_TextProto) {
1585+
if (IsCpp) {
1586+
if (Tok->is(TT_RequiresExpressionLBrace))
1587+
Line.Type = LT_RequiresExpression;
1588+
} else if (Style.Language == FormatStyle::LK_TextProto) {
15861589
FormatToken *Previous = Tok->getPreviousNonComment();
15871590
if (Previous && Previous->isNot(TT_DictLiteral))
15881591
Previous->setType(TT_SelectorName);
@@ -2024,8 +2027,10 @@ class AnnotatingParser {
20242027
if (!consumeToken())
20252028
return LT_Invalid;
20262029
}
2027-
if (Line.Type == LT_AccessModifier)
2028-
return LT_AccessModifier;
2030+
if (Line.Type == LT_AccessModifier || Line.Type == LT_RequiresExpression ||
2031+
Line.Type == LT_SimpleRequirement) {
2032+
return Line.Type;
2033+
}
20292034
if (KeywordVirtualFound)
20302035
return LT_VirtualFunctionDecl;
20312036
if (ImportStatement)
@@ -3102,8 +3107,10 @@ class AnnotatingParser {
31023107
}
31033108
}
31043109

3105-
if (!Scopes.empty() && Scopes.back() == ST_CompoundRequirement)
3110+
if (Line.Type == LT_SimpleRequirement ||
3111+
(!Scopes.empty() && Scopes.back() == ST_CompoundRequirement)) {
31063112
return TT_BinaryOperator;
3113+
}
31073114

31083115
return TT_PointerOrReference;
31093116
}
@@ -3693,8 +3700,15 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
36933700

36943701
if (!Line.Children.empty()) {
36953702
ScopeStack.push_back(ST_ChildBlock);
3696-
for (auto &Child : Line.Children)
3703+
const bool InRequiresExpression = Line.Type == LT_RequiresExpression;
3704+
for (auto &Child : Line.Children) {
3705+
if (InRequiresExpression &&
3706+
!Child->First->isOneOf(tok::kw_typename, tok::kw_requires,
3707+
TT_CompoundRequirementLBrace)) {
3708+
Child->Type = LT_SimpleRequirement;
3709+
}
36973710
annotate(*Child);
3711+
}
36983712
// ScopeStack can become empty if Child has an unmatched `}`.
36993713
if (!ScopeStack.empty())
37003714
ScopeStack.pop_back();

clang/lib/Format/TokenAnnotator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ enum LineType {
3333
LT_VirtualFunctionDecl,
3434
LT_ArrayOfStructInitializer,
3535
LT_CommentAbovePPDirective,
36+
LT_RequiresExpression,
37+
LT_SimpleRequirement,
3638
};
3739

3840
enum ScopeType {

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,21 @@ TEST_F(TokenAnnotatorTest, UnderstandsUsesOfStarAndAmp) {
370370
ASSERT_EQ(Tokens.size(), 18u) << Tokens;
371371
EXPECT_TOKEN(Tokens[8], tok::r_paren, TT_CastRParen);
372372
EXPECT_TOKEN(Tokens[11], tok::star, TT_BinaryOperator);
373+
374+
Tokens = annotate("template <typename T>\n"
375+
"concept C = requires(T a, T b) { a && b; };");
376+
ASSERT_EQ(Tokens.size(), 24u) << Tokens;
377+
EXPECT_TOKEN(Tokens[16], tok::l_brace, TT_RequiresExpressionLBrace);
378+
EXPECT_TOKEN(Tokens[18], tok::ampamp, TT_BinaryOperator);
379+
380+
Tokens = annotate("template <typename T, typename V>\n"
381+
"concept CheckMultiplicableBy = requires(T a, V b) {\n"
382+
" { a * b } -> std::same_as<T>;\n"
383+
"};");
384+
ASSERT_EQ(Tokens.size(), 36u) << Tokens;
385+
EXPECT_TOKEN(Tokens[19], tok::l_brace, TT_RequiresExpressionLBrace);
386+
EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_CompoundRequirementLBrace);
387+
EXPECT_TOKEN(Tokens[22], tok::star, TT_BinaryOperator);
373388
}
374389

375390
TEST_F(TokenAnnotatorTest, UnderstandsUsesOfPlusAndMinus) {
@@ -1456,18 +1471,6 @@ TEST_F(TokenAnnotatorTest, UnderstandsRequiresExpressions) {
14561471
EXPECT_TOKEN(Tokens[13], tok::l_brace, TT_RequiresExpressionLBrace);
14571472
}
14581473

1459-
TEST_F(TokenAnnotatorTest, CompoundRequirement) {
1460-
auto Tokens = annotate("template <typename T, typename V>\n"
1461-
"concept CheckMultiplicableBy = requires(T a, V b) {\n"
1462-
" { a * b } -> std::same_as<T>;\n"
1463-
"};");
1464-
ASSERT_EQ(Tokens.size(), 36u) << Tokens;
1465-
1466-
EXPECT_TOKEN(Tokens[19], tok::l_brace, TT_RequiresExpressionLBrace);
1467-
EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_CompoundRequirementLBrace);
1468-
EXPECT_TOKEN(Tokens[22], tok::star, TT_BinaryOperator);
1469-
}
1470-
14711474
TEST_F(TokenAnnotatorTest, UnderstandsPragmaRegion) {
14721475
// Everything after #pragma region should be ImplicitStringLiteral
14731476
auto Tokens = annotate("#pragma region Foo(Bar: Hello)");

0 commit comments

Comments
 (0)