https://github.com/XDeme updated https://github.com/llvm/llvm-project/pull/77013
>From 45d01cbc7ec958518b1739daa9e9b0dc35c2d194 Mon Sep 17 00:00:00 2001 From: XDeme <fernando.tagawa.gamail....@gmail.com> Date: Thu, 4 Jan 2024 19:04:21 -0300 Subject: [PATCH 1/7] [clang-format] Handle templated elaborated type specifier in function return type. The behaviour now is consistent with the non templated version --- clang/lib/Format/UnwrappedLineParser.cpp | 8 ++++++++ clang/unittests/Format/FormatTest.cpp | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 684609747a5513..aaff6319dd45ef 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -3914,7 +3914,15 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { // (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::r_paren)) + 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 762fc8254bdfc9..f304407d0ce2f4 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -14583,9 +14583,7 @@ 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() {}\nint n;"); // Elaborate types where incorrectly parsing the structural element would // break the indent. >From 7a7d298c1e25940cc0607ba55eac5677b3b02f46 Mon Sep 17 00:00:00 2001 From: XDeme <fernando.tagawa.gamail....@gmail.com> Date: Thu, 4 Jan 2024 21:53:11 -0300 Subject: [PATCH 2/7] Fix edge case in template specialization --- clang/lib/Format/UnwrappedLineParser.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index aaff6319dd45ef..dc6ece09059b5d 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -3903,6 +3903,15 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { parseParens(); } + auto IsTemplate = [&] { + FormatToken *Tok = InitialToken.Previous; + while (Tok) { + if (Tok->is(tok::kw_template)) + return true; + Tok = Tok->Previous; + } + return false; + }; // Note that parsing away template declarations here leads to incorrectly // accepting function declarations as record declarations. // In general, we cannot solve this problem. Consider: @@ -3921,8 +3930,10 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { else if (FormatTok->is(tok::greater)) --AngleNestingLevel; - if (AngleNestingLevel == 0 && FormatTok->is(tok::r_paren)) + if (AngleNestingLevel == 0 && !IsTemplate() && + FormatTok->is(tok::r_paren)) { break; + } if (FormatTok->is(tok::l_brace)) { calculateBraceTypes(/*ExpectClassBody=*/true); if (!tryToParseBracedList()) >From 019992a0e227755015bc46e637d406fee911b9b5 Mon Sep 17 00:00:00 2001 From: XDeme <fernando.tagawa.gamail....@gmail.com> Date: Thu, 4 Jan 2024 22:13:15 -0300 Subject: [PATCH 3/7] Add test --- clang/unittests/Format/FormatTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index f304407d0ce2f4..6ac290b64ca450 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -14584,6 +14584,7 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) { verifyFormat("int i = SomeFunction(a<b, a> b);"); verifyFormat("class A<int> f() {}\nint n;"); + verifyFormat("template <> class Foo<int> F() {\n} n;"); // Elaborate types where incorrectly parsing the structural element would // break the indent. >From e41076ed7799dc7867d8bb9854298da396307090 Mon Sep 17 00:00:00 2001 From: XDeme <fernando.tagawa.gamail....@gmail.com> Date: Sat, 6 Jan 2024 19:54:57 -0300 Subject: [PATCH 4/7] Add test --- clang/unittests/Format/TokenAnnotatorTest.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 2cafc0438ffb46..396ed1c003e975 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -2453,6 +2453,13 @@ 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("void f() override {};"); ASSERT_EQ(Tokens.size(), 9u) << Tokens; EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName); >From 8de0863118d818e3e82342d475082b38b51f145e Mon Sep 17 00:00:00 2001 From: XDeme <fernando.tagawa.gamail....@gmail.com> Date: Wed, 10 Jan 2024 18:07:29 -0300 Subject: [PATCH 5/7] Comment and update --- clang/lib/Format/UnwrappedLineParser.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index dc6ece09059b5d..2d887d719d11c6 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -3915,7 +3915,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { // 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() {} + // template<typename T> + // class A<T> 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, @@ -3931,7 +3932,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { --AngleNestingLevel; if (AngleNestingLevel == 0 && !IsTemplate() && - FormatTok->is(tok::r_paren)) { + FormatTok->is(tok::l_paren)) { break; } if (FormatTok->is(tok::l_brace)) { >From a814099281d2cc88901cc6a1c0ff57a0d0a685e1 Mon Sep 17 00:00:00 2001 From: XDeme <fernando.tagawa.gamail....@gmail.com> Date: Thu, 11 Jan 2024 20:34:02 -0300 Subject: [PATCH 6/7] Update to verify macro --- clang/lib/Format/UnwrappedLineParser.cpp | 34 +++++-------------- clang/unittests/Format/FormatTest.cpp | 2 ++ clang/unittests/Format/TokenAnnotatorTest.cpp | 7 ++++ 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 2d887d719d11c6..b21d3287c6daf8 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -3873,6 +3873,9 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { const FormatToken &InitialToken = *FormatTok; nextToken(); + auto IsNonMacroIdentifier = [](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. @@ -3894,35 +3897,14 @@ 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(); + } } - auto IsTemplate = [&] { - FormatToken *Tok = InitialToken.Previous; - while (Tok) { - if (Tok->is(tok::kw_template)) - return true; - Tok = Tok->Previous; - } - return false; - }; - // Note that parsing away template declarations here leads to incorrectly - // accepting function declarations as record declarations. - // In general, we cannot solve this problem. Consider: - // template<typename T> - // class A<T> 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 { @@ -3931,8 +3913,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { else if (FormatTok->is(tok::greater)) --AngleNestingLevel; - if (AngleNestingLevel == 0 && !IsTemplate() && - FormatTok->is(tok::l_paren)) { + if (AngleNestingLevel == 0 && FormatTok->is(tok::l_paren) && + IsNonMacroIdentifier(FormatTok->Previous)) { break; } if (FormatTok->is(tok::l_brace)) { diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 6ac290b64ca450..0a1105cd52db0e 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -14584,6 +14584,8 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) { verifyFormat("int i = SomeFunction(a<b, a> b);"); verifyFormat("class A<int> f() {}\nint n;"); + verifyFormat("template <typename T> class A<T> f() {}\nint n;"); + verifyFormat("template <> class Foo<int> F() {\n} n;"); // Elaborate types where incorrectly parsing the structural element would diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 396ed1c003e975..a8cc522de3095c 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -2460,6 +2460,13 @@ TEST_F(TokenAnnotatorTest, BraceKind) { 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); >From be0d0029b3ceb99060858b197af2de52c1a4076b Mon Sep 17 00:00:00 2001 From: XDeme <fernando.tagawa.gamail....@gmail.com> Date: Sat, 20 Jan 2024 19:29:13 -0300 Subject: [PATCH 7/7] Wrap new after \n --- clang/unittests/Format/FormatTest.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 0a1105cd52db0e..692ef8c83168b2 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -14583,10 +14583,13 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) { verifyFormat("template <> struct X < 15, i<3 && 42 < 50 && 33 < 28> {};"); verifyFormat("int i = SomeFunction(a<b, a> b);"); - verifyFormat("class A<int> f() {}\nint n;"); - verifyFormat("template <typename T> class A<T> f() {}\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;"); + verifyFormat("template <> class Foo<int> F() {\n" + "} n;"); // Elaborate types where incorrectly parsing the structural element would // break the indent. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits