Skip to content

Commit dc142ea

Browse files
committed
[clang-format] Correctly recognize binary operators in template arguments with parenthesized literals.
Fixes llvm/llvm-project#24602. Before, code like `foo<b & 1>` was formatted correctly but `foo<b & (1)>` wasn't. This patch fixes this inconsistency. Reviewed By: HazardyKnusperkeks, owenpan Differential Revision: https://reviews.llvm.org/D121846
1 parent e2a1f8e commit dc142ea

File tree

2 files changed

+21
-10
lines changed

2 files changed

+21
-10
lines changed

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2177,14 +2177,21 @@ class AnnotatingParser {
21772177

21782178
if (PrevToken->Tok.isLiteral() ||
21792179
PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true,
2180-
tok::kw_false, tok::r_brace) ||
2181-
NextToken->Tok.isLiteral() ||
2182-
NextToken->isOneOf(tok::kw_true, tok::kw_false) ||
2183-
NextToken->isUnaryOperator() ||
2184-
// If we know we're in a template argument, there are no named
2185-
// declarations. Thus, having an identifier on the right-hand side
2186-
// indicates a binary operator.
2187-
(InTemplateArgument && NextToken->Tok.isAnyIdentifier()))
2180+
tok::kw_false, tok::r_brace))
2181+
return TT_BinaryOperator;
2182+
2183+
const FormatToken *NextNonParen = NextToken;
2184+
while (NextNonParen && NextNonParen->is(tok::l_paren))
2185+
NextNonParen = NextNonParen->getNextNonComment();
2186+
if (NextNonParen && (NextNonParen->Tok.isLiteral() ||
2187+
NextNonParen->isOneOf(tok::kw_true, tok::kw_false) ||
2188+
NextNonParen->isUnaryOperator()))
2189+
return TT_BinaryOperator;
2190+
2191+
// If we know we're in a template argument, there are no named declarations.
2192+
// Thus, having an identifier on the right-hand side indicates a binary
2193+
// operator.
2194+
if (InTemplateArgument && NextToken->Tok.isAnyIdentifier())
21882195
return TT_BinaryOperator;
21892196

21902197
// "&&(" is quite unlikely to be two successive unary "&".
@@ -4508,12 +4515,11 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
45084515

45094516
// We only break before r_paren if we're in a block indented context.
45104517
if (Right.is(tok::r_paren)) {
4511-
if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) {
4518+
if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent)
45124519
return Right.MatchingParen &&
45134520
!(Right.MatchingParen->Previous &&
45144521
(Right.MatchingParen->Previous->is(tok::kw_for) ||
45154522
Right.MatchingParen->Previous->isIf()));
4516-
}
45174523

45184524
return false;
45194525
}

clang/unittests/Format/FormatTest.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10333,6 +10333,11 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
1033310333
verifyFormat("vector<a * b> v;");
1033410334
verifyFormat("foo<b && false>();");
1033510335
verifyFormat("foo<b & 1>();");
10336+
verifyFormat("foo<b & (1)>();");
10337+
verifyFormat("foo<b & (~0)>();");
10338+
verifyFormat("foo<b & (true)>();");
10339+
verifyFormat("foo<b & ((1))>();");
10340+
verifyFormat("foo<b & (/*comment*/ 1)>();");
1033610341
verifyFormat("decltype(*::std::declval<const T &>()) void F();");
1033710342
verifyFormat("typeof(*::std::declval<const T &>()) void F();");
1033810343
verifyFormat("_Atomic(*::std::declval<const T &>()) void F();");

0 commit comments

Comments
 (0)