[clang] [clang-format] Fix handling of C-Style variable definition of a struct (PR #76344)

via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 29 17:32:44 PST 2023


https://github.com/XDeme updated https://github.com/llvm/llvm-project/pull/76344

>From a55c720f344645bdad3838aaa39b136c8b8ee6dc Mon Sep 17 00:00:00 2001
From: XDeme <fernando.tagawa.gamail.com at gmail.com>
Date: Sun, 24 Dec 2023 20:18:02 -0300
Subject: [PATCH 1/4] [clang-format] Fix handling of C-Style variable
 definition of a struct

---
 clang/lib/Format/UnwrappedLineParser.cpp      | 8 ++++++++
 clang/unittests/Format/FormatTest.cpp         | 1 +
 clang/unittests/Format/TokenAnnotatorTest.cpp | 6 ++++++
 3 files changed, 15 insertions(+)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 684609747a5513..9cacb0d175adae 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -3873,6 +3873,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
   const FormatToken &InitialToken = *FormatTok;
   nextToken();
 
+  int NonMacroIdentifierCount = 0;
   // The actual identifier can be a nested name specifier, and in macros
   // it is often token-pasted.
   // An [[attribute]] can be before the identifier.
@@ -3898,6 +3899,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
         FormatTok->is(tok::identifier) &&
         FormatTok->TokenText != FormatTok->TokenText.upper();
     nextToken();
+    if (IsNonMacroIdentifier)
+      ++NonMacroIdentifierCount;
     // We can have macros in between 'class' and the class name.
     if (!IsNonMacroIdentifier && FormatTok->is(tok::l_paren))
       parseParens();
@@ -3960,6 +3963,11 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
     }
   };
   if (FormatTok->is(tok::l_brace)) {
+    // Handles C-Style variable declaration of a struct
+    if (Style.isCpp() && NonMacroIdentifierCount == 2) {
+      parseBracedList();
+      return;
+    }
     auto [OpenBraceType, ClosingBraceType] = GetBraceTypes(InitialToken);
     FormatTok->setFinalizedType(OpenBraceType);
     if (ParseAsExpr) {
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 762fc8254bdfc9..d37d1f58b51a4a 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -14548,6 +14548,7 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
   verifyFormat("struct foo f() {}\nint n;");
   verifyFormat("class foo f() {}\nint n;");
   verifyFormat("union foo f() {}\nint n;");
+  verifyFormat("struct MACRO foo f{};");
 
   // Templates.
   verifyFormat("template <class X> void f() {}\nint n;");
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index 2cafc0438ffb46..568574bf73a872 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -503,6 +503,12 @@ TEST_F(TokenAnnotatorTest, UnderstandsVariables) {
       annotate("inline bool var = is_integral_v<int> && is_signed_v<int>;");
   EXPECT_EQ(Tokens.size(), 15u) << Tokens;
   EXPECT_TOKEN(Tokens[8], tok::ampamp, TT_BinaryOperator);
+
+  Tokens = annotate("struct Foo f{};");
+  EXPECT_EQ(Tokens.size(), 7u) << Tokens;
+  EXPECT_TOKEN(Tokens[1], tok::identifier, TT_Unknown);
+  EXPECT_TOKEN(Tokens[2], tok::identifier, TT_StartOfName);
+  EXPECT_TOKEN(Tokens[3], tok::l_brace, TT_Unknown);
 }
 
 TEST_F(TokenAnnotatorTest, UnderstandsVariableTemplates) {

>From 9e2e88495e86f040aeca2a0f0bc69bff3e6986e4 Mon Sep 17 00:00:00 2001
From: XDeme <fernando.tagawa.gamail.com at gmail.com>
Date: Tue, 26 Dec 2023 14:11:09 -0300
Subject: [PATCH 2/4] Added support for templated structs

---
 clang/lib/Format/UnwrappedLineParser.cpp      | 13 +++++++++++++
 clang/unittests/Format/FormatTest.cpp         |  3 ++-
 clang/unittests/Format/TokenAnnotatorTest.cpp |  6 ++++++
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 9cacb0d175adae..e79eefd530451b 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -3917,6 +3917,8 @@ 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;
+    bool ColonFound = false;
     do {
       if (FormatTok->is(tok::l_brace)) {
         calculateBraceTypes(/*ExpectClassBody=*/true);
@@ -3944,6 +3946,17 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
         parseCSharpGenericTypeConstraint();
         break;
       }
+      // Do not count identifiers inside a template angle brackets
+      if(FormatTok->is(tok::colon))
+        ColonFound = true;
+      if (FormatTok->is(tok::less))
+        ++AngleNestingLevel;
+      else if (FormatTok->is(tok::greater))
+        --AngleNestingLevel;
+      if (AngleNestingLevel == 0 && !ColonFound && FormatTok->is(tok::identifier) &&
+          FormatTok->TokenText != FormatTok->TokenText.upper()) {
+        ++NonMacroIdentifierCount;
+      }
       nextToken();
     } while (!eof());
   }
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index d37d1f58b51a4a..04505e25b00c03 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -14543,12 +14543,13 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
   verifyFormat("struct foo a = {bar};\nint n;");
   verifyFormat("class foo a = {bar};\nint n;");
   verifyFormat("union foo a = {bar};\nint n;");
+  verifyFormat("struct MACRO foo f{};");
+  verifyFormat("struct MACRO foo<int> f{};");
 
   // Elaborate types inside function definitions.
   verifyFormat("struct foo f() {}\nint n;");
   verifyFormat("class foo f() {}\nint n;");
   verifyFormat("union foo f() {}\nint n;");
-  verifyFormat("struct MACRO foo f{};");
 
   // Templates.
   verifyFormat("template <class X> void f() {}\nint n;");
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index 568574bf73a872..a78d9a4df16025 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -509,6 +509,12 @@ TEST_F(TokenAnnotatorTest, UnderstandsVariables) {
   EXPECT_TOKEN(Tokens[1], tok::identifier, TT_Unknown);
   EXPECT_TOKEN(Tokens[2], tok::identifier, TT_StartOfName);
   EXPECT_TOKEN(Tokens[3], tok::l_brace, TT_Unknown);
+
+  Tokens = annotate("struct Foo<int> f{};");
+  EXPECT_EQ(Tokens.size(), 10u) << Tokens;
+  EXPECT_TOKEN(Tokens[1], tok::identifier, TT_Unknown);
+  EXPECT_TOKEN(Tokens[5], tok::identifier, TT_StartOfName);
+  EXPECT_TOKEN(Tokens[6], tok::l_brace, TT_Unknown);
 }
 
 TEST_F(TokenAnnotatorTest, UnderstandsVariableTemplates) {

>From f278882b71ddeca883c7d6fe75f704f540da0ee9 Mon Sep 17 00:00:00 2001
From: XDeme <fernando.tagawa.gamail.com at gmail.com>
Date: Tue, 26 Dec 2023 14:14:40 -0300
Subject: [PATCH 3/4] Format and a missing else

---
 clang/lib/Format/UnwrappedLineParser.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index e79eefd530451b..c706c9cbd8d9b0 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -3947,13 +3947,14 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
         break;
       }
       // Do not count identifiers inside a template angle brackets
-      if(FormatTok->is(tok::colon))
+      if (FormatTok->is(tok::colon))
         ColonFound = true;
-      if (FormatTok->is(tok::less))
+      else if (FormatTok->is(tok::less))
         ++AngleNestingLevel;
       else if (FormatTok->is(tok::greater))
         --AngleNestingLevel;
-      if (AngleNestingLevel == 0 && !ColonFound && FormatTok->is(tok::identifier) &&
+      if (AngleNestingLevel == 0 && !ColonFound &&
+          FormatTok->is(tok::identifier) &&
           FormatTok->TokenText != FormatTok->TokenText.upper()) {
         ++NonMacroIdentifierCount;
       }

>From 4bc2007ac55bf015e73b493aeff246b5a2c67798 Mon Sep 17 00:00:00 2001
From: XDeme <fernando.tagawa.gamail.com at gmail.com>
Date: Fri, 29 Dec 2023 22:31:16 -0300
Subject: [PATCH 4/4] Update

---
 clang/lib/Format/UnwrappedLineParser.cpp      | 15 +++++++--------
 clang/unittests/Format/TokenAnnotatorTest.cpp |  4 ++--
 2 files changed, 9 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index c706c9cbd8d9b0..98ef46e957e258 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -3921,7 +3921,8 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
     bool ColonFound = false;
     do {
       if (FormatTok->is(tok::l_brace)) {
-        calculateBraceTypes(/*ExpectClassBody=*/true);
+        calculateBraceTypes(/*ExpectClassBody=*/ColonFound ||
+                            NonMacroIdentifierCount < 2);
         if (!tryToParseBracedList())
           break;
       }
@@ -3946,16 +3947,15 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
         parseCSharpGenericTypeConstraint();
         break;
       }
-      // Do not count identifiers inside a template angle brackets
       if (FormatTok->is(tok::colon))
         ColonFound = true;
       else if (FormatTok->is(tok::less))
         ++AngleNestingLevel;
       else if (FormatTok->is(tok::greater))
         --AngleNestingLevel;
-      if (AngleNestingLevel == 0 && !ColonFound &&
-          FormatTok->is(tok::identifier) &&
-          FormatTok->TokenText != FormatTok->TokenText.upper()) {
+      // Do not count identifiers inside a template angle brackets
+      if (FormatTok->is(tok::identifier) && AngleNestingLevel == 0 &&
+          !ColonFound && FormatTok->TokenText != FormatTok->TokenText.upper()) {
         ++NonMacroIdentifierCount;
       }
       nextToken();
@@ -3978,10 +3978,9 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) {
   };
   if (FormatTok->is(tok::l_brace)) {
     // Handles C-Style variable declaration of a struct
-    if (Style.isCpp() && NonMacroIdentifierCount == 2) {
-      parseBracedList();
+    if (Style.isCpp() && NonMacroIdentifierCount == 2 && tryToParseBracedList())
       return;
-    }
+
     auto [OpenBraceType, ClosingBraceType] = GetBraceTypes(InitialToken);
     FormatTok->setFinalizedType(OpenBraceType);
     if (ParseAsExpr) {
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index a78d9a4df16025..c1898889ab9c52 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -508,13 +508,13 @@ TEST_F(TokenAnnotatorTest, UnderstandsVariables) {
   EXPECT_EQ(Tokens.size(), 7u) << Tokens;
   EXPECT_TOKEN(Tokens[1], tok::identifier, TT_Unknown);
   EXPECT_TOKEN(Tokens[2], tok::identifier, TT_StartOfName);
-  EXPECT_TOKEN(Tokens[3], tok::l_brace, TT_Unknown);
+  EXPECT_BRACE_KIND(Tokens[3], BK_BracedInit);
 
   Tokens = annotate("struct Foo<int> f{};");
   EXPECT_EQ(Tokens.size(), 10u) << Tokens;
   EXPECT_TOKEN(Tokens[1], tok::identifier, TT_Unknown);
   EXPECT_TOKEN(Tokens[5], tok::identifier, TT_StartOfName);
-  EXPECT_TOKEN(Tokens[6], tok::l_brace, TT_Unknown);
+  EXPECT_BRACE_KIND(Tokens[6], BK_BracedInit);
 }
 
 TEST_F(TokenAnnotatorTest, UnderstandsVariableTemplates) {



More information about the cfe-commits mailing list