https://github.com/MythreyaK updated 
https://github.com/llvm/llvm-project/pull/154041

>From 8df889319e8146db958d027d5dee8ed22d6c9d3c Mon Sep 17 00:00:00 2001
From: Mythreya Kuricheti <g...@mythreya.dev>
Date: Sat, 16 Aug 2025 15:48:02 -0700
Subject: [PATCH 1/2] [clang] Include explicit object methods in overload
 suggestions

---
 .../clangd/unittests/CodeCompleteTests.cpp    | 119 ++++++++++++++++++
 clang/lib/Sema/SemaCodeComplete.cpp           |  10 +-
 2 files changed, 128 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/lib/Sema/SemaCodeComplete.cpp 
b/clang/lib/Sema/SemaCodeComplete.cpp
index e4f276086af25..d17b46f8b4070 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1428,10 +1428,18 @@ void ResultBuilder::AddResult(Result R, DeclContext 
*CurContext,
 
   AdjustResultPriorityForDecl(R);
 
+  // Account for explicit object parameter
+  const auto getQualifiers = [&](const CXXMethodDecl *MethodDecl) {
+    if (MethodDecl->isExplicitObjectMemberFunction())
+      return MethodDecl->getFunctionObjectParameterType().getQualifiers();
+    else
+      return MethodDecl->getMethodQualifiers();
+  };
+
   if (HasObjectTypeQualifiers)
     if (const auto *Method = dyn_cast<CXXMethodDecl>(R.Declaration))
       if (Method->isInstance()) {
-        Qualifiers MethodQuals = Method->getMethodQualifiers();
+        Qualifiers MethodQuals = getQualifiers(Method);
         if (ObjectTypeQualifiers == MethodQuals)
           R.Priority += CCD_ObjectQualifierMatch;
         else if (ObjectTypeQualifiers - MethodQuals) {

>From 3e2be0e0397e74aff6e20ff7c69f0fce4a1fb069 Mon Sep 17 00:00:00 2001
From: Mythreya Kuricheti <g...@mythreya.dev>
Date: Sun, 17 Aug 2025 23:03:34 -0700
Subject: [PATCH 2/2] Add const to signature string

---
 .../clangd/unittests/CodeCompleteTests.cpp    | 96 +++++++++----------
 clang/lib/Sema/SemaCodeComplete.cpp           | 28 ++++--
 2 files changed, 69 insertions(+), 55 deletions(-)

diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp 
b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index f5989eca4e1b5..cf07e11d6441e 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -4522,74 +4522,74 @@ TEST(CompletionTest, ListExplicitObjectOverloads) {
   {
     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})"))));
+    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})"))));
+    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})"))));
+    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})"))));
+    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})"))));
+    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})"))));
+    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
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp 
b/clang/lib/Sema/SemaCodeComplete.cpp
index d17b46f8b4070..56fac750637b0 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -3422,34 +3422,48 @@ static void
 AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
                                        const FunctionDecl *Function) {
   const auto *Proto = Function->getType()->getAs<FunctionProtoType>();
-  if (!Proto || !Proto->getMethodQuals())
+
+  // If CXX method, we need to check if explicit object is being used
+  const auto *cxxMethodDecl =
+      llvm::dyn_cast_if_present<CXXMethodDecl>(Function);
+
+  if ((!Proto || !Proto->getMethodQuals()) && !cxxMethodDecl)
     return;
 
   // FIXME: Add ref-qualifier!
 
+  Qualifiers FunctionQuals{};
+
+  if (cxxMethodDecl && cxxMethodDecl->isExplicitObjectMemberFunction()) {
+    FunctionQuals =
+        cxxMethodDecl->getFunctionObjectParameterType().getQualifiers();
+  } else {
+    FunctionQuals = Proto->getMethodQuals();
+  }
+
   // Handle single qualifiers without copying
-  if (Proto->getMethodQuals().hasOnlyConst()) {
+  if (FunctionQuals.hasOnlyConst()) {
     Result.AddInformativeChunk(" const");
     return;
   }
 
-  if (Proto->getMethodQuals().hasOnlyVolatile()) {
+  if (FunctionQuals.hasOnlyVolatile()) {
     Result.AddInformativeChunk(" volatile");
     return;
   }
 
-  if (Proto->getMethodQuals().hasOnlyRestrict()) {
+  if (FunctionQuals.hasOnlyRestrict()) {
     Result.AddInformativeChunk(" restrict");
     return;
   }
 
   // Handle multiple qualifiers.
   std::string QualsStr;
-  if (Proto->isConst())
+  if (FunctionQuals.hasConst())
     QualsStr += " const";
-  if (Proto->isVolatile())
+  if (FunctionQuals.hasVolatile())
     QualsStr += " volatile";
-  if (Proto->isRestrict())
+  if (FunctionQuals.hasRestrict())
     QualsStr += " restrict";
   Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr));
 }

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to