diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -1166,46 +1166,75 @@ } TEST(SignatureHelpTest, OpeningParen) { - llvm::StringLiteral Tests[] = {// Recursive function call. - R"cpp( - int foo(int a, int b, int c); - int main() { - foo(foo $p^( foo(10, 10, 10), ^ ))); - })cpp", - // Functional type cast. - R"cpp( - struct Foo { - Foo(int a, int b, int c); - }; - int main() { - Foo $p^( 10, ^ ); - })cpp", - // New expression. - R"cpp( - struct Foo { - Foo(int a, int b, int c); - }; - int main() { - new Foo $p^( 10, ^ ); - })cpp", - // Macro expansion. - R"cpp( - int foo(int a, int b, int c); - #define FOO foo( - - int main() { - // Macro expansions. - $p^FOO 10, ^ ); - })cpp", - // Macro arguments. - R"cpp( - int foo(int a, int b, int c); - int main() { - #define ID(X) X - // FIXME: figure out why ID(foo (foo(10), )) doesn't work when preserving - // the recovery expression. - ID(foo $p^( 10, ^ )) - })cpp"}; + llvm::StringLiteral Tests[] = { + // Recursive function call. + R"cpp( + int foo(int a, int b, int c); + int main() { + foo(foo $p^( foo(10, 10, 10), ^ ))); + })cpp", + // Functional type cast. + R"cpp( + struct Foo { + Foo(int a, int b, int c); + }; + int main() { + Foo $p^( 10, ^ ); + })cpp", + // New expression. + R"cpp( + struct Foo { + Foo(int a, int b, int c); + }; + int main() { + new Foo $p^( 10, ^ ); + })cpp", + // Macro expansion. + R"cpp( + int foo(int a, int b, int c); + #define FOO foo( + + int main() { + // Macro expansions. + $p^FOO 10, ^ ); + })cpp", + // Macro arguments. + R"cpp( + int foo(int a, int b, int c); + int main() { + #define ID(X) X + // FIXME: figure out why ID(foo (foo(10), )) doesn't work when preserving + // the recovery expression. + ID(foo $p^( 10, ^ )) + })cpp", + // Dependent args. + R"cpp( + int foo(int a, int b); + template void bar(T t) { + foo$p^(t, ^t); + })cpp", + // Dependent args on templated func. + R"cpp( + template + int foo(T, T); + template void bar(T t) { + foo$p^(t, ^t); + })cpp", + // Dependent args on member. + R"cpp( + struct Foo { int foo(int, int); }; + template void bar(T t) { + Foo f; + f.foo$p^(t, ^t); + })cpp", + // Dependent args on templated member. + R"cpp( + struct Foo { template int foo(T, T); }; + template void bar(T t) { + Foo f; + f.foo$p^(t, ^t); + })cpp", + }; for (auto Test : Tests) { Annotations Code(Test); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -5562,22 +5562,38 @@ // FIXME: Provide support for variadic template functions. // Ignore type-dependent call expressions entirely. - if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args) || - Expr::hasAnyTypeDependentArguments(Args)) { + if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args)) return QualType(); + + SmallVector Results; + + Expr *NakedFn = Fn->IgnoreParenCasts(); + // In presence of dependent args we surface all posible signatures, without + // performing any semantic checks on availability. That's to improve user + // experience, it is better to see all overloads rather than none. + if (Expr::hasAnyTypeDependentArguments(Args)) { + if (auto ULE = dyn_cast(NakedFn)) { + for (auto *D : ULE->decls()) + Results.push_back(ResultCandidate(D->getAsFunction())); + } else if (auto UME = dyn_cast(NakedFn)) { + for (auto *D : UME->decls()) + Results.push_back(ResultCandidate(D->getAsFunction())); + } else if (auto *ME = dyn_cast(NakedFn)) { + if (auto *FD = ME->getMemberDecl()->getAsFunction()) + Results.push_back(ResultCandidate(FD)); + } + // FIXME: handle function pointers and lambdas. + return ProduceSignatureHelp(*this, S, Results, Args.size(), OpenParLoc); } // Build an overload candidate set based on the functions we find. SourceLocation Loc = Fn->getExprLoc(); OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); - SmallVector Results; - - Expr *NakedFn = Fn->IgnoreParenCasts(); - if (auto ULE = dyn_cast(NakedFn)) + if (auto ULE = dyn_cast(NakedFn)) { AddOverloadedCallCandidates(ULE, Args, CandidateSet, /*PartialOverloading=*/true); - else if (auto UME = dyn_cast(NakedFn)) { + } else if (auto UME = dyn_cast(NakedFn)) { TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr; if (UME->hasExplicitTemplateArgs()) { UME->copyTemplateArgumentsInto(TemplateArgsBuffer);