Skip to content

Commit a464e05

Browse files
authored
[clang-format] Handle templated elaborated type specifier in function… (#77013)
… return type. The behavior now is consistent with the non template version. Enabled and updated old test.
1 parent 11b3b10 commit a464e05

File tree

3 files changed

+37
-17
lines changed

3 files changed

+37
-17
lines changed

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3882,6 +3882,9 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
38823882
const FormatToken &InitialToken = *FormatTok;
38833883
nextToken();
38843884

3885+
auto IsNonMacroIdentifier = [](const FormatToken *Tok) {
3886+
return Tok->is(tok::identifier) && Tok->TokenText != Tok->TokenText.upper();
3887+
};
38853888
// The actual identifier can be a nested name specifier, and in macros
38863889
// it is often token-pasted.
38873890
// An [[attribute]] can be before the identifier.
@@ -3903,27 +3906,26 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
39033906
}
39043907
if (FormatTok->is(tok::l_square) && handleCppAttributes())
39053908
continue;
3906-
bool IsNonMacroIdentifier =
3907-
FormatTok->is(tok::identifier) &&
3908-
FormatTok->TokenText != FormatTok->TokenText.upper();
39093909
nextToken();
39103910
// We can have macros in between 'class' and the class name.
3911-
if (!IsNonMacroIdentifier && FormatTok->is(tok::l_paren))
3911+
if (!IsNonMacroIdentifier(FormatTok->Previous) &&
3912+
FormatTok->is(tok::l_paren)) {
39123913
parseParens();
3914+
}
39133915
}
39143916

3915-
// Note that parsing away template declarations here leads to incorrectly
3916-
// accepting function declarations as record declarations.
3917-
// In general, we cannot solve this problem. Consider:
3918-
// class A<int> B() {}
3919-
// which can be a function definition or a class definition when B() is a
3920-
// macro. If we find enough real-world cases where this is a problem, we
3921-
// can parse for the 'template' keyword in the beginning of the statement,
3922-
// and thus rule out the record production in case there is no template
3923-
// (this would still leave us with an ambiguity between template function
3924-
// and class declarations).
39253917
if (FormatTok->isOneOf(tok::colon, tok::less)) {
3918+
int AngleNestingLevel = 0;
39263919
do {
3920+
if (FormatTok->is(tok::less))
3921+
++AngleNestingLevel;
3922+
else if (FormatTok->is(tok::greater))
3923+
--AngleNestingLevel;
3924+
3925+
if (AngleNestingLevel == 0 && FormatTok->is(tok::l_paren) &&
3926+
IsNonMacroIdentifier(FormatTok->Previous)) {
3927+
break;
3928+
}
39273929
if (FormatTok->is(tok::l_brace)) {
39283930
calculateBraceTypes(/*ExpectClassBody=*/true);
39293931
if (!tryToParseBracedList())

clang/unittests/Format/FormatTest.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14659,9 +14659,13 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
1465914659
verifyFormat("template <> struct X < 15, i<3 && 42 < 50 && 33 < 28> {};");
1466014660
verifyFormat("int i = SomeFunction(a<b, a> b);");
1466114661

14662-
// FIXME:
14663-
// This now gets parsed incorrectly as class definition.
14664-
// verifyFormat("class A<int> f() {\n}\nint n;");
14662+
verifyFormat("class A<int> f() {}\n"
14663+
"int n;");
14664+
verifyFormat("template <typename T> class A<T> f() {}\n"
14665+
"int n;");
14666+
14667+
verifyFormat("template <> class Foo<int> F() {\n"
14668+
"} n;");
1466514669

1466614670
// Elaborate types where incorrectly parsing the structural element would
1466714671
// break the indent.

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2520,6 +2520,20 @@ TEST_F(TokenAnnotatorTest, BraceKind) {
25202520
EXPECT_BRACE_KIND(Tokens[4], BK_Block);
25212521
EXPECT_BRACE_KIND(Tokens[5], BK_Block);
25222522

2523+
Tokens = annotate("class Foo<int> f() {}");
2524+
ASSERT_EQ(Tokens.size(), 11u) << Tokens;
2525+
EXPECT_TOKEN(Tokens[5], tok::identifier, TT_FunctionDeclarationName);
2526+
EXPECT_TOKEN(Tokens[8], tok::l_brace, TT_FunctionLBrace);
2527+
EXPECT_BRACE_KIND(Tokens[8], BK_Block);
2528+
EXPECT_BRACE_KIND(Tokens[9], BK_Block);
2529+
2530+
Tokens = annotate("template <typename T> class Foo<T> f() {}");
2531+
ASSERT_EQ(Tokens.size(), 16u) << Tokens;
2532+
EXPECT_TOKEN(Tokens[10], tok::identifier, TT_FunctionDeclarationName);
2533+
EXPECT_TOKEN(Tokens[13], tok::l_brace, TT_FunctionLBrace);
2534+
EXPECT_BRACE_KIND(Tokens[13], BK_Block);
2535+
EXPECT_BRACE_KIND(Tokens[14], BK_Block);
2536+
25232537
Tokens = annotate("void f() override {};");
25242538
ASSERT_EQ(Tokens.size(), 9u) << Tokens;
25252539
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName);

0 commit comments

Comments
 (0)