Skip to content

Commit

Permalink
[clang-format] Handle template closer followed by empty paretheses (l…
Browse files Browse the repository at this point in the history
  • Loading branch information
owenca committed Oct 5, 2024
1 parent d5498c3 commit 8f516b1
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 23 deletions.
42 changes: 23 additions & 19 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,25 +189,29 @@ class AnnotatingParser {
next();
}

for (bool SeenTernaryOperator = false; CurrentToken;) {
for (bool SeenTernaryOperator = false, MaybeAngles = true; CurrentToken;) {
const bool InExpr = Contexts[Contexts.size() - 2].IsExpression;
if (CurrentToken->is(tok::greater)) {
const auto *Next = CurrentToken->Next;
// Try to do a better job at looking for ">>" within the condition of
// a statement. Conservatively insert spaces between consecutive ">"
// tokens to prevent splitting right bitshift operators and potentially
// altering program semantics. This check is overly conservative and
// will prevent spaces from being inserted in select nested template
// parameter cases, but should not alter program semantics.
if (Next && Next->is(tok::greater) &&
Left->ParentBracket != tok::less &&
CurrentToken->getStartOfNonWhitespace() ==
Next->getStartOfNonWhitespace().getLocWithOffset(-1)) {
return false;
}
if (InExpr && SeenTernaryOperator &&
(!Next || !Next->isOneOf(tok::l_paren, tok::l_brace))) {
return false;
if (CurrentToken->isNot(TT_TemplateCloser)) {
// Try to do a better job at looking for ">>" within the condition of
// a statement. Conservatively insert spaces between consecutive ">"
// tokens to prevent splitting right shift operators and potentially
// altering program semantics. This check is overly conservative and
// will prevent spaces from being inserted in select nested template
// parameter cases, but should not alter program semantics.
if (Next && Next->is(tok::greater) &&
Left->ParentBracket != tok::less &&
CurrentToken->getStartOfNonWhitespace() ==
Next->getStartOfNonWhitespace().getLocWithOffset(-1)) {
return false;
}
if (InExpr && SeenTernaryOperator &&
(!Next || !Next->isOneOf(tok::l_paren, tok::l_brace))) {
return false;
}
if (!MaybeAngles)
return false;
}
Left->MatchingParen = CurrentToken;
CurrentToken->MatchingParen = Left;
Expand Down Expand Up @@ -243,11 +247,11 @@ class AnnotatingParser {
// operator that was misinterpreted because we are parsing template
// parameters.
// FIXME: This is getting out of hand, write a decent parser.
if (InExpr && !Line.startsWith(tok::kw_template) &&
if (MaybeAngles && InExpr && !Line.startsWith(tok::kw_template) &&
Prev.is(TT_BinaryOperator)) {
const auto Precedence = Prev.getPrecedence();
if (Precedence > prec::Conditional && Precedence < prec::Relational)
return false;
MaybeAngles = false;
}
if (Prev.isOneOf(tok::question, tok::colon) && !Style.isProto())
SeenTernaryOperator = true;
Expand Down Expand Up @@ -1615,7 +1619,7 @@ class AnnotatingParser {
return false;
break;
case tok::greater:
if (Style.Language != FormatStyle::LK_TextProto)
if (Style.Language != FormatStyle::LK_TextProto && Tok->is(TT_Unknown))
Tok->setType(TT_BinaryOperator);
if (Tok->Previous && Tok->Previous->is(TT_TemplateCloser))
Tok->SpacesRequiredBefore = 1;
Expand Down
12 changes: 8 additions & 4 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2551,7 +2551,7 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) {
parseChildBlock();
break;
case tok::r_paren: {
const auto *Prev = LeftParen->Previous;
auto *Prev = LeftParen->Previous;
if (!MightBeStmtExpr && !MightBeFoldExpr && !Line->InMacroBody &&
Style.RemoveParentheses > FormatStyle::RPS_Leave) {
const auto *Next = Tokens->peekNextToken();
Expand All @@ -2575,9 +2575,13 @@ bool UnwrappedLineParser::parseParens(TokenType AmpAmpTokenType) {
FormatTok->Optional = true;
}
}
if (Prev && Prev->is(TT_TypenameMacro)) {
LeftParen->setFinalizedType(TT_TypeDeclarationParen);
FormatTok->setFinalizedType(TT_TypeDeclarationParen);
if (Prev) {
if (Prev->is(TT_TypenameMacro)) {
LeftParen->setFinalizedType(TT_TypeDeclarationParen);
FormatTok->setFinalizedType(TT_TypeDeclarationParen);
} else if (Prev->is(tok::greater) && FormatTok->Previous == LeftParen) {
Prev->setFinalizedType(TT_TemplateCloser);
}
}
nextToken();
return SeenEqual;
Expand Down
7 changes: 7 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3394,6 +3394,13 @@ TEST_F(TokenAnnotatorTest, SplitPenalty) {
EXPECT_SPLIT_PENALTY(Tokens[7], 23u);
}

TEST_F(TokenAnnotatorTest, TemplateInstantiation) {
auto Tokens = annotate("return FixedInt<N | M>();");
ASSERT_EQ(Tokens.size(), 11u) << Tokens;
EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener);
EXPECT_TOKEN(Tokens[6], tok::greater, TT_TemplateCloser);
}

} // namespace
} // namespace format
} // namespace clang

0 comments on commit 8f516b1

Please sign in to comment.