blob: 5ef8c9bfe8eb135771599992334d1ed89a32952e [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"
Ilya Biryukove5128f72017-09-20 07:24:15 +000016#include "Logger.h"
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +000017
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000018#include "clang/Basic/LLVM.h"
19#include "llvm/ADT/SmallString.h"
20#include "llvm/Support/Format.h"
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +000021#include "llvm/Support/FormatVariadic.h"
Krasimir Georgiev50117372017-04-07 11:03:26 +000022#include "llvm/Support/Path.h"
Ilya Biryukov574b7532017-08-02 09:08:39 +000023#include "llvm/Support/raw_ostream.h"
Ilya Biryukove5128f72017-09-20 07:24:15 +000024
25using namespace clang;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000026using namespace clang::clangd;
27
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +000028namespace {
Ilya Biryukove5128f72017-09-20 07:24:15 +000029void logIgnoredField(llvm::StringRef KeyValue, clangd::Logger &Logger) {
30 Logger.log(llvm::formatv("Ignored unknown field \"{0}\"\n", KeyValue));
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +000031}
32} // namespace
33
Krasimir Georgiev50117372017-04-07 11:03:26 +000034URI URI::fromUri(llvm::StringRef uri) {
35 URI Result;
36 Result.uri = uri;
37 uri.consume_front("file://");
Benjamin Kramer8c3ba632017-04-21 15:51:18 +000038 // Also trim authority-less URIs
39 uri.consume_front("file:");
Krasimir Georgiev50117372017-04-07 11:03:26 +000040 // For Windows paths e.g. /X:
41 if (uri.size() > 2 && uri[0] == '/' && uri[2] == ':')
42 uri.consume_front("/");
43 // Make sure that file paths are in native separators
44 Result.file = llvm::sys::path::convert_to_slash(uri);
45 return Result;
46}
47
48URI URI::fromFile(llvm::StringRef file) {
49 using namespace llvm::sys;
50 URI Result;
51 Result.file = file;
52 Result.uri = "file://";
53 // For Windows paths e.g. X:
54 if (file.size() > 1 && file[1] == ':')
55 Result.uri += "/";
56 // Make sure that uri paths are with posix separators
57 Result.uri += path::convert_to_slash(file, path::Style::posix);
58 return Result;
59}
60
61URI URI::parse(llvm::yaml::ScalarNode *Param) {
62 llvm::SmallString<10> Storage;
63 return URI::fromUri(Param->getValue(Storage));
64}
65
Sam McCalldd0566b2017-11-06 15:40:30 +000066json::Expr URI::unparse(const URI &U) { return U.uri; }
Krasimir Georgiev50117372017-04-07 11:03:26 +000067
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000068llvm::Optional<TextDocumentIdentifier>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +000069TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +000070 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000071 TextDocumentIdentifier Result;
72 for (auto &NextKeyValue : *Params) {
73 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
74 if (!KeyString)
75 return llvm::None;
76
77 llvm::SmallString<10> KeyStorage;
78 StringRef KeyValue = KeyString->getValue(KeyStorage);
79 auto *Value =
80 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
81 if (!Value)
82 return llvm::None;
83
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000084 if (KeyValue == "uri") {
Krasimir Georgiev50117372017-04-07 11:03:26 +000085 Result.uri = URI::parse(Value);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000086 } else if (KeyValue == "version") {
87 // FIXME: parse version, but only for VersionedTextDocumentIdentifiers.
88 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +000089 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000090 }
91 }
92 return Result;
93}
94
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +000095llvm::Optional<Position> Position::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +000096 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000097 Position Result;
98 for (auto &NextKeyValue : *Params) {
99 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
100 if (!KeyString)
101 return llvm::None;
102
103 llvm::SmallString<10> KeyStorage;
104 StringRef KeyValue = KeyString->getValue(KeyStorage);
105 auto *Value =
106 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
107 if (!Value)
108 return llvm::None;
109
110 llvm::SmallString<10> Storage;
111 if (KeyValue == "line") {
112 long long Val;
113 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
114 return llvm::None;
115 Result.line = Val;
116 } else if (KeyValue == "character") {
117 long long Val;
118 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
119 return llvm::None;
120 Result.character = Val;
121 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000122 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000123 }
124 }
125 return Result;
126}
127
Sam McCalldd0566b2017-11-06 15:40:30 +0000128json::Expr Position::unparse(const Position &P) {
129 return json::obj{
130 {"line", P.line},
131 {"character", P.character},
132 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000133}
134
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000135llvm::Optional<Range> Range::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000136 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000137 Range Result;
138 for (auto &NextKeyValue : *Params) {
139 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
140 if (!KeyString)
141 return llvm::None;
142
143 llvm::SmallString<10> KeyStorage;
144 StringRef KeyValue = KeyString->getValue(KeyStorage);
145 auto *Value =
146 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
147 if (!Value)
148 return llvm::None;
149
150 llvm::SmallString<10> Storage;
151 if (KeyValue == "start") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000152 auto Parsed = Position::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000153 if (!Parsed)
154 return llvm::None;
155 Result.start = std::move(*Parsed);
156 } else if (KeyValue == "end") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000157 auto Parsed = Position::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000158 if (!Parsed)
159 return llvm::None;
160 Result.end = std::move(*Parsed);
161 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000162 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000163 }
164 }
165 return Result;
166}
167
Sam McCalldd0566b2017-11-06 15:40:30 +0000168json::Expr Range::unparse(const Range &P) {
169 return json::obj{
170 {"start", P.start},
171 {"end", P.end},
172 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000173}
174
Sam McCalldd0566b2017-11-06 15:40:30 +0000175json::Expr Location::unparse(const Location &P) {
176 return json::obj{
177 {"uri", P.uri},
178 {"range", P.range},
179 };
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000180}
181
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000182llvm::Optional<TextDocumentItem>
Ilya Biryukov3847be52017-10-10 14:21:04 +0000183TextDocumentItem::parse(llvm::yaml::MappingNode *Params,
184 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000185 TextDocumentItem Result;
186 for (auto &NextKeyValue : *Params) {
187 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
188 if (!KeyString)
189 return llvm::None;
190
191 llvm::SmallString<10> KeyStorage;
192 StringRef KeyValue = KeyString->getValue(KeyStorage);
193 auto *Value =
194 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
195 if (!Value)
196 return llvm::None;
197
198 llvm::SmallString<10> Storage;
199 if (KeyValue == "uri") {
Krasimir Georgiev50117372017-04-07 11:03:26 +0000200 Result.uri = URI::parse(Value);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000201 } else if (KeyValue == "languageId") {
202 Result.languageId = Value->getValue(Storage);
203 } else if (KeyValue == "version") {
204 long long Val;
205 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
206 return llvm::None;
207 Result.version = Val;
208 } else if (KeyValue == "text") {
209 Result.text = Value->getValue(Storage);
210 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000211 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000212 }
213 }
214 return Result;
215}
216
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000217llvm::Optional<Metadata> Metadata::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000218 clangd::Logger &Logger) {
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000219 Metadata Result;
220 for (auto &NextKeyValue : *Params) {
221 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
222 if (!KeyString)
223 return llvm::None;
224
225 llvm::SmallString<10> KeyStorage;
226 StringRef KeyValue = KeyString->getValue(KeyStorage);
227 auto *Value = NextKeyValue.getValue();
228
229 llvm::SmallString<10> Storage;
230 if (KeyValue == "extraFlags") {
231 auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
232 if (!Seq)
233 return llvm::None;
234 for (auto &Item : *Seq) {
235 auto *Node = dyn_cast<llvm::yaml::ScalarNode>(&Item);
236 if (!Node)
237 return llvm::None;
238 Result.extraFlags.push_back(Node->getValue(Storage));
239 }
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000240 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000241 logIgnoredField(KeyValue, Logger);
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000242 }
243 }
244 return Result;
245}
246
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000247llvm::Optional<TextEdit> TextEdit::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000248 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000249 TextEdit Result;
250 for (auto &NextKeyValue : *Params) {
251 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
252 if (!KeyString)
253 return llvm::None;
254
255 llvm::SmallString<10> KeyStorage;
256 StringRef KeyValue = KeyString->getValue(KeyStorage);
257 auto *Value = NextKeyValue.getValue();
258
259 llvm::SmallString<10> Storage;
260 if (KeyValue == "range") {
261 auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
262 if (!Map)
263 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000264 auto Parsed = Range::parse(Map, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000265 if (!Parsed)
266 return llvm::None;
267 Result.range = std::move(*Parsed);
268 } else if (KeyValue == "newText") {
269 auto *Node = dyn_cast<llvm::yaml::ScalarNode>(Value);
270 if (!Node)
271 return llvm::None;
272 Result.newText = Node->getValue(Storage);
273 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000274 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000275 }
276 }
277 return Result;
278}
279
Sam McCalldd0566b2017-11-06 15:40:30 +0000280json::Expr TextEdit::unparse(const TextEdit &P) {
281 return json::obj{
282 {"range", P.range},
283 {"newText", P.newText},
284 };
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000285}
286
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000287namespace {
288TraceLevel getTraceLevel(llvm::StringRef TraceLevelStr,
289 clangd::Logger &Logger) {
290 if (TraceLevelStr == "off")
291 return TraceLevel::Off;
292 else if (TraceLevelStr == "messages")
293 return TraceLevel::Messages;
294 else if (TraceLevelStr == "verbose")
295 return TraceLevel::Verbose;
296
297 Logger.log(llvm::formatv("Unknown trace level \"{0}\"\n", TraceLevelStr));
298 return TraceLevel::Off;
299}
300} // namespace
301
302llvm::Optional<InitializeParams>
303InitializeParams::parse(llvm::yaml::MappingNode *Params,
304 clangd::Logger &Logger) {
Sam McCall8a5dded2017-10-12 13:29:58 +0000305 // If we don't understand the params, proceed with default parameters.
306 auto ParseFailure = [&] {
307 Logger.log("Failed to decode InitializeParams\n");
308 return InitializeParams();
309 };
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000310 InitializeParams Result;
311 for (auto &NextKeyValue : *Params) {
312 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
313 if (!KeyString)
Sam McCall8a5dded2017-10-12 13:29:58 +0000314 return ParseFailure();
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000315
316 llvm::SmallString<10> KeyStorage;
317 StringRef KeyValue = KeyString->getValue(KeyStorage);
318 auto *Value =
319 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
320 if (!Value)
321 continue;
322
323 if (KeyValue == "processId") {
324 auto *Value =
325 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
326 if (!Value)
Sam McCall8a5dded2017-10-12 13:29:58 +0000327 return ParseFailure();
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000328 long long Val;
329 if (llvm::getAsSignedInteger(Value->getValue(KeyStorage), 0, Val))
Sam McCall8a5dded2017-10-12 13:29:58 +0000330 return ParseFailure();
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000331 Result.processId = Val;
332 } else if (KeyValue == "rootPath") {
333 Result.rootPath = Value->getValue(KeyStorage);
334 } else if (KeyValue == "rootUri") {
335 Result.rootUri = URI::parse(Value);
336 } else if (KeyValue == "initializationOptions") {
337 // Not used
338 } else if (KeyValue == "capabilities") {
339 // Not used
340 } else if (KeyValue == "trace") {
341 Result.trace = getTraceLevel(Value->getValue(KeyStorage), Logger);
342 } else {
343 logIgnoredField(KeyValue, Logger);
344 }
345 }
346 return Result;
347}
348
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000349llvm::Optional<DidOpenTextDocumentParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000350DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000351 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000352 DidOpenTextDocumentParams Result;
353 for (auto &NextKeyValue : *Params) {
354 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
355 if (!KeyString)
356 return llvm::None;
357
358 llvm::SmallString<10> KeyStorage;
359 StringRef KeyValue = KeyString->getValue(KeyStorage);
360 auto *Value =
361 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
362 if (!Value)
363 return llvm::None;
364
365 llvm::SmallString<10> Storage;
366 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000367 auto Parsed = TextDocumentItem::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000368 if (!Parsed)
369 return llvm::None;
370 Result.textDocument = std::move(*Parsed);
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000371 } else if (KeyValue == "metadata") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000372 auto Parsed = Metadata::parse(Value, Logger);
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000373 if (!Parsed)
374 return llvm::None;
375 Result.metadata = std::move(*Parsed);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000376 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000377 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000378 }
379 }
380 return Result;
381}
382
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000383llvm::Optional<DidCloseTextDocumentParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000384DidCloseTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000385 clangd::Logger &Logger) {
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000386 DidCloseTextDocumentParams Result;
387 for (auto &NextKeyValue : *Params) {
388 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
389 if (!KeyString)
390 return llvm::None;
391
392 llvm::SmallString<10> KeyStorage;
393 StringRef KeyValue = KeyString->getValue(KeyStorage);
394 auto *Value = NextKeyValue.getValue();
395
396 if (KeyValue == "textDocument") {
397 auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
398 if (!Map)
399 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000400 auto Parsed = TextDocumentIdentifier::parse(Map, Logger);
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000401 if (!Parsed)
402 return llvm::None;
403 Result.textDocument = std::move(*Parsed);
404 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000405 logIgnoredField(KeyValue, Logger);
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000406 }
407 }
408 return Result;
409}
410
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000411llvm::Optional<DidChangeTextDocumentParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000412DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000413 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000414 DidChangeTextDocumentParams Result;
415 for (auto &NextKeyValue : *Params) {
416 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
417 if (!KeyString)
418 return llvm::None;
419
420 llvm::SmallString<10> KeyStorage;
421 StringRef KeyValue = KeyString->getValue(KeyStorage);
422 auto *Value = NextKeyValue.getValue();
423
424 llvm::SmallString<10> Storage;
425 if (KeyValue == "textDocument") {
426 auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
427 if (!Map)
428 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000429 auto Parsed = TextDocumentIdentifier::parse(Map, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000430 if (!Parsed)
431 return llvm::None;
432 Result.textDocument = std::move(*Parsed);
433 } else if (KeyValue == "contentChanges") {
434 auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
435 if (!Seq)
436 return llvm::None;
437 for (auto &Item : *Seq) {
438 auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
439 if (!I)
440 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000441 auto Parsed = TextDocumentContentChangeEvent::parse(I, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000442 if (!Parsed)
443 return llvm::None;
444 Result.contentChanges.push_back(std::move(*Parsed));
445 }
446 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000447 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000448 }
449 }
450 return Result;
451}
452
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000453llvm::Optional<FileEvent> FileEvent::parse(llvm::yaml::MappingNode *Params,
454 clangd::Logger &Logger) {
455 llvm::Optional<FileEvent> Result = FileEvent();
456 for (auto &NextKeyValue : *Params) {
457 // We have to consume the whole MappingNode because it doesn't support
458 // skipping and we want to be able to parse further valid events.
459 if (!Result)
460 continue;
461
462 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
463 if (!KeyString) {
464 Result.reset();
465 continue;
466 }
467
468 llvm::SmallString<10> KeyStorage;
469 StringRef KeyValue = KeyString->getValue(KeyStorage);
470 auto *Value =
471 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
472 if (!Value) {
473 Result.reset();
474 continue;
475 }
476 llvm::SmallString<10> Storage;
477 if (KeyValue == "uri") {
478 Result->uri = URI::parse(Value);
479 } else if (KeyValue == "type") {
480 long long Val;
481 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val)) {
482 Result.reset();
483 continue;
484 }
485 Result->type = static_cast<FileChangeType>(Val);
486 if (Result->type < FileChangeType::Created ||
487 Result->type > FileChangeType::Deleted)
488 Result.reset();
489 } else {
490 logIgnoredField(KeyValue, Logger);
491 }
492 }
493 return Result;
494}
495
496llvm::Optional<DidChangeWatchedFilesParams>
497DidChangeWatchedFilesParams::parse(llvm::yaml::MappingNode *Params,
498 clangd::Logger &Logger) {
499 DidChangeWatchedFilesParams Result;
500 for (auto &NextKeyValue : *Params) {
501 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
502 if (!KeyString)
503 return llvm::None;
504
505 llvm::SmallString<10> KeyStorage;
506 StringRef KeyValue = KeyString->getValue(KeyStorage);
507 auto *Value = NextKeyValue.getValue();
508
509 llvm::SmallString<10> Storage;
510 if (KeyValue == "changes") {
511 auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
512 if (!Seq)
513 return llvm::None;
514 for (auto &Item : *Seq) {
515 auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
516 if (!I)
517 return llvm::None;
518 auto Parsed = FileEvent::parse(I, Logger);
519 if (Parsed)
520 Result.changes.push_back(std::move(*Parsed));
521 else
522 Logger.log("Failed to decode a FileEvent.\n");
523 }
524 } else {
525 logIgnoredField(KeyValue, Logger);
526 }
527 }
528 return Result;
529}
530
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000531llvm::Optional<TextDocumentContentChangeEvent>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000532TextDocumentContentChangeEvent::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000533 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000534 TextDocumentContentChangeEvent Result;
535 for (auto &NextKeyValue : *Params) {
536 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
537 if (!KeyString)
538 return llvm::None;
539
540 llvm::SmallString<10> KeyStorage;
541 StringRef KeyValue = KeyString->getValue(KeyStorage);
542 auto *Value =
543 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
544 if (!Value)
545 return llvm::None;
546
547 llvm::SmallString<10> Storage;
548 if (KeyValue == "text") {
549 Result.text = Value->getValue(Storage);
550 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000551 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000552 }
553 }
554 return Result;
555}
556
557llvm::Optional<FormattingOptions>
Ilya Biryukov3847be52017-10-10 14:21:04 +0000558FormattingOptions::parse(llvm::yaml::MappingNode *Params,
559 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000560 FormattingOptions Result;
561 for (auto &NextKeyValue : *Params) {
562 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
563 if (!KeyString)
564 return llvm::None;
565
566 llvm::SmallString<10> KeyStorage;
567 StringRef KeyValue = KeyString->getValue(KeyStorage);
568 auto *Value =
569 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
570 if (!Value)
571 return llvm::None;
572
573 llvm::SmallString<10> Storage;
574 if (KeyValue == "tabSize") {
575 long long Val;
576 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
577 return llvm::None;
578 Result.tabSize = Val;
579 } else if (KeyValue == "insertSpaces") {
580 long long Val;
581 StringRef Str = Value->getValue(Storage);
582 if (llvm::getAsSignedInteger(Str, 0, Val)) {
583 if (Str == "true")
584 Val = 1;
585 else if (Str == "false")
586 Val = 0;
587 else
588 return llvm::None;
589 }
590 Result.insertSpaces = Val;
591 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000592 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000593 }
594 }
595 return Result;
596}
597
Sam McCalldd0566b2017-11-06 15:40:30 +0000598json::Expr FormattingOptions::unparse(const FormattingOptions &P) {
599 return json::obj{
600 {"tabSize", P.tabSize},
601 {"insertSpaces", P.insertSpaces},
602 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000603}
604
605llvm::Optional<DocumentRangeFormattingParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000606DocumentRangeFormattingParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000607 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000608 DocumentRangeFormattingParams Result;
609 for (auto &NextKeyValue : *Params) {
610 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
611 if (!KeyString)
612 return llvm::None;
613
614 llvm::SmallString<10> KeyStorage;
615 StringRef KeyValue = KeyString->getValue(KeyStorage);
616 auto *Value =
617 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
618 if (!Value)
619 return llvm::None;
620
621 llvm::SmallString<10> Storage;
622 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000623 auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000624 if (!Parsed)
625 return llvm::None;
626 Result.textDocument = std::move(*Parsed);
627 } else if (KeyValue == "range") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000628 auto Parsed = Range::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000629 if (!Parsed)
630 return llvm::None;
631 Result.range = std::move(*Parsed);
632 } else if (KeyValue == "options") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000633 auto Parsed = FormattingOptions::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000634 if (!Parsed)
635 return llvm::None;
636 Result.options = std::move(*Parsed);
637 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000638 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000639 }
640 }
641 return Result;
642}
643
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000644llvm::Optional<DocumentOnTypeFormattingParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000645DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000646 clangd::Logger &Logger) {
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000647 DocumentOnTypeFormattingParams Result;
648 for (auto &NextKeyValue : *Params) {
649 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
650 if (!KeyString)
651 return llvm::None;
652
653 llvm::SmallString<10> KeyStorage;
654 StringRef KeyValue = KeyString->getValue(KeyStorage);
655
656 if (KeyValue == "ch") {
657 auto *ScalarValue =
658 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
659 if (!ScalarValue)
660 return llvm::None;
661 llvm::SmallString<10> Storage;
662 Result.ch = ScalarValue->getValue(Storage);
663 continue;
664 }
665
666 auto *Value =
667 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
668 if (!Value)
669 return llvm::None;
670 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000671 auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000672 if (!Parsed)
673 return llvm::None;
674 Result.textDocument = std::move(*Parsed);
675 } else if (KeyValue == "position") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000676 auto Parsed = Position::parse(Value, Logger);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000677 if (!Parsed)
678 return llvm::None;
679 Result.position = std::move(*Parsed);
680 } else if (KeyValue == "options") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000681 auto Parsed = FormattingOptions::parse(Value, Logger);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000682 if (!Parsed)
683 return llvm::None;
684 Result.options = std::move(*Parsed);
685 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000686 logIgnoredField(KeyValue, Logger);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000687 }
688 }
689 return Result;
690}
691
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000692llvm::Optional<DocumentFormattingParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000693DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000694 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000695 DocumentFormattingParams Result;
696 for (auto &NextKeyValue : *Params) {
697 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
698 if (!KeyString)
699 return llvm::None;
700
701 llvm::SmallString<10> KeyStorage;
702 StringRef KeyValue = KeyString->getValue(KeyStorage);
703 auto *Value =
704 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
705 if (!Value)
706 return llvm::None;
707
708 llvm::SmallString<10> Storage;
709 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000710 auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000711 if (!Parsed)
712 return llvm::None;
713 Result.textDocument = std::move(*Parsed);
714 } else if (KeyValue == "options") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000715 auto Parsed = FormattingOptions::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000716 if (!Parsed)
717 return llvm::None;
718 Result.options = std::move(*Parsed);
719 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000720 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000721 }
722 }
723 return Result;
724}
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000725
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000726llvm::Optional<Diagnostic> Diagnostic::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000727 clangd::Logger &Logger) {
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000728 Diagnostic Result;
729 for (auto &NextKeyValue : *Params) {
730 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
731 if (!KeyString)
732 return llvm::None;
733
734 llvm::SmallString<10> KeyStorage;
735 StringRef KeyValue = KeyString->getValue(KeyStorage);
736
737 llvm::SmallString<10> Storage;
738 if (KeyValue == "range") {
739 auto *Value =
740 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
741 if (!Value)
742 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000743 auto Parsed = Range::parse(Value, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000744 if (!Parsed)
745 return llvm::None;
746 Result.range = std::move(*Parsed);
747 } else if (KeyValue == "severity") {
748 auto *Value =
749 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
750 if (!Value)
751 return llvm::None;
752 long long Val;
753 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
754 return llvm::None;
755 Result.severity = Val;
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000756 } else if (KeyValue == "code") {
757 // Not currently used
758 } else if (KeyValue == "source") {
759 // Not currently used
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000760 } else if (KeyValue == "message") {
761 auto *Value =
762 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
763 if (!Value)
764 return llvm::None;
765 Result.message = Value->getValue(Storage);
766 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000767 logIgnoredField(KeyValue, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000768 }
769 }
770 return Result;
771}
772
773llvm::Optional<CodeActionContext>
Ilya Biryukov3847be52017-10-10 14:21:04 +0000774CodeActionContext::parse(llvm::yaml::MappingNode *Params,
775 clangd::Logger &Logger) {
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000776 CodeActionContext Result;
777 for (auto &NextKeyValue : *Params) {
778 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
779 if (!KeyString)
780 return llvm::None;
781
782 llvm::SmallString<10> KeyStorage;
783 StringRef KeyValue = KeyString->getValue(KeyStorage);
784 auto *Value = NextKeyValue.getValue();
785
786 llvm::SmallString<10> Storage;
787 if (KeyValue == "diagnostics") {
788 auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
789 if (!Seq)
790 return llvm::None;
791 for (auto &Item : *Seq) {
792 auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
793 if (!I)
794 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000795 auto Parsed = Diagnostic::parse(I, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000796 if (!Parsed)
797 return llvm::None;
798 Result.diagnostics.push_back(std::move(*Parsed));
799 }
800 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000801 logIgnoredField(KeyValue, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000802 }
803 }
804 return Result;
805}
806
807llvm::Optional<CodeActionParams>
Ilya Biryukov3847be52017-10-10 14:21:04 +0000808CodeActionParams::parse(llvm::yaml::MappingNode *Params,
809 clangd::Logger &Logger) {
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000810 CodeActionParams Result;
811 for (auto &NextKeyValue : *Params) {
812 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
813 if (!KeyString)
814 return llvm::None;
815
816 llvm::SmallString<10> KeyStorage;
817 StringRef KeyValue = KeyString->getValue(KeyStorage);
818 auto *Value =
819 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
820 if (!Value)
821 return llvm::None;
822
823 llvm::SmallString<10> Storage;
824 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000825 auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000826 if (!Parsed)
827 return llvm::None;
828 Result.textDocument = std::move(*Parsed);
829 } else if (KeyValue == "range") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000830 auto Parsed = Range::parse(Value, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000831 if (!Parsed)
832 return llvm::None;
833 Result.range = std::move(*Parsed);
834 } else if (KeyValue == "context") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000835 auto Parsed = CodeActionContext::parse(Value, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000836 if (!Parsed)
837 return llvm::None;
838 Result.context = std::move(*Parsed);
839 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000840 logIgnoredField(KeyValue, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000841 }
842 }
843 return Result;
844}
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000845
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000846llvm::Optional<std::map<std::string, std::vector<TextEdit>>>
847parseWorkspaceEditChange(llvm::yaml::MappingNode *Params,
848 clangd::Logger &Logger) {
849 std::map<std::string, std::vector<TextEdit>> Result;
850 for (auto &NextKeyValue : *Params) {
851 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
852 if (!KeyString)
853 return llvm::None;
854
855 llvm::SmallString<10> KeyStorage;
856 StringRef KeyValue = KeyString->getValue(KeyStorage);
857 if (Result.count(KeyValue)) {
858 logIgnoredField(KeyValue, Logger);
859 continue;
860 }
861
862 auto *Value =
863 dyn_cast_or_null<llvm::yaml::SequenceNode>(NextKeyValue.getValue());
864 if (!Value)
865 return llvm::None;
866 for (auto &Item : *Value) {
867 auto *ItemValue = dyn_cast_or_null<llvm::yaml::MappingNode>(&Item);
868 if (!ItemValue)
869 return llvm::None;
870 auto Parsed = TextEdit::parse(ItemValue, Logger);
871 if (!Parsed)
872 return llvm::None;
873
874 Result[KeyValue].push_back(*Parsed);
875 }
876 }
877
878 return Result;
879}
880
881llvm::Optional<WorkspaceEdit>
882WorkspaceEdit::parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger) {
883 WorkspaceEdit Result;
884 for (auto &NextKeyValue : *Params) {
885 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
886 if (!KeyString)
887 return llvm::None;
888
889 llvm::SmallString<10> KeyStorage;
890 StringRef KeyValue = KeyString->getValue(KeyStorage);
891
892 llvm::SmallString<10> Storage;
893 if (KeyValue == "changes") {
894 auto *Value =
895 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
896 if (!Value)
897 return llvm::None;
898 auto Parsed = parseWorkspaceEditChange(Value, Logger);
899 if (!Parsed)
900 return llvm::None;
901 Result.changes = std::move(*Parsed);
902 } else {
903 logIgnoredField(KeyValue, Logger);
904 }
905 }
906 return Result;
907}
908
909const std::string ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
910 "clangd.applyFix";
911
912llvm::Optional<ExecuteCommandParams>
913ExecuteCommandParams::parse(llvm::yaml::MappingNode *Params,
914 clangd::Logger &Logger) {
915 ExecuteCommandParams Result;
916 // Depending on which "command" we parse, we will use this function to parse
917 // the command "arguments".
918 std::function<bool(llvm::yaml::MappingNode * Params)> ArgParser = nullptr;
919
920 for (auto &NextKeyValue : *Params) {
921 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
922 if (!KeyString)
923 return llvm::None;
924
925 llvm::SmallString<10> KeyStorage;
926 StringRef KeyValue = KeyString->getValue(KeyStorage);
927
928 // Note that "commands" has to be parsed before "arguments" for this to
929 // work properly.
930 if (KeyValue == "command") {
931 auto *ScalarValue =
932 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
933 if (!ScalarValue)
934 return llvm::None;
935 llvm::SmallString<10> Storage;
936 Result.command = ScalarValue->getValue(Storage);
937 if (Result.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
938 ArgParser = [&Result, &Logger](llvm::yaml::MappingNode *Params) {
939 auto WE = WorkspaceEdit::parse(Params, Logger);
940 if (WE)
941 Result.workspaceEdit = WE;
942 return WE.hasValue();
943 };
944 } else {
945 return llvm::None;
946 }
947 } else if (KeyValue == "arguments") {
948 auto *Value = NextKeyValue.getValue();
949 auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
950 if (!Seq)
951 return llvm::None;
952 for (auto &Item : *Seq) {
953 auto *ItemValue = dyn_cast_or_null<llvm::yaml::MappingNode>(&Item);
954 if (!ItemValue || !ArgParser)
955 return llvm::None;
956 if (!ArgParser(ItemValue))
957 return llvm::None;
958 }
959 } else {
960 logIgnoredField(KeyValue, Logger);
961 }
962 }
963 if (Result.command.empty())
964 return llvm::None;
965
966 return Result;
967}
968
Sam McCalldd0566b2017-11-06 15:40:30 +0000969json::Expr WorkspaceEdit::unparse(const WorkspaceEdit &WE) {
970 if (!WE.changes)
971 return json::obj{};
972 json::obj FileChanges;
973 for (auto &Change : *WE.changes)
974 FileChanges[Change.first] = json::ary(Change.second);
975 return json::obj{{"changes", std::move(FileChanges)}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000976}
977
Sam McCalldd0566b2017-11-06 15:40:30 +0000978json::Expr
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000979ApplyWorkspaceEditParams::unparse(const ApplyWorkspaceEditParams &Params) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000980 return json::obj{{"edit", Params.edit}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000981}
982
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000983llvm::Optional<TextDocumentPositionParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000984TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000985 clangd::Logger &Logger) {
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000986 TextDocumentPositionParams Result;
987 for (auto &NextKeyValue : *Params) {
988 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
989 if (!KeyString)
990 return llvm::None;
991
992 llvm::SmallString<10> KeyStorage;
993 StringRef KeyValue = KeyString->getValue(KeyStorage);
994 auto *Value =
995 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
996 if (!Value)
Benjamin Kramerd3326a02017-04-21 15:51:23 +0000997 continue;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000998
999 llvm::SmallString<10> Storage;
1000 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +00001001 auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001002 if (!Parsed)
1003 return llvm::None;
1004 Result.textDocument = std::move(*Parsed);
1005 } else if (KeyValue == "position") {
Ilya Biryukove5128f72017-09-20 07:24:15 +00001006 auto Parsed = Position::parse(Value, Logger);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001007 if (!Parsed)
1008 return llvm::None;
1009 Result.position = std::move(*Parsed);
1010 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +00001011 logIgnoredField(KeyValue, Logger);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001012 }
1013 }
1014 return Result;
1015}
1016
Sam McCalldd0566b2017-11-06 15:40:30 +00001017json::Expr CompletionItem::unparse(const CompletionItem &CI) {
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001018 assert(!CI.label.empty() && "completion item label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +00001019 json::obj Result{{"label", CI.label}};
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001020 if (CI.kind != CompletionItemKind::Missing)
Sam McCalldd0566b2017-11-06 15:40:30 +00001021 Result["kind"] = static_cast<int>(CI.kind);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001022 if (!CI.detail.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +00001023 Result["detail"] = CI.detail;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001024 if (!CI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +00001025 Result["documentation"] = CI.documentation;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001026 if (!CI.sortText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +00001027 Result["sortText"] = CI.sortText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001028 if (!CI.filterText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +00001029 Result["filterText"] = CI.filterText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001030 if (!CI.insertText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +00001031 Result["insertText"] = CI.insertText;
1032 if (CI.insertTextFormat != InsertTextFormat::Missing)
1033 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001034 if (CI.textEdit)
Sam McCalldd0566b2017-11-06 15:40:30 +00001035 Result["textEdit"] = *CI.textEdit;
1036 if (!CI.additionalTextEdits.empty())
1037 Result["additionalTextEdits"] = json::ary(CI.additionalTextEdits);
1038 return std::move(Result);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +00001039}
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +00001040
Sam McCallc78ccbd2017-11-08 07:44:12 +00001041bool clangd::operator<(const CompletionItem &L, const CompletionItem &R) {
1042 return (L.sortText.empty() ? L.label : L.sortText) <
1043 (R.sortText.empty() ? R.label : R.sortText);
1044}
1045
Sam McCalla40371b2017-11-15 09:16:29 +00001046json::Expr CompletionList::unparse(const CompletionList &L) {
1047 return json::obj{
1048 {"isIncomplete", L.isIncomplete},
1049 {"items", json::ary(L.items)},
1050 };
1051}
1052
Sam McCalldd0566b2017-11-06 15:40:30 +00001053json::Expr ParameterInformation::unparse(const ParameterInformation &PI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +00001054 assert(!PI.label.empty() && "parameter information label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +00001055 json::obj Result{{"label", PI.label}};
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +00001056 if (!PI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +00001057 Result["documentation"] = PI.documentation;
1058 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +00001059}
1060
Sam McCalldd0566b2017-11-06 15:40:30 +00001061json::Expr SignatureInformation::unparse(const SignatureInformation &SI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +00001062 assert(!SI.label.empty() && "signature information label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +00001063 json::obj Result{
1064 {"label", SI.label},
1065 {"parameters", json::ary(SI.parameters)},
1066 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +00001067 if (!SI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +00001068 Result["documentation"] = SI.documentation;
1069 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +00001070}
1071
Sam McCalldd0566b2017-11-06 15:40:30 +00001072json::Expr SignatureHelp::unparse(const SignatureHelp &SH) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +00001073 assert(SH.activeSignature >= 0 &&
1074 "Unexpected negative value for number of active signatures.");
1075 assert(SH.activeParameter >= 0 &&
1076 "Unexpected negative value for active parameter index");
Sam McCalldd0566b2017-11-06 15:40:30 +00001077 return json::obj{
1078 {"activeSignature", SH.activeSignature},
1079 {"activeParameter", SH.activeParameter},
1080 {"signatures", json::ary(SH.signatures)},
1081 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +00001082}
Haojian Wu345099c2017-11-09 11:30:04 +00001083
1084llvm::Optional<RenameParams>
1085RenameParams::parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger) {
1086 RenameParams Result;
1087 for (auto &NextKeyValue : *Params) {
1088 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
1089 if (!KeyString)
1090 return llvm::None;
1091
1092 llvm::SmallString<10> KeyStorage;
1093 StringRef KeyValue = KeyString->getValue(KeyStorage);
1094
1095 if (KeyValue == "textDocument") {
1096 auto *Value =
1097 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
1098 if (!Value)
1099 continue;
1100 auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
1101 if (!Map)
1102 return llvm::None;
1103 auto Parsed = TextDocumentIdentifier::parse(Map, Logger);
1104 if (!Parsed)
1105 return llvm::None;
1106 Result.textDocument = std::move(*Parsed);
1107 } else if (KeyValue == "position") {
1108 auto *Value =
1109 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
1110 if (!Value)
1111 continue;
1112 auto Parsed = Position::parse(Value, Logger);
1113 if (!Parsed)
1114 return llvm::None;
1115 Result.position = std::move(*Parsed);
1116 } else if (KeyValue == "newName") {
1117 auto *Value = NextKeyValue.getValue();
1118 if (!Value)
1119 continue;
1120 auto *Node = dyn_cast<llvm::yaml::ScalarNode>(Value);
1121 if (!Node)
1122 return llvm::None;
1123 llvm::SmallString<10> Storage;
1124 Result.newName = Node->getValue(Storage);
1125 } else {
1126 logIgnoredField(KeyValue, Logger);
1127 }
1128 }
1129 return Result;
1130}