[clang] [clang-format] Fix parsing of `operator<() {}` (PR #75144)

via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 11 22:33:33 PST 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-format

Author: None (XDeme)

<details>
<summary>Changes</summary>

Fixes llvm/llvm-project#<!-- -->74876.

During the parsing of `operator<(Foo&) {}`, there was no handling for the operator<, so it called `consumeToken()` again starting from `(Foo&)`, causing the `AnnotationParser::Scopes` to have one additional left brace each time it tried to parse it, leaving it unbalanced.
Because of this, in the following code:
```cpp
class Foo {
  void operator<(Foo&) {}
  Foo& f;
};
```
The `&` in the reference member, was being interpreted as `TT_BinaryOperator` instead of  `TT_PointerOrReference`.

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


3 Files Affected:

- (modified) clang/lib/Format/TokenAnnotator.cpp (+9) 
- (modified) clang/unittests/Format/FormatTest.cpp (+7) 
- (modified) clang/unittests/Format/TokenAnnotatorTest.cpp (+11) 


``````````diff
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index eaccb5881ca30f..957612088c7bb0 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -23,6 +23,9 @@
 
 namespace clang {
 namespace format {
+static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
+                                      const AnnotatedLine &Line,
+                                      FormatToken *&ClosingParen);
 
 static bool mustBreakAfterAttributes(const FormatToken &Tok,
                                      const FormatStyle &Style) {
@@ -164,6 +167,12 @@ class AnnotatingParser {
                TT_OverloadedOperatorLParen))) {
         return false;
       }
+      FormatToken *ClosingParen = nullptr;
+      if (Previous.Previous->is(tok::kw_operator) &&
+          isFunctionDeclarationName(Style.isCpp(), *Previous.Previous, Line,
+                                    ClosingParen)) {
+        return false;
+      }
     }
 
     FormatToken *Left = CurrentToken->Previous;
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 24b2fd599dc397..79013a473a7c2e 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11727,6 +11727,13 @@ TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
                "  void func(type &a) { a & member; }\n"
                "  anotherType &member;\n"
                "}");
+
+  Style.ReferenceAlignment = FormatStyle::RAS_Left;
+  verifyFormat("class Foo {\n"
+               "  void operator<(Foo&) {}\n"
+               "  Foo& f;\n"
+               "};",
+               Style);
 }
 
 TEST_F(FormatTest, UnderstandsAttributes) {
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index 65b1f0f4b57659..58a782f909d6aa 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -298,6 +298,17 @@ TEST_F(TokenAnnotatorTest, UnderstandsUsesOfStarAndAmp) {
   ASSERT_EQ(Tokens.size(), 12u) << Tokens;
   EXPECT_TOKEN(Tokens[2], tok::identifier, TT_TypeName);
   EXPECT_TOKEN(Tokens[3], tok::star, TT_PointerOrReference);
+
+  Tokens = annotate("class Foo {\n"
+                    "void operator<(Foo&) {}\n"
+                    "Foo& f;\n"
+                    "};");
+  ASSERT_EQ(Tokens.size(), 19u) << Tokens;
+  EXPECT_TOKEN(Tokens[4], tok::kw_operator, TT_FunctionDeclarationName);
+  EXPECT_TOKEN(Tokens[5], tok::less, TT_OverloadedOperator);
+  EXPECT_TOKEN(Tokens[6], tok::l_paren, TT_OverloadedOperatorLParen);
+  EXPECT_TOKEN(Tokens[10], tok::l_brace, TT_FunctionLBrace);
+  EXPECT_TOKEN(Tokens[13], tok::amp, TT_PointerOrReference);
 }
 
 TEST_F(TokenAnnotatorTest, UnderstandsUsesOfPlusAndMinus) {

``````````

</details>


https://github.com/llvm/llvm-project/pull/75144


More information about the cfe-commits mailing list