https://github.com/Ippo47 updated https://github.com/llvm/llvm-project/pull/199192
>From 8a2a3f3bb62897332fe6dfd022a4724c4a64769c Mon Sep 17 00:00:00 2001 From: paarth <[email protected]> Date: Fri, 8 May 2026 15:22:52 +0530 Subject: [PATCH] [clangd] Fix signature help for static operator() by fixing slicing condition in AddFunctionCandidates (C++) --- .../clangd/unittests/CodeCompleteTests.cpp | 89 +++++++++++++++++++ clang/lib/Sema/SemaCodeComplete.cpp | 19 ++++ clang/lib/Sema/SemaOverload.cpp | 6 +- 3 files changed, 111 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 5808b2145965f..1fbb880121597 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -3494,6 +3494,95 @@ TEST(SignatureHelpTest, SkipExplicitObjectParameter) { } } +TEST(SignatureHelpTest, StaticCallOperator) { + Annotations Code(R"cpp( + struct Abc { + void operator()(bool a) {} + }; + struct AbcStatic { + static void operator()(bool a) {} + }; + void test() { + Abc abc; + AbcStatic abcStatic; + abc($c1^); + abcStatic($c2^); + } + )cpp"); + auto TU = TestTU::withCode(Code.code()); + TU.ExtraArgs = {"-std=c++23"}; + MockFS FS; + auto Inputs = TU.inputs(FS); + auto Preamble = TU.preamble(); + ASSERT_TRUE(Preamble); + { + // Case 1: non-static + const auto Result = signatureHelp(testPath(TU.Filename), Code.point("c1"), + *Preamble, Inputs, MarkupKind::PlainText); + EXPECT_EQ(1U, Result.signatures.size()); + EXPECT_THAT(Result.signatures[0], + AllOf(sig("operator()([[bool a]]) -> void"))); + } + { + // Case 2: static + const auto Result = signatureHelp(testPath(TU.Filename), Code.point("c2"), + *Preamble, Inputs, MarkupKind::PlainText); + EXPECT_EQ(1U, Result.signatures.size()); + EXPECT_THAT(Result.signatures[0], + AllOf(sig("operator()([[bool a]]) -> void"))); + } + { + // Case 3: static template operator() + Annotations TemplateCode(R"cpp( + struct AbcTemplate { + template <typename T> + static void operator()(T a, bool b) {} + }; + void test() { + AbcTemplate abcTemplate; + abcTemplate($c3^); + } + )cpp"); + auto TU2 = TestTU::withCode(TemplateCode.code()); + TU2.ExtraArgs = {"-std=c++23"}; + MockFS FS2; + auto Inputs2 = TU2.inputs(FS2); + auto Preamble2 = TU2.preamble(); + ASSERT_TRUE(Preamble2); + const auto Result = + signatureHelp(testPath(TU2.Filename), TemplateCode.point("c3"), + *Preamble2, Inputs2, MarkupKind::PlainText); + EXPECT_EQ(1U, Result.signatures.size()); + EXPECT_THAT(Result.signatures[0], + AllOf(sig("operator()([[T a]], [[bool b]]) -> void"))); + } + + { + Annotations TemplateCode2(R"cpp( + struct AbcTemplate2 { + template <typename T> + static void operator()(bool a, bool b) { T c; } + }; + void test() { + AbcTemplate2 abcTemplate2; + abcTemplate2($c4^); + } + )cpp"); + auto TU3 = TestTU::withCode(TemplateCode2.code()); + TU3.ExtraArgs = {"-std=c++23"}; + MockFS FS3; + auto Inputs3 = TU3.inputs(FS3); + auto Preamble3 = TU3.preamble(); + ASSERT_TRUE(Preamble3); + const auto Result = + signatureHelp(testPath(TU3.Filename), TemplateCode2.point("c4"), + *Preamble3, Inputs3, MarkupKind::PlainText); + EXPECT_EQ(1U, Result.signatures.size()); + EXPECT_THAT(Result.signatures[0], + AllOf(sig("operator()([[bool a]], [[bool b]]) -> void"))); + } +} + TEST(CompletionTest, IncludedCompletionKinds) { Annotations Test(R"cpp(#include "^)cpp"); auto TU = TestTU::withCode(Test.code()); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index bef5eea9ed442..d0fbc05cc257c 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -6486,6 +6486,25 @@ SemaCodeCompletion::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args, LookupResult R(SemaRef, OpName, Loc, Sema::LookupOrdinaryName); SemaRef.LookupQualifiedName(R, DC); R.suppressDiagnostics(); + for (NamedDecl *D : R) { + NamedDecl *UD = D->getUnderlyingDecl(); + if (auto *FD = dyn_cast<FunctionDecl>(UD); FD && FD->isStatic()) { + SemaRef.AddOverloadCandidate( + FD, DeclAccessPair::make(FD, FD->getAccess()), + ArgsWithoutDependentTypes, CandidateSet, + /*SuppressUserConversions=*/false, + /*PartialOverloading=*/true); + continue; + } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(UD); + FTD && FTD->getTemplatedDecl()->isStatic()) { + SemaRef.AddTemplateOverloadCandidate( + FTD, DeclAccessPair::make(FTD, FTD->getAccess()), nullptr, + ArgsWithoutDependentTypes, CandidateSet, + /*SuppressUserConversions=*/false, + /*PartialOverloading=*/true); + continue; + } + } SmallVector<Expr *, 12> ArgExprs(1, NakedFn); ArgExprs.append(ArgsWithoutDependentTypes.begin(), ArgsWithoutDependentTypes.end()); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index e11bbd7085798..115dfa076ce3c 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -7869,9 +7869,9 @@ void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns, // Slice the first argument (which is the base) when we access // static method as non-static. if (Args.size() > 0 && - (!Args[0] || (FirstArgumentIsBase && isa<CXXMethodDecl>(FD) && - !isa<CXXConstructorDecl>(FD)))) { - assert(cast<CXXMethodDecl>(FD)->isStatic()); + (!Args[0] || (isa<CXXMethodDecl>(FD) && + !isa<CXXConstructorDecl>(FD) && (FirstArgumentIsBase || cast<CXXMethodDecl>(FD)->isStatic())))) { + assert( FirstArgumentIsBase || cast<CXXMethodDecl>(FD)->isStatic()); FunctionArgs = Args.slice(1); } if (FunTmpl) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
