Skip to content

Conversation

@owenca
Copy link
Contributor

@owenca owenca commented Jan 5, 2025

The new line types help to annotate */&/&& in simple requirements as binary operators.

Fixes #121675.

@llvmbot
Copy link
Member

llvmbot commented Jan 5, 2025

@llvm/pr-subscribers-clang-format

Author: Owen Pan (owenca)

Changes

The new line types help to annotate */&/&& in simple requirements as binary operators.

Fixes #121675.


Full diff: https://github.com/llvm/llvm-project/pull/121681.diff

3 Files Affected:

  • (modified) clang/lib/Format/TokenAnnotator.cpp (+19-5)
  • (modified) clang/lib/Format/TokenAnnotator.h (+2)
  • (modified) clang/unittests/Format/TokenAnnotatorTest.cpp (+15-12)
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 945174ca9c5861..fa864f4c5e943d 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -1582,7 +1582,10 @@ class AnnotatingParser {
         return false;
       break;
     case tok::l_brace:
-      if (Style.Language == FormatStyle::LK_TextProto) {
+      if (IsCpp) {
+        if (Tok->is(TT_RequiresExpressionLBrace))
+          Line.Type = LT_RequiresExpression;
+      } else if (Style.Language == FormatStyle::LK_TextProto) {
         FormatToken *Previous = Tok->getPreviousNonComment();
         if (Previous && Previous->isNot(TT_DictLiteral))
           Previous->setType(TT_SelectorName);
@@ -2024,8 +2027,10 @@ class AnnotatingParser {
       if (!consumeToken())
         return LT_Invalid;
     }
-    if (Line.Type == LT_AccessModifier)
-      return LT_AccessModifier;
+    if (Line.Type == LT_AccessModifier || Line.Type == LT_RequiresExpression ||
+        Line.Type == LT_SimpleRequirement) {
+      return Line.Type;
+    }
     if (KeywordVirtualFound)
       return LT_VirtualFunctionDecl;
     if (ImportStatement)
@@ -3102,8 +3107,10 @@ class AnnotatingParser {
       }
     }
 
-    if (!Scopes.empty() && Scopes.back() == ST_CompoundRequirement)
+    if (Line.Type == LT_SimpleRequirement ||
+        (!Scopes.empty() && Scopes.back() == ST_CompoundRequirement)) {
       return TT_BinaryOperator;
+    }
 
     return TT_PointerOrReference;
   }
@@ -3693,8 +3700,15 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
 
   if (!Line.Children.empty()) {
     ScopeStack.push_back(ST_ChildBlock);
-    for (auto &Child : Line.Children)
+    const bool InRequiresExpression = Line.Type == LT_RequiresExpression;
+    for (auto &Child : Line.Children) {
+      if (InRequiresExpression &&
+          !Child->First->isOneOf(tok::kw_typename, tok::kw_requires,
+                                 TT_CompoundRequirementLBrace)) {
+        Child->Type = LT_SimpleRequirement;
+      }
       annotate(*Child);
+    }
     // ScopeStack can become empty if Child has an unmatched `}`.
     if (!ScopeStack.empty())
       ScopeStack.pop_back();
diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h
index 1a250e94d97c50..fa15517042f250 100644
--- a/clang/lib/Format/TokenAnnotator.h
+++ b/clang/lib/Format/TokenAnnotator.h
@@ -33,6 +33,8 @@ enum LineType {
   LT_VirtualFunctionDecl,
   LT_ArrayOfStructInitializer,
   LT_CommentAbovePPDirective,
+  LT_RequiresExpression,
+  LT_SimpleRequirement,
 };
 
 enum ScopeType {
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index a5b2d09a9f704d..c07dbb36deaccc 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -830,6 +830,21 @@ TEST_F(TokenAnnotatorTest, UnderstandsCasts) {
   EXPECT_TOKEN(Tokens[9], tok::identifier, TT_TypeName);
   EXPECT_TOKEN(Tokens[10], tok::r_paren, TT_CastRParen);
   EXPECT_TOKEN(Tokens[11], tok::amp, TT_UnaryOperator);
+
+  Tokens = annotate("template <typename T>\n"
+                    "concept Multiplicable = requires(T a, T b) { a * b; };");
+  ASSERT_EQ(Tokens.size(), 24u) << Tokens;
+  EXPECT_TOKEN(Tokens[16], tok::l_brace, TT_RequiresExpressionLBrace);
+  EXPECT_TOKEN(Tokens[18], tok::star, TT_BinaryOperator);
+
+  Tokens = annotate("template <typename T, typename V>\n"
+                    "concept CheckMultiplicableBy = requires(T a, V b) {\n"
+                    "  { a * b } -> std::same_as<T>;\n"
+                    "};");
+  ASSERT_EQ(Tokens.size(), 36u) << Tokens;
+  EXPECT_TOKEN(Tokens[19], tok::l_brace, TT_RequiresExpressionLBrace);
+  EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_CompoundRequirementLBrace);
+  EXPECT_TOKEN(Tokens[22], tok::star, TT_BinaryOperator);
 }
 
 TEST_F(TokenAnnotatorTest, UnderstandsDynamicExceptionSpecifier) {
@@ -1456,18 +1471,6 @@ TEST_F(TokenAnnotatorTest, UnderstandsRequiresExpressions) {
   EXPECT_TOKEN(Tokens[13], tok::l_brace, TT_RequiresExpressionLBrace);
 }
 
-TEST_F(TokenAnnotatorTest, CompoundRequirement) {
-  auto Tokens = annotate("template <typename T, typename V>\n"
-                         "concept CheckMultiplicableBy = requires(T a, V b) {\n"
-                         "  { a * b } -> std::same_as<T>;\n"
-                         "};");
-  ASSERT_EQ(Tokens.size(), 36u) << Tokens;
-
-  EXPECT_TOKEN(Tokens[19], tok::l_brace, TT_RequiresExpressionLBrace);
-  EXPECT_TOKEN(Tokens[20], tok::l_brace, TT_CompoundRequirementLBrace);
-  EXPECT_TOKEN(Tokens[22], tok::star, TT_BinaryOperator);
-}
-
 TEST_F(TokenAnnotatorTest, UnderstandsPragmaRegion) {
   // Everything after #pragma region should be ImplicitStringLiteral
   auto Tokens = annotate("#pragma region Foo(Bar: Hello)");

The new line types help to annotate */&/&& in simple requirements as binary
operators.

Fixes llvm#121675.
@owenca owenca merged commit 9e4774b into llvm:main Jan 6, 2025
8 checks passed
@owenca owenca deleted the 121675 branch January 6, 2025 09:46
paulhuggett pushed a commit to paulhuggett/llvm-project that referenced this pull request Jan 7, 2025
…vm#121681)

The new line types help to annotate */&/&& in simple requirements as
binary operators.

Fixes llvm#121675.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[clang-format] simple-requirements not formatted as expressions

3 participants