[clang] [clang-format] Don't count template template parameter as declaration (PR #95025)

Emilia Kond via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 11 13:37:04 PDT 2024


https://github.com/rymiel updated https://github.com/llvm/llvm-project/pull/95025

>From 6fc09d022a0e4e395a1b8e17166641dffc7c12eb Mon Sep 17 00:00:00 2001
From: Emilia Kond <emilia at rymiel.space>
Date: Mon, 10 Jun 2024 22:17:29 +0300
Subject: [PATCH 1/3] [clang-format] Don't count template template parameter as
 declaration

In ContinuationIndenter::mustBreak, a break is required between a
template declaration and the function/class declaration it applies to,
if the template declaration spans multiple lines.

However, this also includes template template parameters, which can
cause extra erroneous line breaks in some declarations.

This patch makes template template parameters not be counted as
template declarations.

Fixes https://github.com/llvm/llvm-project/issues/93793
---
 clang/lib/Format/TokenAnnotator.cpp           | 15 ++++++++++++---
 clang/unittests/Format/TokenAnnotatorTest.cpp | 17 +++++++++++++++++
 2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 1fe3b61a5a81f..9ed25d3e4c7ee 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -127,7 +127,7 @@ class AnnotatingParser {
                    SmallVector<ScopeType> &Scopes)
       : Style(Style), Line(Line), CurrentToken(Line.First), AutoFound(false),
         IsCpp(Style.isCpp()), LangOpts(getFormattingLangOpts(Style)),
-        Keywords(Keywords), Scopes(Scopes) {
+        Keywords(Keywords), Scopes(Scopes), TemplateDeclarationDepth(0) {
     assert(IsCpp == LangOpts.CXXOperatorNames);
     Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/false));
     resetTokenMetadata();
@@ -1269,10 +1269,17 @@ class AnnotatingParser {
     if (CurrentToken && CurrentToken->is(tok::less)) {
       CurrentToken->setType(TT_TemplateOpener);
       next();
-      if (!parseAngle())
+      TemplateDeclarationDepth++;
+      if (!parseAngle()) {
+        TemplateDeclarationDepth--;
         return false;
-      if (CurrentToken)
+      }
+      TemplateDeclarationDepth--;
+      if (CurrentToken &&
+          !(TemplateDeclarationDepth > 0 &&
+            CurrentToken->isOneOf(tok::kw_typename, tok::kw_class))) {
         CurrentToken->Previous->ClosesTemplateDeclaration = true;
+      }
       return true;
     }
     return false;
@@ -3073,6 +3080,8 @@ class AnnotatingParser {
   // same decision irrespective of the decisions for tokens leading up to it.
   // Store this information to prevent this from causing exponential runtime.
   llvm::SmallPtrSet<FormatToken *, 16> NonTemplateLess;
+
+  int TemplateDeclarationDepth;
 };
 
 static const int PrecedenceUnaryOperator = prec::PointerToMember + 1;
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index 8cc5c239d30a1..82de72ddeeaa1 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -584,6 +584,23 @@ TEST_F(TokenAnnotatorTest, UnderstandsNonTemplateAngleBrackets) {
   EXPECT_TOKEN(Tokens[20], tok::greater, TT_BinaryOperator);
 }
 
+TEST_F(TokenAnnotatorTest, UnderstandsTemplateTemplateParameters) {
+  auto Tokens = annotate("template <template <typename...> typename X,\n"
+                         "          template <typename...> typename Y,\n"
+                         "          typename... T>\n"
+                         "class A {};");
+  ASSERT_EQ(Tokens.size(), 28u) << Tokens;
+  EXPECT_TOKEN(Tokens[1], tok::less, TT_TemplateOpener);
+  EXPECT_TOKEN(Tokens[3], tok::less, TT_TemplateOpener);
+  EXPECT_TOKEN(Tokens[6], tok::greater, TT_TemplateCloser);
+  EXPECT_EQ(Tokens[6]->ClosesTemplateDeclaration, 0u);
+  EXPECT_TOKEN(Tokens[11], tok::less, TT_TemplateOpener);
+  EXPECT_TOKEN(Tokens[14], tok::greater, TT_TemplateCloser);
+  EXPECT_EQ(Tokens[14]->ClosesTemplateDeclaration, 0u);
+  EXPECT_TOKEN(Tokens[21], tok::greater, TT_TemplateCloser);
+  EXPECT_EQ(Tokens[21]->ClosesTemplateDeclaration, 1u);
+}
+
 TEST_F(TokenAnnotatorTest, UnderstandsWhitespaceSensitiveMacros) {
   FormatStyle Style = getLLVMStyle();
   Style.WhitespaceSensitiveMacros.push_back("FOO");

>From 16f5f19b8d9828396c227ab5c0b6bfe2a270fbf1 Mon Sep 17 00:00:00 2001
From: Emilia Kond <emilia at rymiel.space>
Date: Tue, 11 Jun 2024 23:35:49 +0300
Subject: [PATCH 2/3] Update clang/lib/Format/TokenAnnotator.cpp
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Björn Schäpers <github at hazardy.de>
---
 clang/lib/Format/TokenAnnotator.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 9ed25d3e4c7ee..e658fbf676b7d 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -1276,8 +1276,8 @@ class AnnotatingParser {
       }
       TemplateDeclarationDepth--;
       if (CurrentToken &&
-          !(TemplateDeclarationDepth > 0 &&
-            CurrentToken->isOneOf(tok::kw_typename, tok::kw_class))) {
+          (TemplateDeclarationDepth == 0 ||
+            !CurrentToken->isOneOf(tok::kw_typename, tok::kw_class))) {
         CurrentToken->Previous->ClosesTemplateDeclaration = true;
       }
       return true;

>From 6bf47a67e56b5f66c20c8faf7735dd6eb98ab884 Mon Sep 17 00:00:00 2001
From: Emilia Kond <emilia at rymiel.space>
Date: Tue, 11 Jun 2024 23:36:48 +0300
Subject: [PATCH 3/3] reformat

---
 clang/lib/Format/TokenAnnotator.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index e658fbf676b7d..958b46c535a9d 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -1277,7 +1277,7 @@ class AnnotatingParser {
       TemplateDeclarationDepth--;
       if (CurrentToken &&
           (TemplateDeclarationDepth == 0 ||
-            !CurrentToken->isOneOf(tok::kw_typename, tok::kw_class))) {
+           !CurrentToken->isOneOf(tok::kw_typename, tok::kw_class))) {
         CurrentToken->Previous->ClosesTemplateDeclaration = true;
       }
       return true;



More information about the cfe-commits mailing list