blob: 0c74da2b7bc25a49547e00c3f0738fc4a433fb00 [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
Ilya Biryukov574b7532017-08-02 09:08:39 +000066std::string 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
128std::string Position::unparse(const Position &P) {
129 std::string Result;
130 llvm::raw_string_ostream(Result)
131 << llvm::format(R"({"line": %d, "character": %d})", P.line, P.character);
132 return Result;
133}
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
168std::string Range::unparse(const Range &P) {
169 std::string Result;
170 llvm::raw_string_ostream(Result) << llvm::format(
171 R"({"start": %s, "end": %s})", Position::unparse(P.start).c_str(),
172 Position::unparse(P.end).c_str());
173 return Result;
174}
175
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000176std::string Location::unparse(const Location &P) {
177 std::string Result;
178 llvm::raw_string_ostream(Result) << llvm::format(
179 R"({"uri": %s, "range": %s})", URI::unparse(P.uri).c_str(),
180 Range::unparse(P.range).c_str());
181 return Result;
182}
183
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000184llvm::Optional<TextDocumentItem>
Ilya Biryukove5128f72017-09-20 07:24:15 +0000185TextDocumentItem::parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000186 TextDocumentItem Result;
187 for (auto &NextKeyValue : *Params) {
188 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
189 if (!KeyString)
190 return llvm::None;
191
192 llvm::SmallString<10> KeyStorage;
193 StringRef KeyValue = KeyString->getValue(KeyStorage);
194 auto *Value =
195 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
196 if (!Value)
197 return llvm::None;
198
199 llvm::SmallString<10> Storage;
200 if (KeyValue == "uri") {
Krasimir Georgiev50117372017-04-07 11:03:26 +0000201 Result.uri = URI::parse(Value);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000202 } else if (KeyValue == "languageId") {
203 Result.languageId = Value->getValue(Storage);
204 } else if (KeyValue == "version") {
205 long long Val;
206 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
207 return llvm::None;
208 Result.version = Val;
209 } else if (KeyValue == "text") {
210 Result.text = Value->getValue(Storage);
211 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000212 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000213 }
214 }
215 return Result;
216}
217
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000218llvm::Optional<Metadata> Metadata::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000219 clangd::Logger &Logger) {
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000220 Metadata Result;
221 for (auto &NextKeyValue : *Params) {
222 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
223 if (!KeyString)
224 return llvm::None;
225
226 llvm::SmallString<10> KeyStorage;
227 StringRef KeyValue = KeyString->getValue(KeyStorage);
228 auto *Value = NextKeyValue.getValue();
229
230 llvm::SmallString<10> Storage;
231 if (KeyValue == "extraFlags") {
232 auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
233 if (!Seq)
234 return llvm::None;
235 for (auto &Item : *Seq) {
236 auto *Node = dyn_cast<llvm::yaml::ScalarNode>(&Item);
237 if (!Node)
238 return llvm::None;
239 Result.extraFlags.push_back(Node->getValue(Storage));
240 }
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000241 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000242 logIgnoredField(KeyValue, Logger);
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000243 }
244 }
245 return Result;
246}
247
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000248llvm::Optional<TextEdit> TextEdit::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000249 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000250 TextEdit Result;
251 for (auto &NextKeyValue : *Params) {
252 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
253 if (!KeyString)
254 return llvm::None;
255
256 llvm::SmallString<10> KeyStorage;
257 StringRef KeyValue = KeyString->getValue(KeyStorage);
258 auto *Value = NextKeyValue.getValue();
259
260 llvm::SmallString<10> Storage;
261 if (KeyValue == "range") {
262 auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
263 if (!Map)
264 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000265 auto Parsed = Range::parse(Map, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000266 if (!Parsed)
267 return llvm::None;
268 Result.range = std::move(*Parsed);
269 } else if (KeyValue == "newText") {
270 auto *Node = dyn_cast<llvm::yaml::ScalarNode>(Value);
271 if (!Node)
272 return llvm::None;
273 Result.newText = Node->getValue(Storage);
274 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000275 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000276 }
277 }
278 return Result;
279}
280
281std::string TextEdit::unparse(const TextEdit &P) {
282 std::string Result;
283 llvm::raw_string_ostream(Result) << llvm::format(
284 R"({"range": %s, "newText": "%s"})", Range::unparse(P.range).c_str(),
285 llvm::yaml::escape(P.newText).c_str());
286 return Result;
287}
288
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000289namespace {
290TraceLevel getTraceLevel(llvm::StringRef TraceLevelStr,
291 clangd::Logger &Logger) {
292 if (TraceLevelStr == "off")
293 return TraceLevel::Off;
294 else if (TraceLevelStr == "messages")
295 return TraceLevel::Messages;
296 else if (TraceLevelStr == "verbose")
297 return TraceLevel::Verbose;
298
299 Logger.log(llvm::formatv("Unknown trace level \"{0}\"\n", TraceLevelStr));
300 return TraceLevel::Off;
301}
302} // namespace
303
304llvm::Optional<InitializeParams>
305InitializeParams::parse(llvm::yaml::MappingNode *Params,
306 clangd::Logger &Logger) {
307 InitializeParams Result;
308 for (auto &NextKeyValue : *Params) {
309 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
310 if (!KeyString)
311 return llvm::None;
312
313 llvm::SmallString<10> KeyStorage;
314 StringRef KeyValue = KeyString->getValue(KeyStorage);
315 auto *Value =
316 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
317 if (!Value)
318 continue;
319
320 if (KeyValue == "processId") {
321 auto *Value =
322 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
323 if (!Value)
324 return llvm::None;
325 long long Val;
326 if (llvm::getAsSignedInteger(Value->getValue(KeyStorage), 0, Val))
327 return llvm::None;
328 Result.processId = Val;
329 } else if (KeyValue == "rootPath") {
330 Result.rootPath = Value->getValue(KeyStorage);
331 } else if (KeyValue == "rootUri") {
332 Result.rootUri = URI::parse(Value);
333 } else if (KeyValue == "initializationOptions") {
334 // Not used
335 } else if (KeyValue == "capabilities") {
336 // Not used
337 } else if (KeyValue == "trace") {
338 Result.trace = getTraceLevel(Value->getValue(KeyStorage), Logger);
339 } else {
340 logIgnoredField(KeyValue, Logger);
341 }
342 }
343 return Result;
344}
345
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000346llvm::Optional<DidOpenTextDocumentParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000347DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000348 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000349 DidOpenTextDocumentParams Result;
350 for (auto &NextKeyValue : *Params) {
351 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
352 if (!KeyString)
353 return llvm::None;
354
355 llvm::SmallString<10> KeyStorage;
356 StringRef KeyValue = KeyString->getValue(KeyStorage);
357 auto *Value =
358 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
359 if (!Value)
360 return llvm::None;
361
362 llvm::SmallString<10> Storage;
363 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000364 auto Parsed = TextDocumentItem::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000365 if (!Parsed)
366 return llvm::None;
367 Result.textDocument = std::move(*Parsed);
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000368 } else if (KeyValue == "metadata") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000369 auto Parsed = Metadata::parse(Value, Logger);
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000370 if (!Parsed)
371 return llvm::None;
372 Result.metadata = std::move(*Parsed);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000373 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000374 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000375 }
376 }
377 return Result;
378}
379
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000380llvm::Optional<DidCloseTextDocumentParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000381DidCloseTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000382 clangd::Logger &Logger) {
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000383 DidCloseTextDocumentParams Result;
384 for (auto &NextKeyValue : *Params) {
385 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
386 if (!KeyString)
387 return llvm::None;
388
389 llvm::SmallString<10> KeyStorage;
390 StringRef KeyValue = KeyString->getValue(KeyStorage);
391 auto *Value = NextKeyValue.getValue();
392
393 if (KeyValue == "textDocument") {
394 auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
395 if (!Map)
396 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000397 auto Parsed = TextDocumentIdentifier::parse(Map, Logger);
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000398 if (!Parsed)
399 return llvm::None;
400 Result.textDocument = std::move(*Parsed);
401 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000402 logIgnoredField(KeyValue, Logger);
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000403 }
404 }
405 return Result;
406}
407
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000408llvm::Optional<DidChangeTextDocumentParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000409DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000410 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000411 DidChangeTextDocumentParams Result;
412 for (auto &NextKeyValue : *Params) {
413 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
414 if (!KeyString)
415 return llvm::None;
416
417 llvm::SmallString<10> KeyStorage;
418 StringRef KeyValue = KeyString->getValue(KeyStorage);
419 auto *Value = NextKeyValue.getValue();
420
421 llvm::SmallString<10> Storage;
422 if (KeyValue == "textDocument") {
423 auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
424 if (!Map)
425 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000426 auto Parsed = TextDocumentIdentifier::parse(Map, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000427 if (!Parsed)
428 return llvm::None;
429 Result.textDocument = std::move(*Parsed);
430 } else if (KeyValue == "contentChanges") {
431 auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
432 if (!Seq)
433 return llvm::None;
434 for (auto &Item : *Seq) {
435 auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
436 if (!I)
437 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000438 auto Parsed = TextDocumentContentChangeEvent::parse(I, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000439 if (!Parsed)
440 return llvm::None;
441 Result.contentChanges.push_back(std::move(*Parsed));
442 }
443 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000444 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000445 }
446 }
447 return Result;
448}
449
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000450llvm::Optional<FileEvent> FileEvent::parse(llvm::yaml::MappingNode *Params,
451 clangd::Logger &Logger) {
452 llvm::Optional<FileEvent> Result = FileEvent();
453 for (auto &NextKeyValue : *Params) {
454 // We have to consume the whole MappingNode because it doesn't support
455 // skipping and we want to be able to parse further valid events.
456 if (!Result)
457 continue;
458
459 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
460 if (!KeyString) {
461 Result.reset();
462 continue;
463 }
464
465 llvm::SmallString<10> KeyStorage;
466 StringRef KeyValue = KeyString->getValue(KeyStorage);
467 auto *Value =
468 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
469 if (!Value) {
470 Result.reset();
471 continue;
472 }
473 llvm::SmallString<10> Storage;
474 if (KeyValue == "uri") {
475 Result->uri = URI::parse(Value);
476 } else if (KeyValue == "type") {
477 long long Val;
478 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val)) {
479 Result.reset();
480 continue;
481 }
482 Result->type = static_cast<FileChangeType>(Val);
483 if (Result->type < FileChangeType::Created ||
484 Result->type > FileChangeType::Deleted)
485 Result.reset();
486 } else {
487 logIgnoredField(KeyValue, Logger);
488 }
489 }
490 return Result;
491}
492
493llvm::Optional<DidChangeWatchedFilesParams>
494DidChangeWatchedFilesParams::parse(llvm::yaml::MappingNode *Params,
495 clangd::Logger &Logger) {
496 DidChangeWatchedFilesParams Result;
497 for (auto &NextKeyValue : *Params) {
498 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
499 if (!KeyString)
500 return llvm::None;
501
502 llvm::SmallString<10> KeyStorage;
503 StringRef KeyValue = KeyString->getValue(KeyStorage);
504 auto *Value = NextKeyValue.getValue();
505
506 llvm::SmallString<10> Storage;
507 if (KeyValue == "changes") {
508 auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
509 if (!Seq)
510 return llvm::None;
511 for (auto &Item : *Seq) {
512 auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
513 if (!I)
514 return llvm::None;
515 auto Parsed = FileEvent::parse(I, Logger);
516 if (Parsed)
517 Result.changes.push_back(std::move(*Parsed));
518 else
519 Logger.log("Failed to decode a FileEvent.\n");
520 }
521 } else {
522 logIgnoredField(KeyValue, Logger);
523 }
524 }
525 return Result;
526}
527
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000528llvm::Optional<TextDocumentContentChangeEvent>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000529TextDocumentContentChangeEvent::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000530 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000531 TextDocumentContentChangeEvent Result;
532 for (auto &NextKeyValue : *Params) {
533 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
534 if (!KeyString)
535 return llvm::None;
536
537 llvm::SmallString<10> KeyStorage;
538 StringRef KeyValue = KeyString->getValue(KeyStorage);
539 auto *Value =
540 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
541 if (!Value)
542 return llvm::None;
543
544 llvm::SmallString<10> Storage;
545 if (KeyValue == "text") {
546 Result.text = Value->getValue(Storage);
547 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000548 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000549 }
550 }
551 return Result;
552}
553
554llvm::Optional<FormattingOptions>
Ilya Biryukove5128f72017-09-20 07:24:15 +0000555FormattingOptions::parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000556 FormattingOptions Result;
557 for (auto &NextKeyValue : *Params) {
558 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
559 if (!KeyString)
560 return llvm::None;
561
562 llvm::SmallString<10> KeyStorage;
563 StringRef KeyValue = KeyString->getValue(KeyStorage);
564 auto *Value =
565 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
566 if (!Value)
567 return llvm::None;
568
569 llvm::SmallString<10> Storage;
570 if (KeyValue == "tabSize") {
571 long long Val;
572 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
573 return llvm::None;
574 Result.tabSize = Val;
575 } else if (KeyValue == "insertSpaces") {
576 long long Val;
577 StringRef Str = Value->getValue(Storage);
578 if (llvm::getAsSignedInteger(Str, 0, Val)) {
579 if (Str == "true")
580 Val = 1;
581 else if (Str == "false")
582 Val = 0;
583 else
584 return llvm::None;
585 }
586 Result.insertSpaces = Val;
587 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000588 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000589 }
590 }
591 return Result;
592}
593
594std::string FormattingOptions::unparse(const FormattingOptions &P) {
595 std::string Result;
596 llvm::raw_string_ostream(Result) << llvm::format(
597 R"({"tabSize": %d, "insertSpaces": %d})", P.tabSize, P.insertSpaces);
598 return Result;
599}
600
601llvm::Optional<DocumentRangeFormattingParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000602DocumentRangeFormattingParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000603 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000604 DocumentRangeFormattingParams Result;
605 for (auto &NextKeyValue : *Params) {
606 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
607 if (!KeyString)
608 return llvm::None;
609
610 llvm::SmallString<10> KeyStorage;
611 StringRef KeyValue = KeyString->getValue(KeyStorage);
612 auto *Value =
613 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
614 if (!Value)
615 return llvm::None;
616
617 llvm::SmallString<10> Storage;
618 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000619 auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000620 if (!Parsed)
621 return llvm::None;
622 Result.textDocument = std::move(*Parsed);
623 } else if (KeyValue == "range") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000624 auto Parsed = Range::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000625 if (!Parsed)
626 return llvm::None;
627 Result.range = std::move(*Parsed);
628 } else if (KeyValue == "options") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000629 auto Parsed = FormattingOptions::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000630 if (!Parsed)
631 return llvm::None;
632 Result.options = std::move(*Parsed);
633 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000634 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000635 }
636 }
637 return Result;
638}
639
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000640llvm::Optional<DocumentOnTypeFormattingParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000641DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000642 clangd::Logger &Logger) {
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000643 DocumentOnTypeFormattingParams Result;
644 for (auto &NextKeyValue : *Params) {
645 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
646 if (!KeyString)
647 return llvm::None;
648
649 llvm::SmallString<10> KeyStorage;
650 StringRef KeyValue = KeyString->getValue(KeyStorage);
651
652 if (KeyValue == "ch") {
653 auto *ScalarValue =
654 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
655 if (!ScalarValue)
656 return llvm::None;
657 llvm::SmallString<10> Storage;
658 Result.ch = ScalarValue->getValue(Storage);
659 continue;
660 }
661
662 auto *Value =
663 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
664 if (!Value)
665 return llvm::None;
666 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000667 auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000668 if (!Parsed)
669 return llvm::None;
670 Result.textDocument = std::move(*Parsed);
671 } else if (KeyValue == "position") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000672 auto Parsed = Position::parse(Value, Logger);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000673 if (!Parsed)
674 return llvm::None;
675 Result.position = std::move(*Parsed);
676 } else if (KeyValue == "options") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000677 auto Parsed = FormattingOptions::parse(Value, Logger);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000678 if (!Parsed)
679 return llvm::None;
680 Result.options = std::move(*Parsed);
681 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000682 logIgnoredField(KeyValue, Logger);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000683 }
684 }
685 return Result;
686}
687
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000688llvm::Optional<DocumentFormattingParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000689DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000690 clangd::Logger &Logger) {
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000691 DocumentFormattingParams Result;
692 for (auto &NextKeyValue : *Params) {
693 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
694 if (!KeyString)
695 return llvm::None;
696
697 llvm::SmallString<10> KeyStorage;
698 StringRef KeyValue = KeyString->getValue(KeyStorage);
699 auto *Value =
700 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
701 if (!Value)
702 return llvm::None;
703
704 llvm::SmallString<10> Storage;
705 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000706 auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000707 if (!Parsed)
708 return llvm::None;
709 Result.textDocument = std::move(*Parsed);
710 } else if (KeyValue == "options") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000711 auto Parsed = FormattingOptions::parse(Value, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000712 if (!Parsed)
713 return llvm::None;
714 Result.options = std::move(*Parsed);
715 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000716 logIgnoredField(KeyValue, Logger);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000717 }
718 }
719 return Result;
720}
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000721
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000722llvm::Optional<Diagnostic> Diagnostic::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000723 clangd::Logger &Logger) {
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000724 Diagnostic Result;
725 for (auto &NextKeyValue : *Params) {
726 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
727 if (!KeyString)
728 return llvm::None;
729
730 llvm::SmallString<10> KeyStorage;
731 StringRef KeyValue = KeyString->getValue(KeyStorage);
732
733 llvm::SmallString<10> Storage;
734 if (KeyValue == "range") {
735 auto *Value =
736 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
737 if (!Value)
738 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000739 auto Parsed = Range::parse(Value, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000740 if (!Parsed)
741 return llvm::None;
742 Result.range = std::move(*Parsed);
743 } else if (KeyValue == "severity") {
744 auto *Value =
745 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
746 if (!Value)
747 return llvm::None;
748 long long Val;
749 if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
750 return llvm::None;
751 Result.severity = Val;
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000752 } else if (KeyValue == "code") {
753 // Not currently used
754 } else if (KeyValue == "source") {
755 // Not currently used
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000756 } else if (KeyValue == "message") {
757 auto *Value =
758 dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
759 if (!Value)
760 return llvm::None;
761 Result.message = Value->getValue(Storage);
762 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000763 logIgnoredField(KeyValue, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000764 }
765 }
766 return Result;
767}
768
769llvm::Optional<CodeActionContext>
Ilya Biryukove5128f72017-09-20 07:24:15 +0000770CodeActionContext::parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger) {
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000771 CodeActionContext Result;
772 for (auto &NextKeyValue : *Params) {
773 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
774 if (!KeyString)
775 return llvm::None;
776
777 llvm::SmallString<10> KeyStorage;
778 StringRef KeyValue = KeyString->getValue(KeyStorage);
779 auto *Value = NextKeyValue.getValue();
780
781 llvm::SmallString<10> Storage;
782 if (KeyValue == "diagnostics") {
783 auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
784 if (!Seq)
785 return llvm::None;
786 for (auto &Item : *Seq) {
787 auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
788 if (!I)
789 return llvm::None;
Ilya Biryukove5128f72017-09-20 07:24:15 +0000790 auto Parsed = Diagnostic::parse(I, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000791 if (!Parsed)
792 return llvm::None;
793 Result.diagnostics.push_back(std::move(*Parsed));
794 }
795 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000796 logIgnoredField(KeyValue, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000797 }
798 }
799 return Result;
800}
801
802llvm::Optional<CodeActionParams>
Ilya Biryukove5128f72017-09-20 07:24:15 +0000803CodeActionParams::parse(llvm::yaml::MappingNode *Params, clangd::Logger &Logger) {
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000804 CodeActionParams Result;
805 for (auto &NextKeyValue : *Params) {
806 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
807 if (!KeyString)
808 return llvm::None;
809
810 llvm::SmallString<10> KeyStorage;
811 StringRef KeyValue = KeyString->getValue(KeyStorage);
812 auto *Value =
813 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
814 if (!Value)
815 return llvm::None;
816
817 llvm::SmallString<10> Storage;
818 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000819 auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000820 if (!Parsed)
821 return llvm::None;
822 Result.textDocument = std::move(*Parsed);
823 } else if (KeyValue == "range") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000824 auto Parsed = Range::parse(Value, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000825 if (!Parsed)
826 return llvm::None;
827 Result.range = std::move(*Parsed);
828 } else if (KeyValue == "context") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000829 auto Parsed = CodeActionContext::parse(Value, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000830 if (!Parsed)
831 return llvm::None;
832 Result.context = std::move(*Parsed);
833 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000834 logIgnoredField(KeyValue, Logger);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000835 }
836 }
837 return Result;
838}
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000839
840llvm::Optional<TextDocumentPositionParams>
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +0000841TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params,
Ilya Biryukove5128f72017-09-20 07:24:15 +0000842 clangd::Logger &Logger) {
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000843 TextDocumentPositionParams Result;
844 for (auto &NextKeyValue : *Params) {
845 auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
846 if (!KeyString)
847 return llvm::None;
848
849 llvm::SmallString<10> KeyStorage;
850 StringRef KeyValue = KeyString->getValue(KeyStorage);
851 auto *Value =
852 dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
853 if (!Value)
Benjamin Kramerd3326a02017-04-21 15:51:23 +0000854 continue;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000855
856 llvm::SmallString<10> Storage;
857 if (KeyValue == "textDocument") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000858 auto Parsed = TextDocumentIdentifier::parse(Value, Logger);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000859 if (!Parsed)
860 return llvm::None;
861 Result.textDocument = std::move(*Parsed);
862 } else if (KeyValue == "position") {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000863 auto Parsed = Position::parse(Value, Logger);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000864 if (!Parsed)
865 return llvm::None;
866 Result.position = std::move(*Parsed);
867 } else {
Ilya Biryukove5128f72017-09-20 07:24:15 +0000868 logIgnoredField(KeyValue, Logger);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000869 }
870 }
871 return Result;
872}
873
874std::string CompletionItem::unparse(const CompletionItem &CI) {
875 std::string Result = "{";
876 llvm::raw_string_ostream Os(Result);
877 assert(!CI.label.empty() && "completion item label is required");
878 Os << R"("label":")" << llvm::yaml::escape(CI.label) << R"(",)";
879 if (CI.kind != CompletionItemKind::Missing)
Krasimir Georgiev4714f7c2017-04-11 13:27:15 +0000880 Os << R"("kind":)" << static_cast<int>(CI.kind) << R"(,)";
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000881 if (!CI.detail.empty())
882 Os << R"("detail":")" << llvm::yaml::escape(CI.detail) << R"(",)";
883 if (!CI.documentation.empty())
884 Os << R"("documentation":")" << llvm::yaml::escape(CI.documentation)
885 << R"(",)";
886 if (!CI.sortText.empty())
887 Os << R"("sortText":")" << llvm::yaml::escape(CI.sortText) << R"(",)";
888 if (!CI.filterText.empty())
889 Os << R"("filterText":")" << llvm::yaml::escape(CI.filterText) << R"(",)";
890 if (!CI.insertText.empty())
891 Os << R"("insertText":")" << llvm::yaml::escape(CI.insertText) << R"(",)";
892 if (CI.insertTextFormat != InsertTextFormat::Missing) {
Ilya Biryukovb33c1572017-09-12 13:57:14 +0000893 Os << R"("insertTextFormat":)" << static_cast<int>(CI.insertTextFormat)
894 << R"(,)";
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000895 }
896 if (CI.textEdit)
897 Os << R"("textEdit":)" << TextEdit::unparse(*CI.textEdit) << ',';
898 if (!CI.additionalTextEdits.empty()) {
899 Os << R"("additionalTextEdits":[)";
900 for (const auto &Edit : CI.additionalTextEdits)
901 Os << TextEdit::unparse(Edit) << ",";
902 Os.flush();
903 // The list additionalTextEdits is guaranteed nonempty at this point.
904 // Replace the trailing comma with right brace.
905 Result.back() = ']';
906 }
907 Os.flush();
908 // Label is required, so Result is guaranteed to have a trailing comma.
909 Result.back() = '}';
910 return Result;
911}
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000912
913std::string ParameterInformation::unparse(const ParameterInformation &PI) {
914 std::string Result = "{";
915 llvm::raw_string_ostream Os(Result);
916 assert(!PI.label.empty() && "parameter information label is required");
917 Os << R"("label":")" << llvm::yaml::escape(PI.label) << '\"';
918 if (!PI.documentation.empty())
919 Os << R"(,"documentation":")" << llvm::yaml::escape(PI.documentation)
920 << '\"';
921 Os << '}';
922 Os.flush();
923 return Result;
924}
925
926std::string SignatureInformation::unparse(const SignatureInformation &SI) {
927 std::string Result = "{";
928 llvm::raw_string_ostream Os(Result);
929 assert(!SI.label.empty() && "signature information label is required");
930 Os << R"("label":")" << llvm::yaml::escape(SI.label) << '\"';
931 if (!SI.documentation.empty())
932 Os << R"(,"documentation":")" << llvm::yaml::escape(SI.documentation)
933 << '\"';
934 Os << R"(,"parameters":[)";
935 for (const auto &Parameter : SI.parameters) {
936 Os << ParameterInformation::unparse(Parameter) << ',';
937 }
938 Os.flush();
939 if (SI.parameters.empty())
940 Result.push_back(']');
941 else
942 Result.back() = ']'; // Replace the last `,` with an `]`.
943 Result.push_back('}');
944 return Result;
945}
946
947std::string SignatureHelp::unparse(const SignatureHelp &SH) {
948 std::string Result = "{";
949 llvm::raw_string_ostream Os(Result);
950 assert(SH.activeSignature >= 0 &&
951 "Unexpected negative value for number of active signatures.");
952 assert(SH.activeParameter >= 0 &&
953 "Unexpected negative value for active parameter index");
954 Os << R"("activeSignature":)" << SH.activeSignature
955 << R"(,"activeParameter":)" << SH.activeParameter << R"(,"signatures":[)";
956 for (const auto &Signature : SH.signatures) {
957 Os << SignatureInformation::unparse(Signature) << ',';
958 }
959 Os.flush();
960 if (SH.signatures.empty())
961 Result.push_back(']');
962 else
963 Result.back() = ']'; // Replace the last `,` with an `]`.
964 Result.push_back('}');
965 return Result;
966}