2017-05-16 17:38:59 +08:00
|
|
|
//===--- ClangdLSPServer.cpp - LSP server ------------------------*- C++-*-===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2017-05-16 17:38:59 +08:00
|
|
|
//
|
2018-08-15 00:03:32 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2017-05-16 17:38:59 +08:00
|
|
|
|
|
|
|
#include "ClangdLSPServer.h"
|
2020-09-28 21:09:55 +08:00
|
|
|
#include "ClangdServer.h"
|
2020-05-06 07:39:59 +08:00
|
|
|
#include "CodeComplete.h"
|
2018-03-12 23:28:22 +08:00
|
|
|
#include "Diagnostics.h"
|
2019-09-09 20:28:44 +08:00
|
|
|
#include "DraftStore.h"
|
2020-10-17 02:03:48 +08:00
|
|
|
#include "DumpAST.h"
|
2019-06-26 15:45:27 +08:00
|
|
|
#include "GlobalCompilationDatabase.h"
|
2021-02-12 05:47:58 +08:00
|
|
|
#include "LSPBinder.h"
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
#include "Protocol.h"
|
2019-07-04 15:53:12 +08:00
|
|
|
#include "SemanticHighlighting.h"
|
2017-12-19 20:23:48 +08:00
|
|
|
#include "SourceCode.h"
|
2020-03-18 02:08:23 +08:00
|
|
|
#include "TUScheduler.h"
|
2018-01-29 23:37:46 +08:00
|
|
|
#include "URI.h"
|
2019-06-18 21:37:54 +08:00
|
|
|
#include "refactor/Tweak.h"
|
[clangd] Move non-clang base pieces into separate support/ lib. NFCI
Summary:
This enforces layering, reduces a sprawling clangd/ directory, and makes life
easier for embedders.
Reviewers: kbobyrev
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D79014
2020-04-28 23:49:17 +08:00
|
|
|
#include "support/Context.h"
|
2020-09-28 21:09:55 +08:00
|
|
|
#include "support/MemoryTree.h"
|
[clangd] Move non-clang base pieces into separate support/ lib. NFCI
Summary:
This enforces layering, reduces a sprawling clangd/ directory, and makes life
easier for embedders.
Reviewers: kbobyrev
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D79014
2020-04-28 23:49:17 +08:00
|
|
|
#include "support/Trace.h"
|
2020-10-17 02:03:48 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2020-03-03 19:25:46 +08:00
|
|
|
#include "clang/Basic/Version.h"
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
#include "clang/Tooling/Core/Replacement.h"
|
2019-06-26 15:45:27 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2019-03-28 01:47:49 +08:00
|
|
|
#include "llvm/ADT/Optional.h"
|
2018-08-24 21:09:41 +08:00
|
|
|
#include "llvm/ADT/ScopeExit.h"
|
2019-09-09 20:28:44 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2019-09-24 21:38:33 +08:00
|
|
|
#include "llvm/ADT/iterator_range.h"
|
2020-09-28 21:09:55 +08:00
|
|
|
#include "llvm/Support/Allocator.h"
|
2018-03-16 22:30:42 +08:00
|
|
|
#include "llvm/Support/Errc.h"
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
#include "llvm/Support/Error.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 21:39:15 +08:00
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
2019-09-24 21:38:33 +08:00
|
|
|
#include "llvm/Support/JSON.h"
|
2018-02-01 00:26:27 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
2019-09-09 20:28:44 +08:00
|
|
|
#include "llvm/Support/SHA1.h"
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
#include "llvm/Support/ScopedPrinter.h"
|
2020-10-13 06:10:04 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2020-09-28 21:09:55 +08:00
|
|
|
#include <chrono>
|
2019-09-09 20:28:44 +08:00
|
|
|
#include <cstddef>
|
2020-10-13 06:10:04 +08:00
|
|
|
#include <cstdint>
|
|
|
|
#include <functional>
|
2019-09-24 21:38:33 +08:00
|
|
|
#include <memory>
|
[clangd] Show background index status using LSP 3.15 work-done progress notifications
Summary:
It simply shows the completed/total items on the background queue, e.g.
indexing: 233/1000
The denominator is reset to zero every time the queue goes idle.
The protocol is fairly complicated here (requires creating a remote "progress"
resource before sending updates). We implement the full protocol, but I've added
an extension allowing it to be skipped to reduce the burden on clients - in
particular the lit test takes this shortcut.
The addition of background index progress to DiagnosticConsumer seems ridiculous
at first glance, but I believe that interface is trending in the direction of
"ClangdServer callbacks" anyway. It's due for a rename, but otherwise actually
fits.
Reviewers: kadircet, usaxena95
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D73218
2020-01-23 02:41:45 +08:00
|
|
|
#include <mutex>
|
2019-09-09 20:28:44 +08:00
|
|
|
#include <string>
|
2019-09-24 21:38:33 +08:00
|
|
|
#include <vector>
|
[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 21:39:15 +08:00
|
|
|
|
2018-10-20 23:30:37 +08:00
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
2017-05-16 22:40:30 +08:00
|
|
|
namespace {
|
2020-04-17 05:12:09 +08:00
|
|
|
// Tracks end-to-end latency of high level lsp calls. Measurements are in
|
|
|
|
// seconds.
|
|
|
|
constexpr trace::Metric LSPLatency("lsp_latency", trace::Metric::Distribution,
|
|
|
|
"method_name");
|
|
|
|
|
[clangd] Track document versions, include them with diags, enhance logs
Summary:
This ties to an LSP feature (diagnostic versioning) but really a lot
of the value is in being able to log what's happening with file versions
and queues more descriptively and clearly.
As such it's fairly invasive, for a logging patch :-\
Key decisions:
- at the LSP layer, we don't reqire the client to provide versions (LSP
makes it mandatory but we never enforced it). If not provided,
versions start at 0 and increment. DraftStore handles this.
- don't propagate magically using contexts, but rather manually:
addDocument -> ParseInputs -> (ParsedAST, Preamble, various callbacks)
Context-propagation would hide the versions from ClangdServer, which
would make producing good log messages hard
- within ClangdServer, treat versions as opaque and unordered.
std::string is a convenient type for this, and allows richer versions
for embedders. They're "mandatory" but "null" is a reasonable default.
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75582
2020-03-04 07:33:29 +08:00
|
|
|
// LSP defines file versions as numbers that increase.
|
|
|
|
// ClangdServer treats them as opaque and therefore uses strings instead.
|
2021-03-02 07:16:33 +08:00
|
|
|
std::string encodeVersion(llvm::Optional<int64_t> LSPVersion) {
|
|
|
|
return LSPVersion ? llvm::to_string(*LSPVersion) : "";
|
[clangd] Track document versions, include them with diags, enhance logs
Summary:
This ties to an LSP feature (diagnostic versioning) but really a lot
of the value is in being able to log what's happening with file versions
and queues more descriptively and clearly.
As such it's fairly invasive, for a logging patch :-\
Key decisions:
- at the LSP layer, we don't reqire the client to provide versions (LSP
makes it mandatory but we never enforced it). If not provided,
versions start at 0 and increment. DraftStore handles this.
- don't propagate magically using contexts, but rather manually:
addDocument -> ParseInputs -> (ParsedAST, Preamble, various callbacks)
Context-propagation would hide the versions from ClangdServer, which
would make producing good log messages hard
- within ClangdServer, treat versions as opaque and unordered.
std::string is a convenient type for this, and allows richer versions
for embedders. They're "mandatory" but "null" is a reasonable default.
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75582
2020-03-04 07:33:29 +08:00
|
|
|
}
|
|
|
|
llvm::Optional<int64_t> decodeVersion(llvm::StringRef Encoded) {
|
|
|
|
int64_t Result;
|
|
|
|
if (llvm::to_integer(Encoded, Result, 10))
|
|
|
|
return Result;
|
2020-09-11 17:30:06 +08:00
|
|
|
if (!Encoded.empty()) // Empty can be e.g. diagnostics on close.
|
[clangd] Track document versions, include them with diags, enhance logs
Summary:
This ties to an LSP feature (diagnostic versioning) but really a lot
of the value is in being able to log what's happening with file versions
and queues more descriptively and clearly.
As such it's fairly invasive, for a logging patch :-\
Key decisions:
- at the LSP layer, we don't reqire the client to provide versions (LSP
makes it mandatory but we never enforced it). If not provided,
versions start at 0 and increment. DraftStore handles this.
- don't propagate magically using contexts, but rather manually:
addDocument -> ParseInputs -> (ParsedAST, Preamble, various callbacks)
Context-propagation would hide the versions from ClangdServer, which
would make producing good log messages hard
- within ClangdServer, treat versions as opaque and unordered.
std::string is a convenient type for this, and allows richer versions
for embedders. They're "mandatory" but "null" is a reasonable default.
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75582
2020-03-04 07:33:29 +08:00
|
|
|
elog("unexpected non-numeric version {0}", Encoded);
|
|
|
|
return llvm::None;
|
|
|
|
}
|
|
|
|
|
2021-02-11 23:32:09 +08:00
|
|
|
const llvm::StringLiteral APPLY_FIX_COMMAND = "clangd.applyFix";
|
|
|
|
const llvm::StringLiteral APPLY_TWEAK_COMMAND = "clangd.applyTweak";
|
|
|
|
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
/// Transforms a tweak into a code action that would apply it if executed.
|
|
|
|
/// EXPECTS: T.prepare() was called and returned true.
|
|
|
|
CodeAction toCodeAction(const ClangdServer::TweakRef &T, const URIForFile &File,
|
|
|
|
Range Selection) {
|
|
|
|
CodeAction CA;
|
|
|
|
CA.title = T.Title;
|
2020-09-29 00:12:37 +08:00
|
|
|
CA.kind = T.Kind.str();
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
// This tweak may have an expensive second stage, we only run it if the user
|
|
|
|
// actually chooses it in the UI. We reply with a command that would run the
|
|
|
|
// corresponding tweak.
|
|
|
|
// FIXME: for some tweaks, computing the edits is cheap and we could send them
|
|
|
|
// directly.
|
|
|
|
CA.command.emplace();
|
|
|
|
CA.command->title = T.Title;
|
2021-02-11 23:32:09 +08:00
|
|
|
CA.command->command = std::string(APPLY_TWEAK_COMMAND);
|
|
|
|
TweakArgs Args;
|
|
|
|
Args.file = File;
|
|
|
|
Args.tweakID = T.ID;
|
|
|
|
Args.selection = Selection;
|
|
|
|
CA.command->argument = std::move(Args);
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
return CA;
|
2019-02-03 22:08:30 +08:00
|
|
|
}
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
|
2018-11-23 23:21:19 +08:00
|
|
|
void adjustSymbolKinds(llvm::MutableArrayRef<DocumentSymbol> Syms,
|
|
|
|
SymbolKindBitset Kinds) {
|
|
|
|
for (auto &S : Syms) {
|
|
|
|
S.kind = adjustKindToCapability(S.kind, Kinds);
|
|
|
|
adjustSymbolKinds(S.children, Kinds);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
SymbolKindBitset defaultSymbolKinds() {
|
|
|
|
SymbolKindBitset Defaults;
|
|
|
|
for (size_t I = SymbolKindMin; I <= static_cast<size_t>(SymbolKind::Array);
|
|
|
|
++I)
|
|
|
|
Defaults.set(I);
|
|
|
|
return Defaults;
|
|
|
|
}
|
|
|
|
|
2018-09-28 01:13:07 +08:00
|
|
|
CompletionItemKindBitset defaultCompletionItemKinds() {
|
|
|
|
CompletionItemKindBitset Defaults;
|
|
|
|
for (size_t I = CompletionItemKindMin;
|
|
|
|
I <= static_cast<size_t>(CompletionItemKind::Reference); ++I)
|
|
|
|
Defaults.set(I);
|
|
|
|
return Defaults;
|
|
|
|
}
|
|
|
|
|
2019-10-23 20:40:20 +08:00
|
|
|
// Makes sure edits in \p FE are applicable to latest file contents reported by
|
2019-09-09 20:28:44 +08:00
|
|
|
// editor. If not generates an error message containing information about files
|
|
|
|
// that needs to be saved.
|
2021-03-02 07:16:33 +08:00
|
|
|
llvm::Error validateEdits(const ClangdServer &Server, const FileEdits &FE) {
|
2019-09-09 20:28:44 +08:00
|
|
|
size_t InvalidFileCount = 0;
|
|
|
|
llvm::StringRef LastInvalidFile;
|
2019-10-23 20:40:20 +08:00
|
|
|
for (const auto &It : FE) {
|
2021-03-02 07:16:33 +08:00
|
|
|
if (auto Draft = Server.getDraft(It.first())) {
|
2019-09-09 20:28:44 +08:00
|
|
|
// If the file is open in user's editor, make sure the version we
|
|
|
|
// saw and current version are compatible as this is the text that
|
|
|
|
// will be replaced by editors.
|
2021-03-02 07:16:33 +08:00
|
|
|
if (!It.second.canApplyTo(*Draft)) {
|
2019-09-09 20:28:44 +08:00
|
|
|
++InvalidFileCount;
|
|
|
|
LastInvalidFile = It.first();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!InvalidFileCount)
|
|
|
|
return llvm::Error::success();
|
|
|
|
if (InvalidFileCount == 1)
|
[clangd] Add error() function for creating formatv-style llvm::Errors. NFC
Summary:
This is considerably terser than the makeStringError and friends, and
avoids verbosity cliffs that discourage adding log information.
It follows the syntax used in log/elog/vlog/dlog that have been successful.
The main caveats are:
- it's strictly out-of-place in logger.h, though kind of fits thematically and
in implementation
- it claims the "error" identifier, which seems a bit too opinionated
to put higher up in llvm
I've updated some users of StringError mostly at random - there are lots
more mechanical changes but I'd like to get this reviewed before making
them all.
Reviewers: kbobyrev, hokein
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D83419
2020-07-09 03:49:38 +08:00
|
|
|
return error("File must be saved first: {0}", LastInvalidFile);
|
|
|
|
return error("Files must be saved first: {0} (and {1} others)",
|
|
|
|
LastInvalidFile, InvalidFileCount - 1);
|
2019-09-09 20:28:44 +08:00
|
|
|
}
|
2017-05-16 22:40:30 +08:00
|
|
|
} // namespace
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
// MessageHandler dispatches incoming LSP messages.
|
|
|
|
// It handles cross-cutting concerns:
|
|
|
|
// - serializes/deserializes protocol objects to JSON
|
|
|
|
// - logging of inbound messages
|
|
|
|
// - cancellation handling
|
|
|
|
// - basic call tracing
|
[clangd] Enforce rules around "initialize" request, and create ClangdServer lazily.
Summary:
LSP is a slightly awkward map to C++ object lifetimes: the initialize request
is part of the protocol and provides information that doesn't change over the
lifetime of the server.
Until now, we handled this by initializing ClangdServer and ClangdLSPServer
right away, and making anything that can be set in the "initialize" request
mutable.
With this patch, we create ClangdLSPServer immediately, but defer creating
ClangdServer until "initialize". This opens the door to passing the relevant
initialize params in the constructor and storing them immutably.
(That change isn't actually done in this patch).
To make this safe, we have the MessageDispatcher enforce that the "initialize"
method is called before any other (as required by LSP). That way each method
handler can assume Server is initialized, as today.
As usual, while implementing this I found places where our test cases violated
the protocol.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53398
llvm-svn: 344741
2018-10-18 22:41:50 +08:00
|
|
|
// MessageHandler ensures that initialize() is called before any other handler.
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
class ClangdLSPServer::MessageHandler : public Transport::MessageHandler {
|
|
|
|
public:
|
|
|
|
MessageHandler(ClangdLSPServer &Server) : Server(Server) {}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
bool onNotify(llvm::StringRef Method, llvm::json::Value Params) override {
|
2021-02-12 05:47:58 +08:00
|
|
|
trace::Span Tracer(Method, LSPLatency);
|
|
|
|
SPAN_ATTACH(Tracer, "Params", Params);
|
2019-03-28 01:47:49 +08:00
|
|
|
WithContext HandlerContext(handlerContext());
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
log("<-- {0}", Method);
|
|
|
|
if (Method == "exit")
|
|
|
|
return false;
|
2021-02-12 23:23:53 +08:00
|
|
|
auto Handler = Server.Handlers.NotificationHandlers.find(Method);
|
|
|
|
if (Handler != Server.Handlers.NotificationHandlers.end()) {
|
|
|
|
Handler->second(std::move(Params));
|
|
|
|
Server.maybeExportMemoryProfile();
|
|
|
|
Server.maybeCleanupMemory();
|
|
|
|
} else if (!Server.Server) {
|
[clangd] Enforce rules around "initialize" request, and create ClangdServer lazily.
Summary:
LSP is a slightly awkward map to C++ object lifetimes: the initialize request
is part of the protocol and provides information that doesn't change over the
lifetime of the server.
Until now, we handled this by initializing ClangdServer and ClangdLSPServer
right away, and making anything that can be set in the "initialize" request
mutable.
With this patch, we create ClangdLSPServer immediately, but defer creating
ClangdServer until "initialize". This opens the door to passing the relevant
initialize params in the constructor and storing them immutably.
(That change isn't actually done in this patch).
To make this safe, we have the MessageDispatcher enforce that the "initialize"
method is called before any other (as required by LSP). That way each method
handler can assume Server is initialized, as today.
As usual, while implementing this I found places where our test cases violated
the protocol.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53398
llvm-svn: 344741
2018-10-18 22:41:50 +08:00
|
|
|
elog("Notification {0} before initialization", Method);
|
2020-09-28 21:09:55 +08:00
|
|
|
} else if (Method == "$/cancelRequest") {
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
onCancel(std::move(Params));
|
2020-09-28 21:09:55 +08:00
|
|
|
} else {
|
2021-02-12 23:23:53 +08:00
|
|
|
log("unhandled notification {0}", Method);
|
2020-09-28 21:09:55 +08:00
|
|
|
}
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
bool onCall(llvm::StringRef Method, llvm::json::Value Params,
|
|
|
|
llvm::json::Value ID) override {
|
2019-03-28 01:47:49 +08:00
|
|
|
WithContext HandlerContext(handlerContext());
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
// Calls can be canceled by the client. Add cancellation context.
|
|
|
|
WithContext WithCancel(cancelableRequestContext(ID));
|
2020-04-17 05:12:09 +08:00
|
|
|
trace::Span Tracer(Method, LSPLatency);
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
SPAN_ATTACH(Tracer, "Params", Params);
|
|
|
|
ReplyOnce Reply(ID, Method, &Server, Tracer.Args);
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
log("<-- {0}({1})", Method, ID);
|
2021-02-12 23:23:53 +08:00
|
|
|
auto Handler = Server.Handlers.MethodHandlers.find(Method);
|
|
|
|
if (Handler != Server.Handlers.MethodHandlers.end()) {
|
|
|
|
Handler->second(std::move(Params), std::move(Reply));
|
|
|
|
} else if (!Server.Server) {
|
[clangd] Enforce rules around "initialize" request, and create ClangdServer lazily.
Summary:
LSP is a slightly awkward map to C++ object lifetimes: the initialize request
is part of the protocol and provides information that doesn't change over the
lifetime of the server.
Until now, we handled this by initializing ClangdServer and ClangdLSPServer
right away, and making anything that can be set in the "initialize" request
mutable.
With this patch, we create ClangdLSPServer immediately, but defer creating
ClangdServer until "initialize". This opens the door to passing the relevant
initialize params in the constructor and storing them immutably.
(That change isn't actually done in this patch).
To make this safe, we have the MessageDispatcher enforce that the "initialize"
method is called before any other (as required by LSP). That way each method
handler can assume Server is initialized, as today.
As usual, while implementing this I found places where our test cases violated
the protocol.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53398
llvm-svn: 344741
2018-10-18 22:41:50 +08:00
|
|
|
elog("Call {0} before initialization.", Method);
|
2019-01-07 23:45:19 +08:00
|
|
|
Reply(llvm::make_error<LSPError>("server not initialized",
|
|
|
|
ErrorCode::ServerNotInitialized));
|
2021-02-12 05:47:58 +08:00
|
|
|
} else {
|
2021-02-12 23:23:53 +08:00
|
|
|
Reply(llvm::make_error<LSPError>("method not found",
|
|
|
|
ErrorCode::MethodNotFound));
|
2021-02-12 05:47:58 +08:00
|
|
|
}
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
bool onReply(llvm::json::Value ID,
|
|
|
|
llvm::Expected<llvm::json::Value> Result) override {
|
2019-03-28 01:47:49 +08:00
|
|
|
WithContext HandlerContext(handlerContext());
|
2019-08-05 20:48:09 +08:00
|
|
|
|
|
|
|
Callback<llvm::json::Value> ReplyHandler = nullptr;
|
|
|
|
if (auto IntID = ID.getAsInteger()) {
|
|
|
|
std::lock_guard<std::mutex> Mutex(CallMutex);
|
|
|
|
// Find a corresponding callback for the request ID;
|
|
|
|
for (size_t Index = 0; Index < ReplyCallbacks.size(); ++Index) {
|
|
|
|
if (ReplyCallbacks[Index].first == *IntID) {
|
|
|
|
ReplyHandler = std::move(ReplyCallbacks[Index].second);
|
|
|
|
ReplyCallbacks.erase(ReplyCallbacks.begin() +
|
|
|
|
Index); // remove the entry
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ReplyHandler) {
|
|
|
|
// No callback being found, use a default log callback.
|
|
|
|
ReplyHandler = [&ID](llvm::Expected<llvm::json::Value> Result) {
|
|
|
|
elog("received a reply with ID {0}, but there was no such call", ID);
|
|
|
|
if (!Result)
|
|
|
|
llvm::consumeError(Result.takeError());
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log and run the reply handler.
|
|
|
|
if (Result) {
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
log("<-- reply({0})", ID);
|
2019-08-05 20:48:09 +08:00
|
|
|
ReplyHandler(std::move(Result));
|
|
|
|
} else {
|
|
|
|
auto Err = Result.takeError();
|
|
|
|
log("<-- reply({0}) error: {1}", ID, Err);
|
|
|
|
ReplyHandler(std::move(Err));
|
|
|
|
}
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-08-05 20:48:09 +08:00
|
|
|
// Bind a reply callback to a request. The callback will be invoked when
|
|
|
|
// clangd receives the reply from the LSP client.
|
|
|
|
// Return a call id of the request.
|
|
|
|
llvm::json::Value bindReply(Callback<llvm::json::Value> Reply) {
|
|
|
|
llvm::Optional<std::pair<int, Callback<llvm::json::Value>>> OldestCB;
|
|
|
|
int ID;
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> Mutex(CallMutex);
|
|
|
|
ID = NextCallID++;
|
|
|
|
ReplyCallbacks.emplace_back(ID, std::move(Reply));
|
|
|
|
|
|
|
|
// If the queue overflows, we assume that the client didn't reply the
|
|
|
|
// oldest request, and run the corresponding callback which replies an
|
|
|
|
// error to the client.
|
|
|
|
if (ReplyCallbacks.size() > MaxReplayCallbacks) {
|
|
|
|
elog("more than {0} outstanding LSP calls, forgetting about {1}",
|
|
|
|
MaxReplayCallbacks, ReplyCallbacks.front().first);
|
|
|
|
OldestCB = std::move(ReplyCallbacks.front());
|
|
|
|
ReplyCallbacks.pop_front();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (OldestCB)
|
[clangd] Add error() function for creating formatv-style llvm::Errors. NFC
Summary:
This is considerably terser than the makeStringError and friends, and
avoids verbosity cliffs that discourage adding log information.
It follows the syntax used in log/elog/vlog/dlog that have been successful.
The main caveats are:
- it's strictly out-of-place in logger.h, though kind of fits thematically and
in implementation
- it claims the "error" identifier, which seems a bit too opinionated
to put higher up in llvm
I've updated some users of StringError mostly at random - there are lots
more mechanical changes but I'd like to get this reviewed before making
them all.
Reviewers: kbobyrev, hokein
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D83419
2020-07-09 03:49:38 +08:00
|
|
|
OldestCB->second(
|
|
|
|
error("failed to receive a client reply for request ({0})",
|
|
|
|
OldestCB->first));
|
2019-08-05 20:48:09 +08:00
|
|
|
return ID;
|
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
private:
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
// Function object to reply to an LSP call.
|
|
|
|
// Each instance must be called exactly once, otherwise:
|
|
|
|
// - the bug is logged, and (in debug mode) an assert will fire
|
|
|
|
// - if there was no reply, an error reply is sent
|
|
|
|
// - if there were multiple replies, only the first is sent
|
|
|
|
class ReplyOnce {
|
|
|
|
std::atomic<bool> Replied = {false};
|
2018-10-24 23:18:40 +08:00
|
|
|
std::chrono::steady_clock::time_point Start;
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::json::Value ID;
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
std::string Method;
|
|
|
|
ClangdLSPServer *Server; // Null when moved-from.
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::json::Object *TraceArgs;
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
|
|
|
|
public:
|
2019-01-07 23:45:19 +08:00
|
|
|
ReplyOnce(const llvm::json::Value &ID, llvm::StringRef Method,
|
|
|
|
ClangdLSPServer *Server, llvm::json::Object *TraceArgs)
|
2018-10-24 23:18:40 +08:00
|
|
|
: Start(std::chrono::steady_clock::now()), ID(ID), Method(Method),
|
|
|
|
Server(Server), TraceArgs(TraceArgs) {
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
assert(Server);
|
|
|
|
}
|
|
|
|
ReplyOnce(ReplyOnce &&Other)
|
2018-10-24 23:18:40 +08:00
|
|
|
: Replied(Other.Replied.load()), Start(Other.Start),
|
|
|
|
ID(std::move(Other.ID)), Method(std::move(Other.Method)),
|
|
|
|
Server(Other.Server), TraceArgs(Other.TraceArgs) {
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
Other.Server = nullptr;
|
|
|
|
}
|
2019-01-03 21:28:05 +08:00
|
|
|
ReplyOnce &operator=(ReplyOnce &&) = delete;
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
ReplyOnce(const ReplyOnce &) = delete;
|
2019-01-03 21:28:05 +08:00
|
|
|
ReplyOnce &operator=(const ReplyOnce &) = delete;
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
|
|
|
|
~ReplyOnce() {
|
2019-08-05 20:48:09 +08:00
|
|
|
// There's one legitimate reason to never reply to a request: clangd's
|
|
|
|
// request handler send a call to the client (e.g. applyEdit) and the
|
|
|
|
// client never replied. In this case, the ReplyOnce is owned by
|
|
|
|
// ClangdLSPServer's reply callback table and is destroyed along with the
|
|
|
|
// server. We don't attempt to send a reply in this case, there's little
|
|
|
|
// to be gained from doing so.
|
|
|
|
if (Server && !Server->IsBeingDestroyed && !Replied) {
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
elog("No reply to message {0}({1})", Method, ID);
|
|
|
|
assert(false && "must reply to all calls!");
|
2019-01-07 23:45:19 +08:00
|
|
|
(*this)(llvm::make_error<LSPError>("server failed to reply",
|
|
|
|
ErrorCode::InternalError));
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
void operator()(llvm::Expected<llvm::json::Value> Reply) {
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
assert(Server && "moved-from!");
|
|
|
|
if (Replied.exchange(true)) {
|
|
|
|
elog("Replied twice to message {0}({1})", Method, ID);
|
|
|
|
assert(false && "must reply to each call only once!");
|
|
|
|
return;
|
|
|
|
}
|
2018-10-24 23:18:40 +08:00
|
|
|
auto Duration = std::chrono::steady_clock::now() - Start;
|
|
|
|
if (Reply) {
|
|
|
|
log("--> reply:{0}({1}) {2:ms}", Method, ID, Duration);
|
|
|
|
if (TraceArgs)
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
(*TraceArgs)["Reply"] = *Reply;
|
2018-10-24 23:18:40 +08:00
|
|
|
std::lock_guard<std::mutex> Lock(Server->TranspWriter);
|
|
|
|
Server->Transp.reply(std::move(ID), std::move(Reply));
|
|
|
|
} else {
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::Error Err = Reply.takeError();
|
2018-10-24 23:18:40 +08:00
|
|
|
log("--> reply:{0}({1}) {2:ms}, error: {3}", Method, ID, Duration, Err);
|
|
|
|
if (TraceArgs)
|
2019-01-07 23:45:19 +08:00
|
|
|
(*TraceArgs)["Error"] = llvm::to_string(Err);
|
2018-10-24 23:18:40 +08:00
|
|
|
std::lock_guard<std::mutex> Lock(Server->TranspWriter);
|
|
|
|
Server->Transp.reply(std::move(ID), std::move(Err));
|
[clangd] Ensure that we reply to each call exactly once. NFC (I think!)
Summary:
In debug builds, getting this wrong will trigger asserts.
In production builds, it will send an error reply if none was sent,
and drop redundant replies. (And log).
No tests because this is always a programming error.
(We did have some cases of this, but I fixed them with the new dispatcher).
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53399
llvm-svn: 345144
2018-10-24 22:26:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
// Method calls may be cancelled by ID, so keep track of their state.
|
|
|
|
// This needs a mutex: handlers may finish on a different thread, and that's
|
|
|
|
// when we clean up entries in the map.
|
|
|
|
mutable std::mutex RequestCancelersMutex;
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::StringMap<std::pair<Canceler, /*Cookie*/ unsigned>> RequestCancelers;
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
unsigned NextRequestCookie = 0; // To disambiguate reused IDs, see below.
|
2019-01-07 23:45:19 +08:00
|
|
|
void onCancel(const llvm::json::Value &Params) {
|
|
|
|
const llvm::json::Value *ID = nullptr;
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
if (auto *O = Params.getAsObject())
|
|
|
|
ID = O->get("id");
|
|
|
|
if (!ID) {
|
|
|
|
elog("Bad cancellation request: {0}", Params);
|
|
|
|
return;
|
|
|
|
}
|
2019-01-07 23:45:19 +08:00
|
|
|
auto StrID = llvm::to_string(*ID);
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
|
|
|
|
auto It = RequestCancelers.find(StrID);
|
|
|
|
if (It != RequestCancelers.end())
|
|
|
|
It->second.first(); // Invoke the canceler.
|
|
|
|
}
|
2019-03-28 01:47:49 +08:00
|
|
|
|
|
|
|
Context handlerContext() const {
|
|
|
|
return Context::current().derive(
|
|
|
|
kCurrentOffsetEncoding,
|
2020-09-30 16:56:43 +08:00
|
|
|
Server.Opts.Encoding.getValueOr(OffsetEncoding::UTF16));
|
2019-03-28 01:47:49 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
// We run cancelable requests in a context that does two things:
|
|
|
|
// - allows cancellation using RequestCancelers[ID]
|
|
|
|
// - cleans up the entry in RequestCancelers when it's no longer needed
|
|
|
|
// If a client reuses an ID, the last wins and the first cannot be canceled.
|
2019-01-07 23:45:19 +08:00
|
|
|
Context cancelableRequestContext(const llvm::json::Value &ID) {
|
2020-04-12 00:19:50 +08:00
|
|
|
auto Task = cancelableTask(
|
|
|
|
/*Reason=*/static_cast<int>(ErrorCode::RequestCancelled));
|
2019-01-07 23:45:19 +08:00
|
|
|
auto StrID = llvm::to_string(ID); // JSON-serialize ID for map key.
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
auto Cookie = NextRequestCookie++; // No lock, only called on main thread.
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
|
|
|
|
RequestCancelers[StrID] = {std::move(Task.second), Cookie};
|
|
|
|
}
|
|
|
|
// When the request ends, we can clean up the entry we just added.
|
|
|
|
// The cookie lets us check that it hasn't been overwritten due to ID
|
|
|
|
// reuse.
|
2019-01-07 23:45:19 +08:00
|
|
|
return Task.first.derive(llvm::make_scope_exit([this, StrID, Cookie] {
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
|
|
|
|
auto It = RequestCancelers.find(StrID);
|
|
|
|
if (It != RequestCancelers.end() && It->second.second == Cookie)
|
|
|
|
RequestCancelers.erase(It);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2019-10-09 21:59:31 +08:00
|
|
|
// The maximum number of callbacks held in clangd.
|
|
|
|
//
|
|
|
|
// We bound the maximum size to the pending map to prevent memory leakage
|
|
|
|
// for cases where LSP clients don't reply for the request.
|
|
|
|
// This has to go after RequestCancellers and RequestCancellersMutex since it
|
|
|
|
// can contain a callback that has a cancelable context.
|
|
|
|
static constexpr int MaxReplayCallbacks = 100;
|
|
|
|
mutable std::mutex CallMutex;
|
|
|
|
int NextCallID = 0; /* GUARDED_BY(CallMutex) */
|
|
|
|
std::deque<std::pair</*RequestID*/ int,
|
|
|
|
/*ReplyHandler*/ Callback<llvm::json::Value>>>
|
|
|
|
ReplyCallbacks; /* GUARDED_BY(CallMutex) */
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
ClangdLSPServer &Server;
|
|
|
|
};
|
2019-08-05 20:48:09 +08:00
|
|
|
constexpr int ClangdLSPServer::MessageHandler::MaxReplayCallbacks;
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
|
|
|
|
// call(), notify(), and reply() wrap the Transport, adding logging and locking.
|
2021-02-15 17:41:38 +08:00
|
|
|
void ClangdLSPServer::callMethod(StringRef Method, llvm::json::Value Params,
|
|
|
|
Callback<llvm::json::Value> CB) {
|
2019-08-05 20:48:09 +08:00
|
|
|
auto ID = MsgHandler->bindReply(std::move(CB));
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
log("--> {0}({1})", Method, ID);
|
|
|
|
std::lock_guard<std::mutex> Lock(TranspWriter);
|
|
|
|
Transp.call(Method, std::move(Params), ID);
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
void ClangdLSPServer::notify(llvm::StringRef Method, llvm::json::Value Params) {
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
log("--> {0}", Method);
|
2020-12-22 15:44:20 +08:00
|
|
|
maybeCleanupMemory();
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
std::lock_guard<std::mutex> Lock(TranspWriter);
|
|
|
|
Transp.notify(Method, std::move(Params));
|
|
|
|
}
|
|
|
|
|
2020-03-24 09:24:47 +08:00
|
|
|
static std::vector<llvm::StringRef> semanticTokenTypes() {
|
|
|
|
std::vector<llvm::StringRef> Types;
|
|
|
|
for (unsigned I = 0; I <= static_cast<unsigned>(HighlightingKind::LastKind);
|
|
|
|
++I)
|
|
|
|
Types.push_back(toSemanticTokenType(static_cast<HighlightingKind>(I)));
|
|
|
|
return Types;
|
|
|
|
}
|
|
|
|
|
2021-01-27 16:47:17 +08:00
|
|
|
static std::vector<llvm::StringRef> semanticTokenModifiers() {
|
|
|
|
std::vector<llvm::StringRef> Modifiers;
|
|
|
|
for (unsigned I = 0;
|
|
|
|
I <= static_cast<unsigned>(HighlightingModifier::LastModifier); ++I)
|
|
|
|
Modifiers.push_back(
|
|
|
|
toSemanticTokenModifier(static_cast<HighlightingModifier>(I)));
|
|
|
|
return Modifiers;
|
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onInitialize(const InitializeParams &Params,
|
2019-01-07 23:45:19 +08:00
|
|
|
Callback<llvm::json::Value> Reply) {
|
2019-03-28 01:47:49 +08:00
|
|
|
// Determine character encoding first as it affects constructed ClangdServer.
|
2020-09-30 16:56:43 +08:00
|
|
|
if (Params.capabilities.offsetEncoding && !Opts.Encoding) {
|
|
|
|
Opts.Encoding = OffsetEncoding::UTF16; // fallback
|
2019-03-28 01:47:49 +08:00
|
|
|
for (OffsetEncoding Supported : *Params.capabilities.offsetEncoding)
|
|
|
|
if (Supported != OffsetEncoding::UnsupportedEncoding) {
|
2020-09-30 16:56:43 +08:00
|
|
|
Opts.Encoding = Supported;
|
2019-03-28 01:47:49 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-01 18:02:28 +08:00
|
|
|
if (Params.capabilities.TheiaSemanticHighlighting &&
|
2021-01-28 08:16:47 +08:00
|
|
|
!Params.capabilities.SemanticTokens) {
|
|
|
|
elog("Client requested legacy semanticHighlights notification, which is "
|
|
|
|
"no longer supported. Migrate to standard semanticTokens request");
|
2021-01-20 19:38:32 +08:00
|
|
|
}
|
2020-04-01 18:02:28 +08:00
|
|
|
|
2018-10-19 23:42:23 +08:00
|
|
|
if (Params.rootUri && *Params.rootUri)
|
2020-09-29 16:37:46 +08:00
|
|
|
Opts.WorkspaceRoot = std::string(Params.rootUri->file());
|
2018-10-19 23:42:23 +08:00
|
|
|
else if (Params.rootPath && !Params.rootPath->empty())
|
2020-09-29 16:37:46 +08:00
|
|
|
Opts.WorkspaceRoot = *Params.rootPath;
|
[clangd] Enforce rules around "initialize" request, and create ClangdServer lazily.
Summary:
LSP is a slightly awkward map to C++ object lifetimes: the initialize request
is part of the protocol and provides information that doesn't change over the
lifetime of the server.
Until now, we handled this by initializing ClangdServer and ClangdLSPServer
right away, and making anything that can be set in the "initialize" request
mutable.
With this patch, we create ClangdLSPServer immediately, but defer creating
ClangdServer until "initialize". This opens the door to passing the relevant
initialize params in the constructor and storing them immutably.
(That change isn't actually done in this patch).
To make this safe, we have the MessageDispatcher enforce that the "initialize"
method is called before any other (as required by LSP). That way each method
handler can assume Server is initialized, as today.
As usual, while implementing this I found places where our test cases violated
the protocol.
Reviewers: ioeric
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53398
llvm-svn: 344741
2018-10-18 22:41:50 +08:00
|
|
|
if (Server)
|
2019-01-07 23:45:19 +08:00
|
|
|
return Reply(llvm::make_error<LSPError>("server already initialized",
|
|
|
|
ErrorCode::InvalidRequest));
|
2020-09-29 16:37:46 +08:00
|
|
|
if (Opts.UseDirBasedCDB) {
|
2020-12-04 16:09:03 +08:00
|
|
|
DirectoryBasedGlobalCompilationDatabase::Options CDBOpts(TFS);
|
2021-03-05 19:07:25 +08:00
|
|
|
if (const auto &Dir = Params.initializationOptions.compilationDatabasePath)
|
|
|
|
CDBOpts.CompileCommandsDir = Dir;
|
2021-01-21 01:35:11 +08:00
|
|
|
CDBOpts.ContextProvider = Opts.ContextProvider;
|
2020-12-04 16:09:03 +08:00
|
|
|
BaseCDB =
|
|
|
|
std::make_unique<DirectoryBasedGlobalCompilationDatabase>(CDBOpts);
|
2020-09-29 16:37:46 +08:00
|
|
|
BaseCDB = getQueryDriverDatabase(llvm::makeArrayRef(Opts.QueryDriverGlobs),
|
|
|
|
std::move(BaseCDB));
|
2019-06-26 15:45:27 +08:00
|
|
|
}
|
[clangd] (take 2) Try harder to find a plausible `clang` as argv0, particularly on Mac.
Summary:
This was originally committed in 88bccded8fa169481fa367debf5ec615640635a1,
and reverted in 93f77617abba512d2861e2fc50ce385883f587b6.
This version is now much more testable: the "detect toolchain properties" part
is still not tested but also not active in tests.
All the command manipulation based on the detected properties is
directly tested, and also not active in other tests.
Fixes https://github.com/clangd/clangd/issues/211
Fixes https://github.com/clangd/clangd/issues/178
Reviewers: kbobyrev, ilya-biryukov
Subscribers: mgorny, ormris, cfe-commits, usaxena95, kadircet, arphaman, jkorous, MaskRay
Tags: #clang
Differential Revision: https://reviews.llvm.org/D71029
2019-11-30 02:37:48 +08:00
|
|
|
auto Mangler = CommandMangler::detect();
|
2020-09-29 16:37:46 +08:00
|
|
|
if (Opts.ResourceDir)
|
|
|
|
Mangler.ResourceDir = *Opts.ResourceDir;
|
2019-01-22 17:10:20 +08:00
|
|
|
CDB.emplace(BaseCDB.get(), Params.initializationOptions.fallbackFlags,
|
2020-06-10 04:54:42 +08:00
|
|
|
tooling::ArgumentsAdjuster(std::move(Mangler)));
|
2019-10-15 22:20:52 +08:00
|
|
|
{
|
|
|
|
// Switch caller's context with LSPServer's background context. Since we
|
|
|
|
// rather want to propagate information from LSPServer's context into the
|
|
|
|
// Server, CDB, etc.
|
|
|
|
WithContext MainContext(BackgroundContext.clone());
|
|
|
|
llvm::Optional<WithContextValue> WithOffsetEncoding;
|
2020-09-30 16:56:43 +08:00
|
|
|
if (Opts.Encoding)
|
|
|
|
WithOffsetEncoding.emplace(kCurrentOffsetEncoding, *Opts.Encoding);
|
2020-09-29 16:37:46 +08:00
|
|
|
Server.emplace(*CDB, TFS, Opts,
|
2020-01-24 21:08:56 +08:00
|
|
|
static_cast<ClangdServer::Callbacks *>(this));
|
2019-10-15 22:20:52 +08:00
|
|
|
}
|
2018-10-25 12:22:52 +08:00
|
|
|
applyConfiguration(Params.initializationOptions.ConfigSettings);
|
2018-08-01 19:28:49 +08:00
|
|
|
|
2020-09-29 16:37:46 +08:00
|
|
|
Opts.CodeComplete.EnableSnippets = Params.capabilities.CompletionSnippets;
|
|
|
|
Opts.CodeComplete.IncludeFixIts = Params.capabilities.CompletionFixes;
|
|
|
|
if (!Opts.CodeComplete.BundleOverloads.hasValue())
|
|
|
|
Opts.CodeComplete.BundleOverloads = Params.capabilities.HasSignatureHelp;
|
|
|
|
Opts.CodeComplete.DocumentationFormat =
|
2020-04-30 16:49:32 +08:00
|
|
|
Params.capabilities.CompletionDocumentationFormat;
|
2018-10-17 15:33:42 +08:00
|
|
|
DiagOpts.EmbedFixesInDiagnostics = Params.capabilities.DiagnosticFixes;
|
|
|
|
DiagOpts.SendDiagnosticCategory = Params.capabilities.DiagnosticCategory;
|
2019-04-18 23:17:07 +08:00
|
|
|
DiagOpts.EmitRelatedLocations =
|
|
|
|
Params.capabilities.DiagnosticRelatedInformation;
|
2018-10-17 15:33:42 +08:00
|
|
|
if (Params.capabilities.WorkspaceSymbolKinds)
|
|
|
|
SupportedSymbolKinds |= *Params.capabilities.WorkspaceSymbolKinds;
|
|
|
|
if (Params.capabilities.CompletionItemKinds)
|
|
|
|
SupportedCompletionItemKinds |= *Params.capabilities.CompletionItemKinds;
|
|
|
|
SupportsCodeAction = Params.capabilities.CodeActionStructure;
|
2018-11-23 23:21:19 +08:00
|
|
|
SupportsHierarchicalDocumentSymbol =
|
|
|
|
Params.capabilities.HierarchicalDocumentSymbol;
|
2018-12-20 23:39:12 +08:00
|
|
|
SupportFileStatus = Params.initializationOptions.FileStatus;
|
2019-05-29 18:01:00 +08:00
|
|
|
HoverContentFormat = Params.capabilities.HoverContentFormat;
|
2019-06-04 17:36:59 +08:00
|
|
|
SupportsOffsetsInSignatureHelp = Params.capabilities.OffsetsInSignatureHelp;
|
[clangd] Show background index status using LSP 3.15 work-done progress notifications
Summary:
It simply shows the completed/total items on the background queue, e.g.
indexing: 233/1000
The denominator is reset to zero every time the queue goes idle.
The protocol is fairly complicated here (requires creating a remote "progress"
resource before sending updates). We implement the full protocol, but I've added
an extension allowing it to be skipped to reduce the burden on clients - in
particular the lit test takes this shortcut.
The addition of background index progress to DiagnosticConsumer seems ridiculous
at first glance, but I believe that interface is trending in the direction of
"ClangdServer callbacks" anyway. It's due for a rename, but otherwise actually
fits.
Reviewers: kadircet, usaxena95
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D73218
2020-01-23 02:41:45 +08:00
|
|
|
if (Params.capabilities.WorkDoneProgress)
|
|
|
|
BackgroundIndexProgressState = BackgroundIndexProgress::Empty;
|
|
|
|
BackgroundIndexSkipCreate = Params.capabilities.ImplicitProgressCreation;
|
2021-03-11 20:43:59 +08:00
|
|
|
Opts.ImplicitCancellation = !Params.capabilities.CancelsStaleRequests;
|
2019-07-24 15:49:23 +08:00
|
|
|
|
2021-02-13 04:16:41 +08:00
|
|
|
llvm::json::Object ServerCaps{
|
|
|
|
{"textDocumentSync",
|
|
|
|
llvm::json::Object{
|
|
|
|
{"openClose", true},
|
|
|
|
{"change", (int)TextDocumentSyncKind::Incremental},
|
|
|
|
{"save", true},
|
|
|
|
}},
|
|
|
|
{"documentFormattingProvider", true},
|
|
|
|
{"documentRangeFormattingProvider", true},
|
|
|
|
{"documentOnTypeFormattingProvider",
|
|
|
|
llvm::json::Object{
|
|
|
|
{"firstTriggerCharacter", "\n"},
|
|
|
|
{"moreTriggerCharacter", {}},
|
|
|
|
}},
|
|
|
|
{"completionProvider",
|
|
|
|
llvm::json::Object{
|
|
|
|
{"allCommitCharacters",
|
|
|
|
{" ", "\t", "(", ")", "[", "]", "{", "}", "<",
|
|
|
|
">", ":", ";", ",", "+", "-", "/", "*", "%",
|
|
|
|
"^", "&", "#", "?", ".", "=", "\"", "'", "|"}},
|
|
|
|
{"resolveProvider", false},
|
|
|
|
// We do extra checks, e.g. that > is part of ->.
|
|
|
|
{"triggerCharacters", {".", "<", ">", ":", "\"", "/"}},
|
|
|
|
}},
|
|
|
|
{"semanticTokensProvider",
|
|
|
|
llvm::json::Object{
|
|
|
|
{"full", llvm::json::Object{{"delta", true}}},
|
|
|
|
{"range", false},
|
|
|
|
{"legend",
|
|
|
|
llvm::json::Object{{"tokenTypes", semanticTokenTypes()},
|
|
|
|
{"tokenModifiers", semanticTokenModifiers()}}},
|
|
|
|
}},
|
|
|
|
{"signatureHelpProvider",
|
|
|
|
llvm::json::Object{
|
|
|
|
{"triggerCharacters", {"(", ","}},
|
|
|
|
}},
|
|
|
|
{"declarationProvider", true},
|
|
|
|
{"definitionProvider", true},
|
|
|
|
{"implementationProvider", true},
|
|
|
|
{"documentHighlightProvider", true},
|
|
|
|
{"documentLinkProvider",
|
|
|
|
llvm::json::Object{
|
|
|
|
{"resolveProvider", false},
|
|
|
|
}},
|
|
|
|
{"hoverProvider", true},
|
|
|
|
{"selectionRangeProvider", true},
|
|
|
|
{"documentSymbolProvider", true},
|
|
|
|
{"workspaceSymbolProvider", true},
|
|
|
|
{"referencesProvider", true},
|
|
|
|
{"astProvider", true}, // clangd extension
|
|
|
|
{"typeHierarchyProvider", true},
|
|
|
|
{"memoryUsageProvider", true}, // clangd extension
|
|
|
|
{"compilationDatabase", // clangd extension
|
|
|
|
llvm::json::Object{{"automaticReload", true}}},
|
|
|
|
{"callHierarchyProvider", true},
|
|
|
|
};
|
|
|
|
|
|
|
|
{
|
2021-02-15 17:41:38 +08:00
|
|
|
LSPBinder Binder(Handlers, *this);
|
2021-02-26 21:44:01 +08:00
|
|
|
bindMethods(Binder, Params.capabilities);
|
2021-03-04 23:21:01 +08:00
|
|
|
if (Opts.FeatureModules)
|
|
|
|
for (auto &Mod : *Opts.FeatureModules)
|
2021-02-16 03:56:57 +08:00
|
|
|
Mod.initializeLSP(Binder, Params.rawCapabilities, ServerCaps);
|
2021-02-13 04:16:41 +08:00
|
|
|
}
|
|
|
|
|
2019-07-24 15:49:23 +08:00
|
|
|
// Per LSP, renameProvider can be either boolean or RenameOptions.
|
|
|
|
// RenameOptions will be specified if the client states it supports prepare.
|
2021-02-13 04:16:41 +08:00
|
|
|
ServerCaps["renameProvider"] =
|
|
|
|
Params.capabilities.RenamePrepareSupport
|
|
|
|
? llvm::json::Object{{"prepareProvider", true}}
|
|
|
|
: llvm::json::Value(true);
|
2019-07-24 15:49:23 +08:00
|
|
|
|
2021-02-13 04:16:41 +08:00
|
|
|
// Per LSP, codeActionProvider can be either boolean or CodeActionOptions.
|
2019-08-22 22:53:45 +08:00
|
|
|
// CodeActionOptions is only valid if the client supports action literal
|
|
|
|
// via textDocument.codeAction.codeActionLiteralSupport.
|
|
|
|
llvm::json::Value CodeActionProvider = true;
|
2021-02-13 04:16:41 +08:00
|
|
|
ServerCaps["codeActionProvider"] =
|
|
|
|
Params.capabilities.CodeActionStructure
|
|
|
|
? llvm::json::Object{{"codeActionKinds",
|
|
|
|
{CodeAction::QUICKFIX_KIND,
|
|
|
|
CodeAction::REFACTOR_KIND,
|
|
|
|
CodeAction::INFO_KIND}}}
|
|
|
|
: llvm::json::Value(true);
|
|
|
|
|
|
|
|
if (Opts.FoldingRanges)
|
|
|
|
ServerCaps["foldingRangeProvider"] = true;
|
2019-08-22 22:53:45 +08:00
|
|
|
|
2021-02-11 23:32:09 +08:00
|
|
|
std::vector<llvm::StringRef> Commands;
|
2021-02-12 05:47:58 +08:00
|
|
|
for (llvm::StringRef Command : Handlers.CommandHandlers.keys())
|
2021-02-13 00:59:16 +08:00
|
|
|
Commands.push_back(Command);
|
2021-02-11 23:32:09 +08:00
|
|
|
llvm::sort(Commands);
|
2021-02-13 04:16:41 +08:00
|
|
|
ServerCaps["executeCommandProvider"] =
|
|
|
|
llvm::json::Object{{"commands", Commands}};
|
2021-02-11 23:32:09 +08:00
|
|
|
|
2019-03-28 01:47:49 +08:00
|
|
|
llvm::json::Object Result{
|
2020-03-03 19:25:46 +08:00
|
|
|
{{"serverInfo",
|
|
|
|
llvm::json::Object{{"name", "clangd"},
|
|
|
|
{"version", getClangToolFullVersion("clangd")}}},
|
2021-02-13 04:16:41 +08:00
|
|
|
{"capabilities", std::move(ServerCaps)}}};
|
2020-09-30 16:56:43 +08:00
|
|
|
if (Opts.Encoding)
|
|
|
|
Result["offsetEncoding"] = *Opts.Encoding;
|
2019-03-28 01:47:49 +08:00
|
|
|
Reply(std::move(Result));
|
2017-05-16 22:40:30 +08:00
|
|
|
}
|
|
|
|
|
2020-03-03 19:12:14 +08:00
|
|
|
void ClangdLSPServer::onInitialized(const InitializedParams &Params) {}
|
|
|
|
|
2021-02-12 05:47:58 +08:00
|
|
|
void ClangdLSPServer::onShutdown(const NoParams &,
|
|
|
|
Callback<std::nullptr_t> Reply) {
|
2017-10-25 16:45:41 +08:00
|
|
|
// Do essentially nothing, just say we're ready to exit.
|
|
|
|
ShutdownRequestReceived = true;
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
Reply(nullptr);
|
2017-10-12 21:29:58 +08:00
|
|
|
}
|
2017-05-16 22:40:30 +08:00
|
|
|
|
[clangd] Enable auto-index behind a flag.
Summary:
Ownership and configuration:
The auto-index (background index) is maintained by ClangdServer, like Dynamic.
(This means ClangdServer will be able to enqueue preamble indexing in future).
For now it's enabled by a simple boolean flag in ClangdServer::Options, but
we probably want to eventually allow injecting the storage strategy.
New 'sync' command:
In order to meaningfully test the integration (not just unit-test components)
we need a way for tests to ensure the asynchronous index reads/writes occur
before a certain point.
Because these tests and assertions are few, I think exposing an explicit "sync"
command for use in tests is simpler than allowing threading to be completely
disabled in the background index (as we do for TUScheduler).
Bugs:
I fixed a couple of trivial bugs I found while testing, but there's one I can't.
JSONCompilationDatabase::getAllFiles() may return relative paths, and currently
we trigger an assertion that assumes they are absolute.
There's no efficient way to resolve them (you have to retrieve the corresponding
command and then resolve against its directory property). In general I think
this behavior is broken and we should fix it in JSONCompilationDatabase and
require CompilationDatabase::getAllFiles() to be absolute.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D54894
llvm-svn: 347567
2018-11-27 00:00:11 +08:00
|
|
|
// sync is a clangd extension: it blocks until all background work completes.
|
|
|
|
// It blocks the calling thread, so no messages are processed until it returns!
|
2021-02-12 05:47:58 +08:00
|
|
|
void ClangdLSPServer::onSync(const NoParams &, Callback<std::nullptr_t> Reply) {
|
[clangd] Enable auto-index behind a flag.
Summary:
Ownership and configuration:
The auto-index (background index) is maintained by ClangdServer, like Dynamic.
(This means ClangdServer will be able to enqueue preamble indexing in future).
For now it's enabled by a simple boolean flag in ClangdServer::Options, but
we probably want to eventually allow injecting the storage strategy.
New 'sync' command:
In order to meaningfully test the integration (not just unit-test components)
we need a way for tests to ensure the asynchronous index reads/writes occur
before a certain point.
Because these tests and assertions are few, I think exposing an explicit "sync"
command for use in tests is simpler than allowing threading to be completely
disabled in the background index (as we do for TUScheduler).
Bugs:
I fixed a couple of trivial bugs I found while testing, but there's one I can't.
JSONCompilationDatabase::getAllFiles() may return relative paths, and currently
we trigger an assertion that assumes they are absolute.
There's no efficient way to resolve them (you have to retrieve the corresponding
command and then resolve against its directory property). In general I think
this behavior is broken and we should fix it in JSONCompilationDatabase and
require CompilationDatabase::getAllFiles() to be absolute.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D54894
llvm-svn: 347567
2018-11-27 00:00:11 +08:00
|
|
|
if (Server->blockUntilIdleForTest(/*TimeoutSeconds=*/60))
|
|
|
|
Reply(nullptr);
|
|
|
|
else
|
[clangd] Add error() function for creating formatv-style llvm::Errors. NFC
Summary:
This is considerably terser than the makeStringError and friends, and
avoids verbosity cliffs that discourage adding log information.
It follows the syntax used in log/elog/vlog/dlog that have been successful.
The main caveats are:
- it's strictly out-of-place in logger.h, though kind of fits thematically and
in implementation
- it claims the "error" identifier, which seems a bit too opinionated
to put higher up in llvm
I've updated some users of StringError mostly at random - there are lots
more mechanical changes but I'd like to get this reviewed before making
them all.
Reviewers: kbobyrev, hokein
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D83419
2020-07-09 03:49:38 +08:00
|
|
|
Reply(error("Not idle after a minute"));
|
[clangd] Enable auto-index behind a flag.
Summary:
Ownership and configuration:
The auto-index (background index) is maintained by ClangdServer, like Dynamic.
(This means ClangdServer will be able to enqueue preamble indexing in future).
For now it's enabled by a simple boolean flag in ClangdServer::Options, but
we probably want to eventually allow injecting the storage strategy.
New 'sync' command:
In order to meaningfully test the integration (not just unit-test components)
we need a way for tests to ensure the asynchronous index reads/writes occur
before a certain point.
Because these tests and assertions are few, I think exposing an explicit "sync"
command for use in tests is simpler than allowing threading to be completely
disabled in the background index (as we do for TUScheduler).
Bugs:
I fixed a couple of trivial bugs I found while testing, but there's one I can't.
JSONCompilationDatabase::getAllFiles() may return relative paths, and currently
we trigger an assertion that assumes they are absolute.
There's no efficient way to resolve them (you have to retrieve the corresponding
command and then resolve against its directory property). In general I think
this behavior is broken and we should fix it in JSONCompilationDatabase and
require CompilationDatabase::getAllFiles() to be absolute.
Reviewers: kadircet
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D54894
llvm-svn: 347567
2018-11-27 00:00:11 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onDocumentDidOpen(
|
|
|
|
const DidOpenTextDocumentParams &Params) {
|
2018-03-16 22:30:42 +08:00
|
|
|
PathRef File = Params.textDocument.uri.file();
|
2018-06-13 17:20:41 +08:00
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
const std::string &Contents = Params.textDocument.text;
|
2018-03-16 22:30:42 +08:00
|
|
|
|
2021-03-02 07:16:33 +08:00
|
|
|
Server->addDocument(File, Contents,
|
|
|
|
encodeVersion(Params.textDocument.version),
|
[clangd] Track document versions, include them with diags, enhance logs
Summary:
This ties to an LSP feature (diagnostic versioning) but really a lot
of the value is in being able to log what's happening with file versions
and queues more descriptively and clearly.
As such it's fairly invasive, for a logging patch :-\
Key decisions:
- at the LSP layer, we don't reqire the client to provide versions (LSP
makes it mandatory but we never enforced it). If not provided,
versions start at 0 and increment. DraftStore handles this.
- don't propagate magically using contexts, but rather manually:
addDocument -> ParseInputs -> (ParsedAST, Preamble, various callbacks)
Context-propagation would hide the versions from ClangdServer, which
would make producing good log messages hard
- within ClangdServer, treat versions as opaque and unordered.
std::string is a convenient type for this, and allows richer versions
for embedders. They're "mandatory" but "null" is a reasonable default.
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75582
2020-03-04 07:33:29 +08:00
|
|
|
WantDiagnostics::Yes);
|
2017-05-16 22:40:30 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onDocumentDidChange(
|
|
|
|
const DidChangeTextDocumentParams &Params) {
|
2018-02-23 02:40:39 +08:00
|
|
|
auto WantDiags = WantDiagnostics::Auto;
|
|
|
|
if (Params.wantDiagnostics.hasValue())
|
|
|
|
WantDiags = Params.wantDiagnostics.getValue() ? WantDiagnostics::Yes
|
|
|
|
: WantDiagnostics::No;
|
2018-03-16 22:30:42 +08:00
|
|
|
|
|
|
|
PathRef File = Params.textDocument.uri.file();
|
2021-03-02 07:16:33 +08:00
|
|
|
auto Code = Server->getDraft(File);
|
|
|
|
if (!Code) {
|
|
|
|
log("Trying to incrementally change non-added document: {0}", File);
|
[clangd] Support incremental document syncing
Summary:
This patch adds support for incremental document syncing, as described
in the LSP spec. The protocol specifies ranges in terms of Position (a
line and a character), and our drafts are stored as plain strings. So I
see two things that may not be super efficient for very large files:
- Converting a Position to an offset (the positionToOffset function)
requires searching for end of lines until we reach the desired line.
- When we update a range, we construct a new string, which implies
copying the whole document.
However, for the typical size of a C++ document and the frequency of
update (at which a user types), it may not be an issue. This patch aims
at getting the basic feature in, and we can always improve it later if
we find it's too slow.
Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
Reviewers: malaperle, ilya-biryukov
Reviewed By: ilya-biryukov
Subscribers: MaskRay, klimek, mgorny, ilya-biryukov, jkorous-apple, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D44272
llvm-svn: 328500
2018-03-26 22:41:40 +08:00
|
|
|
return;
|
|
|
|
}
|
2021-03-09 22:35:20 +08:00
|
|
|
std::string NewCode(*Code);
|
2021-03-02 07:16:33 +08:00
|
|
|
for (const auto &Change : Params.contentChanges) {
|
2021-03-09 22:35:20 +08:00
|
|
|
if (auto Err = applyChange(NewCode, Change)) {
|
2021-03-02 07:16:33 +08:00
|
|
|
// If this fails, we are most likely going to be not in sync anymore with
|
|
|
|
// the client. It is better to remove the draft and let further
|
|
|
|
// operations fail rather than giving wrong results.
|
|
|
|
Server->removeDocument(File);
|
|
|
|
elog("Failed to update {0}: {1}", File, std::move(Err));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2021-03-09 22:35:20 +08:00
|
|
|
Server->addDocument(File, NewCode, encodeVersion(Params.textDocument.version),
|
[clangd] Track document versions, include them with diags, enhance logs
Summary:
This ties to an LSP feature (diagnostic versioning) but really a lot
of the value is in being able to log what's happening with file versions
and queues more descriptively and clearly.
As such it's fairly invasive, for a logging patch :-\
Key decisions:
- at the LSP layer, we don't reqire the client to provide versions (LSP
makes it mandatory but we never enforced it). If not provided,
versions start at 0 and increment. DraftStore handles this.
- don't propagate magically using contexts, but rather manually:
addDocument -> ParseInputs -> (ParsedAST, Preamble, various callbacks)
Context-propagation would hide the versions from ClangdServer, which
would make producing good log messages hard
- within ClangdServer, treat versions as opaque and unordered.
std::string is a convenient type for this, and allows richer versions
for embedders. They're "mandatory" but "null" is a reasonable default.
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75582
2020-03-04 07:33:29 +08:00
|
|
|
WantDiags, Params.forceRebuild);
|
2017-05-16 22:40:30 +08:00
|
|
|
}
|
|
|
|
|
2020-04-10 09:27:37 +08:00
|
|
|
void ClangdLSPServer::onDocumentDidSave(
|
|
|
|
const DidSaveTextDocumentParams &Params) {
|
2021-03-02 07:16:33 +08:00
|
|
|
Server->reparseOpenFilesIfNeeded([](llvm::StringRef) { return true; });
|
2020-04-10 09:27:37 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onFileEvent(const DidChangeWatchedFilesParams &Params) {
|
2020-04-10 09:27:37 +08:00
|
|
|
// We could also reparse all open files here. However:
|
|
|
|
// - this could be frequent, and revalidating all the preambles isn't free
|
|
|
|
// - this is useful e.g. when switching git branches, but we're likely to see
|
|
|
|
// fresh headers but still have the old-branch main-file content
|
2018-09-26 13:48:29 +08:00
|
|
|
Server->onFileEvent(Params);
|
2020-12-04 16:09:03 +08:00
|
|
|
// FIXME: observe config files, immediately expire time-based caches, reparse:
|
|
|
|
// - compile_commands.json and compile_flags.txt
|
|
|
|
// - .clang_format and .clang-tidy
|
|
|
|
// - .clangd and clangd/config.yaml
|
2017-10-03 02:00:37 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onCommand(const ExecuteCommandParams &Params,
|
2019-01-07 23:45:19 +08:00
|
|
|
Callback<llvm::json::Value> Reply) {
|
2021-02-12 05:47:58 +08:00
|
|
|
auto It = Handlers.CommandHandlers.find(Params.command);
|
|
|
|
if (It == Handlers.CommandHandlers.end()) {
|
2021-02-11 23:32:09 +08:00
|
|
|
return Reply(llvm::make_error<LSPError>(
|
2019-01-07 23:45:19 +08:00
|
|
|
llvm::formatv("Unsupported command \"{0}\".", Params.command).str(),
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
ErrorCode::InvalidParams));
|
[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 21:39:15 +08:00
|
|
|
}
|
2021-02-11 23:32:09 +08:00
|
|
|
It->second(Params.argument, std::move(Reply));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClangdLSPServer::onCommandApplyEdit(const WorkspaceEdit &WE,
|
|
|
|
Callback<llvm::json::Value> Reply) {
|
|
|
|
// 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
|
|
|
|
// 7. We unwrap the reply and send a reply to the editor.
|
|
|
|
applyEdit(WE, "Fix applied.", std::move(Reply));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClangdLSPServer::onCommandApplyTweak(const TweakArgs &Args,
|
|
|
|
Callback<llvm::json::Value> Reply) {
|
2021-03-02 07:16:33 +08:00
|
|
|
auto Action = [this, Reply = std::move(Reply),
|
|
|
|
File = Args.file](llvm::Expected<Tweak::Effect> R) mutable {
|
2021-02-11 23:32:09 +08:00
|
|
|
if (!R)
|
|
|
|
return Reply(R.takeError());
|
|
|
|
|
|
|
|
assert(R->ShowMessage || (!R->ApplyEdits.empty() && "tweak has no effect"));
|
|
|
|
|
|
|
|
if (R->ShowMessage) {
|
|
|
|
ShowMessageParams Msg;
|
|
|
|
Msg.message = *R->ShowMessage;
|
|
|
|
Msg.type = MessageType::Info;
|
2021-02-15 17:41:38 +08:00
|
|
|
ShowMessage(Msg);
|
2021-02-11 23:32:09 +08:00
|
|
|
}
|
|
|
|
// When no edit is specified, make sure we Reply().
|
|
|
|
if (R->ApplyEdits.empty())
|
|
|
|
return Reply("Tweak applied.");
|
|
|
|
|
2021-03-02 07:16:33 +08:00
|
|
|
if (auto Err = validateEdits(*Server, R->ApplyEdits))
|
2021-02-11 23:32:09 +08:00
|
|
|
return Reply(std::move(Err));
|
|
|
|
|
|
|
|
WorkspaceEdit WE;
|
|
|
|
WE.changes.emplace();
|
|
|
|
for (const auto &It : R->ApplyEdits) {
|
|
|
|
(*WE.changes)[URI::createFile(It.first()).toString()] =
|
|
|
|
It.second.asTextEdits();
|
|
|
|
}
|
|
|
|
// ApplyEdit will take care of calling Reply().
|
|
|
|
return applyEdit(std::move(WE), "Tweak applied.", std::move(Reply));
|
|
|
|
};
|
|
|
|
Server->applyTweak(Args.file.file(), Args.selection, Args.tweakID,
|
|
|
|
std::move(Action));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClangdLSPServer::applyEdit(WorkspaceEdit WE, llvm::json::Value Success,
|
|
|
|
Callback<llvm::json::Value> Reply) {
|
|
|
|
ApplyWorkspaceEditParams Edit;
|
|
|
|
Edit.edit = std::move(WE);
|
2021-02-15 17:41:38 +08:00
|
|
|
ApplyWorkspaceEdit(
|
|
|
|
Edit, [Reply = std::move(Reply), SuccessMessage = std::move(Success)](
|
|
|
|
llvm::Expected<ApplyWorkspaceEditResponse> Response) mutable {
|
2021-02-11 23:32:09 +08:00
|
|
|
if (!Response)
|
|
|
|
return Reply(Response.takeError());
|
|
|
|
if (!Response->applied) {
|
|
|
|
std::string Reason = Response->failureReason
|
|
|
|
? *Response->failureReason
|
|
|
|
: "unknown reason";
|
|
|
|
return Reply(error("edits were not applied: {0}", Reason));
|
|
|
|
}
|
|
|
|
return Reply(SuccessMessage);
|
|
|
|
});
|
[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 21:39:15 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onWorkspaceSymbol(
|
|
|
|
const WorkspaceSymbolParams &Params,
|
|
|
|
Callback<std::vector<SymbolInformation>> Reply) {
|
2018-09-26 13:48:29 +08:00
|
|
|
Server->workspaceSymbols(
|
2021-03-03 05:16:29 +08:00
|
|
|
Params.query, Params.limit.getValueOr(Opts.CodeComplete.Limit),
|
2019-08-15 22:16:06 +08:00
|
|
|
[Reply = std::move(Reply),
|
|
|
|
this](llvm::Expected<std::vector<SymbolInformation>> Items) mutable {
|
|
|
|
if (!Items)
|
|
|
|
return Reply(Items.takeError());
|
|
|
|
for (auto &Sym : *Items)
|
|
|
|
Sym.kind = adjustKindToCapability(Sym.kind, SupportedSymbolKinds);
|
|
|
|
|
|
|
|
Reply(std::move(*Items));
|
|
|
|
});
|
[clangd] Implementation of workspace/symbol request
Summary:
This is a basic implementation of the "workspace/symbol" request which is
used to find symbols by a string query. Since this is similar to code completion
in terms of result, this implementation reuses the "fuzzyFind" in order to get
matches. For now, the scoring algorithm is the same as code completion and
improvements could be done in the future.
The index model doesn't contain quite enough symbols for this to cover
common symbols like methods, enum class enumerators, functions in unamed
namespaces, etc. The index model will be augmented separately to achieve this.
Reviewers: sammccall, ilya-biryukov
Reviewed By: sammccall
Subscribers: jkorous, hokein, simark, sammccall, klimek, mgorny, ilya-biryukov, mgrang, jkorous-apple, ioeric, MaskRay, cfe-commits
Differential Revision: https://reviews.llvm.org/D44882
llvm-svn: 330637
2018-04-24 04:00:52 +08:00
|
|
|
}
|
|
|
|
|
2019-07-24 15:49:23 +08:00
|
|
|
void ClangdLSPServer::onPrepareRename(const TextDocumentPositionParams &Params,
|
|
|
|
Callback<llvm::Optional<Range>> Reply) {
|
2020-10-02 22:01:25 +08:00
|
|
|
Server->prepareRename(
|
2020-10-08 03:16:45 +08:00
|
|
|
Params.textDocument.uri.file(), Params.position, /*NewName*/ llvm::None,
|
|
|
|
Opts.Rename,
|
2020-10-02 22:01:25 +08:00
|
|
|
[Reply = std::move(Reply)](llvm::Expected<RenameResult> Result) mutable {
|
|
|
|
if (!Result)
|
|
|
|
return Reply(Result.takeError());
|
|
|
|
return Reply(std::move(Result->Target));
|
|
|
|
});
|
2019-07-24 15:49:23 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onRename(const RenameParams &Params,
|
|
|
|
Callback<WorkspaceEdit> Reply) {
|
2020-01-29 03:23:46 +08:00
|
|
|
Path File = std::string(Params.textDocument.uri.file());
|
2021-03-02 07:16:33 +08:00
|
|
|
if (!Server->getDraft(File))
|
2019-01-07 23:45:19 +08:00
|
|
|
return Reply(llvm::make_error<LSPError>(
|
|
|
|
"onRename called for non-added file", ErrorCode::InvalidParams));
|
2019-10-23 20:40:20 +08:00
|
|
|
Server->rename(
|
2020-09-29 16:37:46 +08:00
|
|
|
File, Params.position, Params.newName, Opts.Rename,
|
2019-10-23 20:40:20 +08:00
|
|
|
[File, Params, Reply = std::move(Reply),
|
2020-10-02 22:01:25 +08:00
|
|
|
this](llvm::Expected<RenameResult> R) mutable {
|
|
|
|
if (!R)
|
|
|
|
return Reply(R.takeError());
|
2021-03-02 07:16:33 +08:00
|
|
|
if (auto Err = validateEdits(*Server, R->GlobalChanges))
|
2019-10-23 20:40:20 +08:00
|
|
|
return Reply(std::move(Err));
|
|
|
|
WorkspaceEdit Result;
|
|
|
|
Result.changes.emplace();
|
2020-10-02 22:01:25 +08:00
|
|
|
for (const auto &Rep : R->GlobalChanges) {
|
2019-10-23 20:40:20 +08:00
|
|
|
(*Result.changes)[URI::createFile(Rep.first()).toString()] =
|
|
|
|
Rep.second.asTextEdits();
|
|
|
|
}
|
|
|
|
Reply(Result);
|
|
|
|
});
|
2017-11-09 19:30:04 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onDocumentDidClose(
|
|
|
|
const DidCloseTextDocumentParams &Params) {
|
2018-03-16 22:30:42 +08:00
|
|
|
PathRef File = Params.textDocument.uri.file();
|
2018-09-26 13:48:29 +08:00
|
|
|
Server->removeDocument(File);
|
2019-03-25 18:15:11 +08:00
|
|
|
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> Lock(FixItsMutex);
|
|
|
|
FixItsMap.erase(File);
|
|
|
|
}
|
[clangd] Support textDocument/semanticTokens/edits
Summary:
This returns incremental highlights as a set of edits against the
previous highlights.
Server-side, we compute the full set of highlights, this just saves
wire-format size.
For now, the diff used is trivial: everything from the first change to
the last change is sent as a single edit.
The wire format is grungy - the replacement offset/length refer to
positions in the encoded array instead of the logical list of tokens.
We use token-oriented structs and translating to LSP forms when serializing.
This departs from LSP (but is consistent with semanticTokens today).
Tested in VSCode insiders (with a patched client to enable experimental
features).
Reviewers: hokein
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D77225
2020-04-01 22:21:44 +08:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> HLock(SemanticTokensMutex);
|
|
|
|
LastSemanticTokens.erase(File);
|
|
|
|
}
|
2019-03-25 18:15:11 +08:00
|
|
|
// clangd will not send updates for this file anymore, so we empty out the
|
|
|
|
// list of diagnostics shown on the client (e.g. in the "Problems" pane of
|
|
|
|
// VSCode). Note that this cannot race with actual diagnostics responses
|
|
|
|
// because removeDocument() guarantees no diagnostic callbacks will be
|
|
|
|
// executed after it returns.
|
2020-03-03 19:44:40 +08:00
|
|
|
PublishDiagnosticsParams Notification;
|
|
|
|
Notification.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
|
2021-02-15 17:41:38 +08:00
|
|
|
PublishDiagnostics(Notification);
|
2017-05-16 22:40:30 +08:00
|
|
|
}
|
|
|
|
|
2017-09-30 18:08:52 +08:00
|
|
|
void ClangdLSPServer::onDocumentOnTypeFormatting(
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
const DocumentOnTypeFormattingParams &Params,
|
|
|
|
Callback<std::vector<TextEdit>> Reply) {
|
2018-02-16 20:20:47 +08:00
|
|
|
auto File = Params.textDocument.uri.file();
|
2021-03-02 07:16:33 +08:00
|
|
|
Server->formatOnType(File, Params.position, Params.ch, std::move(Reply));
|
2017-05-16 22:40:30 +08:00
|
|
|
}
|
|
|
|
|
2017-09-30 18:08:52 +08:00
|
|
|
void ClangdLSPServer::onDocumentRangeFormatting(
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
const DocumentRangeFormattingParams &Params,
|
|
|
|
Callback<std::vector<TextEdit>> Reply) {
|
2018-02-16 20:20:47 +08:00
|
|
|
auto File = Params.textDocument.uri.file();
|
2021-03-02 07:16:33 +08:00
|
|
|
auto Code = Server->getDraft(File);
|
|
|
|
Server->formatFile(File, Params.range,
|
|
|
|
[Code = std::move(Code), Reply = std::move(Reply)](
|
|
|
|
llvm::Expected<tooling::Replacements> Result) mutable {
|
|
|
|
if (Result)
|
|
|
|
Reply(replacementsToEdits(*Code, Result.get()));
|
|
|
|
else
|
|
|
|
Reply(Result.takeError());
|
|
|
|
});
|
2017-05-16 22:40:30 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onDocumentFormatting(
|
|
|
|
const DocumentFormattingParams &Params,
|
|
|
|
Callback<std::vector<TextEdit>> Reply) {
|
2018-02-16 20:20:47 +08:00
|
|
|
auto File = Params.textDocument.uri.file();
|
2021-03-02 07:16:33 +08:00
|
|
|
auto Code = Server->getDraft(File);
|
|
|
|
Server->formatFile(File,
|
|
|
|
/*Rng=*/llvm::None,
|
|
|
|
[Code = std::move(Code), Reply = std::move(Reply)](
|
[clangd] Run formatting operations asynchronously.
Summary:
They don't need ASTs or anything, so they should still run immediately.
These were sync for historical reasons (they predate clangd having a pervasive
threading model). This worked ok as they were "cheap".
Aside for consistency, there are a couple of reasons to make them async:
- they do IO (finding .clang-format) so aren't trivially cheap
- having TUScheduler involved in running these tasks means we can use it as
an injection point for configuration.
(TUScheduler::run will need to learn about which file is being operated on,
but that's an easy change).
- adding the config system adds more potential IO, too
Reviewers: kbobyrev
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D82642
2020-06-26 18:57:29 +08:00
|
|
|
llvm::Expected<tooling::Replacements> Result) mutable {
|
|
|
|
if (Result)
|
2021-03-02 07:16:33 +08:00
|
|
|
Reply(replacementsToEdits(*Code, Result.get()));
|
[clangd] Run formatting operations asynchronously.
Summary:
They don't need ASTs or anything, so they should still run immediately.
These were sync for historical reasons (they predate clangd having a pervasive
threading model). This worked ok as they were "cheap".
Aside for consistency, there are a couple of reasons to make them async:
- they do IO (finding .clang-format) so aren't trivially cheap
- having TUScheduler involved in running these tasks means we can use it as
an injection point for configuration.
(TUScheduler::run will need to learn about which file is being operated on,
but that's an easy change).
- adding the config system adds more potential IO, too
Reviewers: kbobyrev
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D82642
2020-06-26 18:57:29 +08:00
|
|
|
else
|
|
|
|
Reply(Result.takeError());
|
|
|
|
});
|
2017-05-16 22:40:30 +08:00
|
|
|
}
|
|
|
|
|
2018-11-23 23:21:19 +08:00
|
|
|
/// The functions constructs a flattened view of the DocumentSymbol hierarchy.
|
|
|
|
/// Used by the clients that do not support the hierarchical view.
|
|
|
|
static std::vector<SymbolInformation>
|
|
|
|
flattenSymbolHierarchy(llvm::ArrayRef<DocumentSymbol> Symbols,
|
|
|
|
const URIForFile &FileURI) {
|
|
|
|
std::vector<SymbolInformation> Results;
|
2019-01-07 23:45:19 +08:00
|
|
|
std::function<void(const DocumentSymbol &, llvm::StringRef)> Process =
|
|
|
|
[&](const DocumentSymbol &S, llvm::Optional<llvm::StringRef> ParentName) {
|
2018-11-23 23:21:19 +08:00
|
|
|
SymbolInformation SI;
|
2020-01-29 03:23:46 +08:00
|
|
|
SI.containerName = std::string(ParentName ? "" : *ParentName);
|
2018-11-23 23:21:19 +08:00
|
|
|
SI.name = S.name;
|
|
|
|
SI.kind = S.kind;
|
|
|
|
SI.location.range = S.range;
|
|
|
|
SI.location.uri = FileURI;
|
|
|
|
|
|
|
|
Results.push_back(std::move(SI));
|
|
|
|
std::string FullName =
|
|
|
|
!ParentName ? S.name : (ParentName->str() + "::" + S.name);
|
|
|
|
for (auto &C : S.children)
|
|
|
|
Process(C, /*ParentName=*/FullName);
|
|
|
|
};
|
|
|
|
for (auto &S : Symbols)
|
|
|
|
Process(S, /*ParentName=*/"");
|
|
|
|
return Results;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClangdLSPServer::onDocumentSymbol(const DocumentSymbolParams &Params,
|
2019-01-07 23:45:19 +08:00
|
|
|
Callback<llvm::json::Value> Reply) {
|
2018-11-23 23:21:19 +08:00
|
|
|
URIForFile FileURI = Params.textDocument.uri;
|
2018-09-26 13:48:29 +08:00
|
|
|
Server->documentSymbols(
|
2018-07-06 03:35:01 +08:00
|
|
|
Params.textDocument.uri.file(),
|
2019-08-15 22:16:06 +08:00
|
|
|
[this, FileURI, Reply = std::move(Reply)](
|
|
|
|
llvm::Expected<std::vector<DocumentSymbol>> Items) mutable {
|
|
|
|
if (!Items)
|
|
|
|
return Reply(Items.takeError());
|
|
|
|
adjustSymbolKinds(*Items, SupportedSymbolKinds);
|
|
|
|
if (SupportsHierarchicalDocumentSymbol)
|
|
|
|
return Reply(std::move(*Items));
|
|
|
|
else
|
|
|
|
return Reply(flattenSymbolHierarchy(*Items, FileURI));
|
|
|
|
});
|
2018-07-06 03:35:01 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Implement textDocument/foldingRange
Summary:
This patch introduces basic textDocument/foldingRange support. It relies on
textDocument/documentSymbols to collect all symbols and uses takes ranges
to create folds.
The next steps for textDocument/foldingRange support would be:
* Implementing FoldingRangeClientCapabilities and respecting respect client
preferences
* Specifying folding range kind
* Migrating from DocumentSymbol implementation to custom RecursiveASTVisitor flow that will allow more flexibility
* Supporting more folding range types: comments, PP conditional regions, includes and other code regions (e.g. public/private/protected sections of classes, control flow statement bodies)
Tested: (Neo)Vim (coc-clangd) and VSCode.
Related issue: https://github.com/clangd/clangd/issues/310
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: nridge, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D82436
2020-07-14 15:28:38 +08:00
|
|
|
void ClangdLSPServer::onFoldingRange(
|
|
|
|
const FoldingRangeParams &Params,
|
|
|
|
Callback<std::vector<FoldingRange>> Reply) {
|
|
|
|
Server->foldingRanges(Params.textDocument.uri.file(), std::move(Reply));
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
static llvm::Optional<Command> asCommand(const CodeAction &Action) {
|
2018-10-17 00:29:41 +08:00
|
|
|
Command Cmd;
|
|
|
|
if (Action.command && Action.edit)
|
2018-10-20 23:30:37 +08:00
|
|
|
return None; // Not representable. (We never emit these anyway).
|
2018-10-17 00:29:41 +08:00
|
|
|
if (Action.command) {
|
|
|
|
Cmd = *Action.command;
|
|
|
|
} else if (Action.edit) {
|
2021-02-11 23:32:09 +08:00
|
|
|
Cmd.command = std::string(APPLY_FIX_COMMAND);
|
|
|
|
Cmd.argument = *Action.edit;
|
2018-10-17 00:29:41 +08:00
|
|
|
} else {
|
2018-10-20 23:30:37 +08:00
|
|
|
return None;
|
2018-10-17 00:29:41 +08:00
|
|
|
}
|
|
|
|
Cmd.title = Action.title;
|
|
|
|
if (Action.kind && *Action.kind == CodeAction::QUICKFIX_KIND)
|
|
|
|
Cmd.title = "Apply fix: " + Cmd.title;
|
|
|
|
return Cmd;
|
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onCodeAction(const CodeActionParams &Params,
|
2019-01-07 23:45:19 +08:00
|
|
|
Callback<llvm::json::Value> Reply) {
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
URIForFile File = Params.textDocument.uri;
|
2020-10-09 21:17:26 +08:00
|
|
|
// Checks whether a particular CodeActionKind is included in the response.
|
|
|
|
auto KindAllowed = [Only(Params.context.only)](llvm::StringRef Kind) {
|
|
|
|
if (Only.empty())
|
|
|
|
return true;
|
|
|
|
return llvm::any_of(Only, [&](llvm::StringRef Base) {
|
|
|
|
return Kind.consume_front(Base) && (Kind.empty() || Kind.startswith("."));
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2018-10-17 00:29:41 +08:00
|
|
|
// We provide a code action for Fixes on the specified diagnostics.
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
std::vector<CodeAction> FixIts;
|
2020-10-09 21:17:26 +08:00
|
|
|
if (KindAllowed(CodeAction::QUICKFIX_KIND)) {
|
|
|
|
for (const Diagnostic &D : Params.context.diagnostics) {
|
|
|
|
for (auto &F : getFixes(File.file(), D)) {
|
|
|
|
FixIts.push_back(toCodeAction(F, Params.textDocument.uri));
|
|
|
|
FixIts.back().diagnostics = {D};
|
|
|
|
}
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
}
|
2017-05-16 22:40:30 +08:00
|
|
|
}
|
2018-10-17 00:29:41 +08:00
|
|
|
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
// Now enumerate the semantic code actions.
|
|
|
|
auto ConsumeActions =
|
2021-03-02 07:16:33 +08:00
|
|
|
[Reply = std::move(Reply), File, Selection = Params.range,
|
|
|
|
FixIts = std::move(FixIts), this](
|
2019-08-15 22:16:06 +08:00
|
|
|
llvm::Expected<std::vector<ClangdServer::TweakRef>> Tweaks) mutable {
|
2019-01-30 22:24:17 +08:00
|
|
|
if (!Tweaks)
|
|
|
|
return Reply(Tweaks.takeError());
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
|
|
|
|
std::vector<CodeAction> Actions = std::move(FixIts);
|
|
|
|
Actions.reserve(Actions.size() + Tweaks->size());
|
|
|
|
for (const auto &T : *Tweaks)
|
|
|
|
Actions.push_back(toCodeAction(T, File, Selection));
|
|
|
|
|
2020-09-29 22:28:50 +08:00
|
|
|
// If there's exactly one quick-fix, call it "preferred".
|
|
|
|
// We never consider refactorings etc as preferred.
|
|
|
|
CodeAction *OnlyFix = nullptr;
|
|
|
|
for (auto &Action : Actions) {
|
|
|
|
if (Action.kind && *Action.kind == CodeAction::QUICKFIX_KIND) {
|
|
|
|
if (OnlyFix) {
|
|
|
|
OnlyFix->isPreferred = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Action.isPreferred = true;
|
|
|
|
OnlyFix = &Action;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[clangd] Interfaces for writing code tweaks
Summary:
The code tweaks are an implementation of mini-refactorings exposed
via the LSP code actions. They run in two stages:
- Stage 1. Decides whether the action is available to the user and
collects all the information required to finish the action.
Should be cheap, since this will run over all the actions known to
clangd on each textDocument/codeAction request from the client.
- Stage 2. Uses information from stage 1 to produce the actual edits
that the code action should perform. This stage can be expensive and
will only run if the user chooses to perform the specified action in
the UI.
One unfortunate consequence of this change is increased latency of
processing the textDocument/codeAction requests, which now wait for an
AST. However, we cannot avoid this with what we have available in the LSP
today.
Reviewers: kadircet, ioeric, hokein, sammccall
Reviewed By: sammccall
Subscribers: mgrang, mgorny, MaskRay, jkorous, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D56267
llvm-svn: 352494
2019-01-29 22:17:36 +08:00
|
|
|
if (SupportsCodeAction)
|
|
|
|
return Reply(llvm::json::Array(Actions));
|
|
|
|
std::vector<Command> Commands;
|
|
|
|
for (const auto &Action : Actions) {
|
|
|
|
if (auto Command = asCommand(Action))
|
|
|
|
Commands.push_back(std::move(*Command));
|
|
|
|
}
|
|
|
|
return Reply(llvm::json::Array(Commands));
|
|
|
|
};
|
2020-10-02 17:34:40 +08:00
|
|
|
Server->enumerateTweaks(
|
|
|
|
File.file(), Params.range,
|
2020-10-09 21:17:26 +08:00
|
|
|
[this, KindAllowed(std::move(KindAllowed))](const Tweak &T) {
|
|
|
|
return Opts.TweakFilter(T) && KindAllowed(T.kind());
|
2020-10-02 17:34:40 +08:00
|
|
|
},
|
|
|
|
std::move(ConsumeActions));
|
2017-05-16 22:40:30 +08:00
|
|
|
}
|
|
|
|
|
2019-01-03 21:37:12 +08:00
|
|
|
void ClangdLSPServer::onCompletion(const CompletionParams &Params,
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
Callback<CompletionList> Reply) {
|
2019-06-08 00:24:38 +08:00
|
|
|
if (!shouldRunCompletion(Params)) {
|
|
|
|
// Clients sometimes auto-trigger completions in undesired places (e.g.
|
|
|
|
// 'a >^ '), we return empty results in those cases.
|
|
|
|
vlog("ignored auto-triggered completion, preceding char did not match");
|
|
|
|
return Reply(CompletionList());
|
|
|
|
}
|
2021-03-03 05:16:29 +08:00
|
|
|
auto Opts = this->Opts.CodeComplete;
|
|
|
|
if (Params.limit && *Params.limit >= 0)
|
|
|
|
Opts.Limit = *Params.limit;
|
|
|
|
Server->codeComplete(Params.textDocument.uri.file(), Params.position, Opts,
|
|
|
|
[Reply = std::move(Reply), Opts,
|
|
|
|
this](llvm::Expected<CodeCompleteResult> List) mutable {
|
|
|
|
if (!List)
|
|
|
|
return Reply(List.takeError());
|
|
|
|
CompletionList LSPList;
|
|
|
|
LSPList.isIncomplete = List->HasMore;
|
|
|
|
for (const auto &R : List->Completions) {
|
|
|
|
CompletionItem C = R.render(Opts);
|
|
|
|
C.kind = adjustKindToCapability(
|
|
|
|
C.kind, SupportedCompletionItemKinds);
|
|
|
|
LSPList.items.push_back(std::move(C));
|
|
|
|
}
|
|
|
|
return Reply(std::move(LSPList));
|
|
|
|
});
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClangdLSPServer::onSignatureHelp(const TextDocumentPositionParams &Params,
|
|
|
|
Callback<SignatureHelp> Reply) {
|
2018-09-26 13:48:29 +08:00
|
|
|
Server->signatureHelp(Params.textDocument.uri.file(), Params.position,
|
2019-08-15 22:16:06 +08:00
|
|
|
[Reply = std::move(Reply), this](
|
|
|
|
llvm::Expected<SignatureHelp> Signature) mutable {
|
|
|
|
if (!Signature)
|
|
|
|
return Reply(Signature.takeError());
|
|
|
|
if (SupportsOffsetsInSignatureHelp)
|
|
|
|
return Reply(std::move(*Signature));
|
|
|
|
// Strip out the offsets from signature help for
|
|
|
|
// clients that only support string labels.
|
|
|
|
for (auto &SigInfo : Signature->signatures) {
|
|
|
|
for (auto &Param : SigInfo.parameters)
|
|
|
|
Param.labelOffsets.reset();
|
|
|
|
}
|
|
|
|
return Reply(std::move(*Signature));
|
|
|
|
});
|
2017-10-06 19:54:17 +08:00
|
|
|
}
|
|
|
|
|
2019-02-02 13:56:00 +08:00
|
|
|
// Go to definition has a toggle function: if def and decl are distinct, then
|
|
|
|
// the first press gives you the def, the second gives you the matching def.
|
|
|
|
// getToggle() returns the counterpart location that under the cursor.
|
|
|
|
//
|
|
|
|
// We return the toggled location alone (ignoring other symbols) to encourage
|
|
|
|
// editors to "bounce" quickly between locations, without showing a menu.
|
|
|
|
static Location *getToggle(const TextDocumentPositionParams &Point,
|
|
|
|
LocatedSymbol &Sym) {
|
|
|
|
// Toggle only makes sense with two distinct locations.
|
|
|
|
if (!Sym.Definition || *Sym.Definition == Sym.PreferredDeclaration)
|
|
|
|
return nullptr;
|
|
|
|
if (Sym.Definition->uri.file() == Point.textDocument.uri.file() &&
|
|
|
|
Sym.Definition->range.contains(Point.position))
|
|
|
|
return &Sym.PreferredDeclaration;
|
|
|
|
if (Sym.PreferredDeclaration.uri.file() == Point.textDocument.uri.file() &&
|
|
|
|
Sym.PreferredDeclaration.range.contains(Point.position))
|
|
|
|
return &*Sym.Definition;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onGoToDefinition(const TextDocumentPositionParams &Params,
|
|
|
|
Callback<std::vector<Location>> Reply) {
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
Server->locateSymbolAt(
|
|
|
|
Params.textDocument.uri.file(), Params.position,
|
2019-08-15 22:16:06 +08:00
|
|
|
[Params, Reply = std::move(Reply)](
|
|
|
|
llvm::Expected<std::vector<LocatedSymbol>> Symbols) mutable {
|
|
|
|
if (!Symbols)
|
|
|
|
return Reply(Symbols.takeError());
|
|
|
|
std::vector<Location> Defs;
|
|
|
|
for (auto &S : *Symbols) {
|
|
|
|
if (Location *Toggle = getToggle(Params, S))
|
|
|
|
return Reply(std::vector<Location>{std::move(*Toggle)});
|
|
|
|
Defs.push_back(S.Definition.getValueOr(S.PreferredDeclaration));
|
|
|
|
}
|
|
|
|
Reply(std::move(Defs));
|
|
|
|
});
|
[clangd] Implement textDocument/declaration from LSP 3.14
Summary:
LSP now reflects the declaration/definition distinction.
Language server changes:
- textDocument/definition now returns a definition if one is found, otherwise
the declaration. It no longer returns declaration + definition if they are
distinct.
- textDocument/declaration returns the best declaration we can find.
- For macros, the active macro definition is returned for both methods.
- For include directive, the top of the target file is returned for both.
There doesn't appear to be a discovery mechanism (we can't return everything to
clients that only know about definition), so this changes existing behavior.
In practice, it should greatly reduce the fraction of the time we need to show
the user a menu of options.
C++ API changes:
- findDefinitions is replaced by locateSymbolAt, which returns a
vector<LocatedSymbol> - one for each symbol under the cursor.
- this contains the preferred declaration, the definition (if found), and
the symbol name
This API enables some potentially-neat extensions, like swapping between decl
and def, and exposing the symbol name to the UI in the case of multiple symbols.
Reviewers: hokein
Subscribers: ilya-biryukov, javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D57388
llvm-svn: 352864
2019-02-01 19:26:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClangdLSPServer::onGoToDeclaration(
|
|
|
|
const TextDocumentPositionParams &Params,
|
|
|
|
Callback<std::vector<Location>> Reply) {
|
|
|
|
Server->locateSymbolAt(
|
|
|
|
Params.textDocument.uri.file(), Params.position,
|
2019-08-15 22:16:06 +08:00
|
|
|
[Params, Reply = std::move(Reply)](
|
|
|
|
llvm::Expected<std::vector<LocatedSymbol>> Symbols) mutable {
|
|
|
|
if (!Symbols)
|
|
|
|
return Reply(Symbols.takeError());
|
|
|
|
std::vector<Location> Decls;
|
|
|
|
for (auto &S : *Symbols) {
|
|
|
|
if (Location *Toggle = getToggle(Params, S))
|
|
|
|
return Reply(std::vector<Location>{std::move(*Toggle)});
|
|
|
|
Decls.push_back(std::move(S.PreferredDeclaration));
|
|
|
|
}
|
|
|
|
Reply(std::move(Decls));
|
|
|
|
});
|
2017-06-29 00:12:10 +08:00
|
|
|
}
|
|
|
|
|
2019-05-07 15:55:35 +08:00
|
|
|
void ClangdLSPServer::onSwitchSourceHeader(
|
|
|
|
const TextDocumentIdentifier &Params,
|
2019-05-07 16:30:32 +08:00
|
|
|
Callback<llvm::Optional<URIForFile>> Reply) {
|
2019-10-01 18:21:15 +08:00
|
|
|
Server->switchSourceHeader(
|
|
|
|
Params.uri.file(),
|
|
|
|
[Reply = std::move(Reply),
|
|
|
|
Params](llvm::Expected<llvm::Optional<clangd::Path>> Path) mutable {
|
|
|
|
if (!Path)
|
|
|
|
return Reply(Path.takeError());
|
|
|
|
if (*Path)
|
2019-10-07 19:37:25 +08:00
|
|
|
return Reply(URIForFile::canonicalize(**Path, Params.uri.file()));
|
2019-10-01 18:21:15 +08:00
|
|
|
return Reply(llvm::None);
|
|
|
|
});
|
2017-09-28 11:14:40 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onDocumentHighlight(
|
|
|
|
const TextDocumentPositionParams &Params,
|
|
|
|
Callback<std::vector<DocumentHighlight>> Reply) {
|
|
|
|
Server->findDocumentHighlights(Params.textDocument.uri.file(),
|
|
|
|
Params.position, std::move(Reply));
|
[clangd] Document highlights for clangd
Summary: Implementation of Document Highlights Request as described in
LSP.
Contributed by William Enright (nebiroth).
Reviewers: malaperle, krasimir, bkramer, ilya-biryukov
Reviewed By: malaperle
Subscribers: mgrang, sammccall, klimek, ioeric, rwols, cfe-commits, arphaman, ilya-biryukov
Differential Revision: https://reviews.llvm.org/D38425
llvm-svn: 320474
2017-12-12 20:27:47 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onHover(const TextDocumentPositionParams &Params,
|
2019-01-07 23:45:19 +08:00
|
|
|
Callback<llvm::Optional<Hover>> Reply) {
|
2018-09-26 13:48:29 +08:00
|
|
|
Server->findHover(Params.textDocument.uri.file(), Params.position,
|
2019-08-15 22:16:06 +08:00
|
|
|
[Reply = std::move(Reply), this](
|
|
|
|
llvm::Expected<llvm::Optional<HoverInfo>> H) mutable {
|
|
|
|
if (!H)
|
|
|
|
return Reply(H.takeError());
|
|
|
|
if (!*H)
|
|
|
|
return Reply(llvm::None);
|
|
|
|
|
|
|
|
Hover R;
|
|
|
|
R.contents.kind = HoverContentFormat;
|
|
|
|
R.range = (*H)->SymRange;
|
|
|
|
switch (HoverContentFormat) {
|
|
|
|
case MarkupKind::PlainText:
|
2019-12-10 17:28:37 +08:00
|
|
|
R.contents.value = (*H)->present().asPlainText();
|
2019-08-15 22:16:06 +08:00
|
|
|
return Reply(std::move(R));
|
|
|
|
case MarkupKind::Markdown:
|
2019-12-10 17:28:37 +08:00
|
|
|
R.contents.value = (*H)->present().asMarkdown();
|
2019-08-15 22:16:06 +08:00
|
|
|
return Reply(std::move(R));
|
|
|
|
};
|
|
|
|
llvm_unreachable("unhandled MarkupKind");
|
|
|
|
});
|
[clangd] Implement textDocument/hover
Summary: Implemention of textDocument/hover as described in LSP definition.
This patch adds a basic Hover implementation. When hovering a variable,
function, method or namespace, clangd will return a text containing the
declaration's scope, as well as the declaration of the hovered entity.
For example, for a variable:
Declared in class Foo::Bar
int hello = 2
For macros, the macro definition is returned.
This patch doesn't include:
- markdown support (the client I use doesn't support it yet)
- range support (optional in the Hover response)
- comments associated to variables/functions/classes
They are kept as future work to keep this patch simpler.
I added tests in XRefsTests.cpp. hover.test contains one simple
smoketest to make sure the feature works from a black box perspective.
Reviewers: malaperle, krasimir, bkramer, ilya-biryukov
Subscribers: sammccall, mgrang, klimek, rwols, ilya-biryukov, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D35894
Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
Signed-off-by: William Enright <william.enright@polymtl.ca>
llvm-svn: 325395
2018-02-17 05:38:15 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Add support for type hierarchy (super types only for now)
Summary:
Patch by Nathan Ridge(@nridge)!
This is an LSP extension proposed here:
https://github.com/Microsoft/vscode-languageserver-node/pull/426
An example client implementation can be found here:
https://github.com/theia-ide/theia/pull/3802
Reviewers: kadircet, sammccall
Reviewed By: kadircet
Subscribers: jdoerfert, sammccall, cfe-commits, mgorny, dschaefer, simark, ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, kadircet
Tags: #clang
Differential Revision: https://reviews.llvm.org/D56370
llvm-svn: 356445
2019-03-19 17:27:04 +08:00
|
|
|
void ClangdLSPServer::onTypeHierarchy(
|
|
|
|
const TypeHierarchyParams &Params,
|
|
|
|
Callback<Optional<TypeHierarchyItem>> Reply) {
|
|
|
|
Server->typeHierarchy(Params.textDocument.uri.file(), Params.position,
|
|
|
|
Params.resolve, Params.direction, std::move(Reply));
|
|
|
|
}
|
|
|
|
|
2019-07-13 11:24:48 +08:00
|
|
|
void ClangdLSPServer::onResolveTypeHierarchy(
|
|
|
|
const ResolveTypeHierarchyItemParams &Params,
|
|
|
|
Callback<Optional<TypeHierarchyItem>> Reply) {
|
|
|
|
Server->resolveTypeHierarchy(Params.item, Params.resolve, Params.direction,
|
|
|
|
std::move(Reply));
|
|
|
|
}
|
|
|
|
|
2020-11-16 11:45:17 +08:00
|
|
|
void ClangdLSPServer::onPrepareCallHierarchy(
|
|
|
|
const CallHierarchyPrepareParams &Params,
|
|
|
|
Callback<std::vector<CallHierarchyItem>> Reply) {
|
|
|
|
Server->prepareCallHierarchy(Params.textDocument.uri.file(), Params.position,
|
|
|
|
std::move(Reply));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClangdLSPServer::onCallHierarchyIncomingCalls(
|
|
|
|
const CallHierarchyIncomingCallsParams &Params,
|
|
|
|
Callback<std::vector<CallHierarchyIncomingCall>> Reply) {
|
|
|
|
Server->incomingCalls(Params.item, std::move(Reply));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClangdLSPServer::onCallHierarchyOutgoingCalls(
|
|
|
|
const CallHierarchyOutgoingCallsParams &Params,
|
|
|
|
Callback<std::vector<CallHierarchyOutgoingCall>> Reply) {
|
|
|
|
// FIXME: To be implemented.
|
|
|
|
Reply(std::vector<CallHierarchyOutgoingCall>{});
|
|
|
|
}
|
|
|
|
|
2018-08-01 19:28:49 +08:00
|
|
|
void ClangdLSPServer::applyConfiguration(
|
2018-10-25 12:22:52 +08:00
|
|
|
const ConfigurationSettings &Settings) {
|
2018-10-16 23:55:03 +08:00
|
|
|
// Per-file update to the compilation database.
|
2020-01-14 06:01:10 +08:00
|
|
|
llvm::StringSet<> ModifiedFiles;
|
2018-10-25 12:22:52 +08:00
|
|
|
for (auto &Entry : Settings.compilationDatabaseChanges) {
|
|
|
|
PathRef File = Entry.first;
|
2018-11-02 21:09:36 +08:00
|
|
|
auto Old = CDB->getCompileCommand(File);
|
|
|
|
auto New =
|
|
|
|
tooling::CompileCommand(std::move(Entry.second.workingDirectory), File,
|
|
|
|
std::move(Entry.second.compilationCommand),
|
|
|
|
/*Output=*/"");
|
2018-11-02 22:07:51 +08:00
|
|
|
if (Old != New) {
|
2018-11-02 21:09:36 +08:00
|
|
|
CDB->setCompileCommand(File, std::move(New));
|
2020-01-14 06:01:10 +08:00
|
|
|
ModifiedFiles.insert(File);
|
2018-11-02 22:07:51 +08:00
|
|
|
}
|
2018-08-02 01:39:29 +08:00
|
|
|
}
|
2020-01-14 06:01:10 +08:00
|
|
|
|
2021-03-02 07:16:33 +08:00
|
|
|
Server->reparseOpenFilesIfNeeded(
|
2020-04-10 09:27:37 +08:00
|
|
|
[&](llvm::StringRef File) { return ModifiedFiles.count(File) != 0; });
|
[clangd] DidChangeConfiguration Notification
Summary:
Implementation of DidChangeConfiguration notification handling in
clangd. This currently only supports changing one setting: the path of
the compilation database to be used for the current project. In other
words, it is no longer necessary to restart clangd with a different
command line argument in order to change the compilation database.
Reviewers: malaperle, krasimir, bkramer, ilya-biryukov
Subscribers: jkorous-apple, ioeric, simark, klimek, ilya-biryukov, arphaman, rwols, cfe-commits
Differential Revision: https://reviews.llvm.org/D39571
Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
Signed-off-by: William Enright <william.enright@polymtl.ca>
llvm-svn: 325784
2018-02-22 22:00:39 +08:00
|
|
|
}
|
|
|
|
|
2020-09-28 21:09:55 +08:00
|
|
|
void ClangdLSPServer::maybeExportMemoryProfile() {
|
2020-12-23 04:36:41 +08:00
|
|
|
if (!trace::enabled() || !ShouldProfile())
|
2020-09-28 21:09:55 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
static constexpr trace::Metric MemoryUsage(
|
|
|
|
"memory_usage", trace::Metric::Value, "component_name");
|
|
|
|
trace::Span Tracer("ProfileBrief");
|
|
|
|
MemoryTree MT;
|
|
|
|
profile(MT);
|
|
|
|
record(MT, "clangd_lsp_server", MemoryUsage);
|
|
|
|
}
|
|
|
|
|
2020-12-22 15:44:20 +08:00
|
|
|
void ClangdLSPServer::maybeCleanupMemory() {
|
2020-12-23 04:36:41 +08:00
|
|
|
if (!Opts.MemoryCleanup || !ShouldCleanupMemory())
|
2020-12-22 15:44:20 +08:00
|
|
|
return;
|
|
|
|
Opts.MemoryCleanup();
|
|
|
|
}
|
|
|
|
|
2018-08-01 19:28:49 +08:00
|
|
|
// FIXME: This function needs to be properly tested.
|
|
|
|
void ClangdLSPServer::onChangeConfiguration(
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
const DidChangeConfigurationParams &Params) {
|
2018-08-01 19:28:49 +08:00
|
|
|
applyConfiguration(Params.settings);
|
|
|
|
}
|
|
|
|
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
void ClangdLSPServer::onReference(const ReferenceParams &Params,
|
|
|
|
Callback<std::vector<Location>> Reply) {
|
2021-01-27 00:16:57 +08:00
|
|
|
Server->findReferences(
|
|
|
|
Params.textDocument.uri.file(), Params.position, Opts.CodeComplete.Limit,
|
|
|
|
[Reply = std::move(Reply),
|
|
|
|
IncludeDecl(Params.context.includeDeclaration)](
|
|
|
|
llvm::Expected<ReferencesResult> Refs) mutable {
|
|
|
|
if (!Refs)
|
|
|
|
return Reply(Refs.takeError());
|
|
|
|
// Filter out declarations if the client asked.
|
|
|
|
std::vector<Location> Result;
|
|
|
|
Result.reserve(Refs->References.size());
|
|
|
|
for (auto &Ref : Refs->References) {
|
|
|
|
bool IsDecl = Ref.Attributes & ReferencesResult::Declaration;
|
|
|
|
if (IncludeDecl || !IsDecl)
|
|
|
|
Result.push_back(std::move(Ref.Loc));
|
|
|
|
}
|
|
|
|
return Reply(std::move(Result));
|
|
|
|
});
|
2018-09-05 19:53:07 +08:00
|
|
|
}
|
|
|
|
|
2020-11-18 20:25:09 +08:00
|
|
|
void ClangdLSPServer::onGoToImplementation(
|
|
|
|
const TextDocumentPositionParams &Params,
|
|
|
|
Callback<std::vector<Location>> Reply) {
|
|
|
|
Server->findImplementations(
|
|
|
|
Params.textDocument.uri.file(), Params.position,
|
|
|
|
[Reply = std::move(Reply)](
|
|
|
|
llvm::Expected<std::vector<LocatedSymbol>> Overrides) mutable {
|
|
|
|
if (!Overrides)
|
|
|
|
return Reply(Overrides.takeError());
|
|
|
|
std::vector<Location> Impls;
|
|
|
|
for (const LocatedSymbol &Sym : *Overrides)
|
|
|
|
Impls.push_back(Sym.PreferredDeclaration);
|
|
|
|
return Reply(std::move(Impls));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-11-28 00:40:46 +08:00
|
|
|
void ClangdLSPServer::onSymbolInfo(const TextDocumentPositionParams &Params,
|
|
|
|
Callback<std::vector<SymbolDetails>> Reply) {
|
|
|
|
Server->symbolInfo(Params.textDocument.uri.file(), Params.position,
|
|
|
|
std::move(Reply));
|
|
|
|
}
|
|
|
|
|
2019-09-24 21:38:33 +08:00
|
|
|
void ClangdLSPServer::onSelectionRange(
|
|
|
|
const SelectionRangeParams &Params,
|
|
|
|
Callback<std::vector<SelectionRange>> Reply) {
|
|
|
|
Server->semanticRanges(
|
2020-03-25 07:51:50 +08:00
|
|
|
Params.textDocument.uri.file(), Params.positions,
|
2019-09-24 21:38:33 +08:00
|
|
|
[Reply = std::move(Reply)](
|
2020-03-25 07:51:50 +08:00
|
|
|
llvm::Expected<std::vector<SelectionRange>> Ranges) mutable {
|
|
|
|
if (!Ranges)
|
2019-09-24 21:38:33 +08:00
|
|
|
return Reply(Ranges.takeError());
|
2020-03-25 07:51:50 +08:00
|
|
|
return Reply(std::move(*Ranges));
|
2019-09-24 21:38:33 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-12-17 02:08:51 +08:00
|
|
|
void ClangdLSPServer::onDocumentLink(
|
|
|
|
const DocumentLinkParams &Params,
|
|
|
|
Callback<std::vector<DocumentLink>> Reply) {
|
|
|
|
|
|
|
|
// TODO(forster): This currently resolves all targets eagerly. This is slow,
|
|
|
|
// because it blocks on the preamble/AST being built. We could respond to the
|
|
|
|
// request faster by using string matching or the lexer to find the includes
|
|
|
|
// and resolving the targets lazily.
|
|
|
|
Server->documentLinks(
|
|
|
|
Params.textDocument.uri.file(),
|
|
|
|
[Reply = std::move(Reply)](
|
|
|
|
llvm::Expected<std::vector<DocumentLink>> Links) mutable {
|
|
|
|
if (!Links) {
|
|
|
|
return Reply(Links.takeError());
|
|
|
|
}
|
|
|
|
return Reply(std::move(Links));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
[clangd] Support textDocument/semanticTokens/edits
Summary:
This returns incremental highlights as a set of edits against the
previous highlights.
Server-side, we compute the full set of highlights, this just saves
wire-format size.
For now, the diff used is trivial: everything from the first change to
the last change is sent as a single edit.
The wire format is grungy - the replacement offset/length refer to
positions in the encoded array instead of the logical list of tokens.
We use token-oriented structs and translating to LSP forms when serializing.
This departs from LSP (but is consistent with semanticTokens today).
Tested in VSCode insiders (with a patched client to enable experimental
features).
Reviewers: hokein
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D77225
2020-04-01 22:21:44 +08:00
|
|
|
// Increment a numeric string: "" -> 1 -> 2 -> ... -> 9 -> 10 -> 11 ...
|
|
|
|
static void increment(std::string &S) {
|
|
|
|
for (char &C : llvm::reverse(S)) {
|
|
|
|
if (C != '9') {
|
|
|
|
++C;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
C = '0';
|
|
|
|
}
|
|
|
|
S.insert(S.begin(), '1');
|
|
|
|
}
|
|
|
|
|
2020-03-24 09:24:47 +08:00
|
|
|
void ClangdLSPServer::onSemanticTokens(const SemanticTokensParams &Params,
|
|
|
|
Callback<SemanticTokens> CB) {
|
|
|
|
Server->semanticHighlights(
|
|
|
|
Params.textDocument.uri.file(),
|
[clangd] Support textDocument/semanticTokens/edits
Summary:
This returns incremental highlights as a set of edits against the
previous highlights.
Server-side, we compute the full set of highlights, this just saves
wire-format size.
For now, the diff used is trivial: everything from the first change to
the last change is sent as a single edit.
The wire format is grungy - the replacement offset/length refer to
positions in the encoded array instead of the logical list of tokens.
We use token-oriented structs and translating to LSP forms when serializing.
This departs from LSP (but is consistent with semanticTokens today).
Tested in VSCode insiders (with a patched client to enable experimental
features).
Reviewers: hokein
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D77225
2020-04-01 22:21:44 +08:00
|
|
|
[this, File(Params.textDocument.uri.file().str()), CB(std::move(CB))](
|
|
|
|
llvm::Expected<std::vector<HighlightingToken>> HT) mutable {
|
|
|
|
if (!HT)
|
|
|
|
return CB(HT.takeError());
|
2020-03-24 09:24:47 +08:00
|
|
|
SemanticTokens Result;
|
[clangd] Support textDocument/semanticTokens/edits
Summary:
This returns incremental highlights as a set of edits against the
previous highlights.
Server-side, we compute the full set of highlights, this just saves
wire-format size.
For now, the diff used is trivial: everything from the first change to
the last change is sent as a single edit.
The wire format is grungy - the replacement offset/length refer to
positions in the encoded array instead of the logical list of tokens.
We use token-oriented structs and translating to LSP forms when serializing.
This departs from LSP (but is consistent with semanticTokens today).
Tested in VSCode insiders (with a patched client to enable experimental
features).
Reviewers: hokein
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D77225
2020-04-01 22:21:44 +08:00
|
|
|
Result.tokens = toSemanticTokens(*HT);
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> Lock(SemanticTokensMutex);
|
2020-04-17 05:12:09 +08:00
|
|
|
auto &Last = LastSemanticTokens[File];
|
[clangd] Support textDocument/semanticTokens/edits
Summary:
This returns incremental highlights as a set of edits against the
previous highlights.
Server-side, we compute the full set of highlights, this just saves
wire-format size.
For now, the diff used is trivial: everything from the first change to
the last change is sent as a single edit.
The wire format is grungy - the replacement offset/length refer to
positions in the encoded array instead of the logical list of tokens.
We use token-oriented structs and translating to LSP forms when serializing.
This departs from LSP (but is consistent with semanticTokens today).
Tested in VSCode insiders (with a patched client to enable experimental
features).
Reviewers: hokein
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D77225
2020-04-01 22:21:44 +08:00
|
|
|
|
|
|
|
Last.tokens = Result.tokens;
|
|
|
|
increment(Last.resultId);
|
|
|
|
Result.resultId = Last.resultId;
|
|
|
|
}
|
|
|
|
CB(std::move(Result));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-07-10 22:08:14 +08:00
|
|
|
void ClangdLSPServer::onSemanticTokensDelta(
|
|
|
|
const SemanticTokensDeltaParams &Params,
|
|
|
|
Callback<SemanticTokensOrDelta> CB) {
|
[clangd] Support textDocument/semanticTokens/edits
Summary:
This returns incremental highlights as a set of edits against the
previous highlights.
Server-side, we compute the full set of highlights, this just saves
wire-format size.
For now, the diff used is trivial: everything from the first change to
the last change is sent as a single edit.
The wire format is grungy - the replacement offset/length refer to
positions in the encoded array instead of the logical list of tokens.
We use token-oriented structs and translating to LSP forms when serializing.
This departs from LSP (but is consistent with semanticTokens today).
Tested in VSCode insiders (with a patched client to enable experimental
features).
Reviewers: hokein
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D77225
2020-04-01 22:21:44 +08:00
|
|
|
Server->semanticHighlights(
|
|
|
|
Params.textDocument.uri.file(),
|
|
|
|
[this, PrevResultID(Params.previousResultId),
|
|
|
|
File(Params.textDocument.uri.file().str()), CB(std::move(CB))](
|
|
|
|
llvm::Expected<std::vector<HighlightingToken>> HT) mutable {
|
|
|
|
if (!HT)
|
|
|
|
return CB(HT.takeError());
|
|
|
|
std::vector<SemanticToken> Toks = toSemanticTokens(*HT);
|
|
|
|
|
2020-07-10 22:08:14 +08:00
|
|
|
SemanticTokensOrDelta Result;
|
[clangd] Support textDocument/semanticTokens/edits
Summary:
This returns incremental highlights as a set of edits against the
previous highlights.
Server-side, we compute the full set of highlights, this just saves
wire-format size.
For now, the diff used is trivial: everything from the first change to
the last change is sent as a single edit.
The wire format is grungy - the replacement offset/length refer to
positions in the encoded array instead of the logical list of tokens.
We use token-oriented structs and translating to LSP forms when serializing.
This departs from LSP (but is consistent with semanticTokens today).
Tested in VSCode insiders (with a patched client to enable experimental
features).
Reviewers: hokein
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D77225
2020-04-01 22:21:44 +08:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> Lock(SemanticTokensMutex);
|
2020-04-17 05:12:09 +08:00
|
|
|
auto &Last = LastSemanticTokens[File];
|
[clangd] Support textDocument/semanticTokens/edits
Summary:
This returns incremental highlights as a set of edits against the
previous highlights.
Server-side, we compute the full set of highlights, this just saves
wire-format size.
For now, the diff used is trivial: everything from the first change to
the last change is sent as a single edit.
The wire format is grungy - the replacement offset/length refer to
positions in the encoded array instead of the logical list of tokens.
We use token-oriented structs and translating to LSP forms when serializing.
This departs from LSP (but is consistent with semanticTokens today).
Tested in VSCode insiders (with a patched client to enable experimental
features).
Reviewers: hokein
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D77225
2020-04-01 22:21:44 +08:00
|
|
|
|
|
|
|
if (PrevResultID == Last.resultId) {
|
|
|
|
Result.edits = diffTokens(Last.tokens, Toks);
|
|
|
|
} else {
|
2020-07-10 22:08:14 +08:00
|
|
|
vlog("semanticTokens/full/delta: wanted edits vs {0} but last "
|
|
|
|
"result had ID {1}. Returning full token list.",
|
[clangd] Support textDocument/semanticTokens/edits
Summary:
This returns incremental highlights as a set of edits against the
previous highlights.
Server-side, we compute the full set of highlights, this just saves
wire-format size.
For now, the diff used is trivial: everything from the first change to
the last change is sent as a single edit.
The wire format is grungy - the replacement offset/length refer to
positions in the encoded array instead of the logical list of tokens.
We use token-oriented structs and translating to LSP forms when serializing.
This departs from LSP (but is consistent with semanticTokens today).
Tested in VSCode insiders (with a patched client to enable experimental
features).
Reviewers: hokein
Subscribers: ilya-biryukov, MaskRay, jkorous, mgrang, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D77225
2020-04-01 22:21:44 +08:00
|
|
|
PrevResultID, Last.resultId);
|
|
|
|
Result.tokens = Toks;
|
|
|
|
}
|
|
|
|
|
|
|
|
Last.tokens = std::move(Toks);
|
|
|
|
increment(Last.resultId);
|
|
|
|
Result.resultId = Last.resultId;
|
|
|
|
}
|
|
|
|
|
2020-03-24 09:24:47 +08:00
|
|
|
CB(std::move(Result));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-02-12 05:47:58 +08:00
|
|
|
void ClangdLSPServer::onMemoryUsage(const NoParams &,
|
|
|
|
Callback<MemoryTree> Reply) {
|
2020-10-13 06:10:04 +08:00
|
|
|
llvm::BumpPtrAllocator DetailAlloc;
|
|
|
|
MemoryTree MT(&DetailAlloc);
|
|
|
|
profile(MT);
|
|
|
|
Reply(std::move(MT));
|
|
|
|
}
|
|
|
|
|
2020-10-17 02:03:48 +08:00
|
|
|
void ClangdLSPServer::onAST(const ASTParams &Params,
|
|
|
|
Callback<llvm::Optional<ASTNode>> CB) {
|
|
|
|
Server->getAST(Params.textDocument.uri.file(), Params.range, std::move(CB));
|
|
|
|
}
|
|
|
|
|
2021-02-26 21:44:01 +08:00
|
|
|
ClangdLSPServer::ClangdLSPServer(Transport &Transp, const ThreadsafeFS &TFS,
|
2020-09-29 16:37:46 +08:00
|
|
|
const ClangdLSPServer::Options &Opts)
|
2020-12-23 04:36:41 +08:00
|
|
|
: ShouldProfile(/*Period=*/std::chrono::minutes(5),
|
|
|
|
/*Delay=*/std::chrono::minutes(1)),
|
|
|
|
ShouldCleanupMemory(/*Period=*/std::chrono::minutes(1),
|
|
|
|
/*Delay=*/std::chrono::minutes(1)),
|
|
|
|
BackgroundContext(Context::current().clone()), Transp(Transp),
|
2020-09-29 16:37:46 +08:00
|
|
|
MsgHandler(new MessageHandler(*this)), TFS(TFS),
|
|
|
|
SupportedSymbolKinds(defaultSymbolKinds()),
|
|
|
|
SupportedCompletionItemKinds(defaultCompletionItemKinds()), Opts(Opts) {
|
2021-01-21 05:34:24 +08:00
|
|
|
if (Opts.ConfigProvider) {
|
|
|
|
assert(!Opts.ContextProvider &&
|
|
|
|
"Only one of ConfigProvider and ContextProvider allowed!");
|
|
|
|
this->Opts.ContextProvider = ClangdServer::createConfiguredContextProvider(
|
|
|
|
Opts.ConfigProvider, this);
|
|
|
|
}
|
2021-02-15 17:41:38 +08:00
|
|
|
LSPBinder Bind(this->Handlers, *this);
|
2021-02-12 05:47:58 +08:00
|
|
|
Bind.method("initialize", this, &ClangdLSPServer::onInitialize);
|
2021-02-12 23:23:53 +08:00
|
|
|
}
|
|
|
|
|
2021-02-26 21:44:01 +08:00
|
|
|
void ClangdLSPServer::bindMethods(LSPBinder &Bind,
|
|
|
|
const ClientCapabilities &Caps) {
|
2021-02-12 23:23:53 +08:00
|
|
|
// clang-format off
|
2021-02-12 05:47:58 +08:00
|
|
|
Bind.notification("initialized", this, &ClangdLSPServer::onInitialized);
|
|
|
|
Bind.method("shutdown", this, &ClangdLSPServer::onShutdown);
|
|
|
|
Bind.method("sync", this, &ClangdLSPServer::onSync);
|
|
|
|
Bind.method("textDocument/rangeFormatting", this, &ClangdLSPServer::onDocumentRangeFormatting);
|
|
|
|
Bind.method("textDocument/onTypeFormatting", this, &ClangdLSPServer::onDocumentOnTypeFormatting);
|
|
|
|
Bind.method("textDocument/formatting", this, &ClangdLSPServer::onDocumentFormatting);
|
|
|
|
Bind.method("textDocument/codeAction", this, &ClangdLSPServer::onCodeAction);
|
|
|
|
Bind.method("textDocument/completion", this, &ClangdLSPServer::onCompletion);
|
|
|
|
Bind.method("textDocument/signatureHelp", this, &ClangdLSPServer::onSignatureHelp);
|
|
|
|
Bind.method("textDocument/definition", this, &ClangdLSPServer::onGoToDefinition);
|
|
|
|
Bind.method("textDocument/declaration", this, &ClangdLSPServer::onGoToDeclaration);
|
|
|
|
Bind.method("textDocument/implementation", this, &ClangdLSPServer::onGoToImplementation);
|
|
|
|
Bind.method("textDocument/references", this, &ClangdLSPServer::onReference);
|
|
|
|
Bind.method("textDocument/switchSourceHeader", this, &ClangdLSPServer::onSwitchSourceHeader);
|
|
|
|
Bind.method("textDocument/prepareRename", this, &ClangdLSPServer::onPrepareRename);
|
|
|
|
Bind.method("textDocument/rename", this, &ClangdLSPServer::onRename);
|
|
|
|
Bind.method("textDocument/hover", this, &ClangdLSPServer::onHover);
|
|
|
|
Bind.method("textDocument/documentSymbol", this, &ClangdLSPServer::onDocumentSymbol);
|
|
|
|
Bind.method("workspace/executeCommand", this, &ClangdLSPServer::onCommand);
|
|
|
|
Bind.method("textDocument/documentHighlight", this, &ClangdLSPServer::onDocumentHighlight);
|
|
|
|
Bind.method("workspace/symbol", this, &ClangdLSPServer::onWorkspaceSymbol);
|
|
|
|
Bind.method("textDocument/ast", this, &ClangdLSPServer::onAST);
|
|
|
|
Bind.notification("textDocument/didOpen", this, &ClangdLSPServer::onDocumentDidOpen);
|
|
|
|
Bind.notification("textDocument/didClose", this, &ClangdLSPServer::onDocumentDidClose);
|
|
|
|
Bind.notification("textDocument/didChange", this, &ClangdLSPServer::onDocumentDidChange);
|
|
|
|
Bind.notification("textDocument/didSave", this, &ClangdLSPServer::onDocumentDidSave);
|
|
|
|
Bind.notification("workspace/didChangeWatchedFiles", this, &ClangdLSPServer::onFileEvent);
|
|
|
|
Bind.notification("workspace/didChangeConfiguration", this, &ClangdLSPServer::onChangeConfiguration);
|
|
|
|
Bind.method("textDocument/symbolInfo", this, &ClangdLSPServer::onSymbolInfo);
|
|
|
|
Bind.method("textDocument/typeHierarchy", this, &ClangdLSPServer::onTypeHierarchy);
|
|
|
|
Bind.method("typeHierarchy/resolve", this, &ClangdLSPServer::onResolveTypeHierarchy);
|
|
|
|
Bind.method("textDocument/prepareCallHierarchy", this, &ClangdLSPServer::onPrepareCallHierarchy);
|
|
|
|
Bind.method("callHierarchy/incomingCalls", this, &ClangdLSPServer::onCallHierarchyIncomingCalls);
|
|
|
|
Bind.method("callHierarchy/outgoingCalls", this, &ClangdLSPServer::onCallHierarchyOutgoingCalls);
|
|
|
|
Bind.method("textDocument/selectionRange", this, &ClangdLSPServer::onSelectionRange);
|
|
|
|
Bind.method("textDocument/documentLink", this, &ClangdLSPServer::onDocumentLink);
|
|
|
|
Bind.method("textDocument/semanticTokens/full", this, &ClangdLSPServer::onSemanticTokens);
|
|
|
|
Bind.method("textDocument/semanticTokens/full/delta", this, &ClangdLSPServer::onSemanticTokensDelta);
|
|
|
|
Bind.method("$/memoryUsage", this, &ClangdLSPServer::onMemoryUsage);
|
[clangd] Implement textDocument/foldingRange
Summary:
This patch introduces basic textDocument/foldingRange support. It relies on
textDocument/documentSymbols to collect all symbols and uses takes ranges
to create folds.
The next steps for textDocument/foldingRange support would be:
* Implementing FoldingRangeClientCapabilities and respecting respect client
preferences
* Specifying folding range kind
* Migrating from DocumentSymbol implementation to custom RecursiveASTVisitor flow that will allow more flexibility
* Supporting more folding range types: comments, PP conditional regions, includes and other code regions (e.g. public/private/protected sections of classes, control flow statement bodies)
Tested: (Neo)Vim (coc-clangd) and VSCode.
Related issue: https://github.com/clangd/clangd/issues/310
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: nridge, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D82436
2020-07-14 15:28:38 +08:00
|
|
|
if (Opts.FoldingRanges)
|
2021-02-12 05:47:58 +08:00
|
|
|
Bind.method("textDocument/foldingRange", this, &ClangdLSPServer::onFoldingRange);
|
|
|
|
Bind.command(APPLY_FIX_COMMAND, this, &ClangdLSPServer::onCommandApplyEdit);
|
|
|
|
Bind.command(APPLY_TWEAK_COMMAND, this, &ClangdLSPServer::onCommandApplyTweak);
|
2021-02-15 17:41:38 +08:00
|
|
|
|
|
|
|
ApplyWorkspaceEdit = Bind.outgoingMethod("workspace/applyEdit");
|
|
|
|
PublishDiagnostics = Bind.outgoingNotification("textDocument/publishDiagnostics");
|
|
|
|
ShowMessage = Bind.outgoingNotification("window/showMessage");
|
|
|
|
NotifyFileStatus = Bind.outgoingNotification("textDocument/clangd.fileStatus");
|
|
|
|
CreateWorkDoneProgress = Bind.outgoingMethod("window/workDoneProgress/create");
|
|
|
|
BeginWorkDoneProgress = Bind.outgoingNotification("$/progress");
|
|
|
|
ReportWorkDoneProgress = Bind.outgoingNotification("$/progress");
|
|
|
|
EndWorkDoneProgress = Bind.outgoingNotification("$/progress");
|
2021-02-26 21:44:01 +08:00
|
|
|
if(Caps.SemanticTokenRefreshSupport)
|
|
|
|
SemanticTokensRefresh = Bind.outgoingMethod("workspace/semanticTokens/refresh");
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
// clang-format on
|
|
|
|
}
|
|
|
|
|
2020-03-18 02:08:23 +08:00
|
|
|
ClangdLSPServer::~ClangdLSPServer() {
|
|
|
|
IsBeingDestroyed = true;
|
[clangd] abort if shutdown takes more than a minute.
Summary:
A certain class of bug (e.g. infloop on an AST worker thread) currently means
clangd never terminates, even if the editor shuts down the protocol and closes
our stdin, and the main thread recognizes that.
Instead, let's wait 60 seconds for threads to finish cleanly, and then crash
if they haven't.
(Obviously, we should still fix these bugs).
Reviewers: kadircet
Subscribers: MaskRay, jkorous, arphaman, jfb, usaxena95, cfe-commits, ilya-biryukov
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69329
2019-10-23 17:11:18 +08:00
|
|
|
// Explicitly destroy ClangdServer first, blocking on threads it owns.
|
|
|
|
// This ensures they don't access any other members.
|
|
|
|
Server.reset();
|
|
|
|
}
|
2017-05-16 17:38:59 +08:00
|
|
|
|
[clangd] Refactor JSON-over-stdin/stdout code into Transport abstraction. (re-land r344620)
Summary:
This paves the way for alternative transports (mac XPC, maybe messagepack?),
and also generally improves layering: testing ClangdLSPServer becomes less of
a pipe dream, we split up the JSONOutput monolith, etc.
This isn't a final state, much of what remains in JSONRPCDispatcher can go away,
handlers can call reply() on the transport directly, JSONOutput can be renamed
to StreamLogger and removed, etc. But this patch is sprawling already.
The main observable change (see tests) is that hitting EOF on input is now an
error: the client should send the 'exit' notification.
This is defensible: the protocol doesn't spell this case out. Reproducing the
current behavior for all combinations of shutdown/exit/EOF clutters interfaces.
We can iterate on this if desired.
Reviewers: jkorous, ioeric, hokein
Subscribers: mgorny, ilya-biryukov, MaskRay, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53286
llvm-svn: 344672
2018-10-17 15:32:05 +08:00
|
|
|
bool ClangdLSPServer::run() {
|
2017-05-16 22:40:30 +08:00
|
|
|
// Run the Language Server loop.
|
[clangd] Refactor JSON-over-stdin/stdout code into Transport abstraction. (re-land r344620)
Summary:
This paves the way for alternative transports (mac XPC, maybe messagepack?),
and also generally improves layering: testing ClangdLSPServer becomes less of
a pipe dream, we split up the JSONOutput monolith, etc.
This isn't a final state, much of what remains in JSONRPCDispatcher can go away,
handlers can call reply() on the transport directly, JSONOutput can be renamed
to StreamLogger and removed, etc. But this patch is sprawling already.
The main observable change (see tests) is that hitting EOF on input is now an
error: the client should send the 'exit' notification.
This is defensible: the protocol doesn't spell this case out. Reproducing the
current behavior for all combinations of shutdown/exit/EOF clutters interfaces.
We can iterate on this if desired.
Reviewers: jkorous, ioeric, hokein
Subscribers: mgorny, ilya-biryukov, MaskRay, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53286
llvm-svn: 344672
2018-10-17 15:32:05 +08:00
|
|
|
bool CleanExit = true;
|
[clangd] Lay JSONRPCDispatcher to rest.
Summary:
Most of its functionality is moved into ClangdLSPServer.
The decoupling between JSONRPCDispatcher, ProtocolCallbacks, ClangdLSPServer
was never real, and only served to obfuscate.
Some previous implicit/magic stuff is now explicit:
- the return type of LSP method calls are now in the signature
- no more reply() that gets the ID using global context magic
- arg tracing no longer relies on RequestArgs::stash context magic either
This is mostly refactoring, but some deliberate fixes while here:
- LSP method params are now by const reference
- notifications and calls are now distinct namespaces.
(some tests had protocol errors and needed updating)
- we now reply to calls we failed to decode
- outgoing calls use distinct IDs
A few error codes and message IDs changed in unimportant ways (see tests).
Reviewers: ioeric
Subscribers: mgorny, ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, jfb, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53387
llvm-svn: 344737
2018-10-18 20:32:04 +08:00
|
|
|
if (auto Err = Transp.loop(*MsgHandler)) {
|
[clangd] Refactor JSON-over-stdin/stdout code into Transport abstraction. (re-land r344620)
Summary:
This paves the way for alternative transports (mac XPC, maybe messagepack?),
and also generally improves layering: testing ClangdLSPServer becomes less of
a pipe dream, we split up the JSONOutput monolith, etc.
This isn't a final state, much of what remains in JSONRPCDispatcher can go away,
handlers can call reply() on the transport directly, JSONOutput can be renamed
to StreamLogger and removed, etc. But this patch is sprawling already.
The main observable change (see tests) is that hitting EOF on input is now an
error: the client should send the 'exit' notification.
This is defensible: the protocol doesn't spell this case out. Reproducing the
current behavior for all combinations of shutdown/exit/EOF clutters interfaces.
We can iterate on this if desired.
Reviewers: jkorous, ioeric, hokein
Subscribers: mgorny, ilya-biryukov, MaskRay, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53286
llvm-svn: 344672
2018-10-17 15:32:05 +08:00
|
|
|
elog("Transport error: {0}", std::move(Err));
|
|
|
|
CleanExit = false;
|
|
|
|
}
|
2017-05-16 17:38:59 +08:00
|
|
|
|
[clangd] Refactor JSON-over-stdin/stdout code into Transport abstraction. (re-land r344620)
Summary:
This paves the way for alternative transports (mac XPC, maybe messagepack?),
and also generally improves layering: testing ClangdLSPServer becomes less of
a pipe dream, we split up the JSONOutput monolith, etc.
This isn't a final state, much of what remains in JSONRPCDispatcher can go away,
handlers can call reply() on the transport directly, JSONOutput can be renamed
to StreamLogger and removed, etc. But this patch is sprawling already.
The main observable change (see tests) is that hitting EOF on input is now an
error: the client should send the 'exit' notification.
This is defensible: the protocol doesn't spell this case out. Reproducing the
current behavior for all combinations of shutdown/exit/EOF clutters interfaces.
We can iterate on this if desired.
Reviewers: jkorous, ioeric, hokein
Subscribers: mgorny, ilya-biryukov, MaskRay, arphaman, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53286
llvm-svn: 344672
2018-10-17 15:32:05 +08:00
|
|
|
return CleanExit && ShutdownRequestReceived;
|
2017-05-16 17:38:59 +08:00
|
|
|
}
|
|
|
|
|
2020-09-28 21:09:55 +08:00
|
|
|
void ClangdLSPServer::profile(MemoryTree &MT) const {
|
|
|
|
if (Server)
|
|
|
|
Server->profile(MT.child("clangd_server"));
|
|
|
|
}
|
|
|
|
|
2019-01-07 23:45:19 +08:00
|
|
|
std::vector<Fix> ClangdLSPServer::getFixes(llvm::StringRef File,
|
2018-03-12 23:28:22 +08:00
|
|
|
const clangd::Diagnostic &D) {
|
2017-05-16 17:38:59 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-05-06 07:39:59 +08:00
|
|
|
// A completion request is sent when the user types '>' or ':', but we only
|
|
|
|
// want to trigger on '->' and '::'. We check the preceeding text to make
|
|
|
|
// sure it matches what we expected.
|
|
|
|
// Running the lexer here would be more robust (e.g. we can detect comments
|
|
|
|
// and avoid triggering completion there), but we choose to err on the side
|
|
|
|
// of simplicity here.
|
2019-01-03 21:37:12 +08:00
|
|
|
bool ClangdLSPServer::shouldRunCompletion(
|
|
|
|
const CompletionParams &Params) const {
|
2020-05-06 07:39:59 +08:00
|
|
|
if (Params.context.triggerKind != CompletionTriggerKind::TriggerCharacter)
|
2019-01-03 21:37:12 +08:00
|
|
|
return true;
|
2021-03-02 07:16:33 +08:00
|
|
|
auto Code = Server->getDraft(Params.textDocument.uri.file());
|
2019-01-03 21:37:12 +08:00
|
|
|
if (!Code)
|
|
|
|
return true; // completion code will log the error for untracked doc.
|
2021-03-02 07:16:33 +08:00
|
|
|
auto Offset = positionToOffset(*Code, Params.position,
|
2019-01-03 21:37:12 +08:00
|
|
|
/*AllowColumnsBeyondLineLength=*/false);
|
|
|
|
if (!Offset) {
|
|
|
|
vlog("could not convert position '{0}' to offset for file '{1}'",
|
|
|
|
Params.position, Params.textDocument.uri.file());
|
|
|
|
return true;
|
|
|
|
}
|
2021-03-02 07:16:33 +08:00
|
|
|
return allowImplicitCompletion(*Code, *Offset);
|
2019-01-03 21:37:12 +08:00
|
|
|
}
|
|
|
|
|
[clangd] Track document versions, include them with diags, enhance logs
Summary:
This ties to an LSP feature (diagnostic versioning) but really a lot
of the value is in being able to log what's happening with file versions
and queues more descriptively and clearly.
As such it's fairly invasive, for a logging patch :-\
Key decisions:
- at the LSP layer, we don't reqire the client to provide versions (LSP
makes it mandatory but we never enforced it). If not provided,
versions start at 0 and increment. DraftStore handles this.
- don't propagate magically using contexts, but rather manually:
addDocument -> ParseInputs -> (ParsedAST, Preamble, various callbacks)
Context-propagation would hide the versions from ClangdServer, which
would make producing good log messages hard
- within ClangdServer, treat versions as opaque and unordered.
std::string is a convenient type for this, and allows richer versions
for embedders. They're "mandatory" but "null" is a reasonable default.
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75582
2020-03-04 07:33:29 +08:00
|
|
|
void ClangdLSPServer::onDiagnosticsReady(PathRef File, llvm::StringRef Version,
|
2018-03-13 07:22:35 +08:00
|
|
|
std::vector<Diag> Diagnostics) {
|
2020-03-03 19:44:40 +08:00
|
|
|
PublishDiagnosticsParams Notification;
|
[clangd] Track document versions, include them with diags, enhance logs
Summary:
This ties to an LSP feature (diagnostic versioning) but really a lot
of the value is in being able to log what's happening with file versions
and queues more descriptively and clearly.
As such it's fairly invasive, for a logging patch :-\
Key decisions:
- at the LSP layer, we don't reqire the client to provide versions (LSP
makes it mandatory but we never enforced it). If not provided,
versions start at 0 and increment. DraftStore handles this.
- don't propagate magically using contexts, but rather manually:
addDocument -> ParseInputs -> (ParsedAST, Preamble, various callbacks)
Context-propagation would hide the versions from ClangdServer, which
would make producing good log messages hard
- within ClangdServer, treat versions as opaque and unordered.
std::string is a convenient type for this, and allows richer versions
for embedders. They're "mandatory" but "null" is a reasonable default.
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D75582
2020-03-04 07:33:29 +08:00
|
|
|
Notification.version = decodeVersion(Version);
|
2020-03-03 19:44:40 +08:00
|
|
|
Notification.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
|
2017-05-16 17:38:59 +08:00
|
|
|
DiagnosticToReplacementMap LocalFixIts; // Temporary storage
|
2018-03-13 07:22:35 +08:00
|
|
|
for (auto &Diag : Diagnostics) {
|
2020-03-03 19:44:40 +08:00
|
|
|
toLSPDiags(Diag, Notification.uri, DiagOpts,
|
2019-01-07 23:45:19 +08:00
|
|
|
[&](clangd::Diagnostic Diag, llvm::ArrayRef<Fix> Fixes) {
|
[clangd] Embed fixes as CodeAction, instead of clangd_fixes. Clean up serialization.
Summary:
CodeAction provides us with a standard way of representing fixes inline, so
use it, replacing our existing ad-hoc extension.
After this, it's easy to serialize diagnostics using the structured
toJSON/Protocol.h mechanism rather than assembling JSON ad-hoc.
Reviewers: hokein, arphaman
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53391
llvm-svn: 345119
2018-10-24 15:59:38 +08:00
|
|
|
auto &FixItsForDiagnostic = LocalFixIts[Diag];
|
|
|
|
llvm::copy(Fixes, std::back_inserter(FixItsForDiagnostic));
|
2020-03-03 19:44:40 +08:00
|
|
|
Notification.diagnostics.push_back(std::move(Diag));
|
[clangd] Embed fixes as CodeAction, instead of clangd_fixes. Clean up serialization.
Summary:
CodeAction provides us with a standard way of representing fixes inline, so
use it, replacing our existing ad-hoc extension.
After this, it's easy to serialize diagnostics using the structured
toJSON/Protocol.h mechanism rather than assembling JSON ad-hoc.
Reviewers: hokein, arphaman
Subscribers: ilya-biryukov, ioeric, MaskRay, jkorous, kadircet, cfe-commits
Differential Revision: https://reviews.llvm.org/D53391
llvm-svn: 345119
2018-10-24 15:59:38 +08:00
|
|
|
});
|
2017-05-16 17:38:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Cache FixIts
|
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> Lock(FixItsMutex);
|
|
|
|
FixItsMap[File] = LocalFixIts;
|
|
|
|
}
|
|
|
|
|
2019-03-25 18:15:11 +08:00
|
|
|
// Send a notification to the LSP client.
|
2021-02-15 17:41:38 +08:00
|
|
|
PublishDiagnostics(Notification);
|
2017-05-16 17:38:59 +08:00
|
|
|
}
|
2018-03-16 22:30:42 +08:00
|
|
|
|
[clangd] Show background index status using LSP 3.15 work-done progress notifications
Summary:
It simply shows the completed/total items on the background queue, e.g.
indexing: 233/1000
The denominator is reset to zero every time the queue goes idle.
The protocol is fairly complicated here (requires creating a remote "progress"
resource before sending updates). We implement the full protocol, but I've added
an extension allowing it to be skipped to reduce the burden on clients - in
particular the lit test takes this shortcut.
The addition of background index progress to DiagnosticConsumer seems ridiculous
at first glance, but I believe that interface is trending in the direction of
"ClangdServer callbacks" anyway. It's due for a rename, but otherwise actually
fits.
Reviewers: kadircet, usaxena95
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D73218
2020-01-23 02:41:45 +08:00
|
|
|
void ClangdLSPServer::onBackgroundIndexProgress(
|
|
|
|
const BackgroundQueue::Stats &Stats) {
|
|
|
|
static const char ProgressToken[] = "backgroundIndexProgress";
|
2020-12-22 15:44:20 +08:00
|
|
|
|
|
|
|
// The background index did some work, maybe we need to cleanup
|
|
|
|
maybeCleanupMemory();
|
|
|
|
|
[clangd] Show background index status using LSP 3.15 work-done progress notifications
Summary:
It simply shows the completed/total items on the background queue, e.g.
indexing: 233/1000
The denominator is reset to zero every time the queue goes idle.
The protocol is fairly complicated here (requires creating a remote "progress"
resource before sending updates). We implement the full protocol, but I've added
an extension allowing it to be skipped to reduce the burden on clients - in
particular the lit test takes this shortcut.
The addition of background index progress to DiagnosticConsumer seems ridiculous
at first glance, but I believe that interface is trending in the direction of
"ClangdServer callbacks" anyway. It's due for a rename, but otherwise actually
fits.
Reviewers: kadircet, usaxena95
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D73218
2020-01-23 02:41:45 +08:00
|
|
|
std::lock_guard<std::mutex> Lock(BackgroundIndexProgressMutex);
|
|
|
|
|
|
|
|
auto NotifyProgress = [this](const BackgroundQueue::Stats &Stats) {
|
|
|
|
if (BackgroundIndexProgressState != BackgroundIndexProgress::Live) {
|
|
|
|
WorkDoneProgressBegin Begin;
|
|
|
|
Begin.percentage = true;
|
|
|
|
Begin.title = "indexing";
|
2021-02-15 17:41:38 +08:00
|
|
|
BeginWorkDoneProgress({ProgressToken, std::move(Begin)});
|
[clangd] Show background index status using LSP 3.15 work-done progress notifications
Summary:
It simply shows the completed/total items on the background queue, e.g.
indexing: 233/1000
The denominator is reset to zero every time the queue goes idle.
The protocol is fairly complicated here (requires creating a remote "progress"
resource before sending updates). We implement the full protocol, but I've added
an extension allowing it to be skipped to reduce the burden on clients - in
particular the lit test takes this shortcut.
The addition of background index progress to DiagnosticConsumer seems ridiculous
at first glance, but I believe that interface is trending in the direction of
"ClangdServer callbacks" anyway. It's due for a rename, but otherwise actually
fits.
Reviewers: kadircet, usaxena95
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D73218
2020-01-23 02:41:45 +08:00
|
|
|
BackgroundIndexProgressState = BackgroundIndexProgress::Live;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Stats.Completed < Stats.Enqueued) {
|
|
|
|
assert(Stats.Enqueued > Stats.LastIdle);
|
|
|
|
WorkDoneProgressReport Report;
|
|
|
|
Report.percentage = 100.0 * (Stats.Completed - Stats.LastIdle) /
|
|
|
|
(Stats.Enqueued - Stats.LastIdle);
|
|
|
|
Report.message =
|
|
|
|
llvm::formatv("{0}/{1}", Stats.Completed - Stats.LastIdle,
|
|
|
|
Stats.Enqueued - Stats.LastIdle);
|
2021-02-15 17:41:38 +08:00
|
|
|
ReportWorkDoneProgress({ProgressToken, std::move(Report)});
|
[clangd] Show background index status using LSP 3.15 work-done progress notifications
Summary:
It simply shows the completed/total items on the background queue, e.g.
indexing: 233/1000
The denominator is reset to zero every time the queue goes idle.
The protocol is fairly complicated here (requires creating a remote "progress"
resource before sending updates). We implement the full protocol, but I've added
an extension allowing it to be skipped to reduce the burden on clients - in
particular the lit test takes this shortcut.
The addition of background index progress to DiagnosticConsumer seems ridiculous
at first glance, but I believe that interface is trending in the direction of
"ClangdServer callbacks" anyway. It's due for a rename, but otherwise actually
fits.
Reviewers: kadircet, usaxena95
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D73218
2020-01-23 02:41:45 +08:00
|
|
|
} else {
|
|
|
|
assert(Stats.Completed == Stats.Enqueued);
|
2021-02-15 17:41:38 +08:00
|
|
|
EndWorkDoneProgress({ProgressToken, WorkDoneProgressEnd()});
|
[clangd] Show background index status using LSP 3.15 work-done progress notifications
Summary:
It simply shows the completed/total items on the background queue, e.g.
indexing: 233/1000
The denominator is reset to zero every time the queue goes idle.
The protocol is fairly complicated here (requires creating a remote "progress"
resource before sending updates). We implement the full protocol, but I've added
an extension allowing it to be skipped to reduce the burden on clients - in
particular the lit test takes this shortcut.
The addition of background index progress to DiagnosticConsumer seems ridiculous
at first glance, but I believe that interface is trending in the direction of
"ClangdServer callbacks" anyway. It's due for a rename, but otherwise actually
fits.
Reviewers: kadircet, usaxena95
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D73218
2020-01-23 02:41:45 +08:00
|
|
|
BackgroundIndexProgressState = BackgroundIndexProgress::Empty;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
switch (BackgroundIndexProgressState) {
|
|
|
|
case BackgroundIndexProgress::Unsupported:
|
|
|
|
return;
|
|
|
|
case BackgroundIndexProgress::Creating:
|
|
|
|
// Cache this update for when the progress bar is available.
|
|
|
|
PendingBackgroundIndexProgress = Stats;
|
|
|
|
return;
|
|
|
|
case BackgroundIndexProgress::Empty: {
|
|
|
|
if (BackgroundIndexSkipCreate) {
|
|
|
|
NotifyProgress(Stats);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Cache this update for when the progress bar is available.
|
|
|
|
PendingBackgroundIndexProgress = Stats;
|
|
|
|
BackgroundIndexProgressState = BackgroundIndexProgress::Creating;
|
|
|
|
WorkDoneProgressCreateParams CreateRequest;
|
|
|
|
CreateRequest.token = ProgressToken;
|
2021-02-15 17:41:38 +08:00
|
|
|
CreateWorkDoneProgress(
|
|
|
|
CreateRequest,
|
[clangd] Show background index status using LSP 3.15 work-done progress notifications
Summary:
It simply shows the completed/total items on the background queue, e.g.
indexing: 233/1000
The denominator is reset to zero every time the queue goes idle.
The protocol is fairly complicated here (requires creating a remote "progress"
resource before sending updates). We implement the full protocol, but I've added
an extension allowing it to be skipped to reduce the burden on clients - in
particular the lit test takes this shortcut.
The addition of background index progress to DiagnosticConsumer seems ridiculous
at first glance, but I believe that interface is trending in the direction of
"ClangdServer callbacks" anyway. It's due for a rename, but otherwise actually
fits.
Reviewers: kadircet, usaxena95
Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, jfb, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D73218
2020-01-23 02:41:45 +08:00
|
|
|
[this, NotifyProgress](llvm::Expected<std::nullptr_t> E) {
|
|
|
|
std::lock_guard<std::mutex> Lock(BackgroundIndexProgressMutex);
|
|
|
|
if (E) {
|
|
|
|
NotifyProgress(this->PendingBackgroundIndexProgress);
|
|
|
|
} else {
|
|
|
|
elog("Failed to create background index progress bar: {0}",
|
|
|
|
E.takeError());
|
|
|
|
// give up forever rather than thrashing about
|
|
|
|
BackgroundIndexProgressState = BackgroundIndexProgress::Unsupported;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BackgroundIndexProgress::Live:
|
|
|
|
NotifyProgress(Stats);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-20 23:39:12 +08:00
|
|
|
void ClangdLSPServer::onFileUpdated(PathRef File, const TUStatus &Status) {
|
|
|
|
if (!SupportFileStatus)
|
|
|
|
return;
|
|
|
|
// FIXME: we don't emit "BuildingFile" and `RunningAction`, as these
|
|
|
|
// two statuses are running faster in practice, which leads the UI constantly
|
|
|
|
// changing, and doesn't provide much value. We may want to emit status at a
|
|
|
|
// reasonable time interval (e.g. 0.5s).
|
2020-03-18 02:08:23 +08:00
|
|
|
if (Status.PreambleActivity == PreambleAction::Idle &&
|
|
|
|
(Status.ASTActivity.K == ASTAction::Building ||
|
|
|
|
Status.ASTActivity.K == ASTAction::RunningAction))
|
2018-12-20 23:39:12 +08:00
|
|
|
return;
|
2021-02-15 17:41:38 +08:00
|
|
|
NotifyFileStatus(Status.render(File));
|
2018-12-20 23:39:12 +08:00
|
|
|
}
|
|
|
|
|
2021-02-26 21:44:01 +08:00
|
|
|
void ClangdLSPServer::onSemanticsMaybeChanged(PathRef File) {
|
|
|
|
if (SemanticTokensRefresh) {
|
|
|
|
SemanticTokensRefresh(NoParams{}, [](llvm::Expected<std::nullptr_t> E) {
|
|
|
|
if (E)
|
|
|
|
return;
|
|
|
|
elog("Failed to refresh semantic tokens: {0}", E.takeError());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2018-10-20 23:30:37 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|