annotate clang-tools-extra/clangd/ClangdLSPServer.cpp @ 180:680fa57a2f20

fix compile errors.
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sat, 30 May 2020 17:44:06 +0900
parents 0572611fdcc8
children 2e18cbf3894f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===--- ClangdLSPServer.cpp - LSP server ------------------------*- C++-*-===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8
anatofuz
parents:
diff changeset
9 #include "ClangdLSPServer.h"
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
10 #include "CodeComplete.h"
150
anatofuz
parents:
diff changeset
11 #include "Diagnostics.h"
anatofuz
parents:
diff changeset
12 #include "DraftStore.h"
anatofuz
parents:
diff changeset
13 #include "GlobalCompilationDatabase.h"
anatofuz
parents:
diff changeset
14 #include "Protocol.h"
anatofuz
parents:
diff changeset
15 #include "SemanticHighlighting.h"
anatofuz
parents:
diff changeset
16 #include "SourceCode.h"
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
17 #include "TUScheduler.h"
150
anatofuz
parents:
diff changeset
18 #include "URI.h"
anatofuz
parents:
diff changeset
19 #include "refactor/Tweak.h"
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
20 #include "support/Context.h"
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
21 #include "support/Trace.h"
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
22 #include "clang/Basic/Version.h"
150
anatofuz
parents:
diff changeset
23 #include "clang/Tooling/Core/Replacement.h"
anatofuz
parents:
diff changeset
24 #include "llvm/ADT/ArrayRef.h"
anatofuz
parents:
diff changeset
25 #include "llvm/ADT/Optional.h"
anatofuz
parents:
diff changeset
26 #include "llvm/ADT/ScopeExit.h"
anatofuz
parents:
diff changeset
27 #include "llvm/ADT/StringRef.h"
anatofuz
parents:
diff changeset
28 #include "llvm/ADT/iterator_range.h"
anatofuz
parents:
diff changeset
29 #include "llvm/Support/Errc.h"
anatofuz
parents:
diff changeset
30 #include "llvm/Support/Error.h"
anatofuz
parents:
diff changeset
31 #include "llvm/Support/FormatVariadic.h"
anatofuz
parents:
diff changeset
32 #include "llvm/Support/JSON.h"
anatofuz
parents:
diff changeset
33 #include "llvm/Support/Path.h"
anatofuz
parents:
diff changeset
34 #include "llvm/Support/SHA1.h"
anatofuz
parents:
diff changeset
35 #include "llvm/Support/ScopedPrinter.h"
anatofuz
parents:
diff changeset
36 #include <cstddef>
anatofuz
parents:
diff changeset
37 #include <memory>
anatofuz
parents:
diff changeset
38 #include <mutex>
anatofuz
parents:
diff changeset
39 #include <string>
anatofuz
parents:
diff changeset
40 #include <vector>
anatofuz
parents:
diff changeset
41
anatofuz
parents:
diff changeset
42 namespace clang {
anatofuz
parents:
diff changeset
43 namespace clangd {
anatofuz
parents:
diff changeset
44 namespace {
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
45
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
46 // Tracks end-to-end latency of high level lsp calls. Measurements are in
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
47 // seconds.
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
48 constexpr trace::Metric LSPLatency("lsp_latency", trace::Metric::Distribution,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
49 "method_name");
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
50
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
51 // LSP defines file versions as numbers that increase.
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
52 // ClangdServer treats them as opaque and therefore uses strings instead.
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
53 std::string encodeVersion(int64_t LSPVersion) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
54 return llvm::to_string(LSPVersion);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
55 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
56 llvm::Optional<int64_t> decodeVersion(llvm::StringRef Encoded) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
57 int64_t Result;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
58 if (llvm::to_integer(Encoded, Result, 10))
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
59 return Result;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
60 else if (!Encoded.empty()) // Empty can be e.g. diagnostics on close.
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
61 elog("unexpected non-numeric version {0}", Encoded);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
62 return llvm::None;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
63 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
64
150
anatofuz
parents:
diff changeset
65 /// Transforms a tweak into a code action that would apply it if executed.
anatofuz
parents:
diff changeset
66 /// EXPECTS: T.prepare() was called and returned true.
anatofuz
parents:
diff changeset
67 CodeAction toCodeAction(const ClangdServer::TweakRef &T, const URIForFile &File,
anatofuz
parents:
diff changeset
68 Range Selection) {
anatofuz
parents:
diff changeset
69 CodeAction CA;
anatofuz
parents:
diff changeset
70 CA.title = T.Title;
anatofuz
parents:
diff changeset
71 switch (T.Intent) {
anatofuz
parents:
diff changeset
72 case Tweak::Refactor:
anatofuz
parents:
diff changeset
73 CA.kind = std::string(CodeAction::REFACTOR_KIND);
anatofuz
parents:
diff changeset
74 break;
anatofuz
parents:
diff changeset
75 case Tweak::Info:
anatofuz
parents:
diff changeset
76 CA.kind = std::string(CodeAction::INFO_KIND);
anatofuz
parents:
diff changeset
77 break;
anatofuz
parents:
diff changeset
78 }
anatofuz
parents:
diff changeset
79 // This tweak may have an expensive second stage, we only run it if the user
anatofuz
parents:
diff changeset
80 // actually chooses it in the UI. We reply with a command that would run the
anatofuz
parents:
diff changeset
81 // corresponding tweak.
anatofuz
parents:
diff changeset
82 // FIXME: for some tweaks, computing the edits is cheap and we could send them
anatofuz
parents:
diff changeset
83 // directly.
anatofuz
parents:
diff changeset
84 CA.command.emplace();
anatofuz
parents:
diff changeset
85 CA.command->title = T.Title;
anatofuz
parents:
diff changeset
86 CA.command->command = std::string(Command::CLANGD_APPLY_TWEAK);
anatofuz
parents:
diff changeset
87 CA.command->tweakArgs.emplace();
anatofuz
parents:
diff changeset
88 CA.command->tweakArgs->file = File;
anatofuz
parents:
diff changeset
89 CA.command->tweakArgs->tweakID = T.ID;
anatofuz
parents:
diff changeset
90 CA.command->tweakArgs->selection = Selection;
anatofuz
parents:
diff changeset
91 return CA;
anatofuz
parents:
diff changeset
92 }
anatofuz
parents:
diff changeset
93
anatofuz
parents:
diff changeset
94 void adjustSymbolKinds(llvm::MutableArrayRef<DocumentSymbol> Syms,
anatofuz
parents:
diff changeset
95 SymbolKindBitset Kinds) {
anatofuz
parents:
diff changeset
96 for (auto &S : Syms) {
anatofuz
parents:
diff changeset
97 S.kind = adjustKindToCapability(S.kind, Kinds);
anatofuz
parents:
diff changeset
98 adjustSymbolKinds(S.children, Kinds);
anatofuz
parents:
diff changeset
99 }
anatofuz
parents:
diff changeset
100 }
anatofuz
parents:
diff changeset
101
anatofuz
parents:
diff changeset
102 SymbolKindBitset defaultSymbolKinds() {
anatofuz
parents:
diff changeset
103 SymbolKindBitset Defaults;
anatofuz
parents:
diff changeset
104 for (size_t I = SymbolKindMin; I <= static_cast<size_t>(SymbolKind::Array);
anatofuz
parents:
diff changeset
105 ++I)
anatofuz
parents:
diff changeset
106 Defaults.set(I);
anatofuz
parents:
diff changeset
107 return Defaults;
anatofuz
parents:
diff changeset
108 }
anatofuz
parents:
diff changeset
109
anatofuz
parents:
diff changeset
110 CompletionItemKindBitset defaultCompletionItemKinds() {
anatofuz
parents:
diff changeset
111 CompletionItemKindBitset Defaults;
anatofuz
parents:
diff changeset
112 for (size_t I = CompletionItemKindMin;
anatofuz
parents:
diff changeset
113 I <= static_cast<size_t>(CompletionItemKind::Reference); ++I)
anatofuz
parents:
diff changeset
114 Defaults.set(I);
anatofuz
parents:
diff changeset
115 return Defaults;
anatofuz
parents:
diff changeset
116 }
anatofuz
parents:
diff changeset
117
anatofuz
parents:
diff changeset
118 // Build a lookup table (HighlightingKind => {TextMate Scopes}), which is sent
anatofuz
parents:
diff changeset
119 // to the LSP client.
anatofuz
parents:
diff changeset
120 std::vector<std::vector<std::string>> buildHighlightScopeLookupTable() {
anatofuz
parents:
diff changeset
121 std::vector<std::vector<std::string>> LookupTable;
anatofuz
parents:
diff changeset
122 // HighlightingKind is using as the index.
anatofuz
parents:
diff changeset
123 for (int KindValue = 0; KindValue <= (int)HighlightingKind::LastKind;
anatofuz
parents:
diff changeset
124 ++KindValue)
anatofuz
parents:
diff changeset
125 LookupTable.push_back(
anatofuz
parents:
diff changeset
126 {std::string(toTextMateScope((HighlightingKind)(KindValue)))});
anatofuz
parents:
diff changeset
127 return LookupTable;
anatofuz
parents:
diff changeset
128 }
anatofuz
parents:
diff changeset
129
anatofuz
parents:
diff changeset
130 // Makes sure edits in \p FE are applicable to latest file contents reported by
anatofuz
parents:
diff changeset
131 // editor. If not generates an error message containing information about files
anatofuz
parents:
diff changeset
132 // that needs to be saved.
anatofuz
parents:
diff changeset
133 llvm::Error validateEdits(const DraftStore &DraftMgr, const FileEdits &FE) {
anatofuz
parents:
diff changeset
134 size_t InvalidFileCount = 0;
anatofuz
parents:
diff changeset
135 llvm::StringRef LastInvalidFile;
anatofuz
parents:
diff changeset
136 for (const auto &It : FE) {
anatofuz
parents:
diff changeset
137 if (auto Draft = DraftMgr.getDraft(It.first())) {
anatofuz
parents:
diff changeset
138 // If the file is open in user's editor, make sure the version we
anatofuz
parents:
diff changeset
139 // saw and current version are compatible as this is the text that
anatofuz
parents:
diff changeset
140 // will be replaced by editors.
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
141 if (!It.second.canApplyTo(Draft->Contents)) {
150
anatofuz
parents:
diff changeset
142 ++InvalidFileCount;
anatofuz
parents:
diff changeset
143 LastInvalidFile = It.first();
anatofuz
parents:
diff changeset
144 }
anatofuz
parents:
diff changeset
145 }
anatofuz
parents:
diff changeset
146 }
anatofuz
parents:
diff changeset
147 if (!InvalidFileCount)
anatofuz
parents:
diff changeset
148 return llvm::Error::success();
anatofuz
parents:
diff changeset
149 if (InvalidFileCount == 1)
anatofuz
parents:
diff changeset
150 return llvm::createStringError(llvm::inconvertibleErrorCode(),
anatofuz
parents:
diff changeset
151 "File must be saved first: " +
anatofuz
parents:
diff changeset
152 LastInvalidFile);
anatofuz
parents:
diff changeset
153 return llvm::createStringError(
anatofuz
parents:
diff changeset
154 llvm::inconvertibleErrorCode(),
anatofuz
parents:
diff changeset
155 "Files must be saved first: " + LastInvalidFile + " (and " +
anatofuz
parents:
diff changeset
156 llvm::to_string(InvalidFileCount - 1) + " others)");
anatofuz
parents:
diff changeset
157 }
anatofuz
parents:
diff changeset
158
anatofuz
parents:
diff changeset
159 } // namespace
anatofuz
parents:
diff changeset
160
anatofuz
parents:
diff changeset
161 // MessageHandler dispatches incoming LSP messages.
anatofuz
parents:
diff changeset
162 // It handles cross-cutting concerns:
anatofuz
parents:
diff changeset
163 // - serializes/deserializes protocol objects to JSON
anatofuz
parents:
diff changeset
164 // - logging of inbound messages
anatofuz
parents:
diff changeset
165 // - cancellation handling
anatofuz
parents:
diff changeset
166 // - basic call tracing
anatofuz
parents:
diff changeset
167 // MessageHandler ensures that initialize() is called before any other handler.
anatofuz
parents:
diff changeset
168 class ClangdLSPServer::MessageHandler : public Transport::MessageHandler {
anatofuz
parents:
diff changeset
169 public:
anatofuz
parents:
diff changeset
170 MessageHandler(ClangdLSPServer &Server) : Server(Server) {}
anatofuz
parents:
diff changeset
171
anatofuz
parents:
diff changeset
172 bool onNotify(llvm::StringRef Method, llvm::json::Value Params) override {
anatofuz
parents:
diff changeset
173 WithContext HandlerContext(handlerContext());
anatofuz
parents:
diff changeset
174 log("<-- {0}", Method);
anatofuz
parents:
diff changeset
175 if (Method == "exit")
anatofuz
parents:
diff changeset
176 return false;
anatofuz
parents:
diff changeset
177 if (!Server.Server)
anatofuz
parents:
diff changeset
178 elog("Notification {0} before initialization", Method);
anatofuz
parents:
diff changeset
179 else if (Method == "$/cancelRequest")
anatofuz
parents:
diff changeset
180 onCancel(std::move(Params));
anatofuz
parents:
diff changeset
181 else if (auto Handler = Notifications.lookup(Method))
anatofuz
parents:
diff changeset
182 Handler(std::move(Params));
anatofuz
parents:
diff changeset
183 else
anatofuz
parents:
diff changeset
184 log("unhandled notification {0}", Method);
anatofuz
parents:
diff changeset
185 return true;
anatofuz
parents:
diff changeset
186 }
anatofuz
parents:
diff changeset
187
anatofuz
parents:
diff changeset
188 bool onCall(llvm::StringRef Method, llvm::json::Value Params,
anatofuz
parents:
diff changeset
189 llvm::json::Value ID) override {
anatofuz
parents:
diff changeset
190 WithContext HandlerContext(handlerContext());
anatofuz
parents:
diff changeset
191 // Calls can be canceled by the client. Add cancellation context.
anatofuz
parents:
diff changeset
192 WithContext WithCancel(cancelableRequestContext(ID));
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
193 trace::Span Tracer(Method, LSPLatency);
150
anatofuz
parents:
diff changeset
194 SPAN_ATTACH(Tracer, "Params", Params);
anatofuz
parents:
diff changeset
195 ReplyOnce Reply(ID, Method, &Server, Tracer.Args);
anatofuz
parents:
diff changeset
196 log("<-- {0}({1})", Method, ID);
anatofuz
parents:
diff changeset
197 if (!Server.Server && Method != "initialize") {
anatofuz
parents:
diff changeset
198 elog("Call {0} before initialization.", Method);
anatofuz
parents:
diff changeset
199 Reply(llvm::make_error<LSPError>("server not initialized",
anatofuz
parents:
diff changeset
200 ErrorCode::ServerNotInitialized));
anatofuz
parents:
diff changeset
201 } else if (auto Handler = Calls.lookup(Method))
anatofuz
parents:
diff changeset
202 Handler(std::move(Params), std::move(Reply));
anatofuz
parents:
diff changeset
203 else
anatofuz
parents:
diff changeset
204 Reply(llvm::make_error<LSPError>("method not found",
anatofuz
parents:
diff changeset
205 ErrorCode::MethodNotFound));
anatofuz
parents:
diff changeset
206 return true;
anatofuz
parents:
diff changeset
207 }
anatofuz
parents:
diff changeset
208
anatofuz
parents:
diff changeset
209 bool onReply(llvm::json::Value ID,
anatofuz
parents:
diff changeset
210 llvm::Expected<llvm::json::Value> Result) override {
anatofuz
parents:
diff changeset
211 WithContext HandlerContext(handlerContext());
anatofuz
parents:
diff changeset
212
anatofuz
parents:
diff changeset
213 Callback<llvm::json::Value> ReplyHandler = nullptr;
anatofuz
parents:
diff changeset
214 if (auto IntID = ID.getAsInteger()) {
anatofuz
parents:
diff changeset
215 std::lock_guard<std::mutex> Mutex(CallMutex);
anatofuz
parents:
diff changeset
216 // Find a corresponding callback for the request ID;
anatofuz
parents:
diff changeset
217 for (size_t Index = 0; Index < ReplyCallbacks.size(); ++Index) {
anatofuz
parents:
diff changeset
218 if (ReplyCallbacks[Index].first == *IntID) {
anatofuz
parents:
diff changeset
219 ReplyHandler = std::move(ReplyCallbacks[Index].second);
anatofuz
parents:
diff changeset
220 ReplyCallbacks.erase(ReplyCallbacks.begin() +
anatofuz
parents:
diff changeset
221 Index); // remove the entry
anatofuz
parents:
diff changeset
222 break;
anatofuz
parents:
diff changeset
223 }
anatofuz
parents:
diff changeset
224 }
anatofuz
parents:
diff changeset
225 }
anatofuz
parents:
diff changeset
226
anatofuz
parents:
diff changeset
227 if (!ReplyHandler) {
anatofuz
parents:
diff changeset
228 // No callback being found, use a default log callback.
anatofuz
parents:
diff changeset
229 ReplyHandler = [&ID](llvm::Expected<llvm::json::Value> Result) {
anatofuz
parents:
diff changeset
230 elog("received a reply with ID {0}, but there was no such call", ID);
anatofuz
parents:
diff changeset
231 if (!Result)
anatofuz
parents:
diff changeset
232 llvm::consumeError(Result.takeError());
anatofuz
parents:
diff changeset
233 };
anatofuz
parents:
diff changeset
234 }
anatofuz
parents:
diff changeset
235
anatofuz
parents:
diff changeset
236 // Log and run the reply handler.
anatofuz
parents:
diff changeset
237 if (Result) {
anatofuz
parents:
diff changeset
238 log("<-- reply({0})", ID);
anatofuz
parents:
diff changeset
239 ReplyHandler(std::move(Result));
anatofuz
parents:
diff changeset
240 } else {
anatofuz
parents:
diff changeset
241 auto Err = Result.takeError();
anatofuz
parents:
diff changeset
242 log("<-- reply({0}) error: {1}", ID, Err);
anatofuz
parents:
diff changeset
243 ReplyHandler(std::move(Err));
anatofuz
parents:
diff changeset
244 }
anatofuz
parents:
diff changeset
245 return true;
anatofuz
parents:
diff changeset
246 }
anatofuz
parents:
diff changeset
247
anatofuz
parents:
diff changeset
248 // Bind an LSP method name to a call.
anatofuz
parents:
diff changeset
249 template <typename Param, typename Result>
anatofuz
parents:
diff changeset
250 void bind(const char *Method,
anatofuz
parents:
diff changeset
251 void (ClangdLSPServer::*Handler)(const Param &, Callback<Result>)) {
anatofuz
parents:
diff changeset
252 Calls[Method] = [Method, Handler, this](llvm::json::Value RawParams,
anatofuz
parents:
diff changeset
253 ReplyOnce Reply) {
anatofuz
parents:
diff changeset
254 Param P;
anatofuz
parents:
diff changeset
255 if (fromJSON(RawParams, P)) {
anatofuz
parents:
diff changeset
256 (Server.*Handler)(P, std::move(Reply));
anatofuz
parents:
diff changeset
257 } else {
anatofuz
parents:
diff changeset
258 elog("Failed to decode {0} request.", Method);
anatofuz
parents:
diff changeset
259 Reply(llvm::make_error<LSPError>("failed to decode request",
anatofuz
parents:
diff changeset
260 ErrorCode::InvalidRequest));
anatofuz
parents:
diff changeset
261 }
anatofuz
parents:
diff changeset
262 };
anatofuz
parents:
diff changeset
263 }
anatofuz
parents:
diff changeset
264
anatofuz
parents:
diff changeset
265 // Bind a reply callback to a request. The callback will be invoked when
anatofuz
parents:
diff changeset
266 // clangd receives the reply from the LSP client.
anatofuz
parents:
diff changeset
267 // Return a call id of the request.
anatofuz
parents:
diff changeset
268 llvm::json::Value bindReply(Callback<llvm::json::Value> Reply) {
anatofuz
parents:
diff changeset
269 llvm::Optional<std::pair<int, Callback<llvm::json::Value>>> OldestCB;
anatofuz
parents:
diff changeset
270 int ID;
anatofuz
parents:
diff changeset
271 {
anatofuz
parents:
diff changeset
272 std::lock_guard<std::mutex> Mutex(CallMutex);
anatofuz
parents:
diff changeset
273 ID = NextCallID++;
anatofuz
parents:
diff changeset
274 ReplyCallbacks.emplace_back(ID, std::move(Reply));
anatofuz
parents:
diff changeset
275
anatofuz
parents:
diff changeset
276 // If the queue overflows, we assume that the client didn't reply the
anatofuz
parents:
diff changeset
277 // oldest request, and run the corresponding callback which replies an
anatofuz
parents:
diff changeset
278 // error to the client.
anatofuz
parents:
diff changeset
279 if (ReplyCallbacks.size() > MaxReplayCallbacks) {
anatofuz
parents:
diff changeset
280 elog("more than {0} outstanding LSP calls, forgetting about {1}",
anatofuz
parents:
diff changeset
281 MaxReplayCallbacks, ReplyCallbacks.front().first);
anatofuz
parents:
diff changeset
282 OldestCB = std::move(ReplyCallbacks.front());
anatofuz
parents:
diff changeset
283 ReplyCallbacks.pop_front();
anatofuz
parents:
diff changeset
284 }
anatofuz
parents:
diff changeset
285 }
anatofuz
parents:
diff changeset
286 if (OldestCB)
anatofuz
parents:
diff changeset
287 OldestCB->second(llvm::createStringError(
anatofuz
parents:
diff changeset
288 llvm::inconvertibleErrorCode(),
anatofuz
parents:
diff changeset
289 llvm::formatv("failed to receive a client reply for request ({0})",
anatofuz
parents:
diff changeset
290 OldestCB->first)));
anatofuz
parents:
diff changeset
291 return ID;
anatofuz
parents:
diff changeset
292 }
anatofuz
parents:
diff changeset
293
anatofuz
parents:
diff changeset
294 // Bind an LSP method name to a notification.
anatofuz
parents:
diff changeset
295 template <typename Param>
anatofuz
parents:
diff changeset
296 void bind(const char *Method,
anatofuz
parents:
diff changeset
297 void (ClangdLSPServer::*Handler)(const Param &)) {
anatofuz
parents:
diff changeset
298 Notifications[Method] = [Method, Handler,
anatofuz
parents:
diff changeset
299 this](llvm::json::Value RawParams) {
anatofuz
parents:
diff changeset
300 Param P;
anatofuz
parents:
diff changeset
301 if (!fromJSON(RawParams, P)) {
anatofuz
parents:
diff changeset
302 elog("Failed to decode {0} request.", Method);
anatofuz
parents:
diff changeset
303 return;
anatofuz
parents:
diff changeset
304 }
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
305 trace::Span Tracer(Method, LSPLatency);
150
anatofuz
parents:
diff changeset
306 SPAN_ATTACH(Tracer, "Params", RawParams);
anatofuz
parents:
diff changeset
307 (Server.*Handler)(P);
anatofuz
parents:
diff changeset
308 };
anatofuz
parents:
diff changeset
309 }
anatofuz
parents:
diff changeset
310
anatofuz
parents:
diff changeset
311 private:
anatofuz
parents:
diff changeset
312 // Function object to reply to an LSP call.
anatofuz
parents:
diff changeset
313 // Each instance must be called exactly once, otherwise:
anatofuz
parents:
diff changeset
314 // - the bug is logged, and (in debug mode) an assert will fire
anatofuz
parents:
diff changeset
315 // - if there was no reply, an error reply is sent
anatofuz
parents:
diff changeset
316 // - if there were multiple replies, only the first is sent
anatofuz
parents:
diff changeset
317 class ReplyOnce {
anatofuz
parents:
diff changeset
318 std::atomic<bool> Replied = {false};
anatofuz
parents:
diff changeset
319 std::chrono::steady_clock::time_point Start;
anatofuz
parents:
diff changeset
320 llvm::json::Value ID;
anatofuz
parents:
diff changeset
321 std::string Method;
anatofuz
parents:
diff changeset
322 ClangdLSPServer *Server; // Null when moved-from.
anatofuz
parents:
diff changeset
323 llvm::json::Object *TraceArgs;
anatofuz
parents:
diff changeset
324
anatofuz
parents:
diff changeset
325 public:
anatofuz
parents:
diff changeset
326 ReplyOnce(const llvm::json::Value &ID, llvm::StringRef Method,
anatofuz
parents:
diff changeset
327 ClangdLSPServer *Server, llvm::json::Object *TraceArgs)
anatofuz
parents:
diff changeset
328 : Start(std::chrono::steady_clock::now()), ID(ID), Method(Method),
anatofuz
parents:
diff changeset
329 Server(Server), TraceArgs(TraceArgs) {
anatofuz
parents:
diff changeset
330 assert(Server);
anatofuz
parents:
diff changeset
331 }
anatofuz
parents:
diff changeset
332 ReplyOnce(ReplyOnce &&Other)
anatofuz
parents:
diff changeset
333 : Replied(Other.Replied.load()), Start(Other.Start),
anatofuz
parents:
diff changeset
334 ID(std::move(Other.ID)), Method(std::move(Other.Method)),
anatofuz
parents:
diff changeset
335 Server(Other.Server), TraceArgs(Other.TraceArgs) {
anatofuz
parents:
diff changeset
336 Other.Server = nullptr;
anatofuz
parents:
diff changeset
337 }
anatofuz
parents:
diff changeset
338 ReplyOnce &operator=(ReplyOnce &&) = delete;
anatofuz
parents:
diff changeset
339 ReplyOnce(const ReplyOnce &) = delete;
anatofuz
parents:
diff changeset
340 ReplyOnce &operator=(const ReplyOnce &) = delete;
anatofuz
parents:
diff changeset
341
anatofuz
parents:
diff changeset
342 ~ReplyOnce() {
anatofuz
parents:
diff changeset
343 // There's one legitimate reason to never reply to a request: clangd's
anatofuz
parents:
diff changeset
344 // request handler send a call to the client (e.g. applyEdit) and the
anatofuz
parents:
diff changeset
345 // client never replied. In this case, the ReplyOnce is owned by
anatofuz
parents:
diff changeset
346 // ClangdLSPServer's reply callback table and is destroyed along with the
anatofuz
parents:
diff changeset
347 // server. We don't attempt to send a reply in this case, there's little
anatofuz
parents:
diff changeset
348 // to be gained from doing so.
anatofuz
parents:
diff changeset
349 if (Server && !Server->IsBeingDestroyed && !Replied) {
anatofuz
parents:
diff changeset
350 elog("No reply to message {0}({1})", Method, ID);
anatofuz
parents:
diff changeset
351 assert(false && "must reply to all calls!");
anatofuz
parents:
diff changeset
352 (*this)(llvm::make_error<LSPError>("server failed to reply",
anatofuz
parents:
diff changeset
353 ErrorCode::InternalError));
anatofuz
parents:
diff changeset
354 }
anatofuz
parents:
diff changeset
355 }
anatofuz
parents:
diff changeset
356
anatofuz
parents:
diff changeset
357 void operator()(llvm::Expected<llvm::json::Value> Reply) {
anatofuz
parents:
diff changeset
358 assert(Server && "moved-from!");
anatofuz
parents:
diff changeset
359 if (Replied.exchange(true)) {
anatofuz
parents:
diff changeset
360 elog("Replied twice to message {0}({1})", Method, ID);
anatofuz
parents:
diff changeset
361 assert(false && "must reply to each call only once!");
anatofuz
parents:
diff changeset
362 return;
anatofuz
parents:
diff changeset
363 }
anatofuz
parents:
diff changeset
364 auto Duration = std::chrono::steady_clock::now() - Start;
anatofuz
parents:
diff changeset
365 if (Reply) {
anatofuz
parents:
diff changeset
366 log("--> reply:{0}({1}) {2:ms}", Method, ID, Duration);
anatofuz
parents:
diff changeset
367 if (TraceArgs)
anatofuz
parents:
diff changeset
368 (*TraceArgs)["Reply"] = *Reply;
anatofuz
parents:
diff changeset
369 std::lock_guard<std::mutex> Lock(Server->TranspWriter);
anatofuz
parents:
diff changeset
370 Server->Transp.reply(std::move(ID), std::move(Reply));
anatofuz
parents:
diff changeset
371 } else {
anatofuz
parents:
diff changeset
372 llvm::Error Err = Reply.takeError();
anatofuz
parents:
diff changeset
373 log("--> reply:{0}({1}) {2:ms}, error: {3}", Method, ID, Duration, Err);
anatofuz
parents:
diff changeset
374 if (TraceArgs)
anatofuz
parents:
diff changeset
375 (*TraceArgs)["Error"] = llvm::to_string(Err);
anatofuz
parents:
diff changeset
376 std::lock_guard<std::mutex> Lock(Server->TranspWriter);
anatofuz
parents:
diff changeset
377 Server->Transp.reply(std::move(ID), std::move(Err));
anatofuz
parents:
diff changeset
378 }
anatofuz
parents:
diff changeset
379 }
anatofuz
parents:
diff changeset
380 };
anatofuz
parents:
diff changeset
381
anatofuz
parents:
diff changeset
382 llvm::StringMap<std::function<void(llvm::json::Value)>> Notifications;
anatofuz
parents:
diff changeset
383 llvm::StringMap<std::function<void(llvm::json::Value, ReplyOnce)>> Calls;
anatofuz
parents:
diff changeset
384
anatofuz
parents:
diff changeset
385 // Method calls may be cancelled by ID, so keep track of their state.
anatofuz
parents:
diff changeset
386 // This needs a mutex: handlers may finish on a different thread, and that's
anatofuz
parents:
diff changeset
387 // when we clean up entries in the map.
anatofuz
parents:
diff changeset
388 mutable std::mutex RequestCancelersMutex;
anatofuz
parents:
diff changeset
389 llvm::StringMap<std::pair<Canceler, /*Cookie*/ unsigned>> RequestCancelers;
anatofuz
parents:
diff changeset
390 unsigned NextRequestCookie = 0; // To disambiguate reused IDs, see below.
anatofuz
parents:
diff changeset
391 void onCancel(const llvm::json::Value &Params) {
anatofuz
parents:
diff changeset
392 const llvm::json::Value *ID = nullptr;
anatofuz
parents:
diff changeset
393 if (auto *O = Params.getAsObject())
anatofuz
parents:
diff changeset
394 ID = O->get("id");
anatofuz
parents:
diff changeset
395 if (!ID) {
anatofuz
parents:
diff changeset
396 elog("Bad cancellation request: {0}", Params);
anatofuz
parents:
diff changeset
397 return;
anatofuz
parents:
diff changeset
398 }
anatofuz
parents:
diff changeset
399 auto StrID = llvm::to_string(*ID);
anatofuz
parents:
diff changeset
400 std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
anatofuz
parents:
diff changeset
401 auto It = RequestCancelers.find(StrID);
anatofuz
parents:
diff changeset
402 if (It != RequestCancelers.end())
anatofuz
parents:
diff changeset
403 It->second.first(); // Invoke the canceler.
anatofuz
parents:
diff changeset
404 }
anatofuz
parents:
diff changeset
405
anatofuz
parents:
diff changeset
406 Context handlerContext() const {
anatofuz
parents:
diff changeset
407 return Context::current().derive(
anatofuz
parents:
diff changeset
408 kCurrentOffsetEncoding,
anatofuz
parents:
diff changeset
409 Server.NegotiatedOffsetEncoding.getValueOr(OffsetEncoding::UTF16));
anatofuz
parents:
diff changeset
410 }
anatofuz
parents:
diff changeset
411
anatofuz
parents:
diff changeset
412 // We run cancelable requests in a context that does two things:
anatofuz
parents:
diff changeset
413 // - allows cancellation using RequestCancelers[ID]
anatofuz
parents:
diff changeset
414 // - cleans up the entry in RequestCancelers when it's no longer needed
anatofuz
parents:
diff changeset
415 // If a client reuses an ID, the last wins and the first cannot be canceled.
anatofuz
parents:
diff changeset
416 Context cancelableRequestContext(const llvm::json::Value &ID) {
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
417 auto Task = cancelableTask(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
418 /*Reason=*/static_cast<int>(ErrorCode::RequestCancelled));
150
anatofuz
parents:
diff changeset
419 auto StrID = llvm::to_string(ID); // JSON-serialize ID for map key.
anatofuz
parents:
diff changeset
420 auto Cookie = NextRequestCookie++; // No lock, only called on main thread.
anatofuz
parents:
diff changeset
421 {
anatofuz
parents:
diff changeset
422 std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
anatofuz
parents:
diff changeset
423 RequestCancelers[StrID] = {std::move(Task.second), Cookie};
anatofuz
parents:
diff changeset
424 }
anatofuz
parents:
diff changeset
425 // When the request ends, we can clean up the entry we just added.
anatofuz
parents:
diff changeset
426 // The cookie lets us check that it hasn't been overwritten due to ID
anatofuz
parents:
diff changeset
427 // reuse.
anatofuz
parents:
diff changeset
428 return Task.first.derive(llvm::make_scope_exit([this, StrID, Cookie] {
anatofuz
parents:
diff changeset
429 std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
anatofuz
parents:
diff changeset
430 auto It = RequestCancelers.find(StrID);
anatofuz
parents:
diff changeset
431 if (It != RequestCancelers.end() && It->second.second == Cookie)
anatofuz
parents:
diff changeset
432 RequestCancelers.erase(It);
anatofuz
parents:
diff changeset
433 }));
anatofuz
parents:
diff changeset
434 }
anatofuz
parents:
diff changeset
435
anatofuz
parents:
diff changeset
436 // The maximum number of callbacks held in clangd.
anatofuz
parents:
diff changeset
437 //
anatofuz
parents:
diff changeset
438 // We bound the maximum size to the pending map to prevent memory leakage
anatofuz
parents:
diff changeset
439 // for cases where LSP clients don't reply for the request.
anatofuz
parents:
diff changeset
440 // This has to go after RequestCancellers and RequestCancellersMutex since it
anatofuz
parents:
diff changeset
441 // can contain a callback that has a cancelable context.
anatofuz
parents:
diff changeset
442 static constexpr int MaxReplayCallbacks = 100;
anatofuz
parents:
diff changeset
443 mutable std::mutex CallMutex;
anatofuz
parents:
diff changeset
444 int NextCallID = 0; /* GUARDED_BY(CallMutex) */
anatofuz
parents:
diff changeset
445 std::deque<std::pair</*RequestID*/ int,
anatofuz
parents:
diff changeset
446 /*ReplyHandler*/ Callback<llvm::json::Value>>>
anatofuz
parents:
diff changeset
447 ReplyCallbacks; /* GUARDED_BY(CallMutex) */
anatofuz
parents:
diff changeset
448
anatofuz
parents:
diff changeset
449 ClangdLSPServer &Server;
anatofuz
parents:
diff changeset
450 };
anatofuz
parents:
diff changeset
451 constexpr int ClangdLSPServer::MessageHandler::MaxReplayCallbacks;
anatofuz
parents:
diff changeset
452
anatofuz
parents:
diff changeset
453 // call(), notify(), and reply() wrap the Transport, adding logging and locking.
anatofuz
parents:
diff changeset
454 void ClangdLSPServer::callRaw(StringRef Method, llvm::json::Value Params,
anatofuz
parents:
diff changeset
455 Callback<llvm::json::Value> CB) {
anatofuz
parents:
diff changeset
456 auto ID = MsgHandler->bindReply(std::move(CB));
anatofuz
parents:
diff changeset
457 log("--> {0}({1})", Method, ID);
anatofuz
parents:
diff changeset
458 std::lock_guard<std::mutex> Lock(TranspWriter);
anatofuz
parents:
diff changeset
459 Transp.call(Method, std::move(Params), ID);
anatofuz
parents:
diff changeset
460 }
anatofuz
parents:
diff changeset
461
anatofuz
parents:
diff changeset
462 void ClangdLSPServer::notify(llvm::StringRef Method, llvm::json::Value Params) {
anatofuz
parents:
diff changeset
463 log("--> {0}", Method);
anatofuz
parents:
diff changeset
464 std::lock_guard<std::mutex> Lock(TranspWriter);
anatofuz
parents:
diff changeset
465 Transp.notify(Method, std::move(Params));
anatofuz
parents:
diff changeset
466 }
anatofuz
parents:
diff changeset
467
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
468 static std::vector<llvm::StringRef> semanticTokenTypes() {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
469 std::vector<llvm::StringRef> Types;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
470 for (unsigned I = 0; I <= static_cast<unsigned>(HighlightingKind::LastKind);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
471 ++I)
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
472 Types.push_back(toSemanticTokenType(static_cast<HighlightingKind>(I)));
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
473 return Types;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
474 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
475
150
anatofuz
parents:
diff changeset
476 void ClangdLSPServer::onInitialize(const InitializeParams &Params,
anatofuz
parents:
diff changeset
477 Callback<llvm::json::Value> Reply) {
anatofuz
parents:
diff changeset
478 // Determine character encoding first as it affects constructed ClangdServer.
anatofuz
parents:
diff changeset
479 if (Params.capabilities.offsetEncoding && !NegotiatedOffsetEncoding) {
anatofuz
parents:
diff changeset
480 NegotiatedOffsetEncoding = OffsetEncoding::UTF16; // fallback
anatofuz
parents:
diff changeset
481 for (OffsetEncoding Supported : *Params.capabilities.offsetEncoding)
anatofuz
parents:
diff changeset
482 if (Supported != OffsetEncoding::UnsupportedEncoding) {
anatofuz
parents:
diff changeset
483 NegotiatedOffsetEncoding = Supported;
anatofuz
parents:
diff changeset
484 break;
anatofuz
parents:
diff changeset
485 }
anatofuz
parents:
diff changeset
486 }
anatofuz
parents:
diff changeset
487
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
488 ClangdServerOpts.TheiaSemanticHighlighting =
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
489 Params.capabilities.TheiaSemanticHighlighting;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
490 if (Params.capabilities.TheiaSemanticHighlighting &&
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
491 Params.capabilities.SemanticTokens) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
492 log("Client supports legacy semanticHighlights notification and standard "
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
493 "semanticTokens request, choosing the latter (no notifications).");
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
494 ClangdServerOpts.TheiaSemanticHighlighting = false;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
495 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
496
150
anatofuz
parents:
diff changeset
497 if (Params.rootUri && *Params.rootUri)
anatofuz
parents:
diff changeset
498 ClangdServerOpts.WorkspaceRoot = std::string(Params.rootUri->file());
anatofuz
parents:
diff changeset
499 else if (Params.rootPath && !Params.rootPath->empty())
anatofuz
parents:
diff changeset
500 ClangdServerOpts.WorkspaceRoot = *Params.rootPath;
anatofuz
parents:
diff changeset
501 if (Server)
anatofuz
parents:
diff changeset
502 return Reply(llvm::make_error<LSPError>("server already initialized",
anatofuz
parents:
diff changeset
503 ErrorCode::InvalidRequest));
anatofuz
parents:
diff changeset
504 if (const auto &Dir = Params.initializationOptions.compilationDatabasePath)
anatofuz
parents:
diff changeset
505 CompileCommandsDir = Dir;
anatofuz
parents:
diff changeset
506 if (UseDirBasedCDB) {
anatofuz
parents:
diff changeset
507 BaseCDB = std::make_unique<DirectoryBasedGlobalCompilationDatabase>(
anatofuz
parents:
diff changeset
508 CompileCommandsDir);
anatofuz
parents:
diff changeset
509 BaseCDB = getQueryDriverDatabase(
anatofuz
parents:
diff changeset
510 llvm::makeArrayRef(ClangdServerOpts.QueryDriverGlobs),
anatofuz
parents:
diff changeset
511 std::move(BaseCDB));
anatofuz
parents:
diff changeset
512 }
anatofuz
parents:
diff changeset
513 auto Mangler = CommandMangler::detect();
anatofuz
parents:
diff changeset
514 if (ClangdServerOpts.ResourceDir)
anatofuz
parents:
diff changeset
515 Mangler.ResourceDir = *ClangdServerOpts.ResourceDir;
anatofuz
parents:
diff changeset
516 CDB.emplace(BaseCDB.get(), Params.initializationOptions.fallbackFlags,
anatofuz
parents:
diff changeset
517 tooling::ArgumentsAdjuster(Mangler));
anatofuz
parents:
diff changeset
518 {
anatofuz
parents:
diff changeset
519 // Switch caller's context with LSPServer's background context. Since we
anatofuz
parents:
diff changeset
520 // rather want to propagate information from LSPServer's context into the
anatofuz
parents:
diff changeset
521 // Server, CDB, etc.
anatofuz
parents:
diff changeset
522 WithContext MainContext(BackgroundContext.clone());
anatofuz
parents:
diff changeset
523 llvm::Optional<WithContextValue> WithOffsetEncoding;
anatofuz
parents:
diff changeset
524 if (NegotiatedOffsetEncoding)
anatofuz
parents:
diff changeset
525 WithOffsetEncoding.emplace(kCurrentOffsetEncoding,
anatofuz
parents:
diff changeset
526 *NegotiatedOffsetEncoding);
anatofuz
parents:
diff changeset
527 Server.emplace(*CDB, FSProvider, ClangdServerOpts,
anatofuz
parents:
diff changeset
528 static_cast<ClangdServer::Callbacks *>(this));
anatofuz
parents:
diff changeset
529 }
anatofuz
parents:
diff changeset
530 applyConfiguration(Params.initializationOptions.ConfigSettings);
anatofuz
parents:
diff changeset
531
anatofuz
parents:
diff changeset
532 CCOpts.EnableSnippets = Params.capabilities.CompletionSnippets;
anatofuz
parents:
diff changeset
533 CCOpts.IncludeFixIts = Params.capabilities.CompletionFixes;
anatofuz
parents:
diff changeset
534 if (!CCOpts.BundleOverloads.hasValue())
anatofuz
parents:
diff changeset
535 CCOpts.BundleOverloads = Params.capabilities.HasSignatureHelp;
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
536 CCOpts.DocumentationFormat =
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
537 Params.capabilities.CompletionDocumentationFormat;
150
anatofuz
parents:
diff changeset
538 DiagOpts.EmbedFixesInDiagnostics = Params.capabilities.DiagnosticFixes;
anatofuz
parents:
diff changeset
539 DiagOpts.SendDiagnosticCategory = Params.capabilities.DiagnosticCategory;
anatofuz
parents:
diff changeset
540 DiagOpts.EmitRelatedLocations =
anatofuz
parents:
diff changeset
541 Params.capabilities.DiagnosticRelatedInformation;
anatofuz
parents:
diff changeset
542 if (Params.capabilities.WorkspaceSymbolKinds)
anatofuz
parents:
diff changeset
543 SupportedSymbolKinds |= *Params.capabilities.WorkspaceSymbolKinds;
anatofuz
parents:
diff changeset
544 if (Params.capabilities.CompletionItemKinds)
anatofuz
parents:
diff changeset
545 SupportedCompletionItemKinds |= *Params.capabilities.CompletionItemKinds;
anatofuz
parents:
diff changeset
546 SupportsCodeAction = Params.capabilities.CodeActionStructure;
anatofuz
parents:
diff changeset
547 SupportsHierarchicalDocumentSymbol =
anatofuz
parents:
diff changeset
548 Params.capabilities.HierarchicalDocumentSymbol;
anatofuz
parents:
diff changeset
549 SupportFileStatus = Params.initializationOptions.FileStatus;
anatofuz
parents:
diff changeset
550 HoverContentFormat = Params.capabilities.HoverContentFormat;
anatofuz
parents:
diff changeset
551 SupportsOffsetsInSignatureHelp = Params.capabilities.OffsetsInSignatureHelp;
anatofuz
parents:
diff changeset
552 if (Params.capabilities.WorkDoneProgress)
anatofuz
parents:
diff changeset
553 BackgroundIndexProgressState = BackgroundIndexProgress::Empty;
anatofuz
parents:
diff changeset
554 BackgroundIndexSkipCreate = Params.capabilities.ImplicitProgressCreation;
anatofuz
parents:
diff changeset
555
anatofuz
parents:
diff changeset
556 // Per LSP, renameProvider can be either boolean or RenameOptions.
anatofuz
parents:
diff changeset
557 // RenameOptions will be specified if the client states it supports prepare.
anatofuz
parents:
diff changeset
558 llvm::json::Value RenameProvider =
anatofuz
parents:
diff changeset
559 llvm::json::Object{{"prepareProvider", true}};
anatofuz
parents:
diff changeset
560 if (!Params.capabilities.RenamePrepareSupport) // Only boolean allowed per LSP
anatofuz
parents:
diff changeset
561 RenameProvider = true;
anatofuz
parents:
diff changeset
562
anatofuz
parents:
diff changeset
563 // Per LSP, codeActionProvide can be either boolean or CodeActionOptions.
anatofuz
parents:
diff changeset
564 // CodeActionOptions is only valid if the client supports action literal
anatofuz
parents:
diff changeset
565 // via textDocument.codeAction.codeActionLiteralSupport.
anatofuz
parents:
diff changeset
566 llvm::json::Value CodeActionProvider = true;
anatofuz
parents:
diff changeset
567 if (Params.capabilities.CodeActionStructure)
anatofuz
parents:
diff changeset
568 CodeActionProvider = llvm::json::Object{
anatofuz
parents:
diff changeset
569 {"codeActionKinds",
anatofuz
parents:
diff changeset
570 {CodeAction::QUICKFIX_KIND, CodeAction::REFACTOR_KIND,
anatofuz
parents:
diff changeset
571 CodeAction::INFO_KIND}}};
anatofuz
parents:
diff changeset
572
anatofuz
parents:
diff changeset
573 llvm::json::Object Result{
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
574 {{"serverInfo",
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
575 llvm::json::Object{{"name", "clangd"},
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
576 {"version", getClangToolFullVersion("clangd")}}},
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
577 {"capabilities",
150
anatofuz
parents:
diff changeset
578 llvm::json::Object{
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
579 {"textDocumentSync",
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
580 llvm::json::Object{
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
581 {"openClose", true},
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
582 {"change", (int)TextDocumentSyncKind::Incremental},
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
583 {"save", true},
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
584 }},
150
anatofuz
parents:
diff changeset
585 {"documentFormattingProvider", true},
anatofuz
parents:
diff changeset
586 {"documentRangeFormattingProvider", true},
anatofuz
parents:
diff changeset
587 {"documentOnTypeFormattingProvider",
anatofuz
parents:
diff changeset
588 llvm::json::Object{
anatofuz
parents:
diff changeset
589 {"firstTriggerCharacter", "\n"},
anatofuz
parents:
diff changeset
590 {"moreTriggerCharacter", {}},
anatofuz
parents:
diff changeset
591 }},
anatofuz
parents:
diff changeset
592 {"codeActionProvider", std::move(CodeActionProvider)},
anatofuz
parents:
diff changeset
593 {"completionProvider",
anatofuz
parents:
diff changeset
594 llvm::json::Object{
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
595 {"allCommitCharacters", " \t()[]{}<>:;,+-/*%^&#?.=\"'|"},
150
anatofuz
parents:
diff changeset
596 {"resolveProvider", false},
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
597 // We do extra checks, e.g. that > is part of ->.
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
598 {"triggerCharacters", {".", "<", ">", ":", "\"", "/"}},
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
599 }},
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
600 {"semanticTokensProvider",
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
601 llvm::json::Object{
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
602 {"documentProvider", llvm::json::Object{{"edits", true}}},
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
603 {"rangeProvider", false},
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
604 {"legend",
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
605 llvm::json::Object{{"tokenTypes", semanticTokenTypes()},
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
606 {"tokenModifiers", llvm::json::Array()}}},
150
anatofuz
parents:
diff changeset
607 }},
anatofuz
parents:
diff changeset
608 {"signatureHelpProvider",
anatofuz
parents:
diff changeset
609 llvm::json::Object{
anatofuz
parents:
diff changeset
610 {"triggerCharacters", {"(", ","}},
anatofuz
parents:
diff changeset
611 }},
anatofuz
parents:
diff changeset
612 {"declarationProvider", true},
anatofuz
parents:
diff changeset
613 {"definitionProvider", true},
anatofuz
parents:
diff changeset
614 {"documentHighlightProvider", true},
anatofuz
parents:
diff changeset
615 {"documentLinkProvider",
anatofuz
parents:
diff changeset
616 llvm::json::Object{
anatofuz
parents:
diff changeset
617 {"resolveProvider", false},
anatofuz
parents:
diff changeset
618 }},
anatofuz
parents:
diff changeset
619 {"hoverProvider", true},
anatofuz
parents:
diff changeset
620 {"renameProvider", std::move(RenameProvider)},
anatofuz
parents:
diff changeset
621 {"selectionRangeProvider", true},
anatofuz
parents:
diff changeset
622 {"documentSymbolProvider", true},
anatofuz
parents:
diff changeset
623 {"workspaceSymbolProvider", true},
anatofuz
parents:
diff changeset
624 {"referencesProvider", true},
anatofuz
parents:
diff changeset
625 {"executeCommandProvider",
anatofuz
parents:
diff changeset
626 llvm::json::Object{
anatofuz
parents:
diff changeset
627 {"commands",
anatofuz
parents:
diff changeset
628 {ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND,
anatofuz
parents:
diff changeset
629 ExecuteCommandParams::CLANGD_APPLY_TWEAK}},
anatofuz
parents:
diff changeset
630 }},
anatofuz
parents:
diff changeset
631 {"typeHierarchyProvider", true},
anatofuz
parents:
diff changeset
632 }}}};
anatofuz
parents:
diff changeset
633 if (NegotiatedOffsetEncoding)
anatofuz
parents:
diff changeset
634 Result["offsetEncoding"] = *NegotiatedOffsetEncoding;
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
635 if (ClangdServerOpts.TheiaSemanticHighlighting)
150
anatofuz
parents:
diff changeset
636 Result.getObject("capabilities")
anatofuz
parents:
diff changeset
637 ->insert(
anatofuz
parents:
diff changeset
638 {"semanticHighlighting",
anatofuz
parents:
diff changeset
639 llvm::json::Object{{"scopes", buildHighlightScopeLookupTable()}}});
anatofuz
parents:
diff changeset
640 Reply(std::move(Result));
anatofuz
parents:
diff changeset
641 }
anatofuz
parents:
diff changeset
642
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
643 void ClangdLSPServer::onInitialized(const InitializedParams &Params) {}
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
644
150
anatofuz
parents:
diff changeset
645 void ClangdLSPServer::onShutdown(const ShutdownParams &Params,
anatofuz
parents:
diff changeset
646 Callback<std::nullptr_t> Reply) {
anatofuz
parents:
diff changeset
647 // Do essentially nothing, just say we're ready to exit.
anatofuz
parents:
diff changeset
648 ShutdownRequestReceived = true;
anatofuz
parents:
diff changeset
649 Reply(nullptr);
anatofuz
parents:
diff changeset
650 }
anatofuz
parents:
diff changeset
651
anatofuz
parents:
diff changeset
652 // sync is a clangd extension: it blocks until all background work completes.
anatofuz
parents:
diff changeset
653 // It blocks the calling thread, so no messages are processed until it returns!
anatofuz
parents:
diff changeset
654 void ClangdLSPServer::onSync(const NoParams &Params,
anatofuz
parents:
diff changeset
655 Callback<std::nullptr_t> Reply) {
anatofuz
parents:
diff changeset
656 if (Server->blockUntilIdleForTest(/*TimeoutSeconds=*/60))
anatofuz
parents:
diff changeset
657 Reply(nullptr);
anatofuz
parents:
diff changeset
658 else
anatofuz
parents:
diff changeset
659 Reply(llvm::createStringError(llvm::inconvertibleErrorCode(),
anatofuz
parents:
diff changeset
660 "Not idle after a minute"));
anatofuz
parents:
diff changeset
661 }
anatofuz
parents:
diff changeset
662
anatofuz
parents:
diff changeset
663 void ClangdLSPServer::onDocumentDidOpen(
anatofuz
parents:
diff changeset
664 const DidOpenTextDocumentParams &Params) {
anatofuz
parents:
diff changeset
665 PathRef File = Params.textDocument.uri.file();
anatofuz
parents:
diff changeset
666
anatofuz
parents:
diff changeset
667 const std::string &Contents = Params.textDocument.text;
anatofuz
parents:
diff changeset
668
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
669 auto Version = DraftMgr.addDraft(File, Params.textDocument.version, Contents);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
670 Server->addDocument(File, Contents, encodeVersion(Version),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
671 WantDiagnostics::Yes);
150
anatofuz
parents:
diff changeset
672 }
anatofuz
parents:
diff changeset
673
anatofuz
parents:
diff changeset
674 void ClangdLSPServer::onDocumentDidChange(
anatofuz
parents:
diff changeset
675 const DidChangeTextDocumentParams &Params) {
anatofuz
parents:
diff changeset
676 auto WantDiags = WantDiagnostics::Auto;
anatofuz
parents:
diff changeset
677 if (Params.wantDiagnostics.hasValue())
anatofuz
parents:
diff changeset
678 WantDiags = Params.wantDiagnostics.getValue() ? WantDiagnostics::Yes
anatofuz
parents:
diff changeset
679 : WantDiagnostics::No;
anatofuz
parents:
diff changeset
680
anatofuz
parents:
diff changeset
681 PathRef File = Params.textDocument.uri.file();
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
682 llvm::Expected<DraftStore::Draft> Draft = DraftMgr.updateDraft(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
683 File, Params.textDocument.version, Params.contentChanges);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
684 if (!Draft) {
150
anatofuz
parents:
diff changeset
685 // If this fails, we are most likely going to be not in sync anymore with
anatofuz
parents:
diff changeset
686 // the client. It is better to remove the draft and let further operations
anatofuz
parents:
diff changeset
687 // fail rather than giving wrong results.
anatofuz
parents:
diff changeset
688 DraftMgr.removeDraft(File);
anatofuz
parents:
diff changeset
689 Server->removeDocument(File);
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
690 elog("Failed to update {0}: {1}", File, Draft.takeError());
150
anatofuz
parents:
diff changeset
691 return;
anatofuz
parents:
diff changeset
692 }
anatofuz
parents:
diff changeset
693
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
694 Server->addDocument(File, Draft->Contents, encodeVersion(Draft->Version),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
695 WantDiags, Params.forceRebuild);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
696 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
697
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
698 void ClangdLSPServer::onDocumentDidSave(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
699 const DidSaveTextDocumentParams &Params) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
700 reparseOpenFilesIfNeeded([](llvm::StringRef) { return true; });
150
anatofuz
parents:
diff changeset
701 }
anatofuz
parents:
diff changeset
702
anatofuz
parents:
diff changeset
703 void ClangdLSPServer::onFileEvent(const DidChangeWatchedFilesParams &Params) {
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
704 // We could also reparse all open files here. However:
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
705 // - this could be frequent, and revalidating all the preambles isn't free
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
706 // - this is useful e.g. when switching git branches, but we're likely to see
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
707 // fresh headers but still have the old-branch main-file content
150
anatofuz
parents:
diff changeset
708 Server->onFileEvent(Params);
anatofuz
parents:
diff changeset
709 }
anatofuz
parents:
diff changeset
710
anatofuz
parents:
diff changeset
711 void ClangdLSPServer::onCommand(const ExecuteCommandParams &Params,
anatofuz
parents:
diff changeset
712 Callback<llvm::json::Value> Reply) {
anatofuz
parents:
diff changeset
713 auto ApplyEdit = [this](WorkspaceEdit WE, std::string SuccessMessage,
anatofuz
parents:
diff changeset
714 decltype(Reply) Reply) {
anatofuz
parents:
diff changeset
715 ApplyWorkspaceEditParams Edit;
anatofuz
parents:
diff changeset
716 Edit.edit = std::move(WE);
anatofuz
parents:
diff changeset
717 call<ApplyWorkspaceEditResponse>(
anatofuz
parents:
diff changeset
718 "workspace/applyEdit", std::move(Edit),
anatofuz
parents:
diff changeset
719 [Reply = std::move(Reply), SuccessMessage = std::move(SuccessMessage)](
anatofuz
parents:
diff changeset
720 llvm::Expected<ApplyWorkspaceEditResponse> Response) mutable {
anatofuz
parents:
diff changeset
721 if (!Response)
anatofuz
parents:
diff changeset
722 return Reply(Response.takeError());
anatofuz
parents:
diff changeset
723 if (!Response->applied) {
anatofuz
parents:
diff changeset
724 std::string Reason = Response->failureReason
anatofuz
parents:
diff changeset
725 ? *Response->failureReason
anatofuz
parents:
diff changeset
726 : "unknown reason";
anatofuz
parents:
diff changeset
727 return Reply(llvm::createStringError(
anatofuz
parents:
diff changeset
728 llvm::inconvertibleErrorCode(),
anatofuz
parents:
diff changeset
729 ("edits were not applied: " + Reason).c_str()));
anatofuz
parents:
diff changeset
730 }
anatofuz
parents:
diff changeset
731 return Reply(SuccessMessage);
anatofuz
parents:
diff changeset
732 });
anatofuz
parents:
diff changeset
733 };
anatofuz
parents:
diff changeset
734
anatofuz
parents:
diff changeset
735 if (Params.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND &&
anatofuz
parents:
diff changeset
736 Params.workspaceEdit) {
anatofuz
parents:
diff changeset
737 // The flow for "apply-fix" :
anatofuz
parents:
diff changeset
738 // 1. We publish a diagnostic, including fixits
anatofuz
parents:
diff changeset
739 // 2. The user clicks on the diagnostic, the editor asks us for code actions
anatofuz
parents:
diff changeset
740 // 3. We send code actions, with the fixit embedded as context
anatofuz
parents:
diff changeset
741 // 4. The user selects the fixit, the editor asks us to apply it
anatofuz
parents:
diff changeset
742 // 5. We unwrap the changes and send them back to the editor
anatofuz
parents:
diff changeset
743 // 6. The editor applies the changes (applyEdit), and sends us a reply
anatofuz
parents:
diff changeset
744 // 7. We unwrap the reply and send a reply to the editor.
anatofuz
parents:
diff changeset
745 ApplyEdit(*Params.workspaceEdit, "Fix applied.", std::move(Reply));
anatofuz
parents:
diff changeset
746 } else if (Params.command == ExecuteCommandParams::CLANGD_APPLY_TWEAK &&
anatofuz
parents:
diff changeset
747 Params.tweakArgs) {
anatofuz
parents:
diff changeset
748 auto Code = DraftMgr.getDraft(Params.tweakArgs->file.file());
anatofuz
parents:
diff changeset
749 if (!Code)
anatofuz
parents:
diff changeset
750 return Reply(llvm::createStringError(
anatofuz
parents:
diff changeset
751 llvm::inconvertibleErrorCode(),
anatofuz
parents:
diff changeset
752 "trying to apply a code action for a non-added file"));
anatofuz
parents:
diff changeset
753
anatofuz
parents:
diff changeset
754 auto Action = [this, ApplyEdit, Reply = std::move(Reply),
anatofuz
parents:
diff changeset
755 File = Params.tweakArgs->file, Code = std::move(*Code)](
anatofuz
parents:
diff changeset
756 llvm::Expected<Tweak::Effect> R) mutable {
anatofuz
parents:
diff changeset
757 if (!R)
anatofuz
parents:
diff changeset
758 return Reply(R.takeError());
anatofuz
parents:
diff changeset
759
anatofuz
parents:
diff changeset
760 assert(R->ShowMessage ||
anatofuz
parents:
diff changeset
761 (!R->ApplyEdits.empty() && "tweak has no effect"));
anatofuz
parents:
diff changeset
762
anatofuz
parents:
diff changeset
763 if (R->ShowMessage) {
anatofuz
parents:
diff changeset
764 ShowMessageParams Msg;
anatofuz
parents:
diff changeset
765 Msg.message = *R->ShowMessage;
anatofuz
parents:
diff changeset
766 Msg.type = MessageType::Info;
anatofuz
parents:
diff changeset
767 notify("window/showMessage", Msg);
anatofuz
parents:
diff changeset
768 }
anatofuz
parents:
diff changeset
769 // When no edit is specified, make sure we Reply().
anatofuz
parents:
diff changeset
770 if (R->ApplyEdits.empty())
anatofuz
parents:
diff changeset
771 return Reply("Tweak applied.");
anatofuz
parents:
diff changeset
772
anatofuz
parents:
diff changeset
773 if (auto Err = validateEdits(DraftMgr, R->ApplyEdits))
anatofuz
parents:
diff changeset
774 return Reply(std::move(Err));
anatofuz
parents:
diff changeset
775
anatofuz
parents:
diff changeset
776 WorkspaceEdit WE;
anatofuz
parents:
diff changeset
777 WE.changes.emplace();
anatofuz
parents:
diff changeset
778 for (const auto &It : R->ApplyEdits) {
anatofuz
parents:
diff changeset
779 (*WE.changes)[URI::createFile(It.first()).toString()] =
anatofuz
parents:
diff changeset
780 It.second.asTextEdits();
anatofuz
parents:
diff changeset
781 }
anatofuz
parents:
diff changeset
782 // ApplyEdit will take care of calling Reply().
anatofuz
parents:
diff changeset
783 return ApplyEdit(std::move(WE), "Tweak applied.", std::move(Reply));
anatofuz
parents:
diff changeset
784 };
anatofuz
parents:
diff changeset
785 Server->applyTweak(Params.tweakArgs->file.file(),
anatofuz
parents:
diff changeset
786 Params.tweakArgs->selection, Params.tweakArgs->tweakID,
anatofuz
parents:
diff changeset
787 std::move(Action));
anatofuz
parents:
diff changeset
788 } else {
anatofuz
parents:
diff changeset
789 // We should not get here because ExecuteCommandParams would not have
anatofuz
parents:
diff changeset
790 // parsed in the first place and this handler should not be called. But if
anatofuz
parents:
diff changeset
791 // more commands are added, this will be here has a safe guard.
anatofuz
parents:
diff changeset
792 Reply(llvm::make_error<LSPError>(
anatofuz
parents:
diff changeset
793 llvm::formatv("Unsupported command \"{0}\".", Params.command).str(),
anatofuz
parents:
diff changeset
794 ErrorCode::InvalidParams));
anatofuz
parents:
diff changeset
795 }
anatofuz
parents:
diff changeset
796 }
anatofuz
parents:
diff changeset
797
anatofuz
parents:
diff changeset
798 void ClangdLSPServer::onWorkspaceSymbol(
anatofuz
parents:
diff changeset
799 const WorkspaceSymbolParams &Params,
anatofuz
parents:
diff changeset
800 Callback<std::vector<SymbolInformation>> Reply) {
anatofuz
parents:
diff changeset
801 Server->workspaceSymbols(
anatofuz
parents:
diff changeset
802 Params.query, CCOpts.Limit,
anatofuz
parents:
diff changeset
803 [Reply = std::move(Reply),
anatofuz
parents:
diff changeset
804 this](llvm::Expected<std::vector<SymbolInformation>> Items) mutable {
anatofuz
parents:
diff changeset
805 if (!Items)
anatofuz
parents:
diff changeset
806 return Reply(Items.takeError());
anatofuz
parents:
diff changeset
807 for (auto &Sym : *Items)
anatofuz
parents:
diff changeset
808 Sym.kind = adjustKindToCapability(Sym.kind, SupportedSymbolKinds);
anatofuz
parents:
diff changeset
809
anatofuz
parents:
diff changeset
810 Reply(std::move(*Items));
anatofuz
parents:
diff changeset
811 });
anatofuz
parents:
diff changeset
812 }
anatofuz
parents:
diff changeset
813
anatofuz
parents:
diff changeset
814 void ClangdLSPServer::onPrepareRename(const TextDocumentPositionParams &Params,
anatofuz
parents:
diff changeset
815 Callback<llvm::Optional<Range>> Reply) {
anatofuz
parents:
diff changeset
816 Server->prepareRename(Params.textDocument.uri.file(), Params.position,
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
817 RenameOpts, std::move(Reply));
150
anatofuz
parents:
diff changeset
818 }
anatofuz
parents:
diff changeset
819
anatofuz
parents:
diff changeset
820 void ClangdLSPServer::onRename(const RenameParams &Params,
anatofuz
parents:
diff changeset
821 Callback<WorkspaceEdit> Reply) {
anatofuz
parents:
diff changeset
822 Path File = std::string(Params.textDocument.uri.file());
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
823 if (!DraftMgr.getDraft(File))
150
anatofuz
parents:
diff changeset
824 return Reply(llvm::make_error<LSPError>(
anatofuz
parents:
diff changeset
825 "onRename called for non-added file", ErrorCode::InvalidParams));
anatofuz
parents:
diff changeset
826 Server->rename(
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
827 File, Params.position, Params.newName, RenameOpts,
150
anatofuz
parents:
diff changeset
828 [File, Params, Reply = std::move(Reply),
anatofuz
parents:
diff changeset
829 this](llvm::Expected<FileEdits> Edits) mutable {
anatofuz
parents:
diff changeset
830 if (!Edits)
anatofuz
parents:
diff changeset
831 return Reply(Edits.takeError());
anatofuz
parents:
diff changeset
832 if (auto Err = validateEdits(DraftMgr, *Edits))
anatofuz
parents:
diff changeset
833 return Reply(std::move(Err));
anatofuz
parents:
diff changeset
834 WorkspaceEdit Result;
anatofuz
parents:
diff changeset
835 Result.changes.emplace();
anatofuz
parents:
diff changeset
836 for (const auto &Rep : *Edits) {
anatofuz
parents:
diff changeset
837 (*Result.changes)[URI::createFile(Rep.first()).toString()] =
anatofuz
parents:
diff changeset
838 Rep.second.asTextEdits();
anatofuz
parents:
diff changeset
839 }
anatofuz
parents:
diff changeset
840 Reply(Result);
anatofuz
parents:
diff changeset
841 });
anatofuz
parents:
diff changeset
842 }
anatofuz
parents:
diff changeset
843
anatofuz
parents:
diff changeset
844 void ClangdLSPServer::onDocumentDidClose(
anatofuz
parents:
diff changeset
845 const DidCloseTextDocumentParams &Params) {
anatofuz
parents:
diff changeset
846 PathRef File = Params.textDocument.uri.file();
anatofuz
parents:
diff changeset
847 DraftMgr.removeDraft(File);
anatofuz
parents:
diff changeset
848 Server->removeDocument(File);
anatofuz
parents:
diff changeset
849
anatofuz
parents:
diff changeset
850 {
anatofuz
parents:
diff changeset
851 std::lock_guard<std::mutex> Lock(FixItsMutex);
anatofuz
parents:
diff changeset
852 FixItsMap.erase(File);
anatofuz
parents:
diff changeset
853 }
anatofuz
parents:
diff changeset
854 {
anatofuz
parents:
diff changeset
855 std::lock_guard<std::mutex> HLock(HighlightingsMutex);
anatofuz
parents:
diff changeset
856 FileToHighlightings.erase(File);
anatofuz
parents:
diff changeset
857 }
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
858 {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
859 std::lock_guard<std::mutex> HLock(SemanticTokensMutex);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
860 LastSemanticTokens.erase(File);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
861 }
150
anatofuz
parents:
diff changeset
862 // clangd will not send updates for this file anymore, so we empty out the
anatofuz
parents:
diff changeset
863 // list of diagnostics shown on the client (e.g. in the "Problems" pane of
anatofuz
parents:
diff changeset
864 // VSCode). Note that this cannot race with actual diagnostics responses
anatofuz
parents:
diff changeset
865 // because removeDocument() guarantees no diagnostic callbacks will be
anatofuz
parents:
diff changeset
866 // executed after it returns.
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
867 PublishDiagnosticsParams Notification;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
868 Notification.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
869 publishDiagnostics(Notification);
150
anatofuz
parents:
diff changeset
870 }
anatofuz
parents:
diff changeset
871
anatofuz
parents:
diff changeset
872 void ClangdLSPServer::onDocumentOnTypeFormatting(
anatofuz
parents:
diff changeset
873 const DocumentOnTypeFormattingParams &Params,
anatofuz
parents:
diff changeset
874 Callback<std::vector<TextEdit>> Reply) {
anatofuz
parents:
diff changeset
875 auto File = Params.textDocument.uri.file();
anatofuz
parents:
diff changeset
876 auto Code = DraftMgr.getDraft(File);
anatofuz
parents:
diff changeset
877 if (!Code)
anatofuz
parents:
diff changeset
878 return Reply(llvm::make_error<LSPError>(
anatofuz
parents:
diff changeset
879 "onDocumentOnTypeFormatting called for non-added file",
anatofuz
parents:
diff changeset
880 ErrorCode::InvalidParams));
anatofuz
parents:
diff changeset
881
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
882 Reply(Server->formatOnType(Code->Contents, File, Params.position, Params.ch));
150
anatofuz
parents:
diff changeset
883 }
anatofuz
parents:
diff changeset
884
anatofuz
parents:
diff changeset
885 void ClangdLSPServer::onDocumentRangeFormatting(
anatofuz
parents:
diff changeset
886 const DocumentRangeFormattingParams &Params,
anatofuz
parents:
diff changeset
887 Callback<std::vector<TextEdit>> Reply) {
anatofuz
parents:
diff changeset
888 auto File = Params.textDocument.uri.file();
anatofuz
parents:
diff changeset
889 auto Code = DraftMgr.getDraft(File);
anatofuz
parents:
diff changeset
890 if (!Code)
anatofuz
parents:
diff changeset
891 return Reply(llvm::make_error<LSPError>(
anatofuz
parents:
diff changeset
892 "onDocumentRangeFormatting called for non-added file",
anatofuz
parents:
diff changeset
893 ErrorCode::InvalidParams));
anatofuz
parents:
diff changeset
894
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
895 auto ReplacementsOrError =
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
896 Server->formatRange(Code->Contents, File, Params.range);
150
anatofuz
parents:
diff changeset
897 if (ReplacementsOrError)
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
898 Reply(replacementsToEdits(Code->Contents, ReplacementsOrError.get()));
150
anatofuz
parents:
diff changeset
899 else
anatofuz
parents:
diff changeset
900 Reply(ReplacementsOrError.takeError());
anatofuz
parents:
diff changeset
901 }
anatofuz
parents:
diff changeset
902
anatofuz
parents:
diff changeset
903 void ClangdLSPServer::onDocumentFormatting(
anatofuz
parents:
diff changeset
904 const DocumentFormattingParams &Params,
anatofuz
parents:
diff changeset
905 Callback<std::vector<TextEdit>> Reply) {
anatofuz
parents:
diff changeset
906 auto File = Params.textDocument.uri.file();
anatofuz
parents:
diff changeset
907 auto Code = DraftMgr.getDraft(File);
anatofuz
parents:
diff changeset
908 if (!Code)
anatofuz
parents:
diff changeset
909 return Reply(llvm::make_error<LSPError>(
anatofuz
parents:
diff changeset
910 "onDocumentFormatting called for non-added file",
anatofuz
parents:
diff changeset
911 ErrorCode::InvalidParams));
anatofuz
parents:
diff changeset
912
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
913 auto ReplacementsOrError = Server->formatFile(Code->Contents, File);
150
anatofuz
parents:
diff changeset
914 if (ReplacementsOrError)
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
915 Reply(replacementsToEdits(Code->Contents, ReplacementsOrError.get()));
150
anatofuz
parents:
diff changeset
916 else
anatofuz
parents:
diff changeset
917 Reply(ReplacementsOrError.takeError());
anatofuz
parents:
diff changeset
918 }
anatofuz
parents:
diff changeset
919
anatofuz
parents:
diff changeset
920 /// The functions constructs a flattened view of the DocumentSymbol hierarchy.
anatofuz
parents:
diff changeset
921 /// Used by the clients that do not support the hierarchical view.
anatofuz
parents:
diff changeset
922 static std::vector<SymbolInformation>
anatofuz
parents:
diff changeset
923 flattenSymbolHierarchy(llvm::ArrayRef<DocumentSymbol> Symbols,
anatofuz
parents:
diff changeset
924 const URIForFile &FileURI) {
anatofuz
parents:
diff changeset
925
anatofuz
parents:
diff changeset
926 std::vector<SymbolInformation> Results;
anatofuz
parents:
diff changeset
927 std::function<void(const DocumentSymbol &, llvm::StringRef)> Process =
anatofuz
parents:
diff changeset
928 [&](const DocumentSymbol &S, llvm::Optional<llvm::StringRef> ParentName) {
anatofuz
parents:
diff changeset
929 SymbolInformation SI;
anatofuz
parents:
diff changeset
930 SI.containerName = std::string(ParentName ? "" : *ParentName);
anatofuz
parents:
diff changeset
931 SI.name = S.name;
anatofuz
parents:
diff changeset
932 SI.kind = S.kind;
anatofuz
parents:
diff changeset
933 SI.location.range = S.range;
anatofuz
parents:
diff changeset
934 SI.location.uri = FileURI;
anatofuz
parents:
diff changeset
935
anatofuz
parents:
diff changeset
936 Results.push_back(std::move(SI));
anatofuz
parents:
diff changeset
937 std::string FullName =
anatofuz
parents:
diff changeset
938 !ParentName ? S.name : (ParentName->str() + "::" + S.name);
anatofuz
parents:
diff changeset
939 for (auto &C : S.children)
anatofuz
parents:
diff changeset
940 Process(C, /*ParentName=*/FullName);
anatofuz
parents:
diff changeset
941 };
anatofuz
parents:
diff changeset
942 for (auto &S : Symbols)
anatofuz
parents:
diff changeset
943 Process(S, /*ParentName=*/"");
anatofuz
parents:
diff changeset
944 return Results;
anatofuz
parents:
diff changeset
945 }
anatofuz
parents:
diff changeset
946
anatofuz
parents:
diff changeset
947 void ClangdLSPServer::onDocumentSymbol(const DocumentSymbolParams &Params,
anatofuz
parents:
diff changeset
948 Callback<llvm::json::Value> Reply) {
anatofuz
parents:
diff changeset
949 URIForFile FileURI = Params.textDocument.uri;
anatofuz
parents:
diff changeset
950 Server->documentSymbols(
anatofuz
parents:
diff changeset
951 Params.textDocument.uri.file(),
anatofuz
parents:
diff changeset
952 [this, FileURI, Reply = std::move(Reply)](
anatofuz
parents:
diff changeset
953 llvm::Expected<std::vector<DocumentSymbol>> Items) mutable {
anatofuz
parents:
diff changeset
954 if (!Items)
anatofuz
parents:
diff changeset
955 return Reply(Items.takeError());
anatofuz
parents:
diff changeset
956 adjustSymbolKinds(*Items, SupportedSymbolKinds);
anatofuz
parents:
diff changeset
957 if (SupportsHierarchicalDocumentSymbol)
anatofuz
parents:
diff changeset
958 return Reply(std::move(*Items));
anatofuz
parents:
diff changeset
959 else
anatofuz
parents:
diff changeset
960 return Reply(flattenSymbolHierarchy(*Items, FileURI));
anatofuz
parents:
diff changeset
961 });
anatofuz
parents:
diff changeset
962 }
anatofuz
parents:
diff changeset
963
anatofuz
parents:
diff changeset
964 static llvm::Optional<Command> asCommand(const CodeAction &Action) {
anatofuz
parents:
diff changeset
965 Command Cmd;
anatofuz
parents:
diff changeset
966 if (Action.command && Action.edit)
anatofuz
parents:
diff changeset
967 return None; // Not representable. (We never emit these anyway).
anatofuz
parents:
diff changeset
968 if (Action.command) {
anatofuz
parents:
diff changeset
969 Cmd = *Action.command;
anatofuz
parents:
diff changeset
970 } else if (Action.edit) {
anatofuz
parents:
diff changeset
971 Cmd.command = std::string(Command::CLANGD_APPLY_FIX_COMMAND);
anatofuz
parents:
diff changeset
972 Cmd.workspaceEdit = *Action.edit;
anatofuz
parents:
diff changeset
973 } else {
anatofuz
parents:
diff changeset
974 return None;
anatofuz
parents:
diff changeset
975 }
anatofuz
parents:
diff changeset
976 Cmd.title = Action.title;
anatofuz
parents:
diff changeset
977 if (Action.kind && *Action.kind == CodeAction::QUICKFIX_KIND)
anatofuz
parents:
diff changeset
978 Cmd.title = "Apply fix: " + Cmd.title;
anatofuz
parents:
diff changeset
979 return Cmd;
anatofuz
parents:
diff changeset
980 }
anatofuz
parents:
diff changeset
981
anatofuz
parents:
diff changeset
982 void ClangdLSPServer::onCodeAction(const CodeActionParams &Params,
anatofuz
parents:
diff changeset
983 Callback<llvm::json::Value> Reply) {
anatofuz
parents:
diff changeset
984 URIForFile File = Params.textDocument.uri;
anatofuz
parents:
diff changeset
985 auto Code = DraftMgr.getDraft(File.file());
anatofuz
parents:
diff changeset
986 if (!Code)
anatofuz
parents:
diff changeset
987 return Reply(llvm::make_error<LSPError>(
anatofuz
parents:
diff changeset
988 "onCodeAction called for non-added file", ErrorCode::InvalidParams));
anatofuz
parents:
diff changeset
989 // We provide a code action for Fixes on the specified diagnostics.
anatofuz
parents:
diff changeset
990 std::vector<CodeAction> FixIts;
anatofuz
parents:
diff changeset
991 for (const Diagnostic &D : Params.context.diagnostics) {
anatofuz
parents:
diff changeset
992 for (auto &F : getFixes(File.file(), D)) {
anatofuz
parents:
diff changeset
993 FixIts.push_back(toCodeAction(F, Params.textDocument.uri));
anatofuz
parents:
diff changeset
994 FixIts.back().diagnostics = {D};
anatofuz
parents:
diff changeset
995 }
anatofuz
parents:
diff changeset
996 }
anatofuz
parents:
diff changeset
997
anatofuz
parents:
diff changeset
998 // Now enumerate the semantic code actions.
anatofuz
parents:
diff changeset
999 auto ConsumeActions =
anatofuz
parents:
diff changeset
1000 [Reply = std::move(Reply), File, Code = std::move(*Code),
anatofuz
parents:
diff changeset
1001 Selection = Params.range, FixIts = std::move(FixIts), this](
anatofuz
parents:
diff changeset
1002 llvm::Expected<std::vector<ClangdServer::TweakRef>> Tweaks) mutable {
anatofuz
parents:
diff changeset
1003 if (!Tweaks)
anatofuz
parents:
diff changeset
1004 return Reply(Tweaks.takeError());
anatofuz
parents:
diff changeset
1005
anatofuz
parents:
diff changeset
1006 std::vector<CodeAction> Actions = std::move(FixIts);
anatofuz
parents:
diff changeset
1007 Actions.reserve(Actions.size() + Tweaks->size());
anatofuz
parents:
diff changeset
1008 for (const auto &T : *Tweaks)
anatofuz
parents:
diff changeset
1009 Actions.push_back(toCodeAction(T, File, Selection));
anatofuz
parents:
diff changeset
1010
anatofuz
parents:
diff changeset
1011 if (SupportsCodeAction)
anatofuz
parents:
diff changeset
1012 return Reply(llvm::json::Array(Actions));
anatofuz
parents:
diff changeset
1013 std::vector<Command> Commands;
anatofuz
parents:
diff changeset
1014 for (const auto &Action : Actions) {
anatofuz
parents:
diff changeset
1015 if (auto Command = asCommand(Action))
anatofuz
parents:
diff changeset
1016 Commands.push_back(std::move(*Command));
anatofuz
parents:
diff changeset
1017 }
anatofuz
parents:
diff changeset
1018 return Reply(llvm::json::Array(Commands));
anatofuz
parents:
diff changeset
1019 };
anatofuz
parents:
diff changeset
1020
anatofuz
parents:
diff changeset
1021 Server->enumerateTweaks(File.file(), Params.range, std::move(ConsumeActions));
anatofuz
parents:
diff changeset
1022 }
anatofuz
parents:
diff changeset
1023
anatofuz
parents:
diff changeset
1024 void ClangdLSPServer::onCompletion(const CompletionParams &Params,
anatofuz
parents:
diff changeset
1025 Callback<CompletionList> Reply) {
anatofuz
parents:
diff changeset
1026 if (!shouldRunCompletion(Params)) {
anatofuz
parents:
diff changeset
1027 // Clients sometimes auto-trigger completions in undesired places (e.g.
anatofuz
parents:
diff changeset
1028 // 'a >^ '), we return empty results in those cases.
anatofuz
parents:
diff changeset
1029 vlog("ignored auto-triggered completion, preceding char did not match");
anatofuz
parents:
diff changeset
1030 return Reply(CompletionList());
anatofuz
parents:
diff changeset
1031 }
anatofuz
parents:
diff changeset
1032 Server->codeComplete(Params.textDocument.uri.file(), Params.position, CCOpts,
anatofuz
parents:
diff changeset
1033 [Reply = std::move(Reply),
anatofuz
parents:
diff changeset
1034 this](llvm::Expected<CodeCompleteResult> List) mutable {
anatofuz
parents:
diff changeset
1035 if (!List)
anatofuz
parents:
diff changeset
1036 return Reply(List.takeError());
anatofuz
parents:
diff changeset
1037 CompletionList LSPList;
anatofuz
parents:
diff changeset
1038 LSPList.isIncomplete = List->HasMore;
anatofuz
parents:
diff changeset
1039 for (const auto &R : List->Completions) {
anatofuz
parents:
diff changeset
1040 CompletionItem C = R.render(CCOpts);
anatofuz
parents:
diff changeset
1041 C.kind = adjustKindToCapability(
anatofuz
parents:
diff changeset
1042 C.kind, SupportedCompletionItemKinds);
anatofuz
parents:
diff changeset
1043 LSPList.items.push_back(std::move(C));
anatofuz
parents:
diff changeset
1044 }
anatofuz
parents:
diff changeset
1045 return Reply(std::move(LSPList));
anatofuz
parents:
diff changeset
1046 });
anatofuz
parents:
diff changeset
1047 }
anatofuz
parents:
diff changeset
1048
anatofuz
parents:
diff changeset
1049 void ClangdLSPServer::onSignatureHelp(const TextDocumentPositionParams &Params,
anatofuz
parents:
diff changeset
1050 Callback<SignatureHelp> Reply) {
anatofuz
parents:
diff changeset
1051 Server->signatureHelp(Params.textDocument.uri.file(), Params.position,
anatofuz
parents:
diff changeset
1052 [Reply = std::move(Reply), this](
anatofuz
parents:
diff changeset
1053 llvm::Expected<SignatureHelp> Signature) mutable {
anatofuz
parents:
diff changeset
1054 if (!Signature)
anatofuz
parents:
diff changeset
1055 return Reply(Signature.takeError());
anatofuz
parents:
diff changeset
1056 if (SupportsOffsetsInSignatureHelp)
anatofuz
parents:
diff changeset
1057 return Reply(std::move(*Signature));
anatofuz
parents:
diff changeset
1058 // Strip out the offsets from signature help for
anatofuz
parents:
diff changeset
1059 // clients that only support string labels.
anatofuz
parents:
diff changeset
1060 for (auto &SigInfo : Signature->signatures) {
anatofuz
parents:
diff changeset
1061 for (auto &Param : SigInfo.parameters)
anatofuz
parents:
diff changeset
1062 Param.labelOffsets.reset();
anatofuz
parents:
diff changeset
1063 }
anatofuz
parents:
diff changeset
1064 return Reply(std::move(*Signature));
anatofuz
parents:
diff changeset
1065 });
anatofuz
parents:
diff changeset
1066 }
anatofuz
parents:
diff changeset
1067
anatofuz
parents:
diff changeset
1068 // Go to definition has a toggle function: if def and decl are distinct, then
anatofuz
parents:
diff changeset
1069 // the first press gives you the def, the second gives you the matching def.
anatofuz
parents:
diff changeset
1070 // getToggle() returns the counterpart location that under the cursor.
anatofuz
parents:
diff changeset
1071 //
anatofuz
parents:
diff changeset
1072 // We return the toggled location alone (ignoring other symbols) to encourage
anatofuz
parents:
diff changeset
1073 // editors to "bounce" quickly between locations, without showing a menu.
anatofuz
parents:
diff changeset
1074 static Location *getToggle(const TextDocumentPositionParams &Point,
anatofuz
parents:
diff changeset
1075 LocatedSymbol &Sym) {
anatofuz
parents:
diff changeset
1076 // Toggle only makes sense with two distinct locations.
anatofuz
parents:
diff changeset
1077 if (!Sym.Definition || *Sym.Definition == Sym.PreferredDeclaration)
anatofuz
parents:
diff changeset
1078 return nullptr;
anatofuz
parents:
diff changeset
1079 if (Sym.Definition->uri.file() == Point.textDocument.uri.file() &&
anatofuz
parents:
diff changeset
1080 Sym.Definition->range.contains(Point.position))
anatofuz
parents:
diff changeset
1081 return &Sym.PreferredDeclaration;
anatofuz
parents:
diff changeset
1082 if (Sym.PreferredDeclaration.uri.file() == Point.textDocument.uri.file() &&
anatofuz
parents:
diff changeset
1083 Sym.PreferredDeclaration.range.contains(Point.position))
anatofuz
parents:
diff changeset
1084 return &*Sym.Definition;
anatofuz
parents:
diff changeset
1085 return nullptr;
anatofuz
parents:
diff changeset
1086 }
anatofuz
parents:
diff changeset
1087
anatofuz
parents:
diff changeset
1088 void ClangdLSPServer::onGoToDefinition(const TextDocumentPositionParams &Params,
anatofuz
parents:
diff changeset
1089 Callback<std::vector<Location>> Reply) {
anatofuz
parents:
diff changeset
1090 Server->locateSymbolAt(
anatofuz
parents:
diff changeset
1091 Params.textDocument.uri.file(), Params.position,
anatofuz
parents:
diff changeset
1092 [Params, Reply = std::move(Reply)](
anatofuz
parents:
diff changeset
1093 llvm::Expected<std::vector<LocatedSymbol>> Symbols) mutable {
anatofuz
parents:
diff changeset
1094 if (!Symbols)
anatofuz
parents:
diff changeset
1095 return Reply(Symbols.takeError());
anatofuz
parents:
diff changeset
1096 std::vector<Location> Defs;
anatofuz
parents:
diff changeset
1097 for (auto &S : *Symbols) {
anatofuz
parents:
diff changeset
1098 if (Location *Toggle = getToggle(Params, S))
anatofuz
parents:
diff changeset
1099 return Reply(std::vector<Location>{std::move(*Toggle)});
anatofuz
parents:
diff changeset
1100 Defs.push_back(S.Definition.getValueOr(S.PreferredDeclaration));
anatofuz
parents:
diff changeset
1101 }
anatofuz
parents:
diff changeset
1102 Reply(std::move(Defs));
anatofuz
parents:
diff changeset
1103 });
anatofuz
parents:
diff changeset
1104 }
anatofuz
parents:
diff changeset
1105
anatofuz
parents:
diff changeset
1106 void ClangdLSPServer::onGoToDeclaration(
anatofuz
parents:
diff changeset
1107 const TextDocumentPositionParams &Params,
anatofuz
parents:
diff changeset
1108 Callback<std::vector<Location>> Reply) {
anatofuz
parents:
diff changeset
1109 Server->locateSymbolAt(
anatofuz
parents:
diff changeset
1110 Params.textDocument.uri.file(), Params.position,
anatofuz
parents:
diff changeset
1111 [Params, Reply = std::move(Reply)](
anatofuz
parents:
diff changeset
1112 llvm::Expected<std::vector<LocatedSymbol>> Symbols) mutable {
anatofuz
parents:
diff changeset
1113 if (!Symbols)
anatofuz
parents:
diff changeset
1114 return Reply(Symbols.takeError());
anatofuz
parents:
diff changeset
1115 std::vector<Location> Decls;
anatofuz
parents:
diff changeset
1116 for (auto &S : *Symbols) {
anatofuz
parents:
diff changeset
1117 if (Location *Toggle = getToggle(Params, S))
anatofuz
parents:
diff changeset
1118 return Reply(std::vector<Location>{std::move(*Toggle)});
anatofuz
parents:
diff changeset
1119 Decls.push_back(std::move(S.PreferredDeclaration));
anatofuz
parents:
diff changeset
1120 }
anatofuz
parents:
diff changeset
1121 Reply(std::move(Decls));
anatofuz
parents:
diff changeset
1122 });
anatofuz
parents:
diff changeset
1123 }
anatofuz
parents:
diff changeset
1124
anatofuz
parents:
diff changeset
1125 void ClangdLSPServer::onSwitchSourceHeader(
anatofuz
parents:
diff changeset
1126 const TextDocumentIdentifier &Params,
anatofuz
parents:
diff changeset
1127 Callback<llvm::Optional<URIForFile>> Reply) {
anatofuz
parents:
diff changeset
1128 Server->switchSourceHeader(
anatofuz
parents:
diff changeset
1129 Params.uri.file(),
anatofuz
parents:
diff changeset
1130 [Reply = std::move(Reply),
anatofuz
parents:
diff changeset
1131 Params](llvm::Expected<llvm::Optional<clangd::Path>> Path) mutable {
anatofuz
parents:
diff changeset
1132 if (!Path)
anatofuz
parents:
diff changeset
1133 return Reply(Path.takeError());
anatofuz
parents:
diff changeset
1134 if (*Path)
anatofuz
parents:
diff changeset
1135 return Reply(URIForFile::canonicalize(**Path, Params.uri.file()));
anatofuz
parents:
diff changeset
1136 return Reply(llvm::None);
anatofuz
parents:
diff changeset
1137 });
anatofuz
parents:
diff changeset
1138 }
anatofuz
parents:
diff changeset
1139
anatofuz
parents:
diff changeset
1140 void ClangdLSPServer::onDocumentHighlight(
anatofuz
parents:
diff changeset
1141 const TextDocumentPositionParams &Params,
anatofuz
parents:
diff changeset
1142 Callback<std::vector<DocumentHighlight>> Reply) {
anatofuz
parents:
diff changeset
1143 Server->findDocumentHighlights(Params.textDocument.uri.file(),
anatofuz
parents:
diff changeset
1144 Params.position, std::move(Reply));
anatofuz
parents:
diff changeset
1145 }
anatofuz
parents:
diff changeset
1146
anatofuz
parents:
diff changeset
1147 void ClangdLSPServer::onHover(const TextDocumentPositionParams &Params,
anatofuz
parents:
diff changeset
1148 Callback<llvm::Optional<Hover>> Reply) {
anatofuz
parents:
diff changeset
1149 Server->findHover(Params.textDocument.uri.file(), Params.position,
anatofuz
parents:
diff changeset
1150 [Reply = std::move(Reply), this](
anatofuz
parents:
diff changeset
1151 llvm::Expected<llvm::Optional<HoverInfo>> H) mutable {
anatofuz
parents:
diff changeset
1152 if (!H)
anatofuz
parents:
diff changeset
1153 return Reply(H.takeError());
anatofuz
parents:
diff changeset
1154 if (!*H)
anatofuz
parents:
diff changeset
1155 return Reply(llvm::None);
anatofuz
parents:
diff changeset
1156
anatofuz
parents:
diff changeset
1157 Hover R;
anatofuz
parents:
diff changeset
1158 R.contents.kind = HoverContentFormat;
anatofuz
parents:
diff changeset
1159 R.range = (*H)->SymRange;
anatofuz
parents:
diff changeset
1160 switch (HoverContentFormat) {
anatofuz
parents:
diff changeset
1161 case MarkupKind::PlainText:
anatofuz
parents:
diff changeset
1162 R.contents.value = (*H)->present().asPlainText();
anatofuz
parents:
diff changeset
1163 return Reply(std::move(R));
anatofuz
parents:
diff changeset
1164 case MarkupKind::Markdown:
anatofuz
parents:
diff changeset
1165 R.contents.value = (*H)->present().asMarkdown();
anatofuz
parents:
diff changeset
1166 return Reply(std::move(R));
anatofuz
parents:
diff changeset
1167 };
anatofuz
parents:
diff changeset
1168 llvm_unreachable("unhandled MarkupKind");
anatofuz
parents:
diff changeset
1169 });
anatofuz
parents:
diff changeset
1170 }
anatofuz
parents:
diff changeset
1171
anatofuz
parents:
diff changeset
1172 void ClangdLSPServer::onTypeHierarchy(
anatofuz
parents:
diff changeset
1173 const TypeHierarchyParams &Params,
anatofuz
parents:
diff changeset
1174 Callback<Optional<TypeHierarchyItem>> Reply) {
anatofuz
parents:
diff changeset
1175 Server->typeHierarchy(Params.textDocument.uri.file(), Params.position,
anatofuz
parents:
diff changeset
1176 Params.resolve, Params.direction, std::move(Reply));
anatofuz
parents:
diff changeset
1177 }
anatofuz
parents:
diff changeset
1178
anatofuz
parents:
diff changeset
1179 void ClangdLSPServer::onResolveTypeHierarchy(
anatofuz
parents:
diff changeset
1180 const ResolveTypeHierarchyItemParams &Params,
anatofuz
parents:
diff changeset
1181 Callback<Optional<TypeHierarchyItem>> Reply) {
anatofuz
parents:
diff changeset
1182 Server->resolveTypeHierarchy(Params.item, Params.resolve, Params.direction,
anatofuz
parents:
diff changeset
1183 std::move(Reply));
anatofuz
parents:
diff changeset
1184 }
anatofuz
parents:
diff changeset
1185
anatofuz
parents:
diff changeset
1186 void ClangdLSPServer::applyConfiguration(
anatofuz
parents:
diff changeset
1187 const ConfigurationSettings &Settings) {
anatofuz
parents:
diff changeset
1188 // Per-file update to the compilation database.
anatofuz
parents:
diff changeset
1189 llvm::StringSet<> ModifiedFiles;
anatofuz
parents:
diff changeset
1190 for (auto &Entry : Settings.compilationDatabaseChanges) {
anatofuz
parents:
diff changeset
1191 PathRef File = Entry.first;
anatofuz
parents:
diff changeset
1192 auto Old = CDB->getCompileCommand(File);
anatofuz
parents:
diff changeset
1193 auto New =
anatofuz
parents:
diff changeset
1194 tooling::CompileCommand(std::move(Entry.second.workingDirectory), File,
anatofuz
parents:
diff changeset
1195 std::move(Entry.second.compilationCommand),
anatofuz
parents:
diff changeset
1196 /*Output=*/"");
anatofuz
parents:
diff changeset
1197 if (Old != New) {
anatofuz
parents:
diff changeset
1198 CDB->setCompileCommand(File, std::move(New));
anatofuz
parents:
diff changeset
1199 ModifiedFiles.insert(File);
anatofuz
parents:
diff changeset
1200 }
anatofuz
parents:
diff changeset
1201 }
anatofuz
parents:
diff changeset
1202
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1203 reparseOpenFilesIfNeeded(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1204 [&](llvm::StringRef File) { return ModifiedFiles.count(File) != 0; });
150
anatofuz
parents:
diff changeset
1205 }
anatofuz
parents:
diff changeset
1206
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1207 void ClangdLSPServer::publishTheiaSemanticHighlighting(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1208 const TheiaSemanticHighlightingParams &Params) {
150
anatofuz
parents:
diff changeset
1209 notify("textDocument/semanticHighlighting", Params);
anatofuz
parents:
diff changeset
1210 }
anatofuz
parents:
diff changeset
1211
anatofuz
parents:
diff changeset
1212 void ClangdLSPServer::publishDiagnostics(
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1213 const PublishDiagnosticsParams &Params) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1214 notify("textDocument/publishDiagnostics", Params);
150
anatofuz
parents:
diff changeset
1215 }
anatofuz
parents:
diff changeset
1216
anatofuz
parents:
diff changeset
1217 // FIXME: This function needs to be properly tested.
anatofuz
parents:
diff changeset
1218 void ClangdLSPServer::onChangeConfiguration(
anatofuz
parents:
diff changeset
1219 const DidChangeConfigurationParams &Params) {
anatofuz
parents:
diff changeset
1220 applyConfiguration(Params.settings);
anatofuz
parents:
diff changeset
1221 }
anatofuz
parents:
diff changeset
1222
anatofuz
parents:
diff changeset
1223 void ClangdLSPServer::onReference(const ReferenceParams &Params,
anatofuz
parents:
diff changeset
1224 Callback<std::vector<Location>> Reply) {
anatofuz
parents:
diff changeset
1225 Server->findReferences(Params.textDocument.uri.file(), Params.position,
anatofuz
parents:
diff changeset
1226 CCOpts.Limit,
anatofuz
parents:
diff changeset
1227 [Reply = std::move(Reply)](
anatofuz
parents:
diff changeset
1228 llvm::Expected<ReferencesResult> Refs) mutable {
anatofuz
parents:
diff changeset
1229 if (!Refs)
anatofuz
parents:
diff changeset
1230 return Reply(Refs.takeError());
anatofuz
parents:
diff changeset
1231 return Reply(std::move(Refs->References));
anatofuz
parents:
diff changeset
1232 });
anatofuz
parents:
diff changeset
1233 }
anatofuz
parents:
diff changeset
1234
anatofuz
parents:
diff changeset
1235 void ClangdLSPServer::onSymbolInfo(const TextDocumentPositionParams &Params,
anatofuz
parents:
diff changeset
1236 Callback<std::vector<SymbolDetails>> Reply) {
anatofuz
parents:
diff changeset
1237 Server->symbolInfo(Params.textDocument.uri.file(), Params.position,
anatofuz
parents:
diff changeset
1238 std::move(Reply));
anatofuz
parents:
diff changeset
1239 }
anatofuz
parents:
diff changeset
1240
anatofuz
parents:
diff changeset
1241 void ClangdLSPServer::onSelectionRange(
anatofuz
parents:
diff changeset
1242 const SelectionRangeParams &Params,
anatofuz
parents:
diff changeset
1243 Callback<std::vector<SelectionRange>> Reply) {
anatofuz
parents:
diff changeset
1244 Server->semanticRanges(
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1245 Params.textDocument.uri.file(), Params.positions,
150
anatofuz
parents:
diff changeset
1246 [Reply = std::move(Reply)](
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1247 llvm::Expected<std::vector<SelectionRange>> Ranges) mutable {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1248 if (!Ranges)
150
anatofuz
parents:
diff changeset
1249 return Reply(Ranges.takeError());
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1250 return Reply(std::move(*Ranges));
150
anatofuz
parents:
diff changeset
1251 });
anatofuz
parents:
diff changeset
1252 }
anatofuz
parents:
diff changeset
1253
anatofuz
parents:
diff changeset
1254 void ClangdLSPServer::onDocumentLink(
anatofuz
parents:
diff changeset
1255 const DocumentLinkParams &Params,
anatofuz
parents:
diff changeset
1256 Callback<std::vector<DocumentLink>> Reply) {
anatofuz
parents:
diff changeset
1257
anatofuz
parents:
diff changeset
1258 // TODO(forster): This currently resolves all targets eagerly. This is slow,
anatofuz
parents:
diff changeset
1259 // because it blocks on the preamble/AST being built. We could respond to the
anatofuz
parents:
diff changeset
1260 // request faster by using string matching or the lexer to find the includes
anatofuz
parents:
diff changeset
1261 // and resolving the targets lazily.
anatofuz
parents:
diff changeset
1262 Server->documentLinks(
anatofuz
parents:
diff changeset
1263 Params.textDocument.uri.file(),
anatofuz
parents:
diff changeset
1264 [Reply = std::move(Reply)](
anatofuz
parents:
diff changeset
1265 llvm::Expected<std::vector<DocumentLink>> Links) mutable {
anatofuz
parents:
diff changeset
1266 if (!Links) {
anatofuz
parents:
diff changeset
1267 return Reply(Links.takeError());
anatofuz
parents:
diff changeset
1268 }
anatofuz
parents:
diff changeset
1269 return Reply(std::move(Links));
anatofuz
parents:
diff changeset
1270 });
anatofuz
parents:
diff changeset
1271 }
anatofuz
parents:
diff changeset
1272
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1273 // Increment a numeric string: "" -> 1 -> 2 -> ... -> 9 -> 10 -> 11 ...
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1274 static void increment(std::string &S) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1275 for (char &C : llvm::reverse(S)) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1276 if (C != '9') {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1277 ++C;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1278 return;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1279 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1280 C = '0';
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1281 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1282 S.insert(S.begin(), '1');
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1283 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1284
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1285 void ClangdLSPServer::onSemanticTokens(const SemanticTokensParams &Params,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1286 Callback<SemanticTokens> CB) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1287 Server->semanticHighlights(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1288 Params.textDocument.uri.file(),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1289 [this, File(Params.textDocument.uri.file().str()), CB(std::move(CB))](
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1290 llvm::Expected<std::vector<HighlightingToken>> HT) mutable {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1291 if (!HT)
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1292 return CB(HT.takeError());
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1293 SemanticTokens Result;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1294 Result.tokens = toSemanticTokens(*HT);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1295 {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1296 std::lock_guard<std::mutex> Lock(SemanticTokensMutex);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1297 auto &Last = LastSemanticTokens[File];
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1298
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1299 Last.tokens = Result.tokens;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1300 increment(Last.resultId);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1301 Result.resultId = Last.resultId;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1302 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1303 CB(std::move(Result));
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1304 });
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1305 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1306
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1307 void ClangdLSPServer::onSemanticTokensEdits(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1308 const SemanticTokensEditsParams &Params,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1309 Callback<SemanticTokensOrEdits> CB) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1310 Server->semanticHighlights(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1311 Params.textDocument.uri.file(),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1312 [this, PrevResultID(Params.previousResultId),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1313 File(Params.textDocument.uri.file().str()), CB(std::move(CB))](
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1314 llvm::Expected<std::vector<HighlightingToken>> HT) mutable {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1315 if (!HT)
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1316 return CB(HT.takeError());
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1317 std::vector<SemanticToken> Toks = toSemanticTokens(*HT);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1318
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1319 SemanticTokensOrEdits Result;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1320 {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1321 std::lock_guard<std::mutex> Lock(SemanticTokensMutex);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1322 auto &Last = LastSemanticTokens[File];
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1323
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1324 if (PrevResultID == Last.resultId) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1325 Result.edits = diffTokens(Last.tokens, Toks);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1326 } else {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1327 vlog("semanticTokens/edits: wanted edits vs {0} but last result "
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1328 "had ID {1}. Returning full token list.",
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1329 PrevResultID, Last.resultId);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1330 Result.tokens = Toks;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1331 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1332
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1333 Last.tokens = std::move(Toks);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1334 increment(Last.resultId);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1335 Result.resultId = Last.resultId;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1336 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1337
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1338 CB(std::move(Result));
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1339 });
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1340 }
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1341
150
anatofuz
parents:
diff changeset
1342 ClangdLSPServer::ClangdLSPServer(
anatofuz
parents:
diff changeset
1343 class Transport &Transp, const FileSystemProvider &FSProvider,
anatofuz
parents:
diff changeset
1344 const clangd::CodeCompleteOptions &CCOpts,
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1345 const clangd::RenameOptions &RenameOpts,
150
anatofuz
parents:
diff changeset
1346 llvm::Optional<Path> CompileCommandsDir, bool UseDirBasedCDB,
anatofuz
parents:
diff changeset
1347 llvm::Optional<OffsetEncoding> ForcedOffsetEncoding,
anatofuz
parents:
diff changeset
1348 const ClangdServer::Options &Opts)
anatofuz
parents:
diff changeset
1349 : BackgroundContext(Context::current().clone()), Transp(Transp),
anatofuz
parents:
diff changeset
1350 MsgHandler(new MessageHandler(*this)), FSProvider(FSProvider),
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1351 CCOpts(CCOpts), RenameOpts(RenameOpts),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1352 SupportedSymbolKinds(defaultSymbolKinds()),
150
anatofuz
parents:
diff changeset
1353 SupportedCompletionItemKinds(defaultCompletionItemKinds()),
anatofuz
parents:
diff changeset
1354 UseDirBasedCDB(UseDirBasedCDB),
anatofuz
parents:
diff changeset
1355 CompileCommandsDir(std::move(CompileCommandsDir)), ClangdServerOpts(Opts),
anatofuz
parents:
diff changeset
1356 NegotiatedOffsetEncoding(ForcedOffsetEncoding) {
anatofuz
parents:
diff changeset
1357 // clang-format off
anatofuz
parents:
diff changeset
1358 MsgHandler->bind("initialize", &ClangdLSPServer::onInitialize);
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1359 MsgHandler->bind("initialized", &ClangdLSPServer::onInitialized);
150
anatofuz
parents:
diff changeset
1360 MsgHandler->bind("shutdown", &ClangdLSPServer::onShutdown);
anatofuz
parents:
diff changeset
1361 MsgHandler->bind("sync", &ClangdLSPServer::onSync);
anatofuz
parents:
diff changeset
1362 MsgHandler->bind("textDocument/rangeFormatting", &ClangdLSPServer::onDocumentRangeFormatting);
anatofuz
parents:
diff changeset
1363 MsgHandler->bind("textDocument/onTypeFormatting", &ClangdLSPServer::onDocumentOnTypeFormatting);
anatofuz
parents:
diff changeset
1364 MsgHandler->bind("textDocument/formatting", &ClangdLSPServer::onDocumentFormatting);
anatofuz
parents:
diff changeset
1365 MsgHandler->bind("textDocument/codeAction", &ClangdLSPServer::onCodeAction);
anatofuz
parents:
diff changeset
1366 MsgHandler->bind("textDocument/completion", &ClangdLSPServer::onCompletion);
anatofuz
parents:
diff changeset
1367 MsgHandler->bind("textDocument/signatureHelp", &ClangdLSPServer::onSignatureHelp);
anatofuz
parents:
diff changeset
1368 MsgHandler->bind("textDocument/definition", &ClangdLSPServer::onGoToDefinition);
anatofuz
parents:
diff changeset
1369 MsgHandler->bind("textDocument/declaration", &ClangdLSPServer::onGoToDeclaration);
anatofuz
parents:
diff changeset
1370 MsgHandler->bind("textDocument/references", &ClangdLSPServer::onReference);
anatofuz
parents:
diff changeset
1371 MsgHandler->bind("textDocument/switchSourceHeader", &ClangdLSPServer::onSwitchSourceHeader);
anatofuz
parents:
diff changeset
1372 MsgHandler->bind("textDocument/prepareRename", &ClangdLSPServer::onPrepareRename);
anatofuz
parents:
diff changeset
1373 MsgHandler->bind("textDocument/rename", &ClangdLSPServer::onRename);
anatofuz
parents:
diff changeset
1374 MsgHandler->bind("textDocument/hover", &ClangdLSPServer::onHover);
anatofuz
parents:
diff changeset
1375 MsgHandler->bind("textDocument/documentSymbol", &ClangdLSPServer::onDocumentSymbol);
anatofuz
parents:
diff changeset
1376 MsgHandler->bind("workspace/executeCommand", &ClangdLSPServer::onCommand);
anatofuz
parents:
diff changeset
1377 MsgHandler->bind("textDocument/documentHighlight", &ClangdLSPServer::onDocumentHighlight);
anatofuz
parents:
diff changeset
1378 MsgHandler->bind("workspace/symbol", &ClangdLSPServer::onWorkspaceSymbol);
anatofuz
parents:
diff changeset
1379 MsgHandler->bind("textDocument/didOpen", &ClangdLSPServer::onDocumentDidOpen);
anatofuz
parents:
diff changeset
1380 MsgHandler->bind("textDocument/didClose", &ClangdLSPServer::onDocumentDidClose);
anatofuz
parents:
diff changeset
1381 MsgHandler->bind("textDocument/didChange", &ClangdLSPServer::onDocumentDidChange);
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1382 MsgHandler->bind("textDocument/didSave", &ClangdLSPServer::onDocumentDidSave);
150
anatofuz
parents:
diff changeset
1383 MsgHandler->bind("workspace/didChangeWatchedFiles", &ClangdLSPServer::onFileEvent);
anatofuz
parents:
diff changeset
1384 MsgHandler->bind("workspace/didChangeConfiguration", &ClangdLSPServer::onChangeConfiguration);
anatofuz
parents:
diff changeset
1385 MsgHandler->bind("textDocument/symbolInfo", &ClangdLSPServer::onSymbolInfo);
anatofuz
parents:
diff changeset
1386 MsgHandler->bind("textDocument/typeHierarchy", &ClangdLSPServer::onTypeHierarchy);
anatofuz
parents:
diff changeset
1387 MsgHandler->bind("typeHierarchy/resolve", &ClangdLSPServer::onResolveTypeHierarchy);
anatofuz
parents:
diff changeset
1388 MsgHandler->bind("textDocument/selectionRange", &ClangdLSPServer::onSelectionRange);
anatofuz
parents:
diff changeset
1389 MsgHandler->bind("textDocument/documentLink", &ClangdLSPServer::onDocumentLink);
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1390 MsgHandler->bind("textDocument/semanticTokens", &ClangdLSPServer::onSemanticTokens);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1391 MsgHandler->bind("textDocument/semanticTokens/edits", &ClangdLSPServer::onSemanticTokensEdits);
150
anatofuz
parents:
diff changeset
1392 // clang-format on
anatofuz
parents:
diff changeset
1393 }
anatofuz
parents:
diff changeset
1394
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1395 ClangdLSPServer::~ClangdLSPServer() {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1396 IsBeingDestroyed = true;
150
anatofuz
parents:
diff changeset
1397 // Explicitly destroy ClangdServer first, blocking on threads it owns.
anatofuz
parents:
diff changeset
1398 // This ensures they don't access any other members.
anatofuz
parents:
diff changeset
1399 Server.reset();
anatofuz
parents:
diff changeset
1400 }
anatofuz
parents:
diff changeset
1401
anatofuz
parents:
diff changeset
1402 bool ClangdLSPServer::run() {
anatofuz
parents:
diff changeset
1403 // Run the Language Server loop.
anatofuz
parents:
diff changeset
1404 bool CleanExit = true;
anatofuz
parents:
diff changeset
1405 if (auto Err = Transp.loop(*MsgHandler)) {
anatofuz
parents:
diff changeset
1406 elog("Transport error: {0}", std::move(Err));
anatofuz
parents:
diff changeset
1407 CleanExit = false;
anatofuz
parents:
diff changeset
1408 }
anatofuz
parents:
diff changeset
1409
anatofuz
parents:
diff changeset
1410 return CleanExit && ShutdownRequestReceived;
anatofuz
parents:
diff changeset
1411 }
anatofuz
parents:
diff changeset
1412
anatofuz
parents:
diff changeset
1413 std::vector<Fix> ClangdLSPServer::getFixes(llvm::StringRef File,
anatofuz
parents:
diff changeset
1414 const clangd::Diagnostic &D) {
anatofuz
parents:
diff changeset
1415 std::lock_guard<std::mutex> Lock(FixItsMutex);
anatofuz
parents:
diff changeset
1416 auto DiagToFixItsIter = FixItsMap.find(File);
anatofuz
parents:
diff changeset
1417 if (DiagToFixItsIter == FixItsMap.end())
anatofuz
parents:
diff changeset
1418 return {};
anatofuz
parents:
diff changeset
1419
anatofuz
parents:
diff changeset
1420 const auto &DiagToFixItsMap = DiagToFixItsIter->second;
anatofuz
parents:
diff changeset
1421 auto FixItsIter = DiagToFixItsMap.find(D);
anatofuz
parents:
diff changeset
1422 if (FixItsIter == DiagToFixItsMap.end())
anatofuz
parents:
diff changeset
1423 return {};
anatofuz
parents:
diff changeset
1424
anatofuz
parents:
diff changeset
1425 return FixItsIter->second;
anatofuz
parents:
diff changeset
1426 }
anatofuz
parents:
diff changeset
1427
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1428 // A completion request is sent when the user types '>' or ':', but we only
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1429 // want to trigger on '->' and '::'. We check the preceeding text to make
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1430 // sure it matches what we expected.
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1431 // Running the lexer here would be more robust (e.g. we can detect comments
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1432 // and avoid triggering completion there), but we choose to err on the side
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1433 // of simplicity here.
150
anatofuz
parents:
diff changeset
1434 bool ClangdLSPServer::shouldRunCompletion(
anatofuz
parents:
diff changeset
1435 const CompletionParams &Params) const {
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1436 if (Params.context.triggerKind != CompletionTriggerKind::TriggerCharacter)
150
anatofuz
parents:
diff changeset
1437 return true;
anatofuz
parents:
diff changeset
1438 auto Code = DraftMgr.getDraft(Params.textDocument.uri.file());
anatofuz
parents:
diff changeset
1439 if (!Code)
anatofuz
parents:
diff changeset
1440 return true; // completion code will log the error for untracked doc.
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1441 auto Offset = positionToOffset(Code->Contents, Params.position,
150
anatofuz
parents:
diff changeset
1442 /*AllowColumnsBeyondLineLength=*/false);
anatofuz
parents:
diff changeset
1443 if (!Offset) {
anatofuz
parents:
diff changeset
1444 vlog("could not convert position '{0}' to offset for file '{1}'",
anatofuz
parents:
diff changeset
1445 Params.position, Params.textDocument.uri.file());
anatofuz
parents:
diff changeset
1446 return true;
anatofuz
parents:
diff changeset
1447 }
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1448 return allowImplicitCompletion(Code->Contents, *Offset);
150
anatofuz
parents:
diff changeset
1449 }
anatofuz
parents:
diff changeset
1450
anatofuz
parents:
diff changeset
1451 void ClangdLSPServer::onHighlightingsReady(
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1452 PathRef File, llvm::StringRef Version,
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1453 std::vector<HighlightingToken> Highlightings) {
150
anatofuz
parents:
diff changeset
1454 std::vector<HighlightingToken> Old;
anatofuz
parents:
diff changeset
1455 std::vector<HighlightingToken> HighlightingsCopy = Highlightings;
anatofuz
parents:
diff changeset
1456 {
anatofuz
parents:
diff changeset
1457 std::lock_guard<std::mutex> Lock(HighlightingsMutex);
anatofuz
parents:
diff changeset
1458 Old = std::move(FileToHighlightings[File]);
anatofuz
parents:
diff changeset
1459 FileToHighlightings[File] = std::move(HighlightingsCopy);
anatofuz
parents:
diff changeset
1460 }
anatofuz
parents:
diff changeset
1461 // LSP allows us to send incremental edits of highlightings. Also need to diff
anatofuz
parents:
diff changeset
1462 // to remove highlightings from tokens that should no longer have them.
anatofuz
parents:
diff changeset
1463 std::vector<LineHighlightings> Diffed = diffHighlightings(Highlightings, Old);
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1464 TheiaSemanticHighlightingParams Notification;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1465 Notification.TextDocument.uri =
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1466 URIForFile::canonicalize(File, /*TUPath=*/File);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1467 Notification.TextDocument.version = decodeVersion(Version);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1468 Notification.Lines = toTheiaSemanticHighlightingInformation(Diffed);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1469 publishTheiaSemanticHighlighting(Notification);
150
anatofuz
parents:
diff changeset
1470 }
anatofuz
parents:
diff changeset
1471
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1472 void ClangdLSPServer::onDiagnosticsReady(PathRef File, llvm::StringRef Version,
150
anatofuz
parents:
diff changeset
1473 std::vector<Diag> Diagnostics) {
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1474 PublishDiagnosticsParams Notification;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1475 Notification.version = decodeVersion(Version);
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1476 Notification.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
150
anatofuz
parents:
diff changeset
1477 DiagnosticToReplacementMap LocalFixIts; // Temporary storage
anatofuz
parents:
diff changeset
1478 for (auto &Diag : Diagnostics) {
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1479 toLSPDiags(Diag, Notification.uri, DiagOpts,
150
anatofuz
parents:
diff changeset
1480 [&](clangd::Diagnostic Diag, llvm::ArrayRef<Fix> Fixes) {
anatofuz
parents:
diff changeset
1481 auto &FixItsForDiagnostic = LocalFixIts[Diag];
anatofuz
parents:
diff changeset
1482 llvm::copy(Fixes, std::back_inserter(FixItsForDiagnostic));
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1483 Notification.diagnostics.push_back(std::move(Diag));
150
anatofuz
parents:
diff changeset
1484 });
anatofuz
parents:
diff changeset
1485 }
anatofuz
parents:
diff changeset
1486
anatofuz
parents:
diff changeset
1487 // Cache FixIts
anatofuz
parents:
diff changeset
1488 {
anatofuz
parents:
diff changeset
1489 std::lock_guard<std::mutex> Lock(FixItsMutex);
anatofuz
parents:
diff changeset
1490 FixItsMap[File] = LocalFixIts;
anatofuz
parents:
diff changeset
1491 }
anatofuz
parents:
diff changeset
1492
anatofuz
parents:
diff changeset
1493 // Send a notification to the LSP client.
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1494 publishDiagnostics(Notification);
150
anatofuz
parents:
diff changeset
1495 }
anatofuz
parents:
diff changeset
1496
anatofuz
parents:
diff changeset
1497 void ClangdLSPServer::onBackgroundIndexProgress(
anatofuz
parents:
diff changeset
1498 const BackgroundQueue::Stats &Stats) {
anatofuz
parents:
diff changeset
1499 static const char ProgressToken[] = "backgroundIndexProgress";
anatofuz
parents:
diff changeset
1500 std::lock_guard<std::mutex> Lock(BackgroundIndexProgressMutex);
anatofuz
parents:
diff changeset
1501
anatofuz
parents:
diff changeset
1502 auto NotifyProgress = [this](const BackgroundQueue::Stats &Stats) {
anatofuz
parents:
diff changeset
1503 if (BackgroundIndexProgressState != BackgroundIndexProgress::Live) {
anatofuz
parents:
diff changeset
1504 WorkDoneProgressBegin Begin;
anatofuz
parents:
diff changeset
1505 Begin.percentage = true;
anatofuz
parents:
diff changeset
1506 Begin.title = "indexing";
anatofuz
parents:
diff changeset
1507 progress(ProgressToken, std::move(Begin));
anatofuz
parents:
diff changeset
1508 BackgroundIndexProgressState = BackgroundIndexProgress::Live;
anatofuz
parents:
diff changeset
1509 }
anatofuz
parents:
diff changeset
1510
anatofuz
parents:
diff changeset
1511 if (Stats.Completed < Stats.Enqueued) {
anatofuz
parents:
diff changeset
1512 assert(Stats.Enqueued > Stats.LastIdle);
anatofuz
parents:
diff changeset
1513 WorkDoneProgressReport Report;
anatofuz
parents:
diff changeset
1514 Report.percentage = 100.0 * (Stats.Completed - Stats.LastIdle) /
anatofuz
parents:
diff changeset
1515 (Stats.Enqueued - Stats.LastIdle);
anatofuz
parents:
diff changeset
1516 Report.message =
anatofuz
parents:
diff changeset
1517 llvm::formatv("{0}/{1}", Stats.Completed - Stats.LastIdle,
anatofuz
parents:
diff changeset
1518 Stats.Enqueued - Stats.LastIdle);
anatofuz
parents:
diff changeset
1519 progress(ProgressToken, std::move(Report));
anatofuz
parents:
diff changeset
1520 } else {
anatofuz
parents:
diff changeset
1521 assert(Stats.Completed == Stats.Enqueued);
anatofuz
parents:
diff changeset
1522 progress(ProgressToken, WorkDoneProgressEnd());
anatofuz
parents:
diff changeset
1523 BackgroundIndexProgressState = BackgroundIndexProgress::Empty;
anatofuz
parents:
diff changeset
1524 }
anatofuz
parents:
diff changeset
1525 };
anatofuz
parents:
diff changeset
1526
anatofuz
parents:
diff changeset
1527 switch (BackgroundIndexProgressState) {
anatofuz
parents:
diff changeset
1528 case BackgroundIndexProgress::Unsupported:
anatofuz
parents:
diff changeset
1529 return;
anatofuz
parents:
diff changeset
1530 case BackgroundIndexProgress::Creating:
anatofuz
parents:
diff changeset
1531 // Cache this update for when the progress bar is available.
anatofuz
parents:
diff changeset
1532 PendingBackgroundIndexProgress = Stats;
anatofuz
parents:
diff changeset
1533 return;
anatofuz
parents:
diff changeset
1534 case BackgroundIndexProgress::Empty: {
anatofuz
parents:
diff changeset
1535 if (BackgroundIndexSkipCreate) {
anatofuz
parents:
diff changeset
1536 NotifyProgress(Stats);
anatofuz
parents:
diff changeset
1537 break;
anatofuz
parents:
diff changeset
1538 }
anatofuz
parents:
diff changeset
1539 // Cache this update for when the progress bar is available.
anatofuz
parents:
diff changeset
1540 PendingBackgroundIndexProgress = Stats;
anatofuz
parents:
diff changeset
1541 BackgroundIndexProgressState = BackgroundIndexProgress::Creating;
anatofuz
parents:
diff changeset
1542 WorkDoneProgressCreateParams CreateRequest;
anatofuz
parents:
diff changeset
1543 CreateRequest.token = ProgressToken;
anatofuz
parents:
diff changeset
1544 call<std::nullptr_t>(
anatofuz
parents:
diff changeset
1545 "window/workDoneProgress/create", CreateRequest,
anatofuz
parents:
diff changeset
1546 [this, NotifyProgress](llvm::Expected<std::nullptr_t> E) {
anatofuz
parents:
diff changeset
1547 std::lock_guard<std::mutex> Lock(BackgroundIndexProgressMutex);
anatofuz
parents:
diff changeset
1548 if (E) {
anatofuz
parents:
diff changeset
1549 NotifyProgress(this->PendingBackgroundIndexProgress);
anatofuz
parents:
diff changeset
1550 } else {
anatofuz
parents:
diff changeset
1551 elog("Failed to create background index progress bar: {0}",
anatofuz
parents:
diff changeset
1552 E.takeError());
anatofuz
parents:
diff changeset
1553 // give up forever rather than thrashing about
anatofuz
parents:
diff changeset
1554 BackgroundIndexProgressState = BackgroundIndexProgress::Unsupported;
anatofuz
parents:
diff changeset
1555 }
anatofuz
parents:
diff changeset
1556 });
anatofuz
parents:
diff changeset
1557 break;
anatofuz
parents:
diff changeset
1558 }
anatofuz
parents:
diff changeset
1559 case BackgroundIndexProgress::Live:
anatofuz
parents:
diff changeset
1560 NotifyProgress(Stats);
anatofuz
parents:
diff changeset
1561 break;
anatofuz
parents:
diff changeset
1562 }
anatofuz
parents:
diff changeset
1563 }
anatofuz
parents:
diff changeset
1564
anatofuz
parents:
diff changeset
1565 void ClangdLSPServer::onFileUpdated(PathRef File, const TUStatus &Status) {
anatofuz
parents:
diff changeset
1566 if (!SupportFileStatus)
anatofuz
parents:
diff changeset
1567 return;
anatofuz
parents:
diff changeset
1568 // FIXME: we don't emit "BuildingFile" and `RunningAction`, as these
anatofuz
parents:
diff changeset
1569 // two statuses are running faster in practice, which leads the UI constantly
anatofuz
parents:
diff changeset
1570 // changing, and doesn't provide much value. We may want to emit status at a
anatofuz
parents:
diff changeset
1571 // reasonable time interval (e.g. 0.5s).
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1572 if (Status.PreambleActivity == PreambleAction::Idle &&
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1573 (Status.ASTActivity.K == ASTAction::Building ||
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1574 Status.ASTActivity.K == ASTAction::RunningAction))
150
anatofuz
parents:
diff changeset
1575 return;
anatofuz
parents:
diff changeset
1576 notify("textDocument/clangd.fileStatus", Status.render(File));
anatofuz
parents:
diff changeset
1577 }
anatofuz
parents:
diff changeset
1578
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1579 void ClangdLSPServer::reparseOpenFilesIfNeeded(
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1580 llvm::function_ref<bool(llvm::StringRef File)> Filter) {
150
anatofuz
parents:
diff changeset
1581 // Reparse only opened files that were modified.
anatofuz
parents:
diff changeset
1582 for (const Path &FilePath : DraftMgr.getActiveFiles())
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1583 if (Filter(FilePath))
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1584 if (auto Draft = DraftMgr.getDraft(FilePath)) // else disappeared in race?
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1585 Server->addDocument(FilePath, std::move(Draft->Contents),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1586 encodeVersion(Draft->Version),
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
1587 WantDiagnostics::Auto);
150
anatofuz
parents:
diff changeset
1588 }
anatofuz
parents:
diff changeset
1589
anatofuz
parents:
diff changeset
1590 } // namespace clangd
anatofuz
parents:
diff changeset
1591 } // namespace clang