https://github.com/MythreyaK updated https://github.com/llvm/llvm-project/pull/154041
>From 1c20c7c72f6e47fd0f7f843f112752e68633c331 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/4] [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 f60bf09b8edf684619c8c3e1d76ac98600ded4c4 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/4] 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 9c1b58a17b79eb0a5038cf4db56b11faaf915f2e 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/4] 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..3337c692ff2f0 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-CC6 %s +// CHECK-CC6: COMPLETION: foo1 : [#void#]foo1(<#int a#>) +// CHECK-CC6: COMPLETION: foo2 : [#void#]foo2(<#int a#>)[# const#] +// CHECK-CC6: COMPLETION: foo2 : [#void#]foo2(<#float a#>)[# const#] +// CHECK-CC6: COMPLETION: foo3 : [#void#]foo3(<#int a#>)[# const#] +// CHECK-CC6: 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-CC7 %s +// 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#] +} + +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-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::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-CC9 %s +// CHECK-CC9: COMPLETION: foo1 : [#void#]foo1(<#int a#>) +// 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#] +// CHECK-CC9: 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-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 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-CC11 %s +// 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#] +} + +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-CC12 %s +// CHECK-CC12: OVERLOAD: [#void#]foo2(<#int a#>) +// CHECK-CC12: OVERLOAD: [#void#]foo2(float a) +// TODO: foo2 should be OVERLOAD: [#void#]foo2(<#float a#>) +} >From 2946340dea7eb6d95716dbb0f53b2a428bcb51ba 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/4] 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits