Index: clangd/CodeComplete.cpp =================================================================== --- clangd/CodeComplete.cpp +++ clangd/CodeComplete.cpp @@ -794,7 +794,17 @@ void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, OverloadCandidate *Candidates, - unsigned NumCandidates) override { + unsigned NumCandidates, + SourceLocation OpenParLoc) override { + assert(!OpenParLoc.isInvalid()); + SourceManager &SrcMgr = S.getSourceManager(); + OpenParLoc = SrcMgr.getFileLoc(OpenParLoc); + if (SrcMgr.isInMainFile(OpenParLoc)) + SigHelp.argListStart = sourceLocToPosition(SrcMgr, OpenParLoc); + else + elog("Location oustide main file in signature help: {0}", + OpenParLoc.printToString(SrcMgr)); + std::vector ScoredSignatures; SigHelp.signatures.reserve(NumCandidates); ScoredSignatures.reserve(NumCandidates); Index: clangd/Protocol.h =================================================================== --- clangd/Protocol.h +++ clangd/Protocol.h @@ -828,6 +828,13 @@ /// The active parameter of the active signature. int activeParameter = 0; + + /// Position of the start of the argument list, including opening paren. e.g. + /// foo("first arg", "second arg", + /// ^-argListStart ^-cursor + /// This is a clangd-specific extension, it is only available via C++ API and + /// not currently serialized for the LSP. + Position argListStart; }; llvm::json::Value toJSON(const SignatureHelp &); Index: unittests/clangd/CodeCompleteTests.cpp =================================================================== --- unittests/clangd/CodeCompleteTests.cpp +++ unittests/clangd/CodeCompleteTests.cpp @@ -825,8 +825,7 @@ EXPECT_TRUE(Results.Completions.empty()); } - -SignatureHelp signatures(StringRef Text, +SignatureHelp signatures(StringRef Text, Position Point, std::vector IndexSymbols = {}) { std::unique_ptr Index; if (!IndexSymbols.empty()) @@ -840,9 +839,14 @@ ClangdServer Server(CDB, FS, DiagConsumer, Opts); auto File = testPath("foo.cpp"); + runAddDocument(Server, File, Text); + return cantFail(runSignatureHelp(Server, File, Point)); +} + +SignatureHelp signatures(StringRef Text, + std::vector IndexSymbols = {}) { Annotations Test(Text); - runAddDocument(Server, File, Test.code()); - return cantFail(runSignatureHelp(Server, File, Test.point())); + return signatures(Test.code(), Test.point(), std::move(IndexSymbols)); } MATCHER_P(ParamsAre, P, "") { @@ -907,6 +911,54 @@ EXPECT_EQ(1, Results.activeParameter); } +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 + ID(foo $p^( foo(10), ^ )) + })cpp"}; + + for (auto Test : Tests) { + Annotations Code(Test); + EXPECT_EQ(signatures(Code.code(), Code.point()).argListStart, + Code.point("p")) + << "Test source:" << Test; + } +} + class IndexRequestCollector : public SymbolIndex { public: bool