diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -347,6 +347,10 @@ 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 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -618,6 +618,36 @@ 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 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -4048,6 +4048,41 @@ EXPECT_TRUE(H->Type); } +TEST(Hover, RewrittenBinaryOperatorSpaceship) { + Annotations T(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; + }; + + static_assert(Foo(1) !^= Foo(2)); + )cpp"); + + TestTU TU = TestTU::withCode(T.code()); + TU.ExtraArgs.push_back("-std=c++20"); + auto AST = TU.build(); + auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr); + EXPECT_EQ(HI->Type, + HoverInfo::PrintedType("bool (const Foo &) const noexcept")); + EXPECT_EQ(HI->Name, "operator=="); + EXPECT_EQ(HI->Definition, + "bool operator==(const Foo &) const noexcept = default"); + EXPECT_EQ(HI->Documentation, "Foo spaceship"); +} + } // namespace } // namespace clangd } // namespace clang