Skip to content

Commit 14e1fef

Browse files
authored
[clang-format] Handle template closer followed by empty paretheses (#110408)
Fixes #109925.
1 parent b91a25e commit 14e1fef

File tree

3 files changed

+38
-23
lines changed

3 files changed

+38
-23
lines changed

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -189,25 +189,29 @@ class AnnotatingParser {
189189
next();
190190
}
191191

192-
for (bool SeenTernaryOperator = false; CurrentToken;) {
192+
for (bool SeenTernaryOperator = false, MaybeAngles = true; CurrentToken;) {
193193
const bool InExpr = Contexts[Contexts.size() - 2].IsExpression;
194194
if (CurrentToken->is(tok::greater)) {
195195
const auto *Next = CurrentToken->Next;
196-
// Try to do a better job at looking for ">>" within the condition of
197-
// a statement. Conservatively insert spaces between consecutive ">"
198-
// tokens to prevent splitting right bitshift operators and potentially
199-
// altering program semantics. This check is overly conservative and
200-
// will prevent spaces from being inserted in select nested template
201-
// parameter cases, but should not alter program semantics.
202-
if (Next && Next->is(tok::greater) &&
203-
Left->ParentBracket != tok::less &&
204-
CurrentToken->getStartOfNonWhitespace() ==
205-
Next->getStartOfNonWhitespace().getLocWithOffset(-1)) {
206-
return false;
207-
}
208-
if (InExpr && SeenTernaryOperator &&
209-
(!Next || !Next->isOneOf(tok::l_paren, tok::l_brace))) {
210-
return false;
196+
if (CurrentToken->isNot(TT_TemplateCloser)) {
197+
// Try to do a better job at looking for ">>" within the condition of
198+
// a statement. Conservatively insert spaces between consecutive ">"
199+
// tokens to prevent splitting right shift operators and potentially
200+
// altering program semantics. This check is overly conservative and
201+
// will prevent spaces from being inserted in select nested template
202+
// parameter cases, but should not alter program semantics.
203+
if (Next && Next->is(tok::greater) &&
204+
Left->ParentBracket != tok::less &&
205+
CurrentToken->getStartOfNonWhitespace() ==
206+
Next->getStartOfNonWhitespace().getLocWithOffset(-1)) {
207+
return false;
208+
}
209+
if (InExpr && SeenTernaryOperator &&
210+
(!Next || !Next->isOneOf(tok::l_paren, tok::l_brace))) {
211+
return false;
212+
}
213+
if (!MaybeAngles)
214+
return false;
211215
}
212216
Left->MatchingParen = CurrentToken;
213217
CurrentToken->MatchingParen = Left;
@@ -247,11 +251,11 @@ class AnnotatingParser {
247251
// operator that was misinterpreted because we are parsing template
248252
// parameters.
249253
// FIXME: This is getting out of hand, write a decent parser.
250-
if (InExpr && !Line.startsWith(tok::kw_template) &&
254+
if (MaybeAngles && InExpr && !Line.startsWith(tok::kw_template) &&
251255
Prev.is(TT_BinaryOperator)) {
252256
const auto Precedence = Prev.getPrecedence();
253257
if (Precedence > prec::Conditional && Precedence < prec::Relational)
254-
return false;
258+
MaybeAngles = false;
255259
}
256260
if (Prev.isOneOf(tok::question, tok::colon) && !Style.isProto())
257261
SeenTernaryOperator = true;
@@ -1627,7 +1631,7 @@ class AnnotatingParser {
16271631
return false;
16281632
break;
16291633
case tok::greater:
1630-
if (Style.Language != FormatStyle::LK_TextProto)
1634+
if (Style.Language != FormatStyle::LK_TextProto && Tok->is(TT_Unknown))
16311635
Tok->setType(TT_BinaryOperator);
16321636
if (Tok->Previous && Tok->Previous->is(TT_TemplateCloser))
16331637
Tok->SpacesRequiredBefore = 1;

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2556,7 +2556,7 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) {
25562556
parseChildBlock();
25572557
break;
25582558
case tok::r_paren: {
2559-
const auto *Prev = LeftParen->Previous;
2559+
auto *Prev = LeftParen->Previous;
25602560
if (!MightBeStmtExpr && !MightBeFoldExpr && !Line->InMacroBody &&
25612561
Style.RemoveParentheses > FormatStyle::RPS_Leave) {
25622562
const auto *Next = Tokens->peekNextToken();
@@ -2585,9 +2585,13 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) {
25852585
FormatTok->Optional = true;
25862586
}
25872587
}
2588-
if (Prev && Prev->is(TT_TypenameMacro)) {
2589-
LeftParen->setFinalizedType(TT_TypeDeclarationParen);
2590-
FormatTok->setFinalizedType(TT_TypeDeclarationParen);
2588+
if (Prev) {
2589+
if (Prev->is(TT_TypenameMacro)) {
2590+
LeftParen->setFinalizedType(TT_TypeDeclarationParen);
2591+
FormatTok->setFinalizedType(TT_TypeDeclarationParen);
2592+
} else if (Prev->is(tok::greater) && FormatTok->Previous == LeftParen) {
2593+
Prev->setFinalizedType(TT_TemplateCloser);
2594+
}
25912595
}
25922596
nextToken();
25932597
return SeenEqual;

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3533,6 +3533,13 @@ TEST_F(TokenAnnotatorTest, TemplateName) {
35333533
EXPECT_TOKEN(Tokens[6], tok::greater, TT_TemplateCloser);
35343534
}
35353535

3536+
TEST_F(TokenAnnotatorTest, TemplateInstantiation) {
3537+
auto Tokens = annotate("return FixedInt<N | M>();");
3538+
ASSERT_EQ(Tokens.size(), 11u) << Tokens;
3539+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
3540+
EXPECT_TOKEN(Tokens[6], tok::greater, TT_TemplateCloser);
3541+
}
3542+
35363543
} // namespace
35373544
} // namespace format
35383545
} // namespace clang

0 commit comments

Comments
 (0)