2017-05-16 09:38:59 +00:00
|
|
|
//===--- ClangdLSPServer.cpp - LSP server ------------------------*- C++-*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "ClangdLSPServer.h"
|
|
|
|
#include "JSONRPCDispatcher.h"
|
|
|
|
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
|
|
|
2017-05-16 09:38:59 +00:00
|
|
|
using namespace clang::clangd;
|
|
|
|
using namespace clang;
|
|
|
|
|
2017-05-16 14:40:30 +00:00
|
|
|
namespace {
|
|
|
|
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
std::vector<TextEdit>
|
2017-05-16 14:40:30 +00:00
|
|
|
replacementsToEdits(StringRef Code,
|
|
|
|
const std::vector<tooling::Replacement> &Replacements) {
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
std::vector<TextEdit> Edits;
|
2017-05-16 14:40:30 +00:00
|
|
|
// Turn the replacements into the format specified by the Language Server
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
// Protocol.
|
2017-05-16 14:40:30 +00:00
|
|
|
for (auto &R : Replacements) {
|
|
|
|
Range ReplacementRange = {
|
|
|
|
offsetToPosition(Code, R.getOffset()),
|
|
|
|
offsetToPosition(Code, R.getOffset() + R.getLength())};
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
Edits.push_back({ReplacementRange, R.getReplacementText()});
|
2017-05-16 14:40:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Edits;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onInitialize(Ctx C, InitializeParams &Params) {
|
|
|
|
C.reply(
|
|
|
|
R"({"capabilities":{
|
2017-05-16 14:40:30 +00:00
|
|
|
"textDocumentSync": 1,
|
|
|
|
"documentFormattingProvider": true,
|
|
|
|
"documentRangeFormattingProvider": true,
|
|
|
|
"documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]},
|
|
|
|
"codeActionProvider": true,
|
2017-07-31 09:27:52 +00:00
|
|
|
"completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">",":"]},
|
2017-10-06 11:54:17 +00:00
|
|
|
"signatureHelpProvider": {"triggerCharacters": ["(",","]},
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
"definitionProvider": true,
|
|
|
|
"executeCommandProvider": {"commands": [")" +
|
|
|
|
ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND + R"("]}
|
2017-10-12 13:29:58 +00:00
|
|
|
}})");
|
|
|
|
if (Params.rootUri && !Params.rootUri->file.empty())
|
|
|
|
Server.setRootPath(Params.rootUri->file);
|
|
|
|
else if (Params.rootPath && !Params.rootPath->empty())
|
|
|
|
Server.setRootPath(*Params.rootPath);
|
2017-05-16 14:40:30 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onShutdown(Ctx C, ShutdownParams &Params) {
|
2017-10-25 08:45:41 +00:00
|
|
|
// Do essentially nothing, just say we're ready to exit.
|
|
|
|
ShutdownRequestReceived = true;
|
|
|
|
C.reply("null");
|
2017-10-12 13:29:58 +00:00
|
|
|
}
|
2017-05-16 14:40:30 +00:00
|
|
|
|
2017-10-25 08:45:41 +00:00
|
|
|
void ClangdLSPServer::onExit(Ctx C, ExitParams &Params) { IsDone = true; }
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onDocumentDidOpen(Ctx C,
|
|
|
|
DidOpenTextDocumentParams &Params) {
|
2017-07-06 08:44:54 +00:00
|
|
|
if (Params.metadata && !Params.metadata->extraFlags.empty())
|
2017-09-30 10:08:52 +00:00
|
|
|
CDB.setExtraFlagsForFile(Params.textDocument.uri.file,
|
|
|
|
std::move(Params.metadata->extraFlags));
|
|
|
|
Server.addDocument(Params.textDocument.uri.file, Params.textDocument.text);
|
2017-05-16 14:40:30 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onDocumentDidChange(Ctx C,
|
|
|
|
DidChangeTextDocumentParams &Params) {
|
2017-10-26 10:36:20 +00:00
|
|
|
if (Params.contentChanges.size() != 1)
|
|
|
|
return C.replyError(-32602, "can only apply one change at a time");
|
2017-05-16 14:40:30 +00:00
|
|
|
// We only support full syncing right now.
|
2017-09-30 10:08:52 +00:00
|
|
|
Server.addDocument(Params.textDocument.uri.file,
|
|
|
|
Params.contentChanges[0].text);
|
2017-05-16 14:40:30 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onFileEvent(Ctx C, DidChangeWatchedFilesParams &Params) {
|
2017-10-02 18:00:37 +00:00
|
|
|
Server.onFileEvent(Params);
|
|
|
|
}
|
|
|
|
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
void ClangdLSPServer::onCommand(Ctx C, ExecuteCommandParams &Params) {
|
|
|
|
if (Params.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND &&
|
|
|
|
Params.workspaceEdit) {
|
|
|
|
// The flow for "apply-fix" :
|
|
|
|
// 1. We publish a diagnostic, including fixits
|
|
|
|
// 2. The user clicks on the diagnostic, the editor asks us for code actions
|
|
|
|
// 3. We send code actions, with the fixit embedded as context
|
|
|
|
// 4. The user selects the fixit, the editor asks us to apply it
|
|
|
|
// 5. We unwrap the changes and send them back to the editor
|
|
|
|
// 6. The editor applies the changes (applyEdit), and sends us a reply (but
|
|
|
|
// we ignore it)
|
|
|
|
|
|
|
|
ApplyWorkspaceEditParams ApplyEdit;
|
|
|
|
ApplyEdit.edit = *Params.workspaceEdit;
|
|
|
|
C.reply("\"Fix applied.\"");
|
|
|
|
// We don't need the response so id == 1 is OK.
|
|
|
|
// Ideally, we would wait for the response and if there is no error, we
|
|
|
|
// would reply success/failure to the original RPC.
|
|
|
|
C.call("workspace/applyEdit", ApplyWorkspaceEditParams::unparse(ApplyEdit));
|
|
|
|
} else {
|
|
|
|
// We should not get here because ExecuteCommandParams would not have
|
|
|
|
// parsed in the first place and this handler should not be called. But if
|
|
|
|
// more commands are added, this will be here has a safe guard.
|
|
|
|
C.replyError(
|
|
|
|
1, llvm::formatv("Unsupported command \"{0}\".", Params.command).str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onDocumentDidClose(Ctx C,
|
|
|
|
DidCloseTextDocumentParams &Params) {
|
2017-09-30 10:08:52 +00:00
|
|
|
Server.removeDocument(Params.textDocument.uri.file);
|
2017-05-16 14:40:30 +00:00
|
|
|
}
|
|
|
|
|
2017-09-30 10:08:52 +00:00
|
|
|
void ClangdLSPServer::onDocumentOnTypeFormatting(
|
2017-10-12 13:29:58 +00:00
|
|
|
Ctx C, DocumentOnTypeFormattingParams &Params) {
|
2017-05-16 14:40:30 +00:00
|
|
|
auto File = Params.textDocument.uri.file;
|
2017-09-30 10:08:52 +00:00
|
|
|
std::string Code = Server.getDocument(File);
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
std::string Edits = TextEdit::unparse(
|
|
|
|
replacementsToEdits(Code, Server.formatOnType(File, Params.position)));
|
|
|
|
C.reply(Edits);
|
2017-05-16 14:40:30 +00:00
|
|
|
}
|
|
|
|
|
2017-09-30 10:08:52 +00:00
|
|
|
void ClangdLSPServer::onDocumentRangeFormatting(
|
2017-10-12 13:29:58 +00:00
|
|
|
Ctx C, DocumentRangeFormattingParams &Params) {
|
2017-05-16 14:40:30 +00:00
|
|
|
auto File = Params.textDocument.uri.file;
|
2017-09-30 10:08:52 +00:00
|
|
|
std::string Code = Server.getDocument(File);
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
std::string Edits = TextEdit::unparse(
|
|
|
|
replacementsToEdits(Code, Server.formatRange(File, Params.range)));
|
|
|
|
C.reply(Edits);
|
2017-05-16 14:40:30 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onDocumentFormatting(Ctx C,
|
|
|
|
DocumentFormattingParams &Params) {
|
2017-05-16 14:40:30 +00:00
|
|
|
auto File = Params.textDocument.uri.file;
|
2017-09-30 10:08:52 +00:00
|
|
|
std::string Code = Server.getDocument(File);
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
std::string Edits =
|
|
|
|
TextEdit::unparse(replacementsToEdits(Code, Server.formatFile(File)));
|
|
|
|
C.reply(Edits);
|
2017-05-16 14:40:30 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onCodeAction(Ctx C, CodeActionParams &Params) {
|
2017-05-16 14:40:30 +00:00
|
|
|
// We provide a code action for each diagnostic at the requested location
|
|
|
|
// which has FixIts available.
|
2017-09-30 10:08:52 +00:00
|
|
|
std::string Code = Server.getDocument(Params.textDocument.uri.file);
|
2017-05-16 14:40:30 +00:00
|
|
|
std::string Commands;
|
|
|
|
for (Diagnostic &D : Params.context.diagnostics) {
|
|
|
|
std::vector<clang::tooling::Replacement> Fixes =
|
2017-09-30 10:08:52 +00:00
|
|
|
getFixIts(Params.textDocument.uri.file, D);
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
auto Edits = replacementsToEdits(Code, Fixes);
|
|
|
|
WorkspaceEdit WE;
|
|
|
|
WE.changes = {{llvm::yaml::escape(Params.textDocument.uri.uri), Edits}};
|
2017-05-16 14:40:30 +00:00
|
|
|
|
|
|
|
if (!Edits.empty())
|
|
|
|
Commands +=
|
|
|
|
R"({"title":"Apply FixIt ')" + llvm::yaml::escape(D.message) +
|
[clangd] Handle clangd.applyFix server-side
Summary:
When the user selects a fix-it (or any code action with commands), it is
possible to let the client forward the selected command to the server.
When the clangd.applyFix command is handled on the server, it can send a
workspace/applyEdit request to the client. This has the advantage that
the client doesn't explicitly have to know how to handle
clangd.applyFix. Therefore, the code to handle clangd.applyFix in the VS
Code extension (and any other Clangd client) is not required anymore.
Reviewers: ilya-biryukov, sammccall, Nebiroth, hokein
Reviewed By: hokein
Subscribers: ioeric, hokein, rwols, puremourning, bkramer, ilya-biryukov
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D39276
llvm-svn: 317322
2017-11-03 13:39:15 +00:00
|
|
|
R"('", "command": ")" +
|
|
|
|
ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND +
|
|
|
|
R"(", "arguments": [)" + WorkspaceEdit::unparse(WE) + R"(]},)";
|
2017-05-16 14:40:30 +00:00
|
|
|
}
|
|
|
|
if (!Commands.empty())
|
|
|
|
Commands.pop_back();
|
2017-10-12 13:29:58 +00:00
|
|
|
C.reply("[" + Commands + "]");
|
2017-05-16 14:40:30 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onCompletion(Ctx C, TextDocumentPositionParams &Params) {
|
2017-09-30 10:08:52 +00:00
|
|
|
auto Items = Server
|
2017-08-02 09:08:39 +00:00
|
|
|
.codeComplete(Params.textDocument.uri.file,
|
|
|
|
Position{Params.position.line,
|
|
|
|
Params.position.character})
|
2017-10-05 17:04:13 +00:00
|
|
|
.get() // FIXME(ibiryukov): This could be made async if we
|
|
|
|
// had an API that would allow to attach callbacks to
|
|
|
|
// futures returned by ClangdServer.
|
2017-08-02 09:08:39 +00:00
|
|
|
.Value;
|
2017-05-16 14:40:30 +00:00
|
|
|
|
|
|
|
std::string Completions;
|
|
|
|
for (const auto &Item : Items) {
|
|
|
|
Completions += CompletionItem::unparse(Item);
|
|
|
|
Completions += ",";
|
|
|
|
}
|
|
|
|
if (!Completions.empty())
|
|
|
|
Completions.pop_back();
|
2017-10-12 13:29:58 +00:00
|
|
|
C.reply("[" + Completions + "]");
|
2017-05-16 14:40:30 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onSignatureHelp(Ctx C,
|
|
|
|
TextDocumentPositionParams &Params) {
|
2017-10-26 12:28:13 +00:00
|
|
|
auto SignatureHelp = Server.signatureHelp(
|
|
|
|
Params.textDocument.uri.file,
|
|
|
|
Position{Params.position.line, Params.position.character});
|
|
|
|
if (!SignatureHelp)
|
|
|
|
return C.replyError(-32602, llvm::toString(SignatureHelp.takeError()));
|
|
|
|
C.reply(SignatureHelp::unparse(SignatureHelp->Value));
|
2017-10-06 11:54:17 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onGoToDefinition(Ctx C,
|
|
|
|
TextDocumentPositionParams &Params) {
|
2017-10-26 12:28:13 +00:00
|
|
|
auto Items = Server.findDefinitions(
|
|
|
|
Params.textDocument.uri.file,
|
|
|
|
Position{Params.position.line, Params.position.character});
|
|
|
|
if (!Items)
|
|
|
|
return C.replyError(-32602, llvm::toString(Items.takeError()));
|
2017-06-28 16:12:10 +00:00
|
|
|
|
|
|
|
std::string Locations;
|
2017-10-26 12:28:13 +00:00
|
|
|
for (const auto &Item : Items->Value) {
|
2017-06-28 16:12:10 +00:00
|
|
|
Locations += Location::unparse(Item);
|
|
|
|
Locations += ",";
|
|
|
|
}
|
|
|
|
if (!Locations.empty())
|
|
|
|
Locations.pop_back();
|
2017-10-12 13:29:58 +00:00
|
|
|
C.reply("[" + Locations + "]");
|
2017-06-28 16:12:10 +00:00
|
|
|
}
|
|
|
|
|
2017-10-12 13:29:58 +00:00
|
|
|
void ClangdLSPServer::onSwitchSourceHeader(Ctx C,
|
|
|
|
TextDocumentIdentifier &Params) {
|
2017-09-30 10:08:52 +00:00
|
|
|
llvm::Optional<Path> Result = Server.switchSourceHeader(Params.uri.file);
|
2017-09-28 03:14:40 +00:00
|
|
|
std::string ResultUri;
|
2017-10-12 13:29:58 +00:00
|
|
|
C.reply(Result ? URI::unparse(URI::fromFile(*Result)) : R"("")");
|
2017-09-28 03:14:40 +00:00
|
|
|
}
|
|
|
|
|
2017-08-14 08:45:47 +00:00
|
|
|
ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, unsigned AsyncThreadsCount,
|
2017-09-12 13:57:14 +00:00
|
|
|
bool SnippetCompletions,
|
2017-10-02 15:13:20 +00:00
|
|
|
llvm::Optional<StringRef> ResourceDir,
|
|
|
|
llvm::Optional<Path> CompileCommandsDir)
|
|
|
|
: Out(Out), CDB(/*Logger=*/Out, std::move(CompileCommandsDir)),
|
2017-09-30 10:08:52 +00:00
|
|
|
Server(CDB, /*DiagConsumer=*/*this, FSProvider, AsyncThreadsCount,
|
2017-10-23 14:46:48 +00:00
|
|
|
clangd::CodeCompleteOptions(
|
|
|
|
/*EnableSnippetsAndCodePatterns=*/SnippetCompletions),
|
|
|
|
/*Logger=*/Out, ResourceDir) {}
|
2017-05-16 09:38:59 +00:00
|
|
|
|
2017-10-25 08:45:41 +00:00
|
|
|
bool ClangdLSPServer::run(std::istream &In) {
|
2017-05-16 14:40:30 +00:00
|
|
|
assert(!IsDone && "Run was called before");
|
2017-05-16 09:38:59 +00:00
|
|
|
|
2017-05-16 14:40:30 +00:00
|
|
|
// Set up JSONRPCDispatcher.
|
2017-10-12 13:29:58 +00:00
|
|
|
JSONRPCDispatcher Dispatcher(
|
|
|
|
[](RequestContext Ctx, llvm::yaml::MappingNode *Params) {
|
|
|
|
Ctx.replyError(-32601, "method not found");
|
|
|
|
});
|
2017-09-30 10:08:52 +00:00
|
|
|
registerCallbackHandlers(Dispatcher, Out, /*Callbacks=*/*this);
|
2017-05-16 14:40:30 +00:00
|
|
|
|
|
|
|
// Run the Language Server loop.
|
|
|
|
runLanguageServerLoop(In, Out, Dispatcher, IsDone);
|
2017-05-16 09:38:59 +00:00
|
|
|
|
2017-05-16 14:40:30 +00:00
|
|
|
// Make sure IsDone is set to true after this method exits to ensure assertion
|
|
|
|
// at the start of the method fires if it's ever executed again.
|
|
|
|
IsDone = true;
|
2017-10-25 08:45:41 +00:00
|
|
|
|
|
|
|
return ShutdownRequestReceived;
|
2017-05-16 09:38:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<clang::tooling::Replacement>
|
|
|
|
ClangdLSPServer::getFixIts(StringRef File, const clangd::Diagnostic &D) {
|
|
|
|
std::lock_guard<std::mutex> Lock(FixItsMutex);
|
|
|
|
auto DiagToFixItsIter = FixItsMap.find(File);
|
|
|
|
if (DiagToFixItsIter == FixItsMap.end())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
const auto &DiagToFixItsMap = DiagToFixItsIter->second;
|
|
|
|
auto FixItsIter = DiagToFixItsMap.find(D);
|
|
|
|
if (FixItsIter == DiagToFixItsMap.end())
|
|
|
|
return {};
|
|
|
|
|
|
|
|
return FixItsIter->second;
|
|
|
|
}
|
|
|
|
|
2017-09-30 10:08:52 +00:00
|
|
|
void ClangdLSPServer::onDiagnosticsReady(
|
|
|
|
PathRef File, Tagged<std::vector<DiagWithFixIts>> Diagnostics) {
|
2017-05-16 09:38:59 +00:00
|
|
|
std::string DiagnosticsJSON;
|
|
|
|
|
|
|
|
DiagnosticToReplacementMap LocalFixIts; // Temporary storage
|
2017-09-30 10:08:52 +00:00
|
|
|
for (auto &DiagWithFixes : Diagnostics.Value) {
|
2017-05-16 09:38:59 +00:00
|
|
|
auto Diag = DiagWithFixes.Diag;
|
|
|
|
DiagnosticsJSON +=
|
|
|
|
R"({"range":)" + Range::unparse(Diag.range) +
|
|
|
|
R"(,"severity":)" + std::to_string(Diag.severity) +
|
|
|
|
R"(,"message":")" + llvm::yaml::escape(Diag.message) +
|
|
|
|
R"("},)";
|
|
|
|
|
|
|
|
// We convert to Replacements to become independent of the SourceManager.
|
|
|
|
auto &FixItsForDiagnostic = LocalFixIts[Diag];
|
|
|
|
std::copy(DiagWithFixes.FixIts.begin(), DiagWithFixes.FixIts.end(),
|
|
|
|
std::back_inserter(FixItsForDiagnostic));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cache FixIts
|
|
|
|
{
|
|
|
|
// FIXME(ibiryukov): should be deleted when documents are removed
|
|
|
|
std::lock_guard<std::mutex> Lock(FixItsMutex);
|
|
|
|
FixItsMap[File] = LocalFixIts;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Publish diagnostics.
|
|
|
|
if (!DiagnosticsJSON.empty())
|
|
|
|
DiagnosticsJSON.pop_back(); // Drop trailing comma.
|
|
|
|
Out.writeMessage(
|
|
|
|
R"({"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":")" +
|
|
|
|
URI::fromFile(File).uri + R"(","diagnostics":[)" + DiagnosticsJSON +
|
|
|
|
R"(]}})");
|
|
|
|
}
|