[clang-tools-extra] r315055 - [clangd] Add textDocument/signatureHelp
Ilya Biryukov via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 6 04:54:17 PDT 2017
Author: ibiryukov
Date: Fri Oct 6 04:54:17 2017
New Revision: 315055
URL: http://llvm.org/viewvc/llvm-project?rev=315055&view=rev
Log:
[clangd] Add textDocument/signatureHelp
Summary:
Makes clangd respond to a client's "textDocument/signatureHelp" request by
presenting function/method overloads.
Patch by Raoul Wols.
Reviewers: bkramer, ilya-biryukov, krasimir
Reviewed By: ilya-biryukov
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D38048
Added:
clang-tools-extra/trunk/test/clangd/signature-help.test
Modified:
clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
clang-tools-extra/trunk/clangd/ClangdLSPServer.h
clang-tools-extra/trunk/clangd/ClangdServer.cpp
clang-tools-extra/trunk/clangd/ClangdServer.h
clang-tools-extra/trunk/clangd/ClangdUnit.cpp
clang-tools-extra/trunk/clangd/ClangdUnit.h
clang-tools-extra/trunk/clangd/Protocol.cpp
clang-tools-extra/trunk/clangd/Protocol.h
clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
clang-tools-extra/trunk/clangd/ProtocolHandlers.h
clang-tools-extra/trunk/test/clangd/formatting.test
clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test
clang-tools-extra/trunk/test/clangd/initialize-params.test
Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp Fri Oct 6 04:54:17 2017
@@ -48,6 +48,7 @@ void ClangdLSPServer::onInitialize(Strin
"documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]},
"codeActionProvider": true,
"completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">",":"]},
+ "signatureHelpProvider": {"triggerCharacters": ["(",","]},
"definitionProvider": true
}}})");
if (IP.rootUri && !IP.rootUri->file.empty())
@@ -166,6 +167,18 @@ void ClangdLSPServer::onCompletion(TextD
R"(,"result":[)" + Completions + R"(]})");
}
+void ClangdLSPServer::onSignatureHelp(TextDocumentPositionParams Params,
+ StringRef ID, JSONOutput &Out) {
+ const auto SigHelp = SignatureHelp::unparse(
+ Server
+ .signatureHelp(
+ Params.textDocument.uri.file,
+ Position{Params.position.line, Params.position.character})
+ .Value);
+ Out.writeMessage(R"({"jsonrpc":"2.0","id":)" + ID.str() + R"(,"result":)" +
+ SigHelp + "}");
+}
+
void ClangdLSPServer::onGoToDefinition(TextDocumentPositionParams Params,
StringRef ID, JSONOutput &Out) {
Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.h?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdLSPServer.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdLSPServer.h Fri Oct 6 04:54:17 2017
@@ -67,6 +67,8 @@ private:
JSONOutput &Out) override;
void onCompletion(TextDocumentPositionParams Params, StringRef ID,
JSONOutput &Out) override;
+ void onSignatureHelp(TextDocumentPositionParams Params, StringRef ID,
+ JSONOutput &Out) override;
void onGoToDefinition(TextDocumentPositionParams Params, StringRef ID,
JSONOutput &Out) override;
void onSwitchSourceHeader(TextDocumentIdentifier Params, StringRef ID,
Modified: clang-tools-extra/trunk/clangd/ClangdServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.cpp?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Fri Oct 6 04:54:17 2017
@@ -248,6 +248,35 @@ ClangdServer::codeComplete(PathRef File,
return Future;
}
+Tagged<SignatureHelp>
+ClangdServer::signatureHelp(PathRef File, Position Pos,
+ llvm::Optional<StringRef> OverridenContents,
+ IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS) {
+ std::string DraftStorage;
+ if (!OverridenContents) {
+ auto FileContents = DraftMgr.getDraft(File);
+ assert(FileContents.Draft &&
+ "signatureHelp is called for non-added document");
+
+ DraftStorage = std::move(*FileContents.Draft);
+ OverridenContents = DraftStorage;
+ }
+
+ auto TaggedFS = FSProvider.getTaggedFileSystem(File);
+ if (UsedFS)
+ *UsedFS = TaggedFS.Value;
+
+ std::shared_ptr<CppFile> Resources = Units.getFile(File);
+ assert(Resources && "Calling signatureHelp on non-added file");
+
+ auto Preamble = Resources->getPossiblyStalePreamble();
+ auto Result = clangd::signatureHelp(File, Resources->getCompileCommand(),
+ Preamble ? &Preamble->Preamble : nullptr,
+ *OverridenContents, Pos, TaggedFS.Value,
+ PCHs, Logger);
+ return make_tagged(std::move(Result), TaggedFS.Tag);
+}
+
std::vector<tooling::Replacement> ClangdServer::formatRange(PathRef File,
Range Rng) {
std::string Code = getDocument(File);
Modified: clang-tools-extra/trunk/clangd/ClangdServer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.h?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.h Fri Oct 6 04:54:17 2017
@@ -253,6 +253,18 @@ public:
llvm::Optional<StringRef> OverridenContents = llvm::None,
IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
+ /// Provide signature help for \p File at \p Pos. If \p OverridenContents is
+ /// not None, they will used only for signature help, i.e. no diagnostics
+ /// update will be scheduled and a draft for \p File will not be updated. If
+ /// \p OverridenContents is None, contents of the current draft for \p File
+ /// will be used. If \p UsedFS is non-null, it will be overwritten by
+ /// vfs::FileSystem used for signature help. This method should only be called
+ /// for currently tracked files.
+ Tagged<SignatureHelp>
+ signatureHelp(PathRef File, Position Pos,
+ llvm::Optional<StringRef> OverridenContents = llvm::None,
+ IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
+
/// Get definition of symbol at a specified \p Line and \p Column in \p File.
Tagged<std::vector<Location>> findDefinitions(PathRef File, Position Pos);
Modified: clang-tools-extra/trunk/clangd/ClangdUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.cpp?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdUnit.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp Fri Oct 6 04:54:17 2017
@@ -119,6 +119,44 @@ static int getSeverity(DiagnosticsEngine
llvm_unreachable("Unknown diagnostic level!");
}
+/// Get the optional chunk as a string. This function is possibly recursive.
+///
+/// The parameter info for each parameter is appended to the Parameters.
+std::string
+getOptionalParameters(const CodeCompletionString &CCS,
+ std::vector<ParameterInformation> &Parameters) {
+ std::string Result;
+ for (const auto &Chunk : CCS) {
+ switch (Chunk.Kind) {
+ case CodeCompletionString::CK_Optional:
+ assert(Chunk.Optional &&
+ "Expected the optional code completion string to be non-null.");
+ Result += getOptionalParameters(*Chunk.Optional, Parameters);
+ break;
+ case CodeCompletionString::CK_VerticalSpace:
+ break;
+ case CodeCompletionString::CK_Placeholder:
+ // A string that acts as a placeholder for, e.g., a function call
+ // argument.
+ // Intentional fallthrough here.
+ case CodeCompletionString::CK_CurrentParameter: {
+ // A piece of text that describes the parameter that corresponds to
+ // the code-completion location within a function call, message send,
+ // macro invocation, etc.
+ Result += Chunk.Text;
+ ParameterInformation Info;
+ Info.label = Chunk.Text;
+ Parameters.push_back(std::move(Info));
+ break;
+ }
+ default:
+ Result += Chunk.Text;
+ break;
+ }
+ }
+ return Result;
+}
+
llvm::Optional<DiagWithFixIts> toClangdDiag(StoredDiagnostic D) {
auto Location = D.getLocation();
if (!Location.isValid() || !Location.getManager().isInMainFile(Location))
@@ -284,8 +322,36 @@ std::string escapeSnippet(const llvm::St
return Result;
}
-class CompletionItemsCollector : public CodeCompleteConsumer {
+std::string getDocumentation(const CodeCompletionString &CCS) {
+ // Things like __attribute__((nonnull(1,3))) and [[noreturn]]. Present this
+ // information in the documentation field.
+ std::string Result;
+ const unsigned AnnotationCount = CCS.getAnnotationCount();
+ if (AnnotationCount > 0) {
+ Result += "Annotation";
+ if (AnnotationCount == 1) {
+ Result += ": ";
+ } else /* AnnotationCount > 1 */ {
+ Result += "s: ";
+ }
+ for (unsigned I = 0; I < AnnotationCount; ++I) {
+ Result += CCS.getAnnotation(I);
+ Result.push_back(I == AnnotationCount - 1 ? '\n' : ' ');
+ }
+ }
+ // Add brief documentation (if there is any).
+ if (CCS.getBriefComment() != nullptr) {
+ if (!Result.empty()) {
+ // This means we previously added annotations. Add an extra newline
+ // character to make the annotations stand out.
+ Result.push_back('\n');
+ }
+ Result += CCS.getBriefComment();
+ }
+ return Result;
+}
+class CompletionItemsCollector : public CodeCompleteConsumer {
public:
CompletionItemsCollector(const CodeCompleteOptions &CodeCompleteOpts,
std::vector<CompletionItem> &Items)
@@ -322,7 +388,7 @@ private:
CompletionItem Item;
Item.insertTextFormat = InsertTextFormat::PlainText;
- FillDocumentation(CCS, Item);
+ Item.documentation = getDocumentation(CCS);
// Fill in the label, detail, insertText and filterText fields of the
// CompletionItem.
@@ -339,35 +405,6 @@ private:
virtual void ProcessChunks(const CodeCompletionString &CCS,
CompletionItem &Item) const = 0;
- void FillDocumentation(const CodeCompletionString &CCS,
- CompletionItem &Item) const {
- // Things like __attribute__((nonnull(1,3))) and [[noreturn]]. Present this
- // information in the documentation field.
- const unsigned AnnotationCount = CCS.getAnnotationCount();
- if (AnnotationCount > 0) {
- Item.documentation += "Annotation";
- if (AnnotationCount == 1) {
- Item.documentation += ": ";
- } else /* AnnotationCount > 1 */ {
- Item.documentation += "s: ";
- }
- for (unsigned I = 0; I < AnnotationCount; ++I) {
- Item.documentation += CCS.getAnnotation(I);
- Item.documentation.push_back(I == AnnotationCount - 1 ? '\n' : ' ');
- }
- }
-
- // Add brief documentation (if there is any).
- if (CCS.getBriefComment() != nullptr) {
- if (!Item.documentation.empty()) {
- // This means we previously added annotations. Add an extra newline
- // character to make the annotations stand out.
- Item.documentation.push_back('\n');
- }
- Item.documentation += CCS.getBriefComment();
- }
- }
-
static int GetSortPriority(const CodeCompletionString &CCS) {
int Score = CCS.getPriority();
// Fill in the sortText of the CompletionItem.
@@ -560,14 +597,107 @@ private:
}
}
}; // SnippetCompletionItemsCollector
-} // namespace
-std::vector<CompletionItem>
-clangd::codeComplete(PathRef FileName, tooling::CompileCommand Command,
- PrecompiledPreamble const *Preamble, StringRef Contents,
- Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
- std::shared_ptr<PCHContainerOperations> PCHs,
- bool SnippetCompletions, clangd::Logger &Logger) {
+class SignatureHelpCollector final : public CodeCompleteConsumer {
+
+public:
+ SignatureHelpCollector(const CodeCompleteOptions &CodeCompleteOpts,
+ SignatureHelp &SigHelp)
+ : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
+ SigHelp(SigHelp),
+ Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
+ CCTUInfo(Allocator) {}
+
+ void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
+ OverloadCandidate *Candidates,
+ unsigned NumCandidates) override {
+ SigHelp.signatures.reserve(NumCandidates);
+ // FIXME(rwols): How can we determine the "active overload candidate"?
+ // Right now the overloaded candidates seem to be provided in a "best fit"
+ // order, so I'm not too worried about this.
+ SigHelp.activeSignature = 0;
+ assert(CurrentArg <= std::numeric_limits<int>::max() &&
+ "too many arguments");
+ SigHelp.activeParameter = static_cast<int>(CurrentArg);
+ for (unsigned I = 0; I < NumCandidates; ++I) {
+ const auto &Candidate = Candidates[I];
+ const auto *CCS = Candidate.CreateSignatureString(
+ CurrentArg, S, *Allocator, CCTUInfo, true);
+ assert(CCS && "Expected the CodeCompletionString to be non-null");
+ SigHelp.signatures.push_back(ProcessOverloadCandidate(Candidate, *CCS));
+ }
+ }
+
+ GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
+
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
+
+private:
+ SignatureInformation
+ ProcessOverloadCandidate(const OverloadCandidate &Candidate,
+ const CodeCompletionString &CCS) const {
+ SignatureInformation Result;
+ const char *ReturnType = nullptr;
+
+ Result.documentation = getDocumentation(CCS);
+
+ for (const auto &Chunk : CCS) {
+ switch (Chunk.Kind) {
+ case CodeCompletionString::CK_ResultType:
+ // A piece of text that describes the type of an entity or,
+ // for functions and methods, the return type.
+ assert(!ReturnType && "Unexpected CK_ResultType");
+ ReturnType = Chunk.Text;
+ break;
+ case CodeCompletionString::CK_Placeholder:
+ // A string that acts as a placeholder for, e.g., a function call
+ // argument.
+ // Intentional fallthrough here.
+ case CodeCompletionString::CK_CurrentParameter: {
+ // A piece of text that describes the parameter that corresponds to
+ // the code-completion location within a function call, message send,
+ // macro invocation, etc.
+ Result.label += Chunk.Text;
+ ParameterInformation Info;
+ Info.label = Chunk.Text;
+ Result.parameters.push_back(std::move(Info));
+ break;
+ }
+ case CodeCompletionString::CK_Optional: {
+ // The rest of the parameters are defaulted/optional.
+ assert(Chunk.Optional &&
+ "Expected the optional code completion string to be non-null.");
+ Result.label +=
+ getOptionalParameters(*Chunk.Optional, Result.parameters);
+ break;
+ }
+ case CodeCompletionString::CK_VerticalSpace:
+ break;
+ default:
+ Result.label += Chunk.Text;
+ break;
+ }
+ }
+ if (ReturnType) {
+ Result.label += " -> ";
+ Result.label += ReturnType;
+ }
+ return Result;
+ }
+
+ SignatureHelp &SigHelp;
+ std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
+ CodeCompletionTUInfo CCTUInfo;
+
+}; // SignatureHelpCollector
+
+bool invokeCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
+ const CodeCompleteOptions &Options, PathRef FileName,
+ const tooling::CompileCommand &Command,
+ PrecompiledPreamble const *Preamble, StringRef Contents,
+ Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ clangd::Logger &Logger) {
std::vector<const char *> ArgStrs;
for (const auto &S : Command.CommandLine)
ArgStrs.push_back(S.c_str());
@@ -603,38 +733,73 @@ clangd::codeComplete(PathRef FileName, t
auto &FrontendOpts = Clang->getFrontendOpts();
FrontendOpts.SkipFunctionBodies = true;
-
- FrontendOpts.CodeCompleteOpts.IncludeGlobals = true;
- FrontendOpts.CodeCompleteOpts.IncludeMacros = true;
- FrontendOpts.CodeCompleteOpts.IncludeBriefComments = true;
-
+ FrontendOpts.CodeCompleteOpts = Options;
FrontendOpts.CodeCompletionAt.FileName = FileName;
FrontendOpts.CodeCompletionAt.Line = Pos.line + 1;
FrontendOpts.CodeCompletionAt.Column = Pos.character + 1;
- std::vector<CompletionItem> Items;
- if (SnippetCompletions) {
- FrontendOpts.CodeCompleteOpts.IncludeCodePatterns = true;
- Clang->setCodeCompletionConsumer(new SnippetCompletionItemsCollector(
- FrontendOpts.CodeCompleteOpts, Items));
- } else {
- FrontendOpts.CodeCompleteOpts.IncludeCodePatterns = false;
- Clang->setCodeCompletionConsumer(new PlainTextCompletionItemsCollector(
- FrontendOpts.CodeCompleteOpts, Items));
- }
+ Clang->setCodeCompletionConsumer(Consumer.release());
SyntaxOnlyAction Action;
if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
Logger.log("BeginSourceFile() failed when running codeComplete for " +
FileName);
- return Items;
+ return false;
}
- if (!Action.Execute())
+ if (!Action.Execute()) {
Logger.log("Execute() failed when running codeComplete for " + FileName);
+ return false;
+ }
Action.EndSourceFile();
- return Items;
+ return true;
+}
+
+} // namespace
+
+std::vector<CompletionItem>
+clangd::codeComplete(PathRef FileName, tooling::CompileCommand Command,
+ PrecompiledPreamble const *Preamble, StringRef Contents,
+ Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ bool SnippetCompletions, clangd::Logger &Logger) {
+ std::vector<CompletionItem> Results;
+ CodeCompleteOptions Options;
+ std::unique_ptr<CodeCompleteConsumer> Consumer;
+ Options.IncludeGlobals = true;
+ Options.IncludeMacros = true;
+ Options.IncludeBriefComments = true;
+ if (SnippetCompletions) {
+ Options.IncludeCodePatterns = true;
+ Consumer =
+ llvm::make_unique<SnippetCompletionItemsCollector>(Options, Results);
+ } else {
+ Options.IncludeCodePatterns = false;
+ Consumer =
+ llvm::make_unique<PlainTextCompletionItemsCollector>(Options, Results);
+ }
+ invokeCodeComplete(std::move(Consumer), Options, FileName, Command, Preamble,
+ Contents, Pos, std::move(VFS), std::move(PCHs), Logger);
+ return Results;
+}
+
+SignatureHelp
+clangd::signatureHelp(PathRef FileName, tooling::CompileCommand Command,
+ PrecompiledPreamble const *Preamble, StringRef Contents,
+ Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ clangd::Logger &Logger) {
+ SignatureHelp Result;
+ CodeCompleteOptions Options;
+ Options.IncludeGlobals = false;
+ Options.IncludeMacros = false;
+ Options.IncludeCodePatterns = false;
+ Options.IncludeBriefComments = true;
+ invokeCodeComplete(llvm::make_unique<SignatureHelpCollector>(Options, Result),
+ Options, FileName, Command, Preamble, Contents, Pos,
+ std::move(VFS), std::move(PCHs), Logger);
+ return Result;
}
void clangd::dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) {
Modified: clang-tools-extra/trunk/clangd/ClangdUnit.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.h?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdUnit.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdUnit.h Fri Oct 6 04:54:17 2017
@@ -259,6 +259,14 @@ codeComplete(PathRef FileName, tooling::
std::shared_ptr<PCHContainerOperations> PCHs,
bool SnippetCompletions, clangd::Logger &Logger);
+/// Get signature help at a specified \p Pos in \p FileName.
+SignatureHelp signatureHelp(PathRef FileName, tooling::CompileCommand Command,
+ PrecompiledPreamble const *Preamble,
+ StringRef Contents, Position Pos,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ clangd::Logger &Logger);
+
/// Get definition of symbol at a specified \p Pos.
std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
clangd::Logger &Logger);
Modified: clang-tools-extra/trunk/clangd/Protocol.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.cpp?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.cpp (original)
+++ clang-tools-extra/trunk/clangd/Protocol.cpp Fri Oct 6 04:54:17 2017
@@ -909,3 +909,58 @@ std::string CompletionItem::unparse(cons
Result.back() = '}';
return Result;
}
+
+std::string ParameterInformation::unparse(const ParameterInformation &PI) {
+ std::string Result = "{";
+ llvm::raw_string_ostream Os(Result);
+ assert(!PI.label.empty() && "parameter information label is required");
+ Os << R"("label":")" << llvm::yaml::escape(PI.label) << '\"';
+ if (!PI.documentation.empty())
+ Os << R"(,"documentation":")" << llvm::yaml::escape(PI.documentation)
+ << '\"';
+ Os << '}';
+ Os.flush();
+ return Result;
+}
+
+std::string SignatureInformation::unparse(const SignatureInformation &SI) {
+ std::string Result = "{";
+ llvm::raw_string_ostream Os(Result);
+ assert(!SI.label.empty() && "signature information label is required");
+ Os << R"("label":")" << llvm::yaml::escape(SI.label) << '\"';
+ if (!SI.documentation.empty())
+ Os << R"(,"documentation":")" << llvm::yaml::escape(SI.documentation)
+ << '\"';
+ Os << R"(,"parameters":[)";
+ for (const auto &Parameter : SI.parameters) {
+ Os << ParameterInformation::unparse(Parameter) << ',';
+ }
+ Os.flush();
+ if (SI.parameters.empty())
+ Result.push_back(']');
+ else
+ Result.back() = ']'; // Replace the last `,` with an `]`.
+ Result.push_back('}');
+ return Result;
+}
+
+std::string SignatureHelp::unparse(const SignatureHelp &SH) {
+ std::string Result = "{";
+ llvm::raw_string_ostream Os(Result);
+ assert(SH.activeSignature >= 0 &&
+ "Unexpected negative value for number of active signatures.");
+ assert(SH.activeParameter >= 0 &&
+ "Unexpected negative value for active parameter index");
+ Os << R"("activeSignature":)" << SH.activeSignature
+ << R"(,"activeParameter":)" << SH.activeParameter << R"(,"signatures":[)";
+ for (const auto &Signature : SH.signatures) {
+ Os << SignatureInformation::unparse(Signature) << ',';
+ }
+ Os.flush();
+ if (SH.signatures.empty())
+ Result.push_back(']');
+ else
+ Result.back() = ']'; // Replace the last `,` with an `]`.
+ Result.push_back('}');
+ return Result;
+}
Modified: clang-tools-extra/trunk/clangd/Protocol.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.h?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.h (original)
+++ clang-tools-extra/trunk/clangd/Protocol.h Fri Oct 6 04:54:17 2017
@@ -480,6 +480,48 @@ struct CompletionItem {
static std::string unparse(const CompletionItem &P);
};
+/// A single parameter of a particular signature.
+struct ParameterInformation {
+
+ /// The label of this parameter. Mandatory.
+ std::string label;
+
+ /// The documentation of this parameter. Optional.
+ std::string documentation;
+
+ static std::string unparse(const ParameterInformation &);
+};
+
+/// Represents the signature of something callable.
+struct SignatureInformation {
+
+ /// The label of this signature. Mandatory.
+ std::string label;
+
+ /// The documentation of this signature. Optional.
+ std::string documentation;
+
+ /// The parameters of this signature.
+ std::vector<ParameterInformation> parameters;
+
+ static std::string unparse(const SignatureInformation &);
+};
+
+/// Represents the signature of a callable.
+struct SignatureHelp {
+
+ /// The resulting signatures.
+ std::vector<SignatureInformation> signatures;
+
+ /// The active signature.
+ int activeSignature = 0;
+
+ /// The active parameter of the active signature.
+ int activeParameter = 0;
+
+ static std::string unparse(const SignatureHelp &);
+};
+
} // namespace clangd
} // namespace clang
Modified: clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp (original)
+++ clang-tools-extra/trunk/clangd/ProtocolHandlers.cpp Fri Oct 6 04:54:17 2017
@@ -192,6 +192,23 @@ private:
ProtocolCallbacks &Callbacks;
};
+struct SignatureHelpHandler : Handler {
+ SignatureHelpHandler(JSONOutput &Output, ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
+
+ void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override {
+ auto TDPP = TextDocumentPositionParams::parse(Params, Output);
+ if (!TDPP) {
+ Output.log("Failed to decode TextDocumentPositionParams!\n");
+ return;
+ }
+ Callbacks.onSignatureHelp(*TDPP, ID, Output);
+ }
+
+private:
+ ProtocolCallbacks &Callbacks;
+};
+
struct GotoDefinitionHandler : Handler {
GotoDefinitionHandler(JSONOutput &Output, ProtocolCallbacks &Callbacks)
: Handler(Output), Callbacks(Callbacks) {}
@@ -279,6 +296,9 @@ void clangd::registerCallbackHandlers(JS
"textDocument/completion",
llvm::make_unique<CompletionHandler>(Out, Callbacks));
Dispatcher.registerHandler(
+ "textDocument/signatureHelp",
+ llvm::make_unique<SignatureHelpHandler>(Out, Callbacks));
+ Dispatcher.registerHandler(
"textDocument/definition",
llvm::make_unique<GotoDefinitionHandler>(Out, Callbacks));
Dispatcher.registerHandler(
Modified: clang-tools-extra/trunk/clangd/ProtocolHandlers.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ProtocolHandlers.h?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ProtocolHandlers.h (original)
+++ clang-tools-extra/trunk/clangd/ProtocolHandlers.h Fri Oct 6 04:54:17 2017
@@ -47,6 +47,8 @@ public:
JSONOutput &Out) = 0;
virtual void onCompletion(TextDocumentPositionParams Params, StringRef ID,
JSONOutput &Out) = 0;
+ virtual void onSignatureHelp(TextDocumentPositionParams Params, StringRef ID,
+ JSONOutput &Out) = 0;
virtual void onGoToDefinition(TextDocumentPositionParams Params, StringRef ID,
JSONOutput &Out) = 0;
virtual void onSwitchSourceHeader(TextDocumentIdentifier Params, StringRef ID,
Modified: clang-tools-extra/trunk/test/clangd/formatting.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/formatting.test?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/formatting.test (original)
+++ clang-tools-extra/trunk/test/clangd/formatting.test Fri Oct 6 04:54:17 2017
@@ -4,7 +4,6 @@
Content-Length: 125
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
-# CHECK: Content-Length: 466
# CHECK: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{
# CHECK: "textDocumentSync": 1,
# CHECK: "documentFormattingProvider": true,
Modified: clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test (original)
+++ clang-tools-extra/trunk/test/clangd/initialize-params-invalid.test Fri Oct 6 04:54:17 2017
@@ -5,7 +5,7 @@
Content-Length: 142
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":"","rootUri":"file:///path/to/workspace","capabilities":{},"trace":"off"}}
-# CHECK: Content-Length: 466
+# CHECK: Content-Length: 535
# CHECK: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{
# CHECK: "textDocumentSync": 1,
# CHECK: "documentFormattingProvider": true,
@@ -13,6 +13,7 @@ Content-Length: 142
# CHECK: "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]},
# CHECK: "codeActionProvider": true,
# CHECK: "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">",":"]},
+# CHECK: "signatureHelpProvider": {"triggerCharacters": ["(",","]},
# CHECK: "definitionProvider": true
# CHECK: }}}
#
Modified: clang-tools-extra/trunk/test/clangd/initialize-params.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/initialize-params.test?rev=315055&r1=315054&r2=315055&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clangd/initialize-params.test (original)
+++ clang-tools-extra/trunk/test/clangd/initialize-params.test Fri Oct 6 04:54:17 2017
@@ -5,7 +5,7 @@
Content-Length: 143
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootUri":"file:///path/to/workspace","capabilities":{},"trace":"off"}}
-# CHECK: Content-Length: 466
+# CHECK: Content-Length: 535
# CHECK: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{
# CHECK: "textDocumentSync": 1,
# CHECK: "documentFormattingProvider": true,
@@ -13,6 +13,7 @@ Content-Length: 143
# CHECK: "documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]},
# CHECK: "codeActionProvider": true,
# CHECK: "completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">",":"]},
+# CHECK: "signatureHelpProvider": {"triggerCharacters": ["(",","]},
# CHECK: "definitionProvider": true
# CHECK: }}}
#
Added: clang-tools-extra/trunk/test/clangd/signature-help.test
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clangd/signature-help.test?rev=315055&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clangd/signature-help.test (added)
+++ clang-tools-extra/trunk/test/clangd/signature-help.test Fri Oct 6 04:54:17 2017
@@ -0,0 +1,42 @@
+# RUN: clangd -run-synchronously < %s | FileCheck %s
+# It is absolutely vital that this file has CRLF line endings.
+
+# Start a session.
+Content-Length: 125
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+
+# Modify the document.
+Content-Length: 333
+
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"void foo(int x, int y);\nvoid foo(int x, float y);\nvoid foo(float x, int y);\nvoid foo(float x, float y);\nvoid bar(int x, int y = 0);\nvoid bar(float x = 0, int y = 42);\nint main() { foo("}}}
+
+# Ask for signature help.
+Content-Length: 151
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/signatureHelp","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":8,"character":9}}}
+# CHECK: {"jsonrpc":"2.0","id":1,"result":{"activeSignature":0,"activeParameter":0,"signatures":[
+# CHECK-DAG: {"label":"foo(float x, float y) -> void","parameters":[{"label":"float x"},{"label":"float y"}]}
+# CHECK-DAG: {"label":"foo(float x, int y) -> void","parameters":[{"label":"float x"},{"label":"int y"}]}
+# CHECK-DAG: {"label":"foo(int x, float y) -> void","parameters":[{"label":"int x"},{"label":"float y"}]}
+# CHECK-DAG: {"label":"foo(int x, int y) -> void","parameters":[{"label":"int x"},{"label":"int y"}]}
+# CHECK: ]}
+
+# Modify the document
+Content-Length: 333
+
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":2,"text":"void foo(int x, int y);\nvoid foo(int x, float y);\nvoid foo(float x, int y);\nvoid foo(float x, float y);\nvoid bar(int x, int y = 0);\nvoid bar(float x = 0, int y = 42);\nint main() { bar("}}}
+
+# Ask for signature help (this checks default argument handling).
+Content-Length: 151
+
+{"jsonrpc":"2.0","id":2,"method":"textDocument/signatureHelp","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":8,"character":9}}}
+# CHECK: {"jsonrpc":"2.0","id":2,"result":{"activeSignature":0,"activeParameter":0,"signatures":[
+# CHECK-DAG: {"label":"bar(int x, int y = 0) -> void","parameters":[{"label":"int x"},{"label":"int y = 0"}]}
+# CHECK-DAG: {"label":"bar(float x = 0, int y = 42) -> void","parameters":[{"label":"float x = 0"},{"label":"int y = 42"}]}
+# CHECK: ]}
+
+# Shutdown.
+Content-Length: 49
+
+{"jsonrpc":"2.0","id":100000,"method":"shutdown"}
More information about the cfe-commits
mailing list