[clang] a464e05 - [clang-format] Handle templated elaborated type specifier in function… (#77013)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Jan 20 14:48:03 PST 2024
Author: XDeme
Date: 2024-01-20T14:47:58-08:00
New Revision: a464e05109088f1f3a0ca4c83d6dd900e83bdb4b
URL: https://github.com/llvm/llvm-project/commit/a464e05109088f1f3a0ca4c83d6dd900e83bdb4b
DIFF: https://github.com/llvm/llvm-project/commit/a464e05109088f1f3a0ca4c83d6dd900e83bdb4b.diff
LOG: [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.
Added:
Modified:
clang/lib/Format/UnwrappedLineParser.cpp
clang/unittests/Format/FormatTest.cpp
clang/unittests/Format/TokenAnnotatorTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index c08ce86449b6ea..7bc6410a78a495 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -3882,6 +3882,9 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
const FormatToken &InitialToken = *FormatTok;
nextToken();
+ auto IsNonMacroIdentifier = [](const FormatToken *Tok) {
+ return Tok->is(tok::identifier) && Tok->TokenText != Tok->TokenText.upper();
+ };
// The actual identifier can be a nested name specifier, and in macros
// it is often token-pasted.
// An [[attribute]] can be before the identifier.
@@ -3903,27 +3906,26 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
}
if (FormatTok->is(tok::l_square) && handleCppAttributes())
continue;
- bool IsNonMacroIdentifier =
- FormatTok->is(tok::identifier) &&
- FormatTok->TokenText != FormatTok->TokenText.upper();
nextToken();
// We can have macros in between 'class' and the class name.
- if (!IsNonMacroIdentifier && FormatTok->is(tok::l_paren))
+ if (!IsNonMacroIdentifier(FormatTok->Previous) &&
+ FormatTok->is(tok::l_paren)) {
parseParens();
+ }
}
- // Note that parsing away template declarations here leads to incorrectly
- // accepting function declarations as record declarations.
- // In general, we cannot solve this problem. Consider:
- // class A<int> B() {}
- // which can be a function definition or a class definition when B() is a
- // macro. If we find enough real-world cases where this is a problem, we
- // can parse for the 'template' keyword in the beginning of the statement,
- // and thus rule out the record production in case there is no template
- // (this would still leave us with an ambiguity between template function
- // and class declarations).
if (FormatTok->isOneOf(tok::colon, tok::less)) {
+ int AngleNestingLevel = 0;
do {
+ if (FormatTok->is(tok::less))
+ ++AngleNestingLevel;
+ else if (FormatTok->is(tok::greater))
+ --AngleNestingLevel;
+
+ if (AngleNestingLevel == 0 && FormatTok->is(tok::l_paren) &&
+ IsNonMacroIdentifier(FormatTok->Previous)) {
+ break;
+ }
if (FormatTok->is(tok::l_brace)) {
calculateBraceTypes(/*ExpectClassBody=*/true);
if (!tryToParseBracedList())
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index cab495125415aa..3fb55ae2c1f413 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -14659,9 +14659,13 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
verifyFormat("template <> struct X < 15, i<3 && 42 < 50 && 33 < 28> {};");
verifyFormat("int i = SomeFunction(a<b, a> b);");
- // FIXME:
- // This now gets parsed incorrectly as class definition.
- // verifyFormat("class A<int> f() {\n}\nint n;");
+ verifyFormat("class A<int> f() {}\n"
+ "int n;");
+ verifyFormat("template <typename T> class A<T> f() {}\n"
+ "int n;");
+
+ verifyFormat("template <> class Foo<int> F() {\n"
+ "} n;");
// Elaborate types where incorrectly parsing the structural element would
// break the indent.
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index 64b2abac5cce53..b1e1e70a1abbf0 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -2520,6 +2520,20 @@ TEST_F(TokenAnnotatorTest, BraceKind) {
EXPECT_BRACE_KIND(Tokens[4], BK_Block);
EXPECT_BRACE_KIND(Tokens[5], BK_Block);
+ Tokens = annotate("class Foo<int> f() {}");
+ ASSERT_EQ(Tokens.size(), 11u) << Tokens;
+ EXPECT_TOKEN(Tokens[5], tok::identifier, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[8], tok::l_brace, TT_FunctionLBrace);
+ EXPECT_BRACE_KIND(Tokens[8], BK_Block);
+ EXPECT_BRACE_KIND(Tokens[9], BK_Block);
+
+ Tokens = annotate("template <typename T> class Foo<T> f() {}");
+ ASSERT_EQ(Tokens.size(), 16u) << Tokens;
+ EXPECT_TOKEN(Tokens[10], tok::identifier, TT_FunctionDeclarationName);
+ EXPECT_TOKEN(Tokens[13], tok::l_brace, TT_FunctionLBrace);
+ EXPECT_BRACE_KIND(Tokens[13], BK_Block);
+ EXPECT_BRACE_KIND(Tokens[14], BK_Block);
+
Tokens = annotate("void f() override {};");
ASSERT_EQ(Tokens.size(), 9u) << Tokens;
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName);
More information about the cfe-commits
mailing list