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

>From b279e4b718488a08d25fdc43edae965c0fec288c Mon Sep 17 00:00:00 2001
From: Mythreya Kuricheti <g...@mythreya.dev>
Date: Fri, 15 Aug 2025 00:52:37 -0700
Subject: [PATCH 1/3] [clang] Skip unqualified members in explicit-member
 functions

---
 .../clangd/unittests/CodeCompleteTests.cpp    | 39 +++++++++++++++++++
 clang/lib/Sema/SemaCodeComplete.cpp           | 10 +++++
 2 files changed, 49 insertions(+)

diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp 
b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 1a1c32c241602..360693a02a1f5 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -4473,6 +4473,45 @@ TEST(CompletionTest, SkipExplicitObjectParameter) {
                                   snippetSuffix(""))));
   }
 }
+
+TEST(CompletionTest, MemberAccessInExplicitObjMemfn) {
+  Annotations Code(R"cpp(
+    struct A {
+      int member {};
+
+      void foo(this A& self) {
+        // Should not offer `member` here, since it needs to be 
+        // referenced as `self.member`.
+        mem$c1^;
+        self.mem$c2^;
+      }
+    };
+  )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, ElementsAre());
+  }
+  {
+    auto Result = codeComplete(testPath(TU.Filename), Code.point("c2"),
+                               Preamble.get(), Inputs, Opts);
+
+    EXPECT_THAT(Result.Completions, ElementsAre(named("member")));
+  }
+}
 } // namespace
 } // namespace clangd
 } // namespace clang
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp 
b/clang/lib/Sema/SemaCodeComplete.cpp
index e4f276086af25..224d105c313e6 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1428,6 +1428,16 @@ void ResultBuilder::AddResult(Result R, DeclContext 
*CurContext,
 
   AdjustResultPriorityForDecl(R);
 
+  if (isa<FieldDecl>(R.Declaration)) {
+    // If result is a member in the context of an explicit-object member
+    // function, drop it because it must be accessed through the object
+    // parameter
+    if (auto *MethodDecl = dyn_cast<CXXMethodDecl>(CurContext);
+        MethodDecl && MethodDecl->isExplicitObjectMemberFunction()) {
+      return;
+    }
+  }
+
   if (HasObjectTypeQualifiers)
     if (const auto *Method = dyn_cast<CXXMethodDecl>(R.Declaration))
       if (Method->isInstance()) {

>From 650760be8da5df048556e6128acfaa788f7d0c38 Mon Sep 17 00:00:00 2001
From: Mythreya Kuricheti <g...@mythreya.dev>
Date: Fri, 15 Aug 2025 01:43:48 -0700
Subject: [PATCH 2/3] Add codecomplete lit test

---
 ...parameter.cpp => cpp23-explicit-object.cpp} | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)
 rename clang/test/CodeCompletion/{skip-explicit-object-parameter.cpp => 
cpp23-explicit-object.cpp} (75%)

diff --git a/clang/test/CodeCompletion/skip-explicit-object-parameter.cpp 
b/clang/test/CodeCompletion/cpp23-explicit-object.cpp
similarity index 75%
rename from clang/test/CodeCompletion/skip-explicit-object-parameter.cpp
rename to clang/test/CodeCompletion/cpp23-explicit-object.cpp
index 587d6cb044d19..c903e2dbbf0a9 100644
--- a/clang/test/CodeCompletion/skip-explicit-object-parameter.cpp
+++ b/clang/test/CodeCompletion/cpp23-explicit-object.cpp
@@ -42,7 +42,23 @@ int func3() {
 
 int func4() {
   // TODO (&A::foo)(
-  (&A::bar)(
+  (&A::bar)()
 }
 // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-2):13 
-std=c++23 %s | FileCheck -check-prefix=CHECK-CC5 %s
 // CHECK-CC5: OVERLOAD: [#void#](<#A#>, int)
+
+struct C {
+  int member {};
+  void foo(this C& self) {
+    // Should not offer `member` here, since it needs to be 
+    // referenced as `self.member`.
+    mem
+  }
+  void bar(this C& self) {
+    self.mem
+  }
+};
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-8):8 -std=c++23 
%s | FileCheck --allow-empty %s
+// CHECK-NOT: COMPLETION: member : [#int#]member
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-5):13 
-std=c++23 %s | FileCheck -check-prefix=CHECK-CC6 %s
+// CHECK-CC6: COMPLETION: member : [#int#]member

>From d8cee9131b6408fb69011ddc407522e2b4c95690 Mon Sep 17 00:00:00 2001
From: Mythreya Kuricheti <g...@mythreya.dev>
Date: Sat, 16 Aug 2025 19:07:49 -0700
Subject: [PATCH 3/3] code review

---
 .../clangd/unittests/CodeCompleteTests.cpp    | 15 +++++++--
 clang/lib/Sema/SemaCodeComplete.cpp           | 33 +++++++++++++------
 .../CodeCompletion/cpp23-explicit-object.cpp  | 16 ++++++---
 3 files changed, 47 insertions(+), 17 deletions(-)

diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp 
b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 360693a02a1f5..db41997cf65e0 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -4478,11 +4478,14 @@ TEST(CompletionTest, MemberAccessInExplicitObjMemfn) {
   Annotations Code(R"cpp(
     struct A {
       int member {};
+      int memberFnA(int a);
+      int memberFnA(this A&, float a);
 
       void foo(this A& self) {
-        // Should not offer `member` here, since it needs to be 
-        // referenced as `self.member`.
+        // Should not offer any members here, since 
+        // it needs to be referenced through `self`.
         mem$c1^;
+        // should offer all results
         self.mem$c2^;
       }
     };
@@ -4509,7 +4512,13 @@ TEST(CompletionTest, MemberAccessInExplicitObjMemfn) {
     auto Result = codeComplete(testPath(TU.Filename), Code.point("c2"),
                                Preamble.get(), Inputs, Opts);
 
-    EXPECT_THAT(Result.Completions, ElementsAre(named("member")));
+    EXPECT_THAT(
+        Result.Completions,
+        UnorderedElementsAre(named("member"),
+                             AllOf(named("memberFnA"), signature("(int a)"),
+                                   snippetSuffix("(${1:int a})")),
+                             AllOf(named("memberFnA"), signature("(float a)"),
+                                   snippetSuffix("(${1:float a})"))));
   }
 }
 } // namespace
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp 
b/clang/lib/Sema/SemaCodeComplete.cpp
index 224d105c313e6..eb1bbec82b645 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -197,6 +197,9 @@ class ResultBuilder {
   /// Whether the \p ObjectTypeQualifiers field is active.
   bool HasObjectTypeQualifiers;
 
+  // Whether the member function is using an explicit object parameter
+  bool IsExplicitObjectMemberFunction;
+
   /// The selector that we prefer.
   Selector PreferredSelector;
 
@@ -218,8 +221,8 @@ class ResultBuilder {
                          LookupFilter Filter = nullptr)
       : SemaRef(SemaRef), Allocator(Allocator), CCTUInfo(CCTUInfo),
         Filter(Filter), AllowNestedNameSpecifiers(false),
-        HasObjectTypeQualifiers(false), CompletionContext(CompletionContext),
-        ObjCImplementation(nullptr) {
+        HasObjectTypeQualifiers(false), IsExplicitObjectMemberFunction(false),
+        CompletionContext(CompletionContext), ObjCImplementation(nullptr) {
     // If this is an Objective-C instance method definition, dig out the
     // corresponding implementation.
     switch (CompletionContext.getKind()) {
@@ -275,6 +278,10 @@ class ResultBuilder {
     HasObjectTypeQualifiers = true;
   }
 
+  void setExplicitObjectMemberFn(bool IsExplicitObjectFn) {
+    IsExplicitObjectMemberFunction = IsExplicitObjectFn;
+  }
+
   /// Set the preferred selector.
   ///
   /// When an Objective-C method declaration result is added, and that
@@ -1428,14 +1435,13 @@ void ResultBuilder::AddResult(Result R, DeclContext 
*CurContext,
 
   AdjustResultPriorityForDecl(R);
 
-  if (isa<FieldDecl>(R.Declaration)) {
+  if (IsExplicitObjectMemberFunction &&
+      R.Kind == CodeCompletionResult::RK_Declaration &&
+      (isa<CXXMethodDecl>(R.Declaration) || isa<FieldDecl>(R.Declaration))) {
     // If result is a member in the context of an explicit-object member
     // function, drop it because it must be accessed through the object
     // parameter
-    if (auto *MethodDecl = dyn_cast<CXXMethodDecl>(CurContext);
-        MethodDecl && MethodDecl->isExplicitObjectMemberFunction()) {
-      return;
-    }
+    return;
   }
 
   if (HasObjectTypeQualifiers)
@@ -4646,12 +4652,19 @@ void SemaCodeCompletion::CodeCompleteOrdinaryName(
     break;
   }
 
-  // If we are in a C++ non-static member function, check the qualifiers on
-  // the member function to filter/prioritize the results list.
   auto ThisType = SemaRef.getCurrentThisType();
-  if (!ThisType.isNull())
+  if (ThisType.isNull()) {
+    // check if function scope is an explicit object function
+    if (auto *MethodDecl = llvm::dyn_cast_if_present<CXXMethodDecl>(
+            SemaRef.getCurFunctionDecl()))
+      Results.setExplicitObjectMemberFn(
+          MethodDecl->isExplicitObjectMemberFunction());
+  } else {
+    // If we are in a C++ non-static member function, check the qualifiers on
+    // the member function to filter/prioritize the results list.
     Results.setObjectTypeQualifiers(ThisType->getPointeeType().getQualifiers(),
                                     VK_LValue);
+  }
 
   CodeCompletionDeclConsumer Consumer(Results, SemaRef.CurContext);
   SemaRef.LookupVisibleDecls(S, SemaRef.LookupOrdinaryName, Consumer,
diff --git a/clang/test/CodeCompletion/cpp23-explicit-object.cpp 
b/clang/test/CodeCompletion/cpp23-explicit-object.cpp
index c903e2dbbf0a9..2a40185934a05 100644
--- a/clang/test/CodeCompletion/cpp23-explicit-object.cpp
+++ b/clang/test/CodeCompletion/cpp23-explicit-object.cpp
@@ -49,16 +49,24 @@ int func4() {
 
 struct C {
   int member {};
+  int memberFnA(int a);
+  int memberFnA(this C&, float a);
+
   void foo(this C& self) {
-    // Should not offer `member` here, since it needs to be 
-    // referenced as `self.member`.
+    // Should not offer any members here, since 
+    // it needs to be referenced through `self`.
     mem
   }
   void bar(this C& self) {
+    // should offer all results
     self.mem
   }
 };
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-8):8 -std=c++23 
%s | FileCheck --allow-empty %s
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-7):8 -std=c++23 
%s | FileCheck --allow-empty %s
 // CHECK-NOT: COMPLETION: member : [#int#]member
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-5):13 
-std=c++23 %s | FileCheck -check-prefix=CHECK-CC6 %s
+// CHECK-NOT: COMPLETION: memberFnA : [#int#]memberFnA(<#int a#>)
+// CHECK-NOT: COMPLETION: memberFnA : [#int#]memberFnA(<#float a#>)
+// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-7):13 
-std=c++23 %s | FileCheck -check-prefix=CHECK-CC6 %s
 // CHECK-CC6: COMPLETION: member : [#int#]member
+// CHECK-CC6: COMPLETION: memberFnA : [#int#]memberFnA(<#int a#>)
+// CHECK-CC6: COMPLETION: memberFnA : [#int#]memberFnA(<#float a#>)

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

Reply via email to