Skip to content

Commit 1515e63

Browse files
owencatru
authored andcommitted
[clang-format] Handle template closer followed by empty paretheses (#110408)
Fixes #109925.
1 parent 3e6207e commit 1515e63

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;
@@ -243,11 +247,11 @@ class AnnotatingParser {
243247
// operator that was misinterpreted because we are parsing template
244248
// parameters.
245249
// FIXME: This is getting out of hand, write a decent parser.
246-
if (InExpr && !Line.startsWith(tok::kw_template) &&
250+
if (MaybeAngles && InExpr && !Line.startsWith(tok::kw_template) &&
247251
Prev.is(TT_BinaryOperator)) {
248252
const auto Precedence = Prev.getPrecedence();
249253
if (Precedence > prec::Conditional && Precedence < prec::Relational)
250-
return false;
254+
MaybeAngles = false;
251255
}
252256
if (Prev.isOneOf(tok::question, tok::colon) && !Style.isProto())
253257
SeenTernaryOperator = true;
@@ -1615,7 +1619,7 @@ class AnnotatingParser {
16151619
return false;
16161620
break;
16171621
case tok::greater:
1618-
if (Style.Language != FormatStyle::LK_TextProto)
1622+
if (Style.Language != FormatStyle::LK_TextProto && Tok->is(TT_Unknown))
16191623
Tok->setType(TT_BinaryOperator);
16201624
if (Tok->Previous && Tok->Previous->is(TT_TemplateCloser))
16211625
Tok->SpacesRequiredBefore = 1;

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2551,7 +2551,7 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) {
25512551
parseChildBlock();
25522552
break;
25532553
case tok::r_paren: {
2554-
const auto *Prev = LeftParen->Previous;
2554+
auto *Prev = LeftParen->Previous;
25552555
if (!MightBeStmtExpr && !MightBeFoldExpr && !Line->InMacroBody &&
25562556
Style.RemoveParentheses > FormatStyle::RPS_Leave) {
25572557
const auto *Next = Tokens->peekNextToken();
@@ -2575,9 +2575,13 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) {
25752575
FormatTok->Optional = true;
25762576
}
25772577
}
2578-
if (Prev && Prev->is(TT_TypenameMacro)) {
2579-
LeftParen->setFinalizedType(TT_TypeDeclarationParen);
2580-
FormatTok->setFinalizedType(TT_TypeDeclarationParen);
2578+
if (Prev) {
2579+
if (Prev->is(TT_TypenameMacro)) {
2580+
LeftParen->setFinalizedType(TT_TypeDeclarationParen);
2581+
FormatTok->setFinalizedType(TT_TypeDeclarationParen);
2582+
} else if (Prev->is(tok::greater) && FormatTok->Previous == LeftParen) {
2583+
Prev->setFinalizedType(TT_TemplateCloser);
2584+
}
25812585
}
25822586
nextToken();
25832587
return SeenEqual;

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3394,6 +3394,13 @@ TEST_F(TokenAnnotatorTest, SplitPenalty) {
33943394
EXPECT_SPLIT_PENALTY(Tokens[7], 23u);
33953395
}
33963396

3397+
TEST_F(TokenAnnotatorTest, TemplateInstantiation) {
3398+
auto Tokens = annotate("return FixedInt<N | M>();");
3399+
ASSERT_EQ(Tokens.size(), 11u) << Tokens;
3400+
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
3401+
EXPECT_TOKEN(Tokens[6], tok::greater, TT_TemplateCloser);
3402+
}
3403+
33973404
} // namespace
33983405
} // namespace format
33993406
} // namespace clang

0 commit comments

Comments
 (0)