jackhong12 created this revision.
jackhong12 added reviewers: owenpan, MyDeveloperDay, curdeius, 
HazardyKnusperkeks.
Herald added a project: All.
jackhong12 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

In https://reviews.llvm.org/D127873, I missed the case `bool b = 3 == int{3} && 
true;`. `&&` here will be annotated as a reference operator.

There is a more concise way to handle this problem. Before token annotation, 
clang-format will split the declaration into multiple lines in the struct, 
union, class, and enum cases. For instance, `struct {int n} &&ptr={};` will be 
separated as `struct {`, `int n;` and `} &&ptr={};`. So, the matching `{` will 
be NULL, and we can leverage this to indicate whether `&&` is a reference 
operator or not.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D131750

Files:
  clang/lib/Format/TokenAnnotator.cpp
  clang/unittests/Format/FormatTest.cpp
  clang/unittests/Format/TokenAnnotatorTest.cpp


Index: clang/unittests/Format/TokenAnnotatorTest.cpp
===================================================================
--- clang/unittests/Format/TokenAnnotatorTest.cpp
+++ clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -88,6 +88,10 @@
   EXPECT_EQ(Tokens.size(), 5u) << Tokens;
   EXPECT_TOKEN(Tokens[1], tok::amp, TT_UnaryOperator);
 
+  Tokens = annotate("bool b = 3 == int{3} && true;\n");
+  EXPECT_EQ(Tokens.size(), 13u) << Tokens;
+  EXPECT_TOKEN(Tokens[9], tok::ampamp, TT_BinaryOperator);
+
   Tokens = annotate("struct {\n"
                     "} *ptr;");
   EXPECT_EQ(Tokens.size(), 7u) << Tokens;
Index: clang/unittests/Format/FormatTest.cpp
===================================================================
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -10474,6 +10474,7 @@
   verifyFormat("class {\n"
                "}&& ptr = {};",
                Style);
+  verifyFormat("bool b = 3 == int{3} && true;");
 
   Style.PointerAlignment = FormatStyle::PAS_Middle;
   verifyFormat("struct {\n"
Index: clang/lib/Format/TokenAnnotator.cpp
===================================================================
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2365,24 +2365,14 @@
         !PrevToken->MatchingParen)
       return TT_PointerOrReference;
 
-    // For "} &&"
-    if (PrevToken->is(tok::r_brace) && Tok.is(tok::ampamp)) {
-      const FormatToken *MatchingLBrace = PrevToken->MatchingParen;
-
-      // We check whether there is a TemplateCloser(">") to indicate it's a
-      // template or not. If it's not a template, "&&" is likely a reference
-      // operator.
-      //   struct {} &&ref = {};
-      if (!MatchingLBrace)
-        return TT_PointerOrReference;
-      FormatToken *BeforeLBrace = MatchingLBrace->getPreviousNonComment();
-      if (!BeforeLBrace || BeforeLBrace->isNot(TT_TemplateCloser))
-        return TT_PointerOrReference;
-
-      // If it is a template, "&&" is a binary operator.
-      //   enable_if<>{} && ...
-      return TT_BinaryOperator;
-    }
+    // Before token annotation, clang-format will split the declaration into
+    // multiple lines in the struct, union, class, and enum cases. For 
instance,
+    // `struct {int n} &&ptr={};` will be separated as `struct {`, `int n;` and
+    // `} &&ptr={};`. So, the matching `{` will be NULL, and we can leverage
+    // this to indicate whether `&&` is a reference operator or not.
+    if (PrevToken->is(tok::r_brace) && Tok.is(tok::ampamp) &&
+        !PrevToken->MatchingParen)
+      return TT_PointerOrReference;
 
     if (PrevToken->Tok.isLiteral() ||
         PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true,


Index: clang/unittests/Format/TokenAnnotatorTest.cpp
===================================================================
--- clang/unittests/Format/TokenAnnotatorTest.cpp
+++ clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -88,6 +88,10 @@
   EXPECT_EQ(Tokens.size(), 5u) << Tokens;
   EXPECT_TOKEN(Tokens[1], tok::amp, TT_UnaryOperator);
 
+  Tokens = annotate("bool b = 3 == int{3} && true;\n");
+  EXPECT_EQ(Tokens.size(), 13u) << Tokens;
+  EXPECT_TOKEN(Tokens[9], tok::ampamp, TT_BinaryOperator);
+
   Tokens = annotate("struct {\n"
                     "} *ptr;");
   EXPECT_EQ(Tokens.size(), 7u) << Tokens;
Index: clang/unittests/Format/FormatTest.cpp
===================================================================
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -10474,6 +10474,7 @@
   verifyFormat("class {\n"
                "}&& ptr = {};",
                Style);
+  verifyFormat("bool b = 3 == int{3} && true;");
 
   Style.PointerAlignment = FormatStyle::PAS_Middle;
   verifyFormat("struct {\n"
Index: clang/lib/Format/TokenAnnotator.cpp
===================================================================
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -2365,24 +2365,14 @@
         !PrevToken->MatchingParen)
       return TT_PointerOrReference;
 
-    // For "} &&"
-    if (PrevToken->is(tok::r_brace) && Tok.is(tok::ampamp)) {
-      const FormatToken *MatchingLBrace = PrevToken->MatchingParen;
-
-      // We check whether there is a TemplateCloser(">") to indicate it's a
-      // template or not. If it's not a template, "&&" is likely a reference
-      // operator.
-      //   struct {} &&ref = {};
-      if (!MatchingLBrace)
-        return TT_PointerOrReference;
-      FormatToken *BeforeLBrace = MatchingLBrace->getPreviousNonComment();
-      if (!BeforeLBrace || BeforeLBrace->isNot(TT_TemplateCloser))
-        return TT_PointerOrReference;
-
-      // If it is a template, "&&" is a binary operator.
-      //   enable_if<>{} && ...
-      return TT_BinaryOperator;
-    }
+    // Before token annotation, clang-format will split the declaration into
+    // multiple lines in the struct, union, class, and enum cases. For instance,
+    // `struct {int n} &&ptr={};` will be separated as `struct {`, `int n;` and
+    // `} &&ptr={};`. So, the matching `{` will be NULL, and we can leverage
+    // this to indicate whether `&&` is a reference operator or not.
+    if (PrevToken->is(tok::r_brace) && Tok.is(tok::ampamp) &&
+        !PrevToken->MatchingParen)
+      return TT_PointerOrReference;
 
     if (PrevToken->Tok.isLiteral() ||
         PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::kw_true,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to