1 //===--- 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"
16 #include "clang/Basic/LLVM.h"
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/Support/Format.h"
19 #include "llvm/Support/raw_ostream.h"
20 #include "llvm/Support/Path.h"
21 using namespace clang::clangd;
22 
23 
24 URI URI::fromUri(llvm::StringRef uri) {
25   URI Result;
26   Result.uri = uri;
27   uri.consume_front("file://");
28   // Also trim authority-less URIs
29   uri.consume_front("file:");
30   // For Windows paths e.g. /X:
31   if (uri.size() > 2 && uri[0] == '/' && uri[2] == ':')
32     uri.consume_front("/");
33   // Make sure that file paths are in native separators
34   Result.file = llvm::sys::path::convert_to_slash(uri);
35   return Result;
36 }
37 
38 URI URI::fromFile(llvm::StringRef file) {
39   using namespace llvm::sys;
40   URI Result;
41   Result.file = file;
42   Result.uri = "file://";
43   // For Windows paths e.g. X:
44   if (file.size() > 1 && file[1] == ':')
45     Result.uri += "/";
46   // Make sure that uri paths are with posix separators
47   Result.uri += path::convert_to_slash(file, path::Style::posix);
48   return Result;
49 }
50 
51 URI URI::parse(llvm::yaml::ScalarNode *Param) {
52   llvm::SmallString<10> Storage;
53   return URI::fromUri(Param->getValue(Storage));
54 }
55 
56 std::string URI::unparse(const URI &U) {
57   return U.uri;
58 }
59 
60 llvm::Optional<TextDocumentIdentifier>
61 TextDocumentIdentifier::parse(llvm::yaml::MappingNode *Params) {
62   TextDocumentIdentifier Result;
63   for (auto &NextKeyValue : *Params) {
64     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
65     if (!KeyString)
66       return llvm::None;
67 
68     llvm::SmallString<10> KeyStorage;
69     StringRef KeyValue = KeyString->getValue(KeyStorage);
70     auto *Value =
71         dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
72     if (!Value)
73       return llvm::None;
74 
75     if (KeyValue == "uri") {
76       Result.uri = URI::parse(Value);
77     } else if (KeyValue == "version") {
78       // FIXME: parse version, but only for VersionedTextDocumentIdentifiers.
79     } else {
80       return llvm::None;
81     }
82   }
83   return Result;
84 }
85 
86 llvm::Optional<Position> Position::parse(llvm::yaml::MappingNode *Params) {
87   Position Result;
88   for (auto &NextKeyValue : *Params) {
89     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
90     if (!KeyString)
91       return llvm::None;
92 
93     llvm::SmallString<10> KeyStorage;
94     StringRef KeyValue = KeyString->getValue(KeyStorage);
95     auto *Value =
96         dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
97     if (!Value)
98       return llvm::None;
99 
100     llvm::SmallString<10> Storage;
101     if (KeyValue == "line") {
102       long long Val;
103       if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
104         return llvm::None;
105       Result.line = Val;
106     } else if (KeyValue == "character") {
107       long long Val;
108       if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
109         return llvm::None;
110       Result.character = Val;
111     } else {
112       return llvm::None;
113     }
114   }
115   return Result;
116 }
117 
118 std::string Position::unparse(const Position &P) {
119   std::string Result;
120   llvm::raw_string_ostream(Result)
121       << llvm::format(R"({"line": %d, "character": %d})", P.line, P.character);
122   return Result;
123 }
124 
125 llvm::Optional<Range> Range::parse(llvm::yaml::MappingNode *Params) {
126   Range Result;
127   for (auto &NextKeyValue : *Params) {
128     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
129     if (!KeyString)
130       return llvm::None;
131 
132     llvm::SmallString<10> KeyStorage;
133     StringRef KeyValue = KeyString->getValue(KeyStorage);
134     auto *Value =
135         dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
136     if (!Value)
137       return llvm::None;
138 
139     llvm::SmallString<10> Storage;
140     if (KeyValue == "start") {
141       auto Parsed = Position::parse(Value);
142       if (!Parsed)
143         return llvm::None;
144       Result.start = std::move(*Parsed);
145     } else if (KeyValue == "end") {
146       auto Parsed = Position::parse(Value);
147       if (!Parsed)
148         return llvm::None;
149       Result.end = std::move(*Parsed);
150     } else {
151       return llvm::None;
152     }
153   }
154   return Result;
155 }
156 
157 std::string Range::unparse(const Range &P) {
158   std::string Result;
159   llvm::raw_string_ostream(Result) << llvm::format(
160       R"({"start": %s, "end": %s})", Position::unparse(P.start).c_str(),
161       Position::unparse(P.end).c_str());
162   return Result;
163 }
164 
165 llvm::Optional<TextDocumentItem>
166 TextDocumentItem::parse(llvm::yaml::MappingNode *Params) {
167   TextDocumentItem Result;
168   for (auto &NextKeyValue : *Params) {
169     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
170     if (!KeyString)
171       return llvm::None;
172 
173     llvm::SmallString<10> KeyStorage;
174     StringRef KeyValue = KeyString->getValue(KeyStorage);
175     auto *Value =
176         dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
177     if (!Value)
178       return llvm::None;
179 
180     llvm::SmallString<10> Storage;
181     if (KeyValue == "uri") {
182       Result.uri = URI::parse(Value);
183     } else if (KeyValue == "languageId") {
184       Result.languageId = Value->getValue(Storage);
185     } else if (KeyValue == "version") {
186       long long Val;
187       if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
188         return llvm::None;
189       Result.version = Val;
190     } else if (KeyValue == "text") {
191       Result.text = Value->getValue(Storage);
192     } else {
193       return llvm::None;
194     }
195   }
196   return Result;
197 }
198 
199 llvm::Optional<TextEdit> TextEdit::parse(llvm::yaml::MappingNode *Params) {
200   TextEdit Result;
201   for (auto &NextKeyValue : *Params) {
202     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
203     if (!KeyString)
204       return llvm::None;
205 
206     llvm::SmallString<10> KeyStorage;
207     StringRef KeyValue = KeyString->getValue(KeyStorage);
208     auto *Value = NextKeyValue.getValue();
209 
210     llvm::SmallString<10> Storage;
211     if (KeyValue == "range") {
212       auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
213       if (!Map)
214         return llvm::None;
215       auto Parsed = Range::parse(Map);
216       if (!Parsed)
217         return llvm::None;
218       Result.range = std::move(*Parsed);
219     } else if (KeyValue == "newText") {
220       auto *Node = dyn_cast<llvm::yaml::ScalarNode>(Value);
221       if (!Node)
222         return llvm::None;
223       Result.newText = Node->getValue(Storage);
224     } else {
225       return llvm::None;
226     }
227   }
228   return Result;
229 }
230 
231 std::string TextEdit::unparse(const TextEdit &P) {
232   std::string Result;
233   llvm::raw_string_ostream(Result) << llvm::format(
234       R"({"range": %s, "newText": "%s"})", Range::unparse(P.range).c_str(),
235       llvm::yaml::escape(P.newText).c_str());
236   return Result;
237 }
238 
239 llvm::Optional<DidOpenTextDocumentParams>
240 DidOpenTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
241   DidOpenTextDocumentParams Result;
242   for (auto &NextKeyValue : *Params) {
243     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
244     if (!KeyString)
245       return llvm::None;
246 
247     llvm::SmallString<10> KeyStorage;
248     StringRef KeyValue = KeyString->getValue(KeyStorage);
249     auto *Value =
250         dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
251     if (!Value)
252       return llvm::None;
253 
254     llvm::SmallString<10> Storage;
255     if (KeyValue == "textDocument") {
256       auto Parsed = TextDocumentItem::parse(Value);
257       if (!Parsed)
258         return llvm::None;
259       Result.textDocument = std::move(*Parsed);
260     } else {
261       return llvm::None;
262     }
263   }
264   return Result;
265 }
266 
267 llvm::Optional<DidCloseTextDocumentParams>
268 DidCloseTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
269   DidCloseTextDocumentParams Result;
270   for (auto &NextKeyValue : *Params) {
271     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
272     if (!KeyString)
273       return llvm::None;
274 
275     llvm::SmallString<10> KeyStorage;
276     StringRef KeyValue = KeyString->getValue(KeyStorage);
277     auto *Value = NextKeyValue.getValue();
278 
279     if (KeyValue == "textDocument") {
280       auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
281       if (!Map)
282         return llvm::None;
283       auto Parsed = TextDocumentIdentifier::parse(Map);
284       if (!Parsed)
285         return llvm::None;
286       Result.textDocument = std::move(*Parsed);
287     } else {
288       return llvm::None;
289     }
290   }
291   return Result;
292 }
293 
294 llvm::Optional<DidChangeTextDocumentParams>
295 DidChangeTextDocumentParams::parse(llvm::yaml::MappingNode *Params) {
296   DidChangeTextDocumentParams Result;
297   for (auto &NextKeyValue : *Params) {
298     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
299     if (!KeyString)
300       return llvm::None;
301 
302     llvm::SmallString<10> KeyStorage;
303     StringRef KeyValue = KeyString->getValue(KeyStorage);
304     auto *Value = NextKeyValue.getValue();
305 
306     llvm::SmallString<10> Storage;
307     if (KeyValue == "textDocument") {
308       auto *Map = dyn_cast<llvm::yaml::MappingNode>(Value);
309       if (!Map)
310         return llvm::None;
311       auto Parsed = TextDocumentIdentifier::parse(Map);
312       if (!Parsed)
313         return llvm::None;
314       Result.textDocument = std::move(*Parsed);
315     } else if (KeyValue == "contentChanges") {
316       auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
317       if (!Seq)
318         return llvm::None;
319       for (auto &Item : *Seq) {
320         auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
321         if (!I)
322           return llvm::None;
323         auto Parsed = TextDocumentContentChangeEvent::parse(I);
324         if (!Parsed)
325           return llvm::None;
326         Result.contentChanges.push_back(std::move(*Parsed));
327       }
328     } else {
329       return llvm::None;
330     }
331   }
332   return Result;
333 }
334 
335 llvm::Optional<TextDocumentContentChangeEvent>
336 TextDocumentContentChangeEvent::parse(llvm::yaml::MappingNode *Params) {
337   TextDocumentContentChangeEvent Result;
338   for (auto &NextKeyValue : *Params) {
339     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
340     if (!KeyString)
341       return llvm::None;
342 
343     llvm::SmallString<10> KeyStorage;
344     StringRef KeyValue = KeyString->getValue(KeyStorage);
345     auto *Value =
346         dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
347     if (!Value)
348       return llvm::None;
349 
350     llvm::SmallString<10> Storage;
351     if (KeyValue == "text") {
352       Result.text = Value->getValue(Storage);
353     } else {
354       return llvm::None;
355     }
356   }
357   return Result;
358 }
359 
360 llvm::Optional<FormattingOptions>
361 FormattingOptions::parse(llvm::yaml::MappingNode *Params) {
362   FormattingOptions Result;
363   for (auto &NextKeyValue : *Params) {
364     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
365     if (!KeyString)
366       return llvm::None;
367 
368     llvm::SmallString<10> KeyStorage;
369     StringRef KeyValue = KeyString->getValue(KeyStorage);
370     auto *Value =
371         dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
372     if (!Value)
373       return llvm::None;
374 
375     llvm::SmallString<10> Storage;
376     if (KeyValue == "tabSize") {
377       long long Val;
378       if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
379         return llvm::None;
380       Result.tabSize = Val;
381     } else if (KeyValue == "insertSpaces") {
382       long long Val;
383       StringRef Str = Value->getValue(Storage);
384       if (llvm::getAsSignedInteger(Str, 0, Val)) {
385         if (Str == "true")
386           Val = 1;
387         else if (Str == "false")
388           Val = 0;
389         else
390           return llvm::None;
391       }
392       Result.insertSpaces = Val;
393     } else {
394       return llvm::None;
395     }
396   }
397   return Result;
398 }
399 
400 std::string FormattingOptions::unparse(const FormattingOptions &P) {
401   std::string Result;
402   llvm::raw_string_ostream(Result) << llvm::format(
403       R"({"tabSize": %d, "insertSpaces": %d})", P.tabSize, P.insertSpaces);
404   return Result;
405 }
406 
407 llvm::Optional<DocumentRangeFormattingParams>
408 DocumentRangeFormattingParams::parse(llvm::yaml::MappingNode *Params) {
409   DocumentRangeFormattingParams Result;
410   for (auto &NextKeyValue : *Params) {
411     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
412     if (!KeyString)
413       return llvm::None;
414 
415     llvm::SmallString<10> KeyStorage;
416     StringRef KeyValue = KeyString->getValue(KeyStorage);
417     auto *Value =
418         dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
419     if (!Value)
420       return llvm::None;
421 
422     llvm::SmallString<10> Storage;
423     if (KeyValue == "textDocument") {
424       auto Parsed = TextDocumentIdentifier::parse(Value);
425       if (!Parsed)
426         return llvm::None;
427       Result.textDocument = std::move(*Parsed);
428     } else if (KeyValue == "range") {
429       auto Parsed = Range::parse(Value);
430       if (!Parsed)
431         return llvm::None;
432       Result.range = std::move(*Parsed);
433     } else if (KeyValue == "options") {
434       auto Parsed = FormattingOptions::parse(Value);
435       if (!Parsed)
436         return llvm::None;
437       Result.options = std::move(*Parsed);
438     } else {
439       return llvm::None;
440     }
441   }
442   return Result;
443 }
444 
445 llvm::Optional<DocumentOnTypeFormattingParams>
446 DocumentOnTypeFormattingParams::parse(llvm::yaml::MappingNode *Params) {
447   DocumentOnTypeFormattingParams Result;
448   for (auto &NextKeyValue : *Params) {
449     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
450     if (!KeyString)
451       return llvm::None;
452 
453     llvm::SmallString<10> KeyStorage;
454     StringRef KeyValue = KeyString->getValue(KeyStorage);
455 
456     if (KeyValue == "ch") {
457       auto *ScalarValue =
458           dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
459       if (!ScalarValue)
460         return llvm::None;
461       llvm::SmallString<10> Storage;
462       Result.ch = ScalarValue->getValue(Storage);
463       continue;
464     }
465 
466     auto *Value =
467         dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
468     if (!Value)
469       return llvm::None;
470     if (KeyValue == "textDocument") {
471       auto Parsed = TextDocumentIdentifier::parse(Value);
472       if (!Parsed)
473         return llvm::None;
474       Result.textDocument = std::move(*Parsed);
475     } else if (KeyValue == "position") {
476       auto Parsed = Position::parse(Value);
477       if (!Parsed)
478         return llvm::None;
479       Result.position = std::move(*Parsed);
480     } else if (KeyValue == "options") {
481       auto Parsed = FormattingOptions::parse(Value);
482       if (!Parsed)
483         return llvm::None;
484       Result.options = std::move(*Parsed);
485     } else {
486       return llvm::None;
487     }
488   }
489   return Result;
490 }
491 
492 llvm::Optional<DocumentFormattingParams>
493 DocumentFormattingParams::parse(llvm::yaml::MappingNode *Params) {
494   DocumentFormattingParams Result;
495   for (auto &NextKeyValue : *Params) {
496     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
497     if (!KeyString)
498       return llvm::None;
499 
500     llvm::SmallString<10> KeyStorage;
501     StringRef KeyValue = KeyString->getValue(KeyStorage);
502     auto *Value =
503         dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
504     if (!Value)
505       return llvm::None;
506 
507     llvm::SmallString<10> Storage;
508     if (KeyValue == "textDocument") {
509       auto Parsed = TextDocumentIdentifier::parse(Value);
510       if (!Parsed)
511         return llvm::None;
512       Result.textDocument = std::move(*Parsed);
513     } else if (KeyValue == "options") {
514       auto Parsed = FormattingOptions::parse(Value);
515       if (!Parsed)
516         return llvm::None;
517       Result.options = std::move(*Parsed);
518     } else {
519       return llvm::None;
520     }
521   }
522   return Result;
523 }
524 
525 llvm::Optional<Diagnostic> Diagnostic::parse(llvm::yaml::MappingNode *Params) {
526   Diagnostic Result;
527   for (auto &NextKeyValue : *Params) {
528     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
529     if (!KeyString)
530       return llvm::None;
531 
532     llvm::SmallString<10> KeyStorage;
533     StringRef KeyValue = KeyString->getValue(KeyStorage);
534 
535     llvm::SmallString<10> Storage;
536     if (KeyValue == "range") {
537       auto *Value =
538           dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
539       if (!Value)
540         return llvm::None;
541       auto Parsed = Range::parse(Value);
542       if (!Parsed)
543         return llvm::None;
544       Result.range = std::move(*Parsed);
545     } else if (KeyValue == "severity") {
546       auto *Value =
547           dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
548       if (!Value)
549         return llvm::None;
550       long long Val;
551       if (llvm::getAsSignedInteger(Value->getValue(Storage), 0, Val))
552         return llvm::None;
553       Result.severity = Val;
554     } else if (KeyValue == "message") {
555       auto *Value =
556           dyn_cast_or_null<llvm::yaml::ScalarNode>(NextKeyValue.getValue());
557       if (!Value)
558         return llvm::None;
559       Result.message = Value->getValue(Storage);
560     } else {
561       return llvm::None;
562     }
563   }
564   return Result;
565 }
566 
567 llvm::Optional<CodeActionContext>
568 CodeActionContext::parse(llvm::yaml::MappingNode *Params) {
569   CodeActionContext Result;
570   for (auto &NextKeyValue : *Params) {
571     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
572     if (!KeyString)
573       return llvm::None;
574 
575     llvm::SmallString<10> KeyStorage;
576     StringRef KeyValue = KeyString->getValue(KeyStorage);
577     auto *Value = NextKeyValue.getValue();
578 
579     llvm::SmallString<10> Storage;
580     if (KeyValue == "diagnostics") {
581       auto *Seq = dyn_cast<llvm::yaml::SequenceNode>(Value);
582       if (!Seq)
583         return llvm::None;
584       for (auto &Item : *Seq) {
585         auto *I = dyn_cast<llvm::yaml::MappingNode>(&Item);
586         if (!I)
587           return llvm::None;
588         auto Parsed = Diagnostic::parse(I);
589         if (!Parsed)
590           return llvm::None;
591         Result.diagnostics.push_back(std::move(*Parsed));
592       }
593     } else {
594       return llvm::None;
595     }
596   }
597   return Result;
598 }
599 
600 llvm::Optional<CodeActionParams>
601 CodeActionParams::parse(llvm::yaml::MappingNode *Params) {
602   CodeActionParams Result;
603   for (auto &NextKeyValue : *Params) {
604     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
605     if (!KeyString)
606       return llvm::None;
607 
608     llvm::SmallString<10> KeyStorage;
609     StringRef KeyValue = KeyString->getValue(KeyStorage);
610     auto *Value =
611         dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
612     if (!Value)
613       return llvm::None;
614 
615     llvm::SmallString<10> Storage;
616     if (KeyValue == "textDocument") {
617       auto Parsed = TextDocumentIdentifier::parse(Value);
618       if (!Parsed)
619         return llvm::None;
620       Result.textDocument = std::move(*Parsed);
621     } else if (KeyValue == "range") {
622       auto Parsed = Range::parse(Value);
623       if (!Parsed)
624         return llvm::None;
625       Result.range = std::move(*Parsed);
626     } else if (KeyValue == "context") {
627       auto Parsed = CodeActionContext::parse(Value);
628       if (!Parsed)
629         return llvm::None;
630       Result.context = std::move(*Parsed);
631     } else {
632       return llvm::None;
633     }
634   }
635   return Result;
636 }
637 
638 llvm::Optional<TextDocumentPositionParams>
639 TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params) {
640   TextDocumentPositionParams Result;
641   for (auto &NextKeyValue : *Params) {
642     auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
643     if (!KeyString)
644       return llvm::None;
645 
646     llvm::SmallString<10> KeyStorage;
647     StringRef KeyValue = KeyString->getValue(KeyStorage);
648     auto *Value =
649         dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
650     if (!Value)
651       continue;
652 
653     llvm::SmallString<10> Storage;
654     if (KeyValue == "textDocument") {
655       auto Parsed = TextDocumentIdentifier::parse(Value);
656       if (!Parsed)
657         return llvm::None;
658       Result.textDocument = std::move(*Parsed);
659     } else if (KeyValue == "position") {
660       auto Parsed = Position::parse(Value);
661       if (!Parsed)
662         return llvm::None;
663       Result.position = std::move(*Parsed);
664     } else {
665       return llvm::None;
666     }
667   }
668   return Result;
669 }
670 
671 std::string CompletionItem::unparse(const CompletionItem &CI) {
672   std::string Result = "{";
673   llvm::raw_string_ostream Os(Result);
674   assert(!CI.label.empty() && "completion item label is required");
675   Os << R"("label":")" << llvm::yaml::escape(CI.label) << R"(",)";
676   if (CI.kind != CompletionItemKind::Missing)
677     Os << R"("kind":)" << static_cast<int>(CI.kind) << R"(,)";
678   if (!CI.detail.empty())
679     Os << R"("detail":")" << llvm::yaml::escape(CI.detail) << R"(",)";
680   if (!CI.documentation.empty())
681     Os << R"("documentation":")" << llvm::yaml::escape(CI.documentation)
682        << R"(",)";
683   if (!CI.sortText.empty())
684     Os << R"("sortText":")" << llvm::yaml::escape(CI.sortText) << R"(",)";
685   if (!CI.filterText.empty())
686     Os << R"("filterText":")" << llvm::yaml::escape(CI.filterText) << R"(",)";
687   if (!CI.insertText.empty())
688     Os << R"("insertText":")" << llvm::yaml::escape(CI.insertText) << R"(",)";
689   if (CI.insertTextFormat != InsertTextFormat::Missing) {
690     Os << R"("insertTextFormat":")" << static_cast<int>(CI.insertTextFormat)
691        << R"(",)";
692   }
693   if (CI.textEdit)
694     Os << R"("textEdit":)" << TextEdit::unparse(*CI.textEdit) << ',';
695   if (!CI.additionalTextEdits.empty()) {
696     Os << R"("additionalTextEdits":[)";
697     for (const auto &Edit : CI.additionalTextEdits)
698       Os << TextEdit::unparse(Edit) << ",";
699     Os.flush();
700     // The list additionalTextEdits is guaranteed nonempty at this point.
701     // Replace the trailing comma with right brace.
702     Result.back() = ']';
703   }
704   Os.flush();
705   // Label is required, so Result is guaranteed to have a trailing comma.
706   Result.back() = '}';
707   return Result;
708 }
709