blob: 2aa13109f442b78332f88d42be1b09efeb7803cf [file] [log] [blame]
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +00001//===--- Protocol.cpp - Language Server Protocol Implementation -----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains the serialization code for the LSP structs.
11// FIXME: This is extremely repetetive and ugly. Is there a better way?
12//
13//===----------------------------------------------------------------------===//
14
15#include "Protocol.h"
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +000016
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000017#include "clang/Basic/LLVM.h"
18#include "llvm/ADT/SmallString.h"
19#include "llvm/Support/Format.h"
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +000020#include "llvm/Support/FormatVariadic.h"
Krasimir Georgiev50117372017-04-07 11:03:26 +000021#include "llvm/Support/Path.h"
Ilya Biryukov574b7532017-08-02 09:08:39 +000022#include "llvm/Support/raw_ostream.h"
Ilya Biryukove5128f72017-09-20 07:24:15 +000023
24using namespace clang;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000025using namespace clang::clangd;
26
Krasimir Georgiev50117372017-04-07 11:03:26 +000027URI URI::fromUri(llvm::StringRef uri) {
28 URI Result;
29 Result.uri = uri;
30 uri.consume_front("file://");
Benjamin Kramer8c3ba632017-04-21 15:51:18 +000031 // Also trim authority-less URIs
32 uri.consume_front("file:");
Krasimir Georgiev50117372017-04-07 11:03:26 +000033 // For Windows paths e.g. /X:
34 if (uri.size() > 2 && uri[0] == '/' && uri[2] == ':')
35 uri.consume_front("/");
36 // Make sure that file paths are in native separators
37 Result.file = llvm::sys::path::convert_to_slash(uri);
38 return Result;
39}
40
41URI URI::fromFile(llvm::StringRef file) {
42 using namespace llvm::sys;
43 URI Result;
44 Result.file = file;
45 Result.uri = "file://";
46 // For Windows paths e.g. X:
47 if (file.size() > 1 && file[1] == ':')
48 Result.uri += "/";
49 // Make sure that uri paths are with posix separators
50 Result.uri += path::convert_to_slash(file, path::Style::posix);
51 return Result;
52}
53
Sam McCalldd0566b2017-11-06 15:40:30 +000054json::Expr URI::unparse(const URI &U) { return U.uri; }
Krasimir Georgiev50117372017-04-07 11:03:26 +000055
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000056llvm::Optional<TextDocumentIdentifier>
Sam McCallec109022017-11-28 09:37:43 +000057TextDocumentIdentifier::parse(const json::Expr &Params) {
58 const json::obj *O = Params.asObject();
59 if (!O)
60 return None;
61
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000062 TextDocumentIdentifier Result;
Sam McCallec109022017-11-28 09:37:43 +000063 if (auto U = O->getString("uri"))
64 Result.uri = URI::parse(*U);
65 // FIXME: parse 'version', but only for VersionedTextDocumentIdentifiers.
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000066 return Result;
67}
68
Sam McCallec109022017-11-28 09:37:43 +000069llvm::Optional<Position> Position::parse(const json::Expr &Params) {
70 const json::obj *O = Params.asObject();
71 if (!O)
72 return None;
73
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000074 Position Result;
Sam McCallec109022017-11-28 09:37:43 +000075 if (auto L = O->getInteger("line"))
76 Result.line = *L;
77 if (auto C = O->getInteger("character"))
78 Result.character = *C;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000079 return Result;
80}
81
Sam McCalldd0566b2017-11-06 15:40:30 +000082json::Expr Position::unparse(const Position &P) {
83 return json::obj{
84 {"line", P.line},
85 {"character", P.character},
86 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000087}
88
Sam McCallec109022017-11-28 09:37:43 +000089llvm::Optional<Range> Range::parse(const json::Expr &Params) {
90 const json::obj *O = Params.asObject();
91 if (!O)
92 return None;
93
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000094 Range Result;
Sam McCallec109022017-11-28 09:37:43 +000095 if (auto *S = O->get("start")) {
96 if (auto P = Position::parse(*S))
97 Result.start = std::move(*P);
98 else
99 return None;
100 }
101 if (auto *E = O->get("end")) {
102 if (auto P = Position::parse(*E))
103 Result.end = std::move(*P);
104 else
105 return None;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000106 }
107 return Result;
108}
109
Sam McCalldd0566b2017-11-06 15:40:30 +0000110json::Expr Range::unparse(const Range &P) {
111 return json::obj{
112 {"start", P.start},
113 {"end", P.end},
114 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000115}
116
Sam McCalldd0566b2017-11-06 15:40:30 +0000117json::Expr Location::unparse(const Location &P) {
118 return json::obj{
119 {"uri", P.uri},
120 {"range", P.range},
121 };
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000122}
123
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000124llvm::Optional<TextDocumentItem>
Sam McCallec109022017-11-28 09:37:43 +0000125TextDocumentItem::parse(const json::Expr &Params) {
126 const json::obj *O = Params.asObject();
127 if (!O)
128 return None;
129
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000130 TextDocumentItem Result;
Sam McCallec109022017-11-28 09:37:43 +0000131 if (auto U = O->getString("uri"))
132 Result.uri = URI::parse(*U);
133 if (auto L = O->getString("languageId"))
134 Result.languageId = *L;
135 if (auto V = O->getInteger("version"))
136 Result.version = *V;
137 if (auto T = O->getString("text"))
138 Result.text = *T;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000139 return Result;
140}
141
Sam McCallec109022017-11-28 09:37:43 +0000142llvm::Optional<Metadata> Metadata::parse(const json::Expr &Params) {
143 const json::obj *O = Params.asObject();
144 if (!O)
145 return None;
146
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000147 Metadata Result;
Sam McCallec109022017-11-28 09:37:43 +0000148 if (auto *Flags = O->getArray("extraFlags"))
149 for (auto &F : *Flags) {
150 if (auto S = F.asString())
151 Result.extraFlags.push_back(*S);
152 else
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000153 return llvm::None;
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000154 }
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000155 return Result;
156}
157
Sam McCallec109022017-11-28 09:37:43 +0000158llvm::Optional<TextEdit> TextEdit::parse(const json::Expr &Params) {
159 const json::obj *O = Params.asObject();
160 if (!O)
161 return None;
162
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000163 TextEdit Result;
Sam McCallec109022017-11-28 09:37:43 +0000164 if (auto *R = O->get("range")) {
165 if (auto Parsed = Range::parse(*R))
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000166 Result.range = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000167 else
168 return llvm::None;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000169 }
Sam McCallec109022017-11-28 09:37:43 +0000170 if (auto T = O->getString("newText"))
171 Result.newText = *T;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000172 return Result;
173}
174
Sam McCalldd0566b2017-11-06 15:40:30 +0000175json::Expr TextEdit::unparse(const TextEdit &P) {
176 return json::obj{
177 {"range", P.range},
178 {"newText", P.newText},
179 };
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000180}
181
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000182namespace {
Sam McCallec109022017-11-28 09:37:43 +0000183TraceLevel getTraceLevel(llvm::StringRef TraceLevelStr) {
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000184 if (TraceLevelStr == "off")
185 return TraceLevel::Off;
186 else if (TraceLevelStr == "messages")
187 return TraceLevel::Messages;
188 else if (TraceLevelStr == "verbose")
189 return TraceLevel::Verbose;
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000190 return TraceLevel::Off;
191}
192} // namespace
193
194llvm::Optional<InitializeParams>
Sam McCallec109022017-11-28 09:37:43 +0000195InitializeParams::parse(const json::Expr &Params) {
196 const json::obj *O = Params.asObject();
197 if (!O)
198 return None;
199
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000200 InitializeParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000201 if (auto P = O->getInteger("processId"))
202 Result.processId = *P;
203 if (auto R = O->getString("rootPath"))
204 Result.rootPath = *R;
205 if (auto R = O->getString("rootUri"))
206 Result.rootUri = URI::parse(*R);
207 if (auto T = O->getString("trace"))
208 Result.trace = getTraceLevel(*T);
209 // initializationOptions, capabilities unused
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000210 return Result;
211}
212
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000213llvm::Optional<DidOpenTextDocumentParams>
Sam McCallec109022017-11-28 09:37:43 +0000214DidOpenTextDocumentParams::parse(const json::Expr &Params) {
215 const json::obj *O = Params.asObject();
216 if (!O)
217 return None;
218
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000219 DidOpenTextDocumentParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000220 if (auto *D = O->get("textDocument")) {
221 if (auto Parsed = TextDocumentItem::parse(*D))
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000222 Result.textDocument = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000223 else
224 return llvm::None;
225 }
226 if (auto *M = O->get("metadata")) {
227 if (auto Parsed = Metadata::parse(*M))
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000228 Result.metadata = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000229 else
230 return llvm::None;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000231 }
232 return Result;
233}
234
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000235llvm::Optional<DidCloseTextDocumentParams>
Sam McCallec109022017-11-28 09:37:43 +0000236DidCloseTextDocumentParams::parse(const json::Expr &Params) {
237 const json::obj *O = Params.asObject();
238 if (!O)
239 return None;
240
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000241 DidCloseTextDocumentParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000242 if (auto *D = O->get("textDocument")) {
243 if (auto Parsed = TextDocumentIdentifier::parse(*D))
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000244 Result.textDocument = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000245 else
246 return llvm::None;
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000247 }
248 return Result;
249}
250
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000251llvm::Optional<DidChangeTextDocumentParams>
Sam McCallec109022017-11-28 09:37:43 +0000252DidChangeTextDocumentParams::parse(const json::Expr &Params) {
253 const json::obj *O = Params.asObject();
254 if (!O)
255 return None;
256
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000257 DidChangeTextDocumentParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000258 if (auto *D = O->get("textDocument")) {
259 if (auto Parsed = TextDocumentIdentifier::parse(*D))
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000260 Result.textDocument = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000261 else
262 return llvm::None;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000263 }
Sam McCallec109022017-11-28 09:37:43 +0000264 if (auto *A = O->getArray("contentChanges"))
265 for (auto &E : *A) {
266 if (auto Parsed = TextDocumentContentChangeEvent::parse(E))
267 Result.contentChanges.push_back(std::move(*Parsed));
268 else
269 return llvm::None;
270 }
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000271 return Result;
272}
273
Sam McCallec109022017-11-28 09:37:43 +0000274llvm::Optional<FileEvent> FileEvent::parse(const json::Expr &Params) {
275 const json::obj *O = Params.asObject();
276 if (!O)
277 return None;
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000278
Sam McCallec109022017-11-28 09:37:43 +0000279 FileEvent Result;
280 if (auto U = O->getString("uri"))
281 Result.uri = URI::parse(*U);
282 if (auto T = O->getInteger("type")) {
283 if (*T < static_cast<int>(FileChangeType::Created) ||
284 *T > static_cast<int>(FileChangeType::Deleted))
285 return llvm::None;
286 Result.type = static_cast<FileChangeType>(*T);
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000287 }
288 return Result;
289}
290
291llvm::Optional<DidChangeWatchedFilesParams>
Sam McCallec109022017-11-28 09:37:43 +0000292DidChangeWatchedFilesParams::parse(const json::Expr &Params) {
293 const json::obj *O = Params.asObject();
294 if (!O)
295 return None;
296
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000297 DidChangeWatchedFilesParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000298 if (auto *C = O->getArray("changes"))
299 for (auto &E : *C) {
300 if (auto Parsed = FileEvent::parse(E))
301 Result.changes.push_back(std::move(*Parsed));
302 else
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000303 return llvm::None;
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000304 }
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000305 return Result;
306}
307
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000308llvm::Optional<TextDocumentContentChangeEvent>
Sam McCallec109022017-11-28 09:37:43 +0000309TextDocumentContentChangeEvent::parse(const json::Expr &Params) {
310 const json::obj *O = Params.asObject();
311 if (!O)
312 return None;
313
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000314 TextDocumentContentChangeEvent Result;
Sam McCallec109022017-11-28 09:37:43 +0000315 if (auto T = O->getString("text"))
316 Result.text = *T;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000317 return Result;
318}
319
320llvm::Optional<FormattingOptions>
Sam McCallec109022017-11-28 09:37:43 +0000321FormattingOptions::parse(const json::Expr &Params) {
322 const json::obj *O = Params.asObject();
323 if (!O)
324 return None;
325
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000326 FormattingOptions Result;
Sam McCallec109022017-11-28 09:37:43 +0000327 if (auto T = O->getInteger("tabSize"))
328 Result.tabSize = *T;
329 if (auto I = O->getBoolean("insertSpaces"))
330 Result.insertSpaces = *I;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000331 return Result;
332}
333
Sam McCalldd0566b2017-11-06 15:40:30 +0000334json::Expr FormattingOptions::unparse(const FormattingOptions &P) {
335 return json::obj{
336 {"tabSize", P.tabSize},
337 {"insertSpaces", P.insertSpaces},
338 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000339}
340
341llvm::Optional<DocumentRangeFormattingParams>
Sam McCallec109022017-11-28 09:37:43 +0000342DocumentRangeFormattingParams::parse(const json::Expr &Params) {
343 const json::obj *O = Params.asObject();
344 if (!O)
345 return None;
346
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000347 DocumentRangeFormattingParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000348 if (auto *D = O->get("textDocument")) {
349 if (auto Parsed = TextDocumentIdentifier::parse(*D))
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000350 Result.textDocument = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000351 else
352 return llvm::None;
353 }
354 if (auto *R = O->get("range")) {
355 if (auto Parsed = Range::parse(*R))
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000356 Result.range = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000357 else
358 return llvm::None;
359 }
360 if (auto *F = O->get("options")) {
361 if (auto Parsed = FormattingOptions::parse(*F))
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000362 Result.options = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000363 else
364 return llvm::None;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000365 }
366 return Result;
367}
368
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000369llvm::Optional<DocumentOnTypeFormattingParams>
Sam McCallec109022017-11-28 09:37:43 +0000370DocumentOnTypeFormattingParams::parse(const json::Expr &Params) {
371 const json::obj *O = Params.asObject();
372 if (!O)
373 return None;
374
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000375 DocumentOnTypeFormattingParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000376 if (auto Ch = O->getString("ch"))
377 Result.ch = *Ch;
378 if (auto *D = O->get("textDocument")) {
379 if (auto Parsed = TextDocumentIdentifier::parse(*D))
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000380 Result.textDocument = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000381 else
382 return llvm::None;
383 }
384 if (auto *P = O->get("position")) {
385 if (auto Parsed = Position::parse(*P))
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000386 Result.position = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000387 else
388 return llvm::None;
389 }
390 if (auto *F = O->get("options")) {
391 if (auto Parsed = FormattingOptions::parse(*F))
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000392 Result.options = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000393 else
394 return llvm::None;
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000395 }
396 return Result;
397}
398
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000399llvm::Optional<DocumentFormattingParams>
Sam McCallec109022017-11-28 09:37:43 +0000400DocumentFormattingParams::parse(const json::Expr &Params) {
401 const json::obj *O = Params.asObject();
402 if (!O)
403 return None;
404
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000405 DocumentFormattingParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000406 if (auto *D = O->get("textDocument")) {
407 if (auto Parsed = TextDocumentIdentifier::parse(*D))
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000408 Result.textDocument = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000409 else
410 return llvm::None;
411 }
412 if (auto *F = O->get("options")) {
413 if (auto Parsed = FormattingOptions::parse(*F))
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000414 Result.options = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000415 else
416 return llvm::None;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000417 }
418 return Result;
419}
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000420
Sam McCallec109022017-11-28 09:37:43 +0000421llvm::Optional<Diagnostic> Diagnostic::parse(const json::Expr &Params) {
422 const json::obj *O = Params.asObject();
423 if (!O)
424 return None;
425
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000426 Diagnostic Result;
Sam McCallec109022017-11-28 09:37:43 +0000427 if (auto *R = O->get("range")) {
428 if (auto Parsed = Range::parse(*R))
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000429 Result.range = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000430 else
431 return llvm::None;
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000432 }
Sam McCallec109022017-11-28 09:37:43 +0000433 if (auto S = O->getInteger("severity"))
434 Result.severity = *S;
435 if (auto M = O->getString("message"))
436 Result.message = *M;
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000437 return Result;
438}
439
440llvm::Optional<CodeActionContext>
Sam McCallec109022017-11-28 09:37:43 +0000441CodeActionContext::parse(const json::Expr &Params) {
442 const json::obj *O = Params.asObject();
443 if (!O)
444 return None;
445
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000446 CodeActionContext Result;
Sam McCallec109022017-11-28 09:37:43 +0000447 if (auto *D = O->getArray("diagnostics"))
448 for (auto &E : *D) {
449 if (auto Parsed = Diagnostic::parse(E))
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000450 Result.diagnostics.push_back(std::move(*Parsed));
Sam McCallec109022017-11-28 09:37:43 +0000451 else
452 return llvm::None;
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000453 }
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000454 return Result;
455}
456
457llvm::Optional<CodeActionParams>
Sam McCallec109022017-11-28 09:37:43 +0000458CodeActionParams::parse(const json::Expr &Params) {
459 const json::obj *O = Params.asObject();
460 if (!O)
461 return None;
462
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000463 CodeActionParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000464 if (auto *D = O->get("textDocument")) {
465 if (auto Parsed = TextDocumentIdentifier::parse(*D))
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000466 Result.textDocument = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000467 else
468 return llvm::None;
469 }
470 if (auto *R = O->get("range")) {
471 if (auto Parsed = Range::parse(*R))
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000472 Result.range = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000473 else
474 return llvm::None;
475 }
476 if (auto *R = O->get("context")) {
477 if (auto Parsed = CodeActionContext::parse(*R))
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000478 Result.context = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000479 else
480 return llvm::None;
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000481 }
482 return Result;
483}
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000484
Sam McCallec109022017-11-28 09:37:43 +0000485llvm::Optional<std::map<std::string, std::vector<TextEdit>>>
486parseWorkspaceEditChange(const json::Expr &Params) {
487 const json::obj *O = Params.asObject();
488 if (!O)
489 return None;
490
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000491 std::map<std::string, std::vector<TextEdit>> Result;
Sam McCallec109022017-11-28 09:37:43 +0000492 for (const auto &KV : *O) {
493 auto &Values = Result[StringRef(KV.first)];
494 if (auto *Edits = KV.second.asArray())
495 for (auto &Edit : *Edits) {
496 if (auto Parsed = TextEdit::parse(Edit))
497 Values.push_back(std::move(*Parsed));
498 else
499 return llvm::None;
500 }
501 else
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000502 return llvm::None;
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000503 }
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000504 return Result;
505}
506
Sam McCallec109022017-11-28 09:37:43 +0000507llvm::Optional<WorkspaceEdit> WorkspaceEdit::parse(const json::Expr &Params) {
508 const json::obj *O = Params.asObject();
509 if (!O)
510 return None;
511
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000512 WorkspaceEdit Result;
Sam McCallec109022017-11-28 09:37:43 +0000513 if (auto *C = O->get("changes")) {
514 if (auto Parsed = parseWorkspaceEditChange(*C))
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000515 Result.changes = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000516 else
517 return llvm::None;
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000518 }
519 return Result;
520}
521
522const std::string ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
523 "clangd.applyFix";
524
525llvm::Optional<ExecuteCommandParams>
Sam McCallec109022017-11-28 09:37:43 +0000526ExecuteCommandParams::parse(const json::Expr &Params) {
527 const json::obj *O = Params.asObject();
528 if (!O)
529 return None;
530
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000531 ExecuteCommandParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000532 if (auto Command = O->getString("command"))
533 Result.command = *Command;
534 auto Args = O->getArray("arguments");
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000535
Sam McCallec109022017-11-28 09:37:43 +0000536 if (Result.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
537 if (!Args || Args->size() != 1)
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000538 return llvm::None;
Sam McCallec109022017-11-28 09:37:43 +0000539 if (auto Parsed = WorkspaceEdit::parse(Args->front()))
540 Result.workspaceEdit = std::move(*Parsed);
541 else
542 return llvm::None;
543 } else
544 return llvm::None; // Unrecognized command.
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000545 return Result;
546}
547
Sam McCalldd0566b2017-11-06 15:40:30 +0000548json::Expr WorkspaceEdit::unparse(const WorkspaceEdit &WE) {
549 if (!WE.changes)
550 return json::obj{};
551 json::obj FileChanges;
552 for (auto &Change : *WE.changes)
553 FileChanges[Change.first] = json::ary(Change.second);
554 return json::obj{{"changes", std::move(FileChanges)}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000555}
556
Sam McCalldd0566b2017-11-06 15:40:30 +0000557json::Expr
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000558ApplyWorkspaceEditParams::unparse(const ApplyWorkspaceEditParams &Params) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000559 return json::obj{{"edit", Params.edit}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000560}
561
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000562llvm::Optional<TextDocumentPositionParams>
Sam McCallec109022017-11-28 09:37:43 +0000563TextDocumentPositionParams::parse(const json::Expr &Params) {
564 const json::obj *O = Params.asObject();
565 if (!O)
566 return None;
567
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000568 TextDocumentPositionParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000569 if (auto *D = O->get("textDocument")) {
570 if (auto Parsed = TextDocumentIdentifier::parse(*D))
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000571 Result.textDocument = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000572 else
573 return llvm::None;
574 }
575 if (auto *P = O->get("position")) {
576 if (auto Parsed = Position::parse(*P))
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000577 Result.position = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000578 else
579 return llvm::None;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000580 }
581 return Result;
582}
583
Sam McCalldd0566b2017-11-06 15:40:30 +0000584json::Expr CompletionItem::unparse(const CompletionItem &CI) {
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000585 assert(!CI.label.empty() && "completion item label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +0000586 json::obj Result{{"label", CI.label}};
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000587 if (CI.kind != CompletionItemKind::Missing)
Sam McCalldd0566b2017-11-06 15:40:30 +0000588 Result["kind"] = static_cast<int>(CI.kind);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000589 if (!CI.detail.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000590 Result["detail"] = CI.detail;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000591 if (!CI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000592 Result["documentation"] = CI.documentation;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000593 if (!CI.sortText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000594 Result["sortText"] = CI.sortText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000595 if (!CI.filterText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000596 Result["filterText"] = CI.filterText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000597 if (!CI.insertText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000598 Result["insertText"] = CI.insertText;
599 if (CI.insertTextFormat != InsertTextFormat::Missing)
600 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000601 if (CI.textEdit)
Sam McCalldd0566b2017-11-06 15:40:30 +0000602 Result["textEdit"] = *CI.textEdit;
603 if (!CI.additionalTextEdits.empty())
604 Result["additionalTextEdits"] = json::ary(CI.additionalTextEdits);
605 return std::move(Result);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000606}
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000607
Sam McCallc78ccbd2017-11-08 07:44:12 +0000608bool clangd::operator<(const CompletionItem &L, const CompletionItem &R) {
609 return (L.sortText.empty() ? L.label : L.sortText) <
610 (R.sortText.empty() ? R.label : R.sortText);
611}
612
Sam McCalla40371b2017-11-15 09:16:29 +0000613json::Expr CompletionList::unparse(const CompletionList &L) {
614 return json::obj{
615 {"isIncomplete", L.isIncomplete},
616 {"items", json::ary(L.items)},
617 };
618}
619
Sam McCalldd0566b2017-11-06 15:40:30 +0000620json::Expr ParameterInformation::unparse(const ParameterInformation &PI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000621 assert(!PI.label.empty() && "parameter information label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +0000622 json::obj Result{{"label", PI.label}};
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000623 if (!PI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000624 Result["documentation"] = PI.documentation;
625 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000626}
627
Sam McCalldd0566b2017-11-06 15:40:30 +0000628json::Expr SignatureInformation::unparse(const SignatureInformation &SI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000629 assert(!SI.label.empty() && "signature information label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +0000630 json::obj Result{
631 {"label", SI.label},
632 {"parameters", json::ary(SI.parameters)},
633 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000634 if (!SI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000635 Result["documentation"] = SI.documentation;
636 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000637}
638
Sam McCalldd0566b2017-11-06 15:40:30 +0000639json::Expr SignatureHelp::unparse(const SignatureHelp &SH) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000640 assert(SH.activeSignature >= 0 &&
641 "Unexpected negative value for number of active signatures.");
642 assert(SH.activeParameter >= 0 &&
643 "Unexpected negative value for active parameter index");
Sam McCalldd0566b2017-11-06 15:40:30 +0000644 return json::obj{
645 {"activeSignature", SH.activeSignature},
646 {"activeParameter", SH.activeParameter},
647 {"signatures", json::ary(SH.signatures)},
648 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000649}
Haojian Wu345099c2017-11-09 11:30:04 +0000650
Sam McCallec109022017-11-28 09:37:43 +0000651llvm::Optional<RenameParams> RenameParams::parse(const json::Expr &Params) {
652 const json::obj *O = Params.asObject();
653 if (!O)
654 return None;
655
Haojian Wu345099c2017-11-09 11:30:04 +0000656 RenameParams Result;
Sam McCallec109022017-11-28 09:37:43 +0000657 if (auto *D = O->get("textDocument")) {
658 if (auto Parsed = TextDocumentIdentifier::parse(*D))
Haojian Wu345099c2017-11-09 11:30:04 +0000659 Result.textDocument = std::move(*Parsed);
Sam McCallec109022017-11-28 09:37:43 +0000660 else
661 return llvm::None;
Haojian Wu345099c2017-11-09 11:30:04 +0000662 }
Sam McCallec109022017-11-28 09:37:43 +0000663 if (auto *P = O->get("position")) {
664 if (auto Parsed = Position::parse(*P))
665 Result.position = std::move(*Parsed);
666 else
667 return llvm::None;
668 }
669 if (auto N = O->getString("newName"))
670 Result.newName = *N;
Haojian Wu345099c2017-11-09 11:30:04 +0000671 return Result;
672}