https://github.com/MythreyaK updated https://github.com/llvm/llvm-project/pull/154041
>From 471fa8c60c27a99ce029b1168679a6c5b0271108 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/5] [clang] Include explicit object methods in overload suggestions --- .../clangd/unittests/CodeCompleteTests.cpp | 120 ++++++++++++++++++ clang/lib/Sema/SemaCodeComplete.cpp | 10 +- 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 3f1623904d8cc..022eca4cf5395 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -4532,6 +4532,126 @@ TEST(CompletionTest, MemberAccessInExplicitObjMemfn) { EXPECT_THAT(Result.Completions, ElementsAre()); } } + +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 eb1bbec82b645..5bd1ef72e724c 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -1435,6 +1435,14 @@ 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 (IsExplicitObjectMemberFunction && R.Kind == CodeCompletionResult::RK_Declaration && (isa<CXXMethodDecl>(R.Declaration) || isa<FieldDecl>(R.Declaration))) { @@ -1447,7 +1455,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, 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 aa2c6fe5d8c6ab6ba492c1dd6800fe816bbb72a6 Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Mon, 18 Aug 2025 00:45:13 -0700 Subject: [PATCH 2/5] Add const to signature string --- .../clangd/unittests/CodeCompleteTests.cpp | 96 +++++++++---------- clang/lib/Sema/SemaCodeComplete.cpp | 27 ++++++ 2 files changed, 75 insertions(+), 48 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 022eca4cf5395..5e60cce303bb9 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -4581,74 +4581,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})")))); } } diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 5bd1ef72e724c..28b4900452849 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -3434,9 +3434,36 @@ static void AddQualifierToCompletionString(CodeCompletionBuilder &Result, Result.AddTextChunk(Result.getAllocator().CopyString(PrintedNNS)); } +// Sets the function qualifiers completion string by inspecting the explicit +// object +static void AddCXXExplicitObjectFunctionTypeQualsToCompletionString( + CodeCompletionBuilder &Result, const CXXMethodDecl *Function) { + const auto Quals = Function->getFunctionObjectParameterType(); + + if (!Quals.hasQualifiers()) + return; + + std::string QualsStr; + if (Quals.getQualifiers().hasConst()) + QualsStr += " const"; + if (Quals.getQualifiers().hasVolatile()) + QualsStr += " volatile"; + if (Quals.getQualifiers().hasRestrict()) + QualsStr += " restrict"; + Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr)); +} + static void AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result, const FunctionDecl *Function) { + if (auto *CxxMethodDecl = llvm::dyn_cast_if_present<CXXMethodDecl>(Function); + CxxMethodDecl && CxxMethodDecl->hasCXXExplicitFunctionObjectParameter()) { + // if explicit object method, infer quals from the object parameter + AddCXXExplicitObjectFunctionTypeQualsToCompletionString(Result, + CxxMethodDecl); + return; + } + const auto *Proto = Function->getType()->getAs<FunctionProtoType>(); if (!Proto || !Proto->getMethodQuals()) return; >From 639da07724cc542cd430203226e2d332199f8346 Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Mon, 18 Aug 2025 02:05:58 -0700 Subject: [PATCH 3/5] Update tests --- .../clangd/unittests/CodeCompleteTests.cpp | 13 ++++ .../CodeCompletion/cpp23-explicit-object.cpp | 70 +++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 5e60cce303bb9..7640569128172 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -4538,6 +4538,7 @@ TEST(CompletionTest, ListExplicitObjectOverloads) { struct S { void foo1(int a); void foo2(int a) const; + void foo2(this const S& self, float a); void foo3(this const S& self, int a); void foo4(this S& self, int a); }; @@ -4587,6 +4588,8 @@ TEST(CompletionTest, ListExplicitObjectOverloads) { snippetSuffix("(${1:int a})")), AllOf(named("foo2"), signature("(int a) const"), snippetSuffix("(${1:int a})")), + AllOf(named("foo2"), signature("(float a) const"), + snippetSuffix("(${1:float a})")), AllOf(named("foo3"), signature("(int a) const"), snippetSuffix("(${1:int a})")), AllOf(named("foo4"), signature("(int a)"), @@ -4599,6 +4602,8 @@ TEST(CompletionTest, ListExplicitObjectOverloads) { Result.Completions, UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"), snippetSuffix("(${1:int a})")), + AllOf(named("foo2"), signature("(float a) const"), + snippetSuffix("(${1:float a})")), AllOf(named("foo3"), signature("(int a) const"), snippetSuffix("(${1:int a})")))); } @@ -4609,6 +4614,8 @@ TEST(CompletionTest, ListExplicitObjectOverloads) { Result.Completions, UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"), snippetSuffix("(${1:int a})")), + AllOf(named("foo2"), signature("(float a) const"), + snippetSuffix("(${1:float a})")), AllOf(named("foo3"), signature("(int a) const"), snippetSuffix("(${1:int a})")))); } @@ -4621,6 +4628,8 @@ TEST(CompletionTest, ListExplicitObjectOverloads) { snippetSuffix("(${1:int a})")), AllOf(named("foo2"), signature("(int a) const"), snippetSuffix("(${1:int a})")), + AllOf(named("foo2"), signature("(float a) const"), + snippetSuffix("(${1:float a})")), AllOf(named("foo3"), signature("(int a) const"), snippetSuffix("(${1:int a})")), AllOf(named("foo4"), signature("(int a)"), @@ -4635,6 +4644,8 @@ TEST(CompletionTest, ListExplicitObjectOverloads) { snippetSuffix("(${1:int a})")), AllOf(named("foo2"), signature("(int a) const"), snippetSuffix("(${1:int a})")), + AllOf(named("foo2"), signature("(float a) const"), + snippetSuffix("(${1:float a})")), AllOf(named("foo3"), signature("(int a) const"), snippetSuffix("(${1:int a})")), AllOf(named("foo4"), signature("(int a)"), @@ -4647,6 +4658,8 @@ TEST(CompletionTest, ListExplicitObjectOverloads) { Result.Completions, UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"), snippetSuffix("(${1:int a})")), + AllOf(named("foo2"), signature("(float a) const"), + snippetSuffix("(${1:float a})")), AllOf(named("foo3"), signature("(int a) const"), snippetSuffix("(${1:int a})")))); } diff --git a/clang/test/CodeCompletion/cpp23-explicit-object.cpp b/clang/test/CodeCompletion/cpp23-explicit-object.cpp index 08e5565f3d186..ea97237ecd24b 100644 --- a/clang/test/CodeCompletion/cpp23-explicit-object.cpp +++ b/clang/test/CodeCompletion/cpp23-explicit-object.cpp @@ -81,3 +81,73 @@ struct C { } }; + +struct S { + void foo1(int a); + void foo2(int a) const; + void foo2(this const S& self, float a); + void foo3(this const S& self, int a); + void foo4(this S& self, int a); +}; + +void S::foo1(int a) { + this->; +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-1):9 -std=c++23 %s | FileCheck -check-prefix=CHECK-CC7 %s +// CHECK-CC7: COMPLETION: foo1 : [#void#]foo1(<#int a#>) +// CHECK-CC7: COMPLETION: foo2 : [#void#]foo2(<#int a#>)[# const#] +// CHECK-CC7: COMPLETION: foo2 : [#void#]foo2(<#float a#>)[# const#] +// CHECK-CC7: COMPLETION: foo3 : [#void#]foo3(<#int a#>)[# const#] +// CHECK-CC7: COMPLETION: foo4 : [#void#]foo4(<#int a#>) +} + +void S::foo2(int a) const { + this->; +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-1):9 -std=c++23 %s | FileCheck -check-prefix=CHECK-CC8 %s +// CHECK-CC8: COMPLETION: foo2 : [#void#]foo2(<#int a#>)[# const#] +// CHECK-CC8: COMPLETION: foo2 : [#void#]foo2(<#float a#>)[# const#] +// CHECK-CC8: COMPLETION: foo3 : [#void#]foo3(<#int a#>)[# const#] +} + +void S::foo3(this const S& self, int a) { + self.; +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-1):8 -std=c++23 %s | FileCheck -check-prefix=CHECK-CC9 %s +// CHECK-CC9: COMPLETION: foo2 : [#void#]foo2(<#int a#>)[# const#] +// CHECK-CC9: COMPLETION: foo2 : [#void#]foo2(<#float a#>)[# const#] +// CHECK-CC9: COMPLETION: foo3 : [#void#]foo3(<#int a#>)[# const#] +} + +void S::foo4(this S& self, int a) { + self.; +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-1):8 -std=c++23 %s | FileCheck -check-prefix=CHECK-CC10 %s +// CHECK-CC10: COMPLETION: foo1 : [#void#]foo1(<#int a#>) +// CHECK-CC10: COMPLETION: foo2 : [#void#]foo2(<#int a#>)[# const#] +// CHECK-CC10: COMPLETION: foo2 : [#void#]foo2(<#float a#>)[# const#] +// CHECK-CC10: COMPLETION: foo3 : [#void#]foo3(<#int a#>)[# const#] +// CHECK-CC10: COMPLETION: foo4 : [#void#]foo4(<#int a#>) +} + +void test1(S s) { + s.; +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-1):5 -std=c++23 %s | FileCheck -check-prefix=CHECK-CC11 %s +// CHECK-CC11: COMPLETION: foo1 : [#void#]foo1(<#int a#>) +// CHECK-CC11: COMPLETION: foo2 : [#void#]foo2(<#int a#>)[# const#] +// CHECK-CC11: COMPLETION: foo2 : [#void#]foo2(<#float a#>)[# const#] +// CHECK-CC11: COMPLETION: foo3 : [#void#]foo3(<#int a#>)[# const#] +// CHECK-CC11: COMPLETION: foo4 : [#void#]foo4(<#int a#>) +} + +void test2(const S s) { + s.; +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-1):5 -std=c++23 %s | FileCheck -check-prefix=CHECK-CC12 %s +// CHECK-CC12: COMPLETION: foo2 : [#void#]foo2(<#int a#>)[# const#] +// CHECK-CC12: COMPLETION: foo2 : [#void#]foo2(<#float a#>)[# const#] +// CHECK-CC12: COMPLETION: foo3 : [#void#]foo3(<#int a#>)[# const#] +} + +void test3(S s) { + s.foo2(); +// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:%(line-1):10 -std=c++23 %s | FileCheck -check-prefix=CHECK-CC13 %s +// CHECK-CC13: OVERLOAD: [#void#]foo2(<#int a#>) +// CHECK-CC13: OVERLOAD: [#void#]foo2(float a) +// TODO: foo2 should be OVERLOAD: [#void#]foo2(<#float a#>) +} >From d2476ed6018439149b803b94edcdaecf6efbf387 Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Wed, 20 Aug 2025 01:48:52 -0700 Subject: [PATCH 4/5] code review --- clang/lib/Sema/SemaCodeComplete.cpp | 86 ++++++++++++++--------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 28b4900452849..eb27432edb15d 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -413,6 +413,37 @@ class ResultBuilder { bool IsImpossibleToSatisfy(const NamedDecl *ND) const; //@} }; + +void AddFunctionTypeQuals(CodeCompletionBuilder &Result, + const Qualifiers Quals) { + // FIXME: Add ref-qualifier! + + // Handle single qualifiers without copying + if (Quals.hasOnlyConst()) { + Result.AddInformativeChunk(" const"); + return; + } + + if (Quals.hasOnlyVolatile()) { + Result.AddInformativeChunk(" volatile"); + return; + } + + if (Quals.hasOnlyRestrict()) { + Result.AddInformativeChunk(" restrict"); + return; + } + + // Handle multiple qualifiers. + std::string QualsStr; + if (Quals.hasConst()) + QualsStr += " const"; + if (Quals.hasVolatile()) + QualsStr += " volatile"; + if (Quals.hasRestrict()) + QualsStr += " restrict"; + Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr)); +} } // namespace void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) { @@ -1436,7 +1467,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, AdjustResultPriorityForDecl(R); // Account for explicit object parameter - const auto getQualifiers = [&](const CXXMethodDecl *MethodDecl) { + const auto GetQualifiers = [&](const CXXMethodDecl *MethodDecl) { if (MethodDecl->isExplicitObjectMemberFunction()) return MethodDecl->getFunctionObjectParameterType().getQualifiers(); else @@ -1455,7 +1486,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, if (HasObjectTypeQualifiers) if (const auto *Method = dyn_cast<CXXMethodDecl>(R.Declaration)) if (Method->isInstance()) { - Qualifiers MethodQuals = getQualifiers(Method); + Qualifiers MethodQuals = GetQualifiers(Method); if (ObjectTypeQualifiers == MethodQuals) R.Priority += CCD_ObjectQualifierMatch; else if (ObjectTypeQualifiers - MethodQuals) { @@ -3438,19 +3469,15 @@ static void AddQualifierToCompletionString(CodeCompletionBuilder &Result, // object static void AddCXXExplicitObjectFunctionTypeQualsToCompletionString( CodeCompletionBuilder &Result, const CXXMethodDecl *Function) { - const auto Quals = Function->getFunctionObjectParameterType(); + assert(isa<CXXMethodDecl>(Function) && + Function->hasCXXExplicitFunctionObjectParameter() && + "Valid only on CXX explicit object methods"); + const auto Quals = Function->getFunctionObjectParameterType(); if (!Quals.hasQualifiers()) return; - std::string QualsStr; - if (Quals.getQualifiers().hasConst()) - QualsStr += " const"; - if (Quals.getQualifiers().hasVolatile()) - QualsStr += " volatile"; - if (Quals.getQualifiers().hasRestrict()) - QualsStr += " restrict"; - Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr)); + AddFunctionTypeQuals(Result, Quals.getQualifiers()); } static void @@ -3461,40 +3488,13 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result, // if explicit object method, infer quals from the object parameter AddCXXExplicitObjectFunctionTypeQualsToCompletionString(Result, CxxMethodDecl); - return; - } - - const auto *Proto = Function->getType()->getAs<FunctionProtoType>(); - if (!Proto || !Proto->getMethodQuals()) - return; - - // FIXME: Add ref-qualifier! - - // Handle single qualifiers without copying - if (Proto->getMethodQuals().hasOnlyConst()) { - Result.AddInformativeChunk(" const"); - return; - } - - if (Proto->getMethodQuals().hasOnlyVolatile()) { - Result.AddInformativeChunk(" volatile"); - return; - } + } else { + const auto *Proto = Function->getType()->getAs<FunctionProtoType>(); + if (!Proto || !Proto->getMethodQuals()) + return; - if (Proto->getMethodQuals().hasOnlyRestrict()) { - Result.AddInformativeChunk(" restrict"); - return; + AddFunctionTypeQuals(Result, Proto->getMethodQuals()); } - - // Handle multiple qualifiers. - std::string QualsStr; - if (Proto->isConst()) - QualsStr += " const"; - if (Proto->isVolatile()) - QualsStr += " volatile"; - if (Proto->isRestrict()) - QualsStr += " restrict"; - Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr)); } static void >From 888ef93149457b20a1186d0bc4a25a499bf72294 Mon Sep 17 00:00:00 2001 From: Mythreya Kuricheti <g...@mythreya.dev> Date: Wed, 20 Aug 2025 23:00:38 -0700 Subject: [PATCH 5/5] code review --- clang/lib/Sema/SemaCodeComplete.cpp | 74 ++++++++++++----------------- 1 file changed, 31 insertions(+), 43 deletions(-) diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index eb27432edb15d..c6adead5a65f5 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -413,37 +413,6 @@ class ResultBuilder { bool IsImpossibleToSatisfy(const NamedDecl *ND) const; //@} }; - -void AddFunctionTypeQuals(CodeCompletionBuilder &Result, - const Qualifiers Quals) { - // FIXME: Add ref-qualifier! - - // Handle single qualifiers without copying - if (Quals.hasOnlyConst()) { - Result.AddInformativeChunk(" const"); - return; - } - - if (Quals.hasOnlyVolatile()) { - Result.AddInformativeChunk(" volatile"); - return; - } - - if (Quals.hasOnlyRestrict()) { - Result.AddInformativeChunk(" restrict"); - return; - } - - // Handle multiple qualifiers. - std::string QualsStr; - if (Quals.hasConst()) - QualsStr += " const"; - if (Quals.hasVolatile()) - QualsStr += " volatile"; - if (Quals.hasRestrict()) - QualsStr += " restrict"; - Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr)); -} } // namespace void PreferredTypeBuilder::enterReturn(Sema &S, SourceLocation Tok) { @@ -3465,19 +3434,35 @@ static void AddQualifierToCompletionString(CodeCompletionBuilder &Result, Result.AddTextChunk(Result.getAllocator().CopyString(PrintedNNS)); } -// Sets the function qualifiers completion string by inspecting the explicit -// object -static void AddCXXExplicitObjectFunctionTypeQualsToCompletionString( - CodeCompletionBuilder &Result, const CXXMethodDecl *Function) { - assert(isa<CXXMethodDecl>(Function) && - Function->hasCXXExplicitFunctionObjectParameter() && - "Valid only on CXX explicit object methods"); +static void AddFunctionTypeQuals(CodeCompletionBuilder &Result, + const Qualifiers Quals) { + // FIXME: Add ref-qualifier! + + // Handle single qualifiers without copying + if (Quals.hasOnlyConst()) { + Result.AddInformativeChunk(" const"); + return; + } - const auto Quals = Function->getFunctionObjectParameterType(); - if (!Quals.hasQualifiers()) + if (Quals.hasOnlyVolatile()) { + Result.AddInformativeChunk(" volatile"); return; + } - AddFunctionTypeQuals(Result, Quals.getQualifiers()); + if (Quals.hasOnlyRestrict()) { + Result.AddInformativeChunk(" restrict"); + return; + } + + // Handle multiple qualifiers. + std::string QualsStr; + if (Quals.hasConst()) + QualsStr += " const"; + if (Quals.hasVolatile()) + QualsStr += " volatile"; + if (Quals.hasRestrict()) + QualsStr += " restrict"; + Result.AddInformativeChunk(Result.getAllocator().CopyString(QualsStr)); } static void @@ -3486,8 +3471,11 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result, if (auto *CxxMethodDecl = llvm::dyn_cast_if_present<CXXMethodDecl>(Function); CxxMethodDecl && CxxMethodDecl->hasCXXExplicitFunctionObjectParameter()) { // if explicit object method, infer quals from the object parameter - AddCXXExplicitObjectFunctionTypeQualsToCompletionString(Result, - CxxMethodDecl); + const auto Quals = CxxMethodDecl->getFunctionObjectParameterType(); + if (!Quals.hasQualifiers()) + return; + + AddFunctionTypeQuals(Result, Quals.getQualifiers()); } else { const auto *Proto = Function->getType()->getAs<FunctionProtoType>(); if (!Proto || !Proto->getMethodQuals()) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits