[clang-tools-extra] 6f065bf - [clangd][c++20]Consider rewritten binary operators in TargetFinder

Jens Massberg via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 26 02:29:15 PDT 2023


Author: Jens Massberg
Date: 2023-06-26T11:26:10+02:00
New Revision: 6f065bfd633d7ca006f62b894108d5369dc46836

URL: https://github.com/llvm/llvm-project/commit/6f065bfd633d7ca006f62b894108d5369dc46836
DIFF: https://github.com/llvm/llvm-project/commit/6f065bfd633d7ca006f62b894108d5369dc46836.diff

LOG: [clangd][c++20]Consider rewritten binary operators in TargetFinder

In C++20 some binary operations can be rewritten, e.g. `a != b`
can be rewritten to `!(a == b)` if `!=` is not explicitly defined.
The `TargetFinder` hasn't considered the corresponding `CXXRewrittenBinaryOperator` yet. This resulted that the definition of such operators couldn't be found
when navigating to such a `!=` operator, see https://github.com/clangd/clangd/issues/1476.

In this patch we add support of `CXXRewrittenBinaryOperator` in `FindTarget`.
In such a case we redirect to the inner binary operator of the decomposed form.
E.g. in case that `a != b` has been rewritten to `!(a == b)` we go to the
`==` operator. The `==` operator might be implicitly defined (e.g. by a `<=>`
operator), but this case is already handled, see the new test.

I'm not sure if I the hover test which is added in this patch is the right one,
but at least is passed with this patch and fails without it :)

Note, that it might be a bit missleading that hovering over a `!=` refers to
"instance method operator==".

Differential Revision: https://reviews.llvm.org/D153331

Added: 
    

Modified: 
    clang-tools-extra/clangd/FindTarget.cpp
    clang-tools-extra/clangd/unittests/FindTargetTests.cpp
    clang-tools-extra/clangd/unittests/HoverTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp
index efbd05e2b74d3..eead9e6a3a7a4 100644
--- a/clang-tools-extra/clangd/FindTarget.cpp
+++ b/clang-tools-extra/clangd/FindTarget.cpp
@@ -347,6 +347,10 @@ struct TargetFinder {
       void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE) {
         Outer.add(CDE->getOperatorDelete(), Flags);
       }
+      void
+      VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *RBO) {
+        Outer.add(RBO->getDecomposedForm().InnerBinOp, Flags);
+      }
     };
     Visitor(*this, Flags).Visit(S);
   }

diff  --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
index 81e891b2db01e..9979628941bfe 100644
--- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp
@@ -618,6 +618,36 @@ TEST_F(TargetDeclTest, Coroutine) {
   EXPECT_DECLS("RecordTypeLoc", "struct executor");
 }
 
+TEST_F(TargetDeclTest, RewrittenBinaryOperator) {
+  Flags.push_back("-std=c++20");
+
+  Code = R"cpp(
+  namespace std {
+    struct strong_ordering {
+      int n;
+      constexpr operator int() const { return n; }
+      static const strong_ordering equal, greater, less;
+    };
+    constexpr strong_ordering strong_ordering::equal = {0};
+    constexpr strong_ordering strong_ordering::greater = {1};
+    constexpr strong_ordering strong_ordering::less = {-1};
+    }
+
+    struct Foo
+    {
+      int x;
+      auto operator<=>(const Foo&) const = default;
+    };
+
+    bool x = (Foo(1) [[!=]] Foo(2));
+  )cpp";
+  EXPECT_DECLS("CXXRewrittenBinaryOperator",
+               {"std::strong_ordering operator<=>(const Foo &) const = default",
+                Rel::TemplatePattern},
+               {"bool operator==(const Foo &) const noexcept = default",
+                Rel::TemplateInstantiation});
+}
+
 TEST_F(TargetDeclTest, FunctionTemplate) {
   Code = R"cpp(
     // Implicit specialization.

diff  --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 5338a680b787a..7002e27e9938f 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -2927,6 +2927,41 @@ TEST(Hover, All) {
          HI.Definition = "__attribute__((nonnull))";
          HI.Documentation = Attr::getDocumentation(attr::NonNull).str();
        }},
+      {
+          R"cpp(
+          namespace std {
+          struct strong_ordering {
+            int n;
+            constexpr operator int() const { return n; }
+            static const strong_ordering equal, greater, less;
+          };
+          constexpr strong_ordering strong_ordering::equal = {0};
+          constexpr strong_ordering strong_ordering::greater = {1};
+          constexpr strong_ordering strong_ordering::less = {-1};
+          }
+
+          struct Foo
+          {
+            int x;
+            // Foo spaceship
+            auto operator<=>(const Foo&) const = default;
+          };
+
+          bool x = Foo(1) [[!^=]] Foo(2);
+         )cpp",
+          [](HoverInfo &HI) {
+            HI.Type = "bool (const Foo &) const noexcept";
+            HI.Value = "true";
+            HI.Name = "operator==";
+            HI.Parameters = {{{"const Foo &"}, std::nullopt, std::nullopt}};
+            HI.ReturnType = "bool";
+            HI.Kind = index::SymbolKind::InstanceMethod;
+            HI.LocalScope = "Foo::";
+            HI.NamespaceScope = "";
+            HI.Definition =
+                "bool operator==(const Foo &) const noexcept = default";
+            HI.Documentation = "Foo spaceship";
+          }},
   };
 
   // Create a tiny index, so tests above can verify documentation is fetched.
@@ -2942,7 +2977,7 @@ TEST(Hover, All) {
 
     Annotations T(Case.Code);
     TestTU TU = TestTU::withCode(T.code());
-    TU.ExtraArgs.push_back("-std=c++17");
+    TU.ExtraArgs.push_back("-std=c++20");
     TU.ExtraArgs.push_back("-xobjective-c++");
 
     TU.ExtraArgs.push_back("-Wno-gnu-designator");
@@ -4076,7 +4111,6 @@ constexpr u64 pow_with_mod(u64 a, u64 b, u64 p) {
   EXPECT_TRUE(H->Value);
   EXPECT_TRUE(H->Type);
 }
-
 } // namespace
 } // namespace clangd
 } // namespace clang


        


More information about the cfe-commits mailing list