https://github.com/MythreyaK created https://github.com/llvm/llvm-project/pull/154041
Fixes #109608. (signature help still needs fixing. Will add a commit soon) Include methods that use explicit object in code complete suggestions. ```cpp struct S { void foo1() const; void foo2(); void foo3(this const S& self); void foo4(this S& self); }; int foo(const S arg) { arg.f^ // Now suggests foo3 as well } ``` Signature for void `foo3(this const S& self)` is shown as `(int a)` instead of `(int a) const`. >From d730c1fce8f16ae8139a2108ff55d911769fb0fa Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Sat, 16 Aug 2025 15:48:02 -0700 Subject: [PATCH] [clang] Include explicit object methods in overload suggestions --- .../clangd/unittests/CodeCompleteTests.cpp | 119 ++++++++++++++++++ clang/include/clang/AST/DeclCXX.h | 5 +- 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 1a1c32c241602..f5989eca4e1b5 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -4473,6 +4473,125 @@ TEST(CompletionTest, SkipExplicitObjectParameter) { snippetSuffix("")))); } } + +TEST(CompletionTest, ListExplicitObjectOverloads) { + Annotations Code(R"cpp( + struct S { + void foo1(int a); + void foo2(int a) const; + void foo3(this const S& self, int a); + void foo4(this S& self, int a); + }; + + void S::foo1(int a) { + this->$c1^; + } + + void S::foo2(int a) const { + this->$c2^; + } + + void S::foo3(this const S& self, int a) { + self.$c3^; + } + + void S::foo4(this S& self, int a) { + self.$c4^; + } + + void test1(S s) { + s.$c5^; + } + + void test2(const S s) { + s.$c6^; + } + )cpp"); + + auto TU = TestTU::withCode(Code.code()); + TU.ExtraArgs = {"-std=c++23"}; + + auto Preamble = TU.preamble(); + ASSERT_TRUE(Preamble); + + CodeCompleteOptions Opts{}; + + MockFS FS; + auto Inputs = TU.inputs(FS); + + { + auto Result = codeComplete(testPath(TU.Filename), Code.point("c1"), + Preamble.get(), Inputs, Opts); + EXPECT_THAT(Result.Completions, + UnorderedElementsAre( + AllOf(named("foo1"), signature("(int a)"), + snippetSuffix("(${1:int a})")), + AllOf(named("foo2"), signature("(int a) const"), + snippetSuffix("(${1:int a})")), + AllOf(named("foo3"), signature("(int a)" /* const */), + snippetSuffix("(${1:int a})")), + AllOf(named("foo4"), signature("(int a)"), + snippetSuffix("(${1:int a})")))); + } + { + auto Result = codeComplete(testPath(TU.Filename), Code.point("c2"), + Preamble.get(), Inputs, Opts); + EXPECT_THAT(Result.Completions, + UnorderedElementsAre( + AllOf(named("foo2"), signature("(int a) const"), + snippetSuffix("(${1:int a})")), + AllOf(named("foo3"), signature("(int a)" /* const */), + snippetSuffix("(${1:int a})")))); + } + { + auto Result = codeComplete(testPath(TU.Filename), Code.point("c3"), + Preamble.get(), Inputs, Opts); + EXPECT_THAT(Result.Completions, + UnorderedElementsAre( + AllOf(named("foo2"), signature("(int a) const"), + snippetSuffix("(${1:int a})")), + AllOf(named("foo3"), signature("(int a)" /* const */), + snippetSuffix("(${1:int a})")))); + } + { + auto Result = codeComplete(testPath(TU.Filename), Code.point("c4"), + Preamble.get(), Inputs, Opts); + EXPECT_THAT(Result.Completions, + UnorderedElementsAre( + AllOf(named("foo1"), signature("(int a)"), + snippetSuffix("(${1:int a})")), + AllOf(named("foo2"), signature("(int a) const"), + snippetSuffix("(${1:int a})")), + AllOf(named("foo3"), signature("(int a)" /* const */), + snippetSuffix("(${1:int a})")), + AllOf(named("foo4"), signature("(int a)"), + snippetSuffix("(${1:int a})")))); + } + { + auto Result = codeComplete(testPath(TU.Filename), Code.point("c5"), + Preamble.get(), Inputs, Opts); + EXPECT_THAT(Result.Completions, + UnorderedElementsAre( + AllOf(named("foo1"), signature("(int a)"), + snippetSuffix("(${1:int a})")), + AllOf(named("foo2"), signature("(int a) const"), + snippetSuffix("(${1:int a})")), + AllOf(named("foo3"), signature("(int a)" /* const */), + snippetSuffix("(${1:int a})")), + AllOf(named("foo4"), signature("(int a)"), + snippetSuffix("(${1:int a})")))); + } + { + auto Result = codeComplete(testPath(TU.Filename), Code.point("c6"), + Preamble.get(), Inputs, Opts); + EXPECT_THAT(Result.Completions, + UnorderedElementsAre( + AllOf(named("foo2"), signature("(int a) const"), + snippetSuffix("(${1:int a})")), + AllOf(named("foo3"), signature("(int a)" /* const */), + snippetSuffix("(${1:int a})")))); + } +} } // namespace } // namespace clangd } // namespace clang diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 1d2ef0f4f2319..5f0fe1580611e 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -2288,7 +2288,10 @@ class CXXMethodDecl : public FunctionDecl { const CXXRecordDecl *Decl); Qualifiers getMethodQualifiers() const { - return getType()->castAs<FunctionProtoType>()->getMethodQuals(); + if (isExplicitObjectMemberFunction()) + return getFunctionObjectParameterType().getQualifiers(); + else + return getType()->castAs<FunctionProtoType>()->getMethodQuals(); } /// Retrieve the ref-qualifier associated with this method. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits