llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-tools-extra
Author: Mythreya Kuricheti (MythreyaK)
<details>
<summary>Changes</summary>
Fix for #<!-- -->109608.
Draft to gather feedback.
Signature help still needs fixing--signature for void `foo3(this const S&
self)` is shown as `(int a)` instead of `(int a) const`. ~~Will add a commit
soon.~~ Done :heavy_check_mark:.
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
}
```
---
Full diff: https://github.com/llvm/llvm-project/pull/154041.diff
2 Files Affected:
- (modified) clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp (+119)
- (modified) clang/lib/Sema/SemaCodeComplete.cpp (+36-1)
``````````diff
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 1a1c32c241602..cf07e11d6441e 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..af900c777a707 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) {
@@ -3410,9 +3418,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;
``````````
</details>
https://github.com/llvm/llvm-project/pull/154041
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits