ClangdLSPServer.h
10.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//===--- ClangdLSPServer.h - LSP server --------------------------*- C++-*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
#include "ClangdServer.h"
#include "Context.h"
#include "DraftStore.h"
#include "Features.inc"
#include "FindSymbols.h"
#include "GlobalCompilationDatabase.h"
#include "Path.h"
#include "Protocol.h"
#include "Transport.h"
#include "clang/Tooling/Core/Replacement.h"
#include "llvm/ADT/Optional.h"
#include <memory>
namespace clang {
namespace clangd {
class SymbolIndex;
/// This class exposes ClangdServer's capabilities via Language Server Protocol.
///
/// MessageHandler binds the implemented LSP methods (e.g. onInitialize) to
/// corresponding JSON-RPC methods ("initialize").
/// The server also supports $/cancelRequest (MessageHandler provides this).
class ClangdLSPServer : private DiagnosticsConsumer {
public:
/// If \p CompileCommandsDir has a value, compile_commands.json will be
/// loaded only from \p CompileCommandsDir. Otherwise, clangd will look
/// for compile_commands.json in all parent directories of each file.
/// If UseDirBasedCDB is false, compile commands are not read from disk.
// FIXME: Clean up signature around CDBs.
ClangdLSPServer(Transport &Transp, const FileSystemProvider &FSProvider,
const clangd::CodeCompleteOptions &CCOpts,
llvm::Optional<Path> CompileCommandsDir, bool UseDirBasedCDB,
llvm::Optional<OffsetEncoding> ForcedOffsetEncoding,
const ClangdServer::Options &Opts);
/// The destructor blocks on any outstanding background tasks.
~ClangdLSPServer();
/// Run LSP server loop, communicating with the Transport provided in the
/// constructor. This method must not be executed more than once.
///
/// \return Whether we shut down cleanly with a 'shutdown' -> 'exit' sequence.
bool run();
private:
// Implement DiagnosticsConsumer.
void onDiagnosticsReady(PathRef File, std::vector<Diag> Diagnostics) override;
void onFileUpdated(PathRef File, const TUStatus &Status) override;
void
onHighlightingsReady(PathRef File,
std::vector<HighlightingToken> Highlightings) override;
// LSP methods. Notifications have signature void(const Params&).
// Calls have signature void(const Params&, Callback<Response>).
void onInitialize(const InitializeParams &, Callback<llvm::json::Value>);
void onShutdown(const ShutdownParams &, Callback<std::nullptr_t>);
void onSync(const NoParams &, Callback<std::nullptr_t>);
void onDocumentDidOpen(const DidOpenTextDocumentParams &);
void onDocumentDidChange(const DidChangeTextDocumentParams &);
void onDocumentDidClose(const DidCloseTextDocumentParams &);
void onDocumentOnTypeFormatting(const DocumentOnTypeFormattingParams &,
Callback<std::vector<TextEdit>>);
void onDocumentRangeFormatting(const DocumentRangeFormattingParams &,
Callback<std::vector<TextEdit>>);
void onDocumentFormatting(const DocumentFormattingParams &,
Callback<std::vector<TextEdit>>);
// The results are serialized 'vector<DocumentSymbol>' if
// SupportsHierarchicalDocumentSymbol is true and 'vector<SymbolInformation>'
// otherwise.
void onDocumentSymbol(const DocumentSymbolParams &,
Callback<llvm::json::Value>);
void onCodeAction(const CodeActionParams &, Callback<llvm::json::Value>);
void onCompletion(const CompletionParams &, Callback<CompletionList>);
void onSignatureHelp(const TextDocumentPositionParams &,
Callback<SignatureHelp>);
void onGoToDeclaration(const TextDocumentPositionParams &,
Callback<std::vector<Location>>);
void onGoToDefinition(const TextDocumentPositionParams &,
Callback<std::vector<Location>>);
void onReference(const ReferenceParams &, Callback<std::vector<Location>>);
void onSwitchSourceHeader(const TextDocumentIdentifier &,
Callback<llvm::Optional<URIForFile>>);
void onDocumentHighlight(const TextDocumentPositionParams &,
Callback<std::vector<DocumentHighlight>>);
void onFileEvent(const DidChangeWatchedFilesParams &);
void onCommand(const ExecuteCommandParams &, Callback<llvm::json::Value>);
void onWorkspaceSymbol(const WorkspaceSymbolParams &,
Callback<std::vector<SymbolInformation>>);
void onPrepareRename(const TextDocumentPositionParams &,
Callback<llvm::Optional<Range>>);
void onRename(const RenameParams &, Callback<WorkspaceEdit>);
void onHover(const TextDocumentPositionParams &,
Callback<llvm::Optional<Hover>>);
void onTypeHierarchy(const TypeHierarchyParams &,
Callback<llvm::Optional<TypeHierarchyItem>>);
void onResolveTypeHierarchy(const ResolveTypeHierarchyItemParams &,
Callback<llvm::Optional<TypeHierarchyItem>>);
void onChangeConfiguration(const DidChangeConfigurationParams &);
void onSymbolInfo(const TextDocumentPositionParams &,
Callback<std::vector<SymbolDetails>>);
void onSelectionRange(const SelectionRangeParams &,
Callback<std::vector<SelectionRange>>);
void onDocumentLink(const DocumentLinkParams &,
Callback<std::vector<DocumentLink>>);
std::vector<Fix> getFixes(StringRef File, const clangd::Diagnostic &D);
/// Checks if completion request should be ignored. We need this due to the
/// limitation of the LSP. Per LSP, a client sends requests for all "trigger
/// character" we specify, but for '>' and ':' we need to check they actually
/// produce '->' and '::', respectively.
bool shouldRunCompletion(const CompletionParams &Params) const;
/// Forces a reparse of all currently opened files. As a result, this method
/// may be very expensive. This method is normally called when the
/// compilation database is changed.
void reparseOpenedFiles();
void applyConfiguration(const ConfigurationSettings &Settings);
/// Sends a "publishSemanticHighlighting" notification to the LSP client.
void publishSemanticHighlighting(SemanticHighlightingParams Params);
/// Sends a "publishDiagnostics" notification to the LSP client.
void publishDiagnostics(const URIForFile &File,
std::vector<clangd::Diagnostic> Diagnostics);
/// Since initialization of CDBs and ClangdServer is done lazily, the
/// following context captures the one used while creating ClangdLSPServer and
/// passes it to above mentioned object instances to make sure they share the
/// same state.
Context BackgroundContext;
/// Used to indicate that the 'shutdown' request was received from the
/// Language Server client.
bool ShutdownRequestReceived = false;
/// Used to indicate the ClangdLSPServer is being destroyed.
std::atomic<bool> IsBeingDestroyed = {false};
std::mutex FixItsMutex;
typedef std::map<clangd::Diagnostic, std::vector<Fix>, LSPDiagnosticCompare>
DiagnosticToReplacementMap;
/// Caches FixIts per file and diagnostics
llvm::StringMap<DiagnosticToReplacementMap> FixItsMap;
std::mutex HighlightingsMutex;
llvm::StringMap<std::vector<HighlightingToken>> FileToHighlightings;
// Most code should not deal with Transport directly.
// MessageHandler deals with incoming messages, use call() etc for outgoing.
clangd::Transport &Transp;
class MessageHandler;
std::unique_ptr<MessageHandler> MsgHandler;
std::mutex TranspWriter;
template <typename Response>
void call(StringRef Method, llvm::json::Value Params, Callback<Response> CB) {
// Wrap the callback with LSP conversion and error-handling.
auto HandleReply =
[CB = std::move(CB), Ctx = Context::current().clone()](
llvm::Expected<llvm::json::Value> RawResponse) mutable {
Response Rsp;
if (!RawResponse) {
CB(RawResponse.takeError());
} else if (fromJSON(*RawResponse, Rsp)) {
CB(std::move(Rsp));
} else {
elog("Failed to decode {0} response", *RawResponse);
CB(llvm::make_error<LSPError>("failed to decode reponse",
ErrorCode::InvalidParams));
}
};
callRaw(Method, std::move(Params), std::move(HandleReply));
}
void callRaw(StringRef Method, llvm::json::Value Params,
Callback<llvm::json::Value> CB);
void notify(StringRef Method, llvm::json::Value Params);
const FileSystemProvider &FSProvider;
/// Options used for code completion
clangd::CodeCompleteOptions CCOpts;
/// Options used for diagnostics.
ClangdDiagnosticOptions DiagOpts;
/// The supported kinds of the client.
SymbolKindBitset SupportedSymbolKinds;
/// The supported completion item kinds of the client.
CompletionItemKindBitset SupportedCompletionItemKinds;
/// Whether the client supports CodeAction response objects.
bool SupportsCodeAction = false;
/// From capabilities of textDocument/documentSymbol.
bool SupportsHierarchicalDocumentSymbol = false;
/// Whether the client supports showing file status.
bool SupportFileStatus = false;
/// Which kind of markup should we use in textDocument/hover responses.
MarkupKind HoverContentFormat = MarkupKind::PlainText;
/// Whether the client supports offsets for parameter info labels.
bool SupportsOffsetsInSignatureHelp = false;
// Store of the current versions of the open documents.
DraftStore DraftMgr;
// The CDB is created by the "initialize" LSP method.
bool UseDirBasedCDB; // FIXME: make this a capability.
llvm::Optional<Path> CompileCommandsDir; // FIXME: merge with capability?
std::unique_ptr<GlobalCompilationDatabase> BaseCDB;
// CDB is BaseCDB plus any commands overridden via LSP extensions.
llvm::Optional<OverlayCDB> CDB;
ClangdServer::Options ClangdServerOpts;
llvm::Optional<OffsetEncoding> NegotiatedOffsetEncoding;
// The ClangdServer is created by the "initialize" LSP method.
llvm::Optional<ClangdServer> Server;
};
} // namespace clangd
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H