1 | //===--- Protocol.cpp - Language Server Protocol Implementation -----------===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains the serialization code for the LSP structs. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "Protocol.h" |
14 | #include "URI.h" |
15 | #include "support/Logger.h" |
16 | #include "clang/Basic/LLVM.h" |
17 | #include "clang/Index/IndexSymbol.h" |
18 | #include "llvm/ADT/StringExtras.h" |
19 | #include "llvm/ADT/StringRef.h" |
20 | #include "llvm/ADT/StringSwitch.h" |
21 | #include "llvm/Support/ErrorHandling.h" |
22 | #include "llvm/Support/JSON.h" |
23 | #include "llvm/Support/Path.h" |
24 | #include "llvm/Support/raw_ostream.h" |
25 | |
26 | namespace clang { |
27 | namespace clangd { |
28 | namespace { |
29 | |
30 | // Helper that doesn't treat `null` and absent fields as failures. |
31 | template <typename T> |
32 | bool mapOptOrNull(const llvm::json::Value &Params, llvm::StringLiteral Prop, |
33 | T &Out, llvm::json::Path P) { |
34 | auto *O = Params.getAsObject(); |
35 | assert(O); |
36 | auto *V = O->get(K: Prop); |
37 | // Field is missing or null. |
38 | if (!V || V->getAsNull()) |
39 | return true; |
40 | return fromJSON(*V, Out, P.field(Field: Prop)); |
41 | } |
42 | } // namespace |
43 | |
44 | char LSPError::ID; |
45 | |
46 | URIForFile URIForFile::canonicalize(llvm::StringRef AbsPath, |
47 | llvm::StringRef TUPath) { |
48 | assert(llvm::sys::path::is_absolute(AbsPath) && "the path is relative"); |
49 | auto Resolved = URI::resolvePath(AbsPath, HintPath: TUPath); |
50 | if (!Resolved) { |
51 | elog(Fmt: "URIForFile: failed to resolve path {0} with TU path {1}: " |
52 | "{2}.\nUsing unresolved path.", |
53 | Vals&: AbsPath, Vals&: TUPath, Vals: Resolved.takeError()); |
54 | return URIForFile(std::string(AbsPath)); |
55 | } |
56 | return URIForFile(std::move(*Resolved)); |
57 | } |
58 | |
59 | llvm::Expected<URIForFile> URIForFile::fromURI(const URI &U, |
60 | llvm::StringRef HintPath) { |
61 | auto Resolved = URI::resolve(U, HintPath); |
62 | if (!Resolved) |
63 | return Resolved.takeError(); |
64 | return URIForFile(std::move(*Resolved)); |
65 | } |
66 | |
67 | bool fromJSON(const llvm::json::Value &E, URIForFile &R, llvm::json::Path P) { |
68 | if (auto S = E.getAsString()) { |
69 | auto Parsed = URI::parse(Uri: *S); |
70 | if (!Parsed) { |
71 | consumeError(Err: Parsed.takeError()); |
72 | P.report(Message: "failed to parse URI"); |
73 | return false; |
74 | } |
75 | if (Parsed->scheme() != "file"&& Parsed->scheme() != "test") { |
76 | P.report(Message: "clangd only supports 'file' URI scheme for workspace files"); |
77 | return false; |
78 | } |
79 | // "file" and "test" schemes do not require hint path. |
80 | auto U = URIForFile::fromURI(U: *Parsed, /*HintPath=*/""); |
81 | if (!U) { |
82 | P.report(Message: "unresolvable URI"); |
83 | consumeError(Err: U.takeError()); |
84 | return false; |
85 | } |
86 | R = std::move(*U); |
87 | return true; |
88 | } |
89 | return false; |
90 | } |
91 | |
92 | llvm::json::Value toJSON(const URIForFile &U) { return U.uri(); } |
93 | |
94 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const URIForFile &U) { |
95 | return OS << U.uri(); |
96 | } |
97 | |
98 | llvm::json::Value toJSON(const TextDocumentIdentifier &R) { |
99 | return llvm::json::Object{{.K: "uri", .V: R.uri}}; |
100 | } |
101 | |
102 | bool fromJSON(const llvm::json::Value &Params, TextDocumentIdentifier &R, |
103 | llvm::json::Path P) { |
104 | llvm::json::ObjectMapper O(Params, P); |
105 | return O && O.map(Prop: "uri", Out&: R.uri); |
106 | } |
107 | |
108 | llvm::json::Value toJSON(const VersionedTextDocumentIdentifier &R) { |
109 | auto Result = toJSON(R: static_cast<const TextDocumentIdentifier &>(R)); |
110 | Result.getAsObject()->try_emplace(K: "version", Args: R.version); |
111 | return Result; |
112 | } |
113 | |
114 | bool fromJSON(const llvm::json::Value &Params, |
115 | VersionedTextDocumentIdentifier &R, llvm::json::Path P) { |
116 | llvm::json::ObjectMapper O(Params, P); |
117 | return fromJSON(Params, R&: static_cast<TextDocumentIdentifier &>(R), P) && O && |
118 | O.map(Prop: "version", Out&: R.version); |
119 | } |
120 | |
121 | bool fromJSON(const llvm::json::Value &Params, Position &R, |
122 | llvm::json::Path P) { |
123 | llvm::json::ObjectMapper O(Params, P); |
124 | return O && O.map(Prop: "line", Out&: R.line) && O.map(Prop: "character", Out&: R.character); |
125 | } |
126 | |
127 | llvm::json::Value toJSON(const Position &P) { |
128 | return llvm::json::Object{ |
129 | {.K: "line", .V: P.line}, |
130 | {.K: "character", .V: P.character}, |
131 | }; |
132 | } |
133 | |
134 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &P) { |
135 | return OS << P.line << ':' << P.character; |
136 | } |
137 | |
138 | bool fromJSON(const llvm::json::Value &Params, Range &R, llvm::json::Path P) { |
139 | llvm::json::ObjectMapper O(Params, P); |
140 | return O && O.map(Prop: "start", Out&: R.start) && O.map(Prop: "end", Out&: R.end); |
141 | } |
142 | |
143 | llvm::json::Value toJSON(const Range &P) { |
144 | return llvm::json::Object{ |
145 | {.K: "start", .V: P.start}, |
146 | {.K: "end", .V: P.end}, |
147 | }; |
148 | } |
149 | |
150 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Range &R) { |
151 | return OS << R.start << '-' << R.end; |
152 | } |
153 | |
154 | llvm::json::Value toJSON(const Location &P) { |
155 | return llvm::json::Object{ |
156 | {.K: "uri", .V: P.uri}, |
157 | {.K: "range", .V: P.range}, |
158 | }; |
159 | } |
160 | |
161 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Location &L) { |
162 | return OS << L.range << '@' << L.uri; |
163 | } |
164 | |
165 | llvm::json::Value toJSON(const ReferenceLocation &P) { |
166 | llvm::json::Object Result{ |
167 | {.K: "uri", .V: P.uri}, |
168 | {.K: "range", .V: P.range}, |
169 | }; |
170 | if (P.containerName) |
171 | Result.insert(E: {.K: "containerName", .V: P.containerName}); |
172 | return Result; |
173 | } |
174 | |
175 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
176 | const ReferenceLocation &L) { |
177 | return OS << L.range << '@' << L.uri << " (container: "<< L.containerName |
178 | << ")"; |
179 | } |
180 | |
181 | bool fromJSON(const llvm::json::Value &Params, TextDocumentItem &R, |
182 | llvm::json::Path P) { |
183 | llvm::json::ObjectMapper O(Params, P); |
184 | return O && O.map(Prop: "uri", Out&: R.uri) && O.map(Prop: "languageId", Out&: R.languageId) && |
185 | O.map(Prop: "version", Out&: R.version) && O.map(Prop: "text", Out&: R.text); |
186 | } |
187 | |
188 | bool fromJSON(const llvm::json::Value &Params, TextEdit &R, |
189 | llvm::json::Path P) { |
190 | llvm::json::ObjectMapper O(Params, P); |
191 | return O && O.map(Prop: "range", Out&: R.range) && O.map(Prop: "newText", Out&: R.newText) && |
192 | O.mapOptional(Prop: "annotationId", Out&: R.annotationId); |
193 | } |
194 | |
195 | llvm::json::Value toJSON(const TextEdit &P) { |
196 | llvm::json::Object Result{ |
197 | {.K: "range", .V: P.range}, |
198 | {.K: "newText", .V: P.newText}, |
199 | }; |
200 | if (!P.annotationId.empty()) |
201 | Result["annotationId"] = P.annotationId; |
202 | return Result; |
203 | } |
204 | |
205 | bool fromJSON(const llvm::json::Value &Params, ChangeAnnotation &R, |
206 | llvm::json::Path P) { |
207 | llvm::json::ObjectMapper O(Params, P); |
208 | return O && O.map(Prop: "label", Out&: R.label) && |
209 | O.map(Prop: "needsConfirmation", Out&: R.needsConfirmation) && |
210 | O.mapOptional(Prop: "description", Out&: R.description); |
211 | } |
212 | llvm::json::Value toJSON(const ChangeAnnotation & CA) { |
213 | llvm::json::Object Result{{.K: "label", .V: CA.label}}; |
214 | if (CA.needsConfirmation) |
215 | Result["needsConfirmation"] = *CA.needsConfirmation; |
216 | if (!CA.description.empty()) |
217 | Result["description"] = CA.description; |
218 | return Result; |
219 | } |
220 | |
221 | bool fromJSON(const llvm::json::Value &Params, TextDocumentEdit &R, |
222 | llvm::json::Path P) { |
223 | llvm::json::ObjectMapper O(Params, P); |
224 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && O.map(Prop: "edits", Out&: R.edits); |
225 | } |
226 | llvm::json::Value toJSON(const TextDocumentEdit &P) { |
227 | llvm::json::Object Result{{.K: "textDocument", .V: P.textDocument}, |
228 | {.K: "edits", .V: P.edits}}; |
229 | return Result; |
230 | } |
231 | |
232 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) { |
233 | OS << TE.range << " => \""; |
234 | llvm::printEscapedString(Name: TE.newText, Out&: OS); |
235 | return OS << '"'; |
236 | } |
237 | |
238 | bool fromJSON(const llvm::json::Value &E, TraceLevel &Out, llvm::json::Path P) { |
239 | if (auto S = E.getAsString()) { |
240 | if (*S == "off") { |
241 | Out = TraceLevel::Off; |
242 | return true; |
243 | } |
244 | if (*S == "messages") { |
245 | Out = TraceLevel::Messages; |
246 | return true; |
247 | } |
248 | if (*S == "verbose") { |
249 | Out = TraceLevel::Verbose; |
250 | return true; |
251 | } |
252 | } |
253 | return false; |
254 | } |
255 | |
256 | bool fromJSON(const llvm::json::Value &E, SymbolKind &Out, llvm::json::Path P) { |
257 | if (auto T = E.getAsInteger()) { |
258 | if (*T < static_cast<int>(SymbolKind::File) || |
259 | *T > static_cast<int>(SymbolKind::TypeParameter)) |
260 | return false; |
261 | Out = static_cast<SymbolKind>(*T); |
262 | return true; |
263 | } |
264 | return false; |
265 | } |
266 | |
267 | bool fromJSON(const llvm::json::Value &E, SymbolKindBitset &Out, |
268 | llvm::json::Path P) { |
269 | if (auto *A = E.getAsArray()) { |
270 | for (size_t I = 0; I < A->size(); ++I) { |
271 | SymbolKind KindOut; |
272 | if (fromJSON(E: (*A)[I], Out&: KindOut, P: P.index(Index: I))) |
273 | Out.set(position: size_t(KindOut)); |
274 | } |
275 | return true; |
276 | } |
277 | return false; |
278 | } |
279 | |
280 | SymbolKind adjustKindToCapability(SymbolKind Kind, |
281 | SymbolKindBitset &SupportedSymbolKinds) { |
282 | auto KindVal = static_cast<size_t>(Kind); |
283 | if (KindVal >= SymbolKindMin && KindVal <= SupportedSymbolKinds.size() && |
284 | SupportedSymbolKinds[KindVal]) |
285 | return Kind; |
286 | |
287 | switch (Kind) { |
288 | // Provide some fall backs for common kinds that are close enough. |
289 | case SymbolKind::Struct: |
290 | return SymbolKind::Class; |
291 | case SymbolKind::EnumMember: |
292 | return SymbolKind::Enum; |
293 | default: |
294 | return SymbolKind::String; |
295 | } |
296 | } |
297 | |
298 | SymbolKind indexSymbolKindToSymbolKind(index::SymbolKind Kind) { |
299 | switch (Kind) { |
300 | case index::SymbolKind::Unknown: |
301 | return SymbolKind::Variable; |
302 | case index::SymbolKind::Module: |
303 | return SymbolKind::Module; |
304 | case index::SymbolKind::Namespace: |
305 | return SymbolKind::Namespace; |
306 | case index::SymbolKind::NamespaceAlias: |
307 | return SymbolKind::Namespace; |
308 | case index::SymbolKind::Macro: |
309 | return SymbolKind::String; |
310 | case index::SymbolKind::Enum: |
311 | return SymbolKind::Enum; |
312 | case index::SymbolKind::Struct: |
313 | return SymbolKind::Struct; |
314 | case index::SymbolKind::Class: |
315 | return SymbolKind::Class; |
316 | case index::SymbolKind::Protocol: |
317 | return SymbolKind::Interface; |
318 | case index::SymbolKind::Extension: |
319 | return SymbolKind::Interface; |
320 | case index::SymbolKind::Union: |
321 | return SymbolKind::Class; |
322 | case index::SymbolKind::TypeAlias: |
323 | return SymbolKind::Class; |
324 | case index::SymbolKind::Function: |
325 | return SymbolKind::Function; |
326 | case index::SymbolKind::Variable: |
327 | return SymbolKind::Variable; |
328 | case index::SymbolKind::Field: |
329 | return SymbolKind::Field; |
330 | case index::SymbolKind::EnumConstant: |
331 | return SymbolKind::EnumMember; |
332 | case index::SymbolKind::InstanceMethod: |
333 | case index::SymbolKind::ClassMethod: |
334 | case index::SymbolKind::StaticMethod: |
335 | return SymbolKind::Method; |
336 | case index::SymbolKind::InstanceProperty: |
337 | case index::SymbolKind::ClassProperty: |
338 | case index::SymbolKind::StaticProperty: |
339 | return SymbolKind::Property; |
340 | case index::SymbolKind::Constructor: |
341 | case index::SymbolKind::Destructor: |
342 | return SymbolKind::Constructor; |
343 | case index::SymbolKind::ConversionFunction: |
344 | return SymbolKind::Function; |
345 | case index::SymbolKind::Parameter: |
346 | case index::SymbolKind::NonTypeTemplateParm: |
347 | return SymbolKind::Variable; |
348 | case index::SymbolKind::Using: |
349 | return SymbolKind::Namespace; |
350 | case index::SymbolKind::TemplateTemplateParm: |
351 | case index::SymbolKind::TemplateTypeParm: |
352 | return SymbolKind::TypeParameter; |
353 | case index::SymbolKind::Concept: |
354 | return SymbolKind::Interface; |
355 | } |
356 | llvm_unreachable("invalid symbol kind"); |
357 | } |
358 | |
359 | bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R, |
360 | llvm::json::Path P) { |
361 | const llvm::json::Object *O = Params.getAsObject(); |
362 | if (!O) { |
363 | P.report(Message: "expected object"); |
364 | return false; |
365 | } |
366 | if (auto *TextDocument = O->getObject(K: "textDocument")) { |
367 | if (auto *SemanticHighlighting = |
368 | TextDocument->getObject(K: "semanticHighlightingCapabilities")) { |
369 | if (auto SemanticHighlightingSupport = |
370 | SemanticHighlighting->getBoolean(K: "semanticHighlighting")) |
371 | R.TheiaSemanticHighlighting = *SemanticHighlightingSupport; |
372 | } |
373 | if (auto *InactiveRegions = |
374 | TextDocument->getObject(K: "inactiveRegionsCapabilities")) { |
375 | if (auto InactiveRegionsSupport = |
376 | InactiveRegions->getBoolean(K: "inactiveRegions")) { |
377 | R.InactiveRegions = *InactiveRegionsSupport; |
378 | } |
379 | } |
380 | if (TextDocument->getObject(K: "semanticTokens")) |
381 | R.SemanticTokens = true; |
382 | if (auto *Diagnostics = TextDocument->getObject(K: "publishDiagnostics")) { |
383 | if (auto CategorySupport = Diagnostics->getBoolean(K: "categorySupport")) |
384 | R.DiagnosticCategory = *CategorySupport; |
385 | if (auto CodeActions = Diagnostics->getBoolean(K: "codeActionsInline")) |
386 | R.DiagnosticFixes = *CodeActions; |
387 | if (auto RelatedInfo = Diagnostics->getBoolean(K: "relatedInformation")) |
388 | R.DiagnosticRelatedInformation = *RelatedInfo; |
389 | } |
390 | if (auto *References = TextDocument->getObject(K: "references")) |
391 | if (auto ContainerSupport = References->getBoolean(K: "container")) |
392 | R.ReferenceContainer = *ContainerSupport; |
393 | if (auto *Completion = TextDocument->getObject(K: "completion")) { |
394 | if (auto *Item = Completion->getObject(K: "completionItem")) { |
395 | if (auto SnippetSupport = Item->getBoolean(K: "snippetSupport")) |
396 | R.CompletionSnippets = *SnippetSupport; |
397 | if (auto LabelDetailsSupport = Item->getBoolean(K: "labelDetailsSupport")) |
398 | R.CompletionLabelDetail = *LabelDetailsSupport; |
399 | if (const auto *DocumentationFormat = |
400 | Item->getArray(K: "documentationFormat")) { |
401 | for (const auto &Format : *DocumentationFormat) { |
402 | if (fromJSON(Format, R.CompletionDocumentationFormat, P)) |
403 | break; |
404 | } |
405 | } |
406 | } |
407 | if (auto *ItemKind = Completion->getObject(K: "completionItemKind")) { |
408 | if (auto *ValueSet = ItemKind->get(K: "valueSet")) { |
409 | R.CompletionItemKinds.emplace(); |
410 | if (!fromJSON(*ValueSet, *R.CompletionItemKinds, |
411 | P.field(Field: "textDocument") |
412 | .field(Field: "completion") |
413 | .field(Field: "completionItemKind") |
414 | .field(Field: "valueSet"))) |
415 | return false; |
416 | } |
417 | } |
418 | if (auto EditsNearCursor = Completion->getBoolean(K: "editsNearCursor")) |
419 | R.CompletionFixes = *EditsNearCursor; |
420 | } |
421 | if (auto *CodeAction = TextDocument->getObject(K: "codeAction")) { |
422 | if (CodeAction->getObject(K: "codeActionLiteralSupport")) |
423 | R.CodeActionStructure = true; |
424 | } |
425 | if (auto *DocumentSymbol = TextDocument->getObject(K: "documentSymbol")) { |
426 | if (auto HierarchicalSupport = |
427 | DocumentSymbol->getBoolean(K: "hierarchicalDocumentSymbolSupport")) |
428 | R.HierarchicalDocumentSymbol = *HierarchicalSupport; |
429 | } |
430 | if (auto *Hover = TextDocument->getObject(K: "hover")) { |
431 | if (auto *ContentFormat = Hover->getArray(K: "contentFormat")) { |
432 | for (const auto &Format : *ContentFormat) { |
433 | if (fromJSON(Format, R.HoverContentFormat, P)) |
434 | break; |
435 | } |
436 | } |
437 | } |
438 | if (auto *Help = TextDocument->getObject(K: "signatureHelp")) { |
439 | R.HasSignatureHelp = true; |
440 | if (auto *Info = Help->getObject(K: "signatureInformation")) { |
441 | if (auto *Parameter = Info->getObject(K: "parameterInformation")) { |
442 | if (auto OffsetSupport = Parameter->getBoolean(K: "labelOffsetSupport")) |
443 | R.OffsetsInSignatureHelp = *OffsetSupport; |
444 | } |
445 | if (const auto *DocumentationFormat = |
446 | Info->getArray(K: "documentationFormat")) { |
447 | for (const auto &Format : *DocumentationFormat) { |
448 | if (fromJSON(Format, R.SignatureHelpDocumentationFormat, P)) |
449 | break; |
450 | } |
451 | } |
452 | } |
453 | } |
454 | if (auto *Folding = TextDocument->getObject(K: "foldingRange")) { |
455 | if (auto LineFolding = Folding->getBoolean(K: "lineFoldingOnly")) |
456 | R.LineFoldingOnly = *LineFolding; |
457 | } |
458 | if (auto *Rename = TextDocument->getObject(K: "rename")) { |
459 | if (auto RenameSupport = Rename->getBoolean(K: "prepareSupport")) |
460 | R.RenamePrepareSupport = *RenameSupport; |
461 | } |
462 | } |
463 | if (auto *Workspace = O->getObject(K: "workspace")) { |
464 | if (auto *Symbol = Workspace->getObject(K: "symbol")) { |
465 | if (auto *SymbolKind = Symbol->getObject(K: "symbolKind")) { |
466 | if (auto *ValueSet = SymbolKind->get(K: "valueSet")) { |
467 | R.WorkspaceSymbolKinds.emplace(); |
468 | if (!fromJSON(E: *ValueSet, Out&: *R.WorkspaceSymbolKinds, |
469 | P: P.field(Field: "workspace") |
470 | .field(Field: "symbol") |
471 | .field(Field: "symbolKind") |
472 | .field(Field: "valueSet"))) |
473 | return false; |
474 | } |
475 | } |
476 | } |
477 | if (auto *SemanticTokens = Workspace->getObject(K: "semanticTokens")) { |
478 | if (auto RefreshSupport = SemanticTokens->getBoolean(K: "refreshSupport")) |
479 | R.SemanticTokenRefreshSupport = *RefreshSupport; |
480 | } |
481 | if (auto *WorkspaceEdit = Workspace->getObject(K: "workspaceEdit")) { |
482 | if (auto DocumentChanges = WorkspaceEdit->getBoolean(K: "documentChanges")) |
483 | R.DocumentChanges = *DocumentChanges; |
484 | if (WorkspaceEdit->getObject(K: "changeAnnotationSupport")) { |
485 | R.ChangeAnnotation = true; |
486 | } |
487 | } |
488 | } |
489 | if (auto *Window = O->getObject(K: "window")) { |
490 | if (auto WorkDoneProgress = Window->getBoolean(K: "workDoneProgress")) |
491 | R.WorkDoneProgress = *WorkDoneProgress; |
492 | if (auto Implicit = Window->getBoolean(K: "implicitWorkDoneProgressCreate")) |
493 | R.ImplicitProgressCreation = *Implicit; |
494 | } |
495 | if (auto *General = O->getObject(K: "general")) { |
496 | if (auto *StaleRequestSupport = General->getObject(K: "staleRequestSupport")) { |
497 | if (auto Cancel = StaleRequestSupport->getBoolean(K: "cancel")) |
498 | R.CancelsStaleRequests = *Cancel; |
499 | } |
500 | } |
501 | if (auto *OffsetEncoding = O->get(K: "offsetEncoding")) { |
502 | R.offsetEncoding.emplace(); |
503 | if (!fromJSON(E: *OffsetEncoding, Out&: *R.offsetEncoding, |
504 | P: P.field(Field: "offsetEncoding"))) |
505 | return false; |
506 | } |
507 | |
508 | if (auto *Experimental = O->getObject(K: "experimental")) { |
509 | if (auto *TextDocument = Experimental->getObject(K: "textDocument")) { |
510 | if (auto *Completion = TextDocument->getObject(K: "completion")) { |
511 | if (auto EditsNearCursor = Completion->getBoolean(K: "editsNearCursor")) |
512 | R.CompletionFixes |= *EditsNearCursor; |
513 | } |
514 | if (auto *References = TextDocument->getObject(K: "references")) { |
515 | if (auto ContainerSupport = References->getBoolean(K: "container")) { |
516 | R.ReferenceContainer |= *ContainerSupport; |
517 | } |
518 | } |
519 | if (auto *Diagnostics = TextDocument->getObject(K: "publishDiagnostics")) { |
520 | if (auto CodeActions = Diagnostics->getBoolean(K: "codeActionsInline")) { |
521 | R.DiagnosticFixes |= *CodeActions; |
522 | } |
523 | } |
524 | if (auto *InactiveRegions = |
525 | TextDocument->getObject(K: "inactiveRegionsCapabilities")) { |
526 | if (auto InactiveRegionsSupport = |
527 | InactiveRegions->getBoolean(K: "inactiveRegions")) { |
528 | R.InactiveRegions |= *InactiveRegionsSupport; |
529 | } |
530 | } |
531 | } |
532 | if (auto *Window = Experimental->getObject(K: "window")) { |
533 | if (auto Implicit = |
534 | Window->getBoolean(K: "implicitWorkDoneProgressCreate")) { |
535 | R.ImplicitProgressCreation |= *Implicit; |
536 | } |
537 | } |
538 | if (auto *OffsetEncoding = Experimental->get(K: "offsetEncoding")) { |
539 | R.offsetEncoding.emplace(); |
540 | if (!fromJSON(E: *OffsetEncoding, Out&: *R.offsetEncoding, |
541 | P: P.field(Field: "offsetEncoding"))) |
542 | return false; |
543 | } |
544 | } |
545 | |
546 | return true; |
547 | } |
548 | |
549 | bool fromJSON(const llvm::json::Value &Params, InitializeParams &R, |
550 | llvm::json::Path P) { |
551 | llvm::json::ObjectMapper O(Params, P); |
552 | if (!O) |
553 | return false; |
554 | // We deliberately don't fail if we can't parse individual fields. |
555 | // Failing to handle a slightly malformed initialize would be a disaster. |
556 | O.map(Prop: "processId", Out&: R.processId); |
557 | O.map(Prop: "rootUri", Out&: R.rootUri); |
558 | O.map(Prop: "rootPath", Out&: R.rootPath); |
559 | O.map(Prop: "capabilities", Out&: R.capabilities); |
560 | if (auto *RawCaps = Params.getAsObject()->getObject(K: "capabilities")) |
561 | R.rawCapabilities = *RawCaps; |
562 | O.map(Prop: "trace", Out&: R.trace); |
563 | O.map(Prop: "initializationOptions", Out&: R.initializationOptions); |
564 | return true; |
565 | } |
566 | |
567 | llvm::json::Value toJSON(const WorkDoneProgressCreateParams &P) { |
568 | return llvm::json::Object{{.K: "token", .V: P.token}}; |
569 | } |
570 | |
571 | llvm::json::Value toJSON(const WorkDoneProgressBegin &P) { |
572 | llvm::json::Object Result{ |
573 | {.K: "kind", .V: "begin"}, |
574 | {.K: "title", .V: P.title}, |
575 | }; |
576 | if (P.cancellable) |
577 | Result["cancellable"] = true; |
578 | if (P.percentage) |
579 | Result["percentage"] = 0; |
580 | |
581 | // FIXME: workaround for older gcc/clang |
582 | return std::move(Result); |
583 | } |
584 | |
585 | llvm::json::Value toJSON(const WorkDoneProgressReport &P) { |
586 | llvm::json::Object Result{{.K: "kind", .V: "report"}}; |
587 | if (P.cancellable) |
588 | Result["cancellable"] = *P.cancellable; |
589 | if (P.message) |
590 | Result["message"] = *P.message; |
591 | if (P.percentage) |
592 | Result["percentage"] = *P.percentage; |
593 | // FIXME: workaround for older gcc/clang |
594 | return std::move(Result); |
595 | } |
596 | |
597 | llvm::json::Value toJSON(const WorkDoneProgressEnd &P) { |
598 | llvm::json::Object Result{{.K: "kind", .V: "end"}}; |
599 | if (P.message) |
600 | Result["message"] = *P.message; |
601 | // FIXME: workaround for older gcc/clang |
602 | return std::move(Result); |
603 | } |
604 | |
605 | llvm::json::Value toJSON(const MessageType &R) { |
606 | return static_cast<int64_t>(R); |
607 | } |
608 | |
609 | llvm::json::Value toJSON(const ShowMessageParams &R) { |
610 | return llvm::json::Object{{.K: "type", .V: R.type}, {.K: "message", .V: R.message}}; |
611 | } |
612 | |
613 | bool fromJSON(const llvm::json::Value &Params, DidOpenTextDocumentParams &R, |
614 | llvm::json::Path P) { |
615 | llvm::json::ObjectMapper O(Params, P); |
616 | return O && O.map(Prop: "textDocument", Out&: R.textDocument); |
617 | } |
618 | |
619 | bool fromJSON(const llvm::json::Value &Params, DidCloseTextDocumentParams &R, |
620 | llvm::json::Path P) { |
621 | llvm::json::ObjectMapper O(Params, P); |
622 | return O && O.map(Prop: "textDocument", Out&: R.textDocument); |
623 | } |
624 | |
625 | bool fromJSON(const llvm::json::Value &Params, DidSaveTextDocumentParams &R, |
626 | llvm::json::Path P) { |
627 | llvm::json::ObjectMapper O(Params, P); |
628 | return O && O.map(Prop: "textDocument", Out&: R.textDocument); |
629 | } |
630 | |
631 | bool fromJSON(const llvm::json::Value &Params, DidChangeTextDocumentParams &R, |
632 | llvm::json::Path P) { |
633 | llvm::json::ObjectMapper O(Params, P); |
634 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && |
635 | O.map(Prop: "contentChanges", Out&: R.contentChanges) && |
636 | O.map(Prop: "wantDiagnostics", Out&: R.wantDiagnostics) && |
637 | mapOptOrNull(Params, Prop: "forceRebuild", Out&: R.forceRebuild, P); |
638 | } |
639 | |
640 | bool fromJSON(const llvm::json::Value &E, FileChangeType &Out, |
641 | llvm::json::Path P) { |
642 | if (auto T = E.getAsInteger()) { |
643 | if (*T < static_cast<int>(FileChangeType::Created) || |
644 | *T > static_cast<int>(FileChangeType::Deleted)) |
645 | return false; |
646 | Out = static_cast<FileChangeType>(*T); |
647 | return true; |
648 | } |
649 | return false; |
650 | } |
651 | |
652 | bool fromJSON(const llvm::json::Value &Params, FileEvent &R, |
653 | llvm::json::Path P) { |
654 | llvm::json::ObjectMapper O(Params, P); |
655 | return O && O.map(Prop: "uri", Out&: R.uri) && O.map(Prop: "type", Out&: R.type); |
656 | } |
657 | |
658 | bool fromJSON(const llvm::json::Value &Params, DidChangeWatchedFilesParams &R, |
659 | llvm::json::Path P) { |
660 | llvm::json::ObjectMapper O(Params, P); |
661 | return O && O.map(Prop: "changes", Out&: R.changes); |
662 | } |
663 | |
664 | bool fromJSON(const llvm::json::Value &Params, |
665 | TextDocumentContentChangeEvent &R, llvm::json::Path P) { |
666 | llvm::json::ObjectMapper O(Params, P); |
667 | return O && O.map(Prop: "range", Out&: R.range) && O.map(Prop: "rangeLength", Out&: R.rangeLength) && |
668 | O.map(Prop: "text", Out&: R.text); |
669 | } |
670 | |
671 | bool fromJSON(const llvm::json::Value &Params, DocumentRangeFormattingParams &R, |
672 | llvm::json::Path P) { |
673 | llvm::json::ObjectMapper O(Params, P); |
674 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && O.map(Prop: "range", Out&: R.range); |
675 | ; |
676 | } |
677 | |
678 | bool fromJSON(const llvm::json::Value &Params, |
679 | DocumentRangesFormattingParams &R, llvm::json::Path P) { |
680 | llvm::json::ObjectMapper O(Params, P); |
681 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && |
682 | O.map(Prop: "ranges", Out&: R.ranges); |
683 | ; |
684 | } |
685 | |
686 | bool fromJSON(const llvm::json::Value &Params, |
687 | DocumentOnTypeFormattingParams &R, llvm::json::Path P) { |
688 | llvm::json::ObjectMapper O(Params, P); |
689 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && |
690 | O.map(Prop: "position", Out&: R.position) && O.map(Prop: "ch", Out&: R.ch); |
691 | } |
692 | |
693 | bool fromJSON(const llvm::json::Value &Params, DocumentFormattingParams &R, |
694 | llvm::json::Path P) { |
695 | llvm::json::ObjectMapper O(Params, P); |
696 | return O && O.map(Prop: "textDocument", Out&: R.textDocument); |
697 | } |
698 | |
699 | bool fromJSON(const llvm::json::Value &Params, DocumentSymbolParams &R, |
700 | llvm::json::Path P) { |
701 | llvm::json::ObjectMapper O(Params, P); |
702 | return O && O.map(Prop: "textDocument", Out&: R.textDocument); |
703 | } |
704 | |
705 | llvm::json::Value toJSON(const DiagnosticRelatedInformation &DRI) { |
706 | return llvm::json::Object{ |
707 | {.K: "location", .V: DRI.location}, |
708 | {.K: "message", .V: DRI.message}, |
709 | }; |
710 | } |
711 | |
712 | llvm::json::Value toJSON(DiagnosticTag Tag) { return static_cast<int>(Tag); } |
713 | |
714 | llvm::json::Value toJSON(const CodeDescription &D) { |
715 | return llvm::json::Object{{.K: "href", .V: D.href}}; |
716 | } |
717 | |
718 | llvm::json::Value toJSON(const Diagnostic &D) { |
719 | llvm::json::Object Diag{ |
720 | {.K: "range", .V: D.range}, |
721 | {.K: "severity", .V: D.severity}, |
722 | {.K: "message", .V: D.message}, |
723 | }; |
724 | if (D.category) |
725 | Diag["category"] = *D.category; |
726 | if (D.codeActions) |
727 | Diag["codeActions"] = D.codeActions; |
728 | if (!D.code.empty()) |
729 | Diag["code"] = D.code; |
730 | if (D.codeDescription) |
731 | Diag["codeDescription"] = *D.codeDescription; |
732 | if (!D.source.empty()) |
733 | Diag["source"] = D.source; |
734 | if (D.relatedInformation) |
735 | Diag["relatedInformation"] = *D.relatedInformation; |
736 | if (!D.data.empty()) |
737 | Diag["data"] = llvm::json::Object(D.data); |
738 | if (!D.tags.empty()) |
739 | Diag["tags"] = llvm::json::Array{D.tags}; |
740 | // FIXME: workaround for older gcc/clang |
741 | return std::move(Diag); |
742 | } |
743 | |
744 | bool fromJSON(const llvm::json::Value &Params, Diagnostic &R, |
745 | llvm::json::Path P) { |
746 | llvm::json::ObjectMapper O(Params, P); |
747 | if (!O) |
748 | return false; |
749 | if (auto *Data = Params.getAsObject()->getObject(K: "data")) |
750 | R.data = *Data; |
751 | return O.map(Prop: "range", Out&: R.range) && O.map(Prop: "message", Out&: R.message) && |
752 | mapOptOrNull(Params, Prop: "severity", Out&: R.severity, P) && |
753 | mapOptOrNull(Params, Prop: "category", Out&: R.category, P) && |
754 | mapOptOrNull(Params, Prop: "code", Out&: R.code, P) && |
755 | mapOptOrNull(Params, Prop: "source", Out&: R.source, P); |
756 | } |
757 | |
758 | llvm::json::Value toJSON(const PublishDiagnosticsParams &PDP) { |
759 | llvm::json::Object Result{ |
760 | {.K: "uri", .V: PDP.uri}, |
761 | {.K: "diagnostics", .V: PDP.diagnostics}, |
762 | }; |
763 | if (PDP.version) |
764 | Result["version"] = PDP.version; |
765 | return std::move(Result); |
766 | } |
767 | |
768 | bool fromJSON(const llvm::json::Value &Params, CodeActionContext &R, |
769 | llvm::json::Path P) { |
770 | llvm::json::ObjectMapper O(Params, P); |
771 | if (!O || !O.map(Prop: "diagnostics", Out&: R.diagnostics)) |
772 | return false; |
773 | O.map(Prop: "only", Out&: R.only); |
774 | return true; |
775 | } |
776 | |
777 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) { |
778 | OS << D.range << " ["; |
779 | switch (D.severity) { |
780 | case 1: |
781 | OS << "error"; |
782 | break; |
783 | case 2: |
784 | OS << "warning"; |
785 | break; |
786 | case 3: |
787 | OS << "note"; |
788 | break; |
789 | case 4: |
790 | OS << "remark"; |
791 | break; |
792 | default: |
793 | OS << "diagnostic"; |
794 | break; |
795 | } |
796 | return OS << '(' << D.severity << "): "<< D.message << "]"; |
797 | } |
798 | |
799 | bool fromJSON(const llvm::json::Value &Params, CodeActionParams &R, |
800 | llvm::json::Path P) { |
801 | llvm::json::ObjectMapper O(Params, P); |
802 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && |
803 | O.map(Prop: "range", Out&: R.range) && O.map(Prop: "context", Out&: R.context); |
804 | } |
805 | |
806 | bool fromJSON(const llvm::json::Value &Params, WorkspaceEdit &R, |
807 | llvm::json::Path P) { |
808 | llvm::json::ObjectMapper O(Params, P); |
809 | return O && O.map(Prop: "changes", Out&: R.changes) && |
810 | O.map(Prop: "documentChanges", Out&: R.documentChanges) && |
811 | O.mapOptional(Prop: "changeAnnotations", Out&: R.changeAnnotations); |
812 | } |
813 | |
814 | bool fromJSON(const llvm::json::Value &Params, ExecuteCommandParams &R, |
815 | llvm::json::Path P) { |
816 | llvm::json::ObjectMapper O(Params, P); |
817 | if (!O || !O.map(Prop: "command", Out&: R.command)) |
818 | return false; |
819 | |
820 | const auto *Args = Params.getAsObject()->get(K: "arguments"); |
821 | if (!Args) |
822 | return true; // Missing args is ok, argument is null. |
823 | const auto *ArgsArray = Args->getAsArray(); |
824 | if (!ArgsArray) { |
825 | P.field(Field: "arguments").report(Message: "expected array"); |
826 | return false; |
827 | } |
828 | if (ArgsArray->size() > 1) { |
829 | P.field(Field: "arguments").report(Message: "Command should have 0 or 1 argument"); |
830 | return false; |
831 | } |
832 | if (ArgsArray->size() == 1) { |
833 | R.argument = ArgsArray->front(); |
834 | } |
835 | return true; |
836 | } |
837 | |
838 | llvm::json::Value toJSON(const SymbolInformation &P) { |
839 | llvm::json::Object O{ |
840 | {.K: "name", .V: P.name}, |
841 | {.K: "kind", .V: static_cast<int>(P.kind)}, |
842 | {.K: "location", .V: P.location}, |
843 | {.K: "containerName", .V: P.containerName}, |
844 | }; |
845 | if (P.score) |
846 | O["score"] = *P.score; |
847 | return std::move(O); |
848 | } |
849 | |
850 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, |
851 | const SymbolInformation &SI) { |
852 | O << SI.containerName << "::"<< SI.name << " - "<< toJSON(P: SI); |
853 | return O; |
854 | } |
855 | |
856 | bool operator==(const SymbolDetails &LHS, const SymbolDetails &RHS) { |
857 | return LHS.name == RHS.name && LHS.containerName == RHS.containerName && |
858 | LHS.USR == RHS.USR && LHS.ID == RHS.ID && |
859 | LHS.declarationRange == RHS.declarationRange && |
860 | LHS.definitionRange == RHS.definitionRange; |
861 | } |
862 | |
863 | llvm::json::Value toJSON(const SymbolDetails &P) { |
864 | llvm::json::Object Result{{.K: "name", .V: llvm::json::Value(nullptr)}, |
865 | {.K: "containerName", .V: llvm::json::Value(nullptr)}, |
866 | {.K: "usr", .V: llvm::json::Value(nullptr)}, |
867 | {.K: "id", .V: llvm::json::Value(nullptr)}}; |
868 | |
869 | if (!P.name.empty()) |
870 | Result["name"] = P.name; |
871 | |
872 | if (!P.containerName.empty()) |
873 | Result["containerName"] = P.containerName; |
874 | |
875 | if (!P.USR.empty()) |
876 | Result["usr"] = P.USR; |
877 | |
878 | if (P.ID) |
879 | Result["id"] = P.ID.str(); |
880 | |
881 | if (P.declarationRange) |
882 | Result["declarationRange"] = *P.declarationRange; |
883 | |
884 | if (P.definitionRange) |
885 | Result["definitionRange"] = *P.definitionRange; |
886 | |
887 | // FIXME: workaround for older gcc/clang |
888 | return std::move(Result); |
889 | } |
890 | |
891 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const SymbolDetails &S) { |
892 | if (!S.containerName.empty()) { |
893 | O << S.containerName; |
894 | llvm::StringRef ContNameRef; |
895 | if (!ContNameRef.ends_with(Suffix: "::")) { |
896 | O << " "; |
897 | } |
898 | } |
899 | O << S.name << " - "<< toJSON(P: S); |
900 | return O; |
901 | } |
902 | |
903 | bool fromJSON(const llvm::json::Value &Params, WorkspaceSymbolParams &R, |
904 | llvm::json::Path P) { |
905 | llvm::json::ObjectMapper O(Params, P); |
906 | return O && O.map(Prop: "query", Out&: R.query) && |
907 | mapOptOrNull(Params, Prop: "limit", Out&: R.limit, P); |
908 | } |
909 | |
910 | llvm::json::Value toJSON(const Command &C) { |
911 | auto Cmd = llvm::json::Object{{.K: "title", .V: C.title}, {.K: "command", .V: C.command}}; |
912 | if (!C.argument.getAsNull()) |
913 | Cmd["arguments"] = llvm::json::Array{C.argument}; |
914 | return std::move(Cmd); |
915 | } |
916 | |
917 | const llvm::StringLiteral CodeAction::QUICKFIX_KIND = "quickfix"; |
918 | const llvm::StringLiteral CodeAction::REFACTOR_KIND = "refactor"; |
919 | const llvm::StringLiteral CodeAction::INFO_KIND = "info"; |
920 | |
921 | llvm::json::Value toJSON(const CodeAction &CA) { |
922 | auto CodeAction = llvm::json::Object{{.K: "title", .V: CA.title}}; |
923 | if (CA.kind) |
924 | CodeAction["kind"] = *CA.kind; |
925 | if (CA.diagnostics) |
926 | CodeAction["diagnostics"] = llvm::json::Array(*CA.diagnostics); |
927 | if (CA.isPreferred) |
928 | CodeAction["isPreferred"] = true; |
929 | if (CA.edit) |
930 | CodeAction["edit"] = *CA.edit; |
931 | if (CA.command) |
932 | CodeAction["command"] = *CA.command; |
933 | return std::move(CodeAction); |
934 | } |
935 | |
936 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const DocumentSymbol &S) { |
937 | return O << S.name << " - "<< toJSON(S); |
938 | } |
939 | |
940 | llvm::json::Value toJSON(const DocumentSymbol &S) { |
941 | llvm::json::Object Result{{.K: "name", .V: S.name}, |
942 | {.K: "kind", .V: static_cast<int>(S.kind)}, |
943 | {.K: "range", .V: S.range}, |
944 | {.K: "selectionRange", .V: S.selectionRange}}; |
945 | |
946 | if (!S.detail.empty()) |
947 | Result["detail"] = S.detail; |
948 | if (!S.children.empty()) |
949 | Result["children"] = S.children; |
950 | if (S.deprecated) |
951 | Result["deprecated"] = true; |
952 | // FIXME: workaround for older gcc/clang |
953 | return std::move(Result); |
954 | } |
955 | |
956 | llvm::json::Value toJSON(const WorkspaceEdit &WE) { |
957 | llvm::json::Object Result; |
958 | if (WE.changes) { |
959 | llvm::json::Object FileChanges; |
960 | for (auto &Change : *WE.changes) |
961 | FileChanges[Change.first] = llvm::json::Array(Change.second); |
962 | Result["changes"] = std::move(FileChanges); |
963 | } |
964 | if (WE.documentChanges) |
965 | Result["documentChanges"] = *WE.documentChanges; |
966 | if (!WE.changeAnnotations.empty()) { |
967 | llvm::json::Object ChangeAnnotations; |
968 | for (auto &Annotation : WE.changeAnnotations) |
969 | ChangeAnnotations[Annotation.first] = Annotation.second; |
970 | Result["changeAnnotations"] = std::move(ChangeAnnotations); |
971 | } |
972 | return Result; |
973 | } |
974 | |
975 | bool fromJSON(const llvm::json::Value &Params, TweakArgs &A, |
976 | llvm::json::Path P) { |
977 | llvm::json::ObjectMapper O(Params, P); |
978 | return O && O.map(Prop: "file", Out&: A.file) && O.map(Prop: "selection", Out&: A.selection) && |
979 | O.map(Prop: "tweakID", Out&: A.tweakID); |
980 | } |
981 | |
982 | llvm::json::Value toJSON(const TweakArgs &A) { |
983 | return llvm::json::Object{ |
984 | {.K: "tweakID", .V: A.tweakID}, {.K: "selection", .V: A.selection}, {.K: "file", .V: A.file}}; |
985 | } |
986 | |
987 | llvm::json::Value toJSON(const ApplyWorkspaceEditParams &Params) { |
988 | return llvm::json::Object{{.K: "edit", .V: Params.edit}}; |
989 | } |
990 | |
991 | bool fromJSON(const llvm::json::Value &Response, ApplyWorkspaceEditResponse &R, |
992 | llvm::json::Path P) { |
993 | llvm::json::ObjectMapper O(Response, P); |
994 | return O && O.map(Prop: "applied", Out&: R.applied) && |
995 | O.map(Prop: "failureReason", Out&: R.failureReason); |
996 | } |
997 | |
998 | bool fromJSON(const llvm::json::Value &Params, TextDocumentPositionParams &R, |
999 | llvm::json::Path P) { |
1000 | llvm::json::ObjectMapper O(Params, P); |
1001 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && |
1002 | O.map(Prop: "position", Out&: R.position); |
1003 | } |
1004 | |
1005 | bool fromJSON(const llvm::json::Value &Params, CompletionContext &R, |
1006 | llvm::json::Path P) { |
1007 | llvm::json::ObjectMapper O(Params, P); |
1008 | int TriggerKind; |
1009 | if (!O || !O.map(Prop: "triggerKind", Out&: TriggerKind) || |
1010 | !mapOptOrNull(Params, Prop: "triggerCharacter", Out&: R.triggerCharacter, P)) |
1011 | return false; |
1012 | R.triggerKind = static_cast<CompletionTriggerKind>(TriggerKind); |
1013 | return true; |
1014 | } |
1015 | |
1016 | bool fromJSON(const llvm::json::Value &Params, CompletionParams &R, |
1017 | llvm::json::Path P) { |
1018 | if (!fromJSON(Params, R&: static_cast<TextDocumentPositionParams &>(R), P) || |
1019 | !mapOptOrNull(Params, Prop: "limit", Out&: R.limit, P)) |
1020 | return false; |
1021 | if (auto *Context = Params.getAsObject()->get(K: "context")) |
1022 | return fromJSON(Params: *Context, R&: R.context, P: P.field(Field: "context")); |
1023 | return true; |
1024 | } |
1025 | |
1026 | static llvm::StringRef toTextKind(MarkupKind Kind) { |
1027 | switch (Kind) { |
1028 | case MarkupKind::PlainText: |
1029 | return "plaintext"; |
1030 | case MarkupKind::Markdown: |
1031 | return "markdown"; |
1032 | } |
1033 | llvm_unreachable("Invalid MarkupKind"); |
1034 | } |
1035 | |
1036 | bool fromJSON(const llvm::json::Value &V, MarkupKind &K, llvm::json::Path P) { |
1037 | auto Str = V.getAsString(); |
1038 | if (!Str) { |
1039 | P.report(Message: "expected string"); |
1040 | return false; |
1041 | } |
1042 | if (*Str == "plaintext") |
1043 | K = MarkupKind::PlainText; |
1044 | else if (*Str == "markdown") |
1045 | K = MarkupKind::Markdown; |
1046 | else { |
1047 | P.report(Message: "unknown markup kind"); |
1048 | return false; |
1049 | } |
1050 | return true; |
1051 | } |
1052 | |
1053 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind K) { |
1054 | return OS << toTextKind(Kind: K); |
1055 | } |
1056 | |
1057 | llvm::json::Value toJSON(const MarkupContent &MC) { |
1058 | if (MC.value.empty()) |
1059 | return nullptr; |
1060 | |
1061 | return llvm::json::Object{ |
1062 | {.K: "kind", .V: toTextKind(Kind: MC.kind)}, |
1063 | {.K: "value", .V: MC.value}, |
1064 | }; |
1065 | } |
1066 | |
1067 | llvm::json::Value toJSON(const Hover &H) { |
1068 | llvm::json::Object Result{{.K: "contents", .V: toJSON(MC: H.contents)}}; |
1069 | |
1070 | if (H.range) |
1071 | Result["range"] = toJSON(P: *H.range); |
1072 | |
1073 | return std::move(Result); |
1074 | } |
1075 | |
1076 | bool fromJSON(const llvm::json::Value &E, CompletionItemKind &Out, |
1077 | llvm::json::Path P) { |
1078 | if (auto T = E.getAsInteger()) { |
1079 | if (*T < static_cast<int>(CompletionItemKind::Text) || |
1080 | *T > static_cast<int>(CompletionItemKind::TypeParameter)) |
1081 | return false; |
1082 | Out = static_cast<CompletionItemKind>(*T); |
1083 | return true; |
1084 | } |
1085 | return false; |
1086 | } |
1087 | |
1088 | CompletionItemKind |
1089 | adjustKindToCapability(CompletionItemKind Kind, |
1090 | CompletionItemKindBitset &SupportedCompletionItemKinds) { |
1091 | auto KindVal = static_cast<size_t>(Kind); |
1092 | if (KindVal >= CompletionItemKindMin && |
1093 | KindVal <= SupportedCompletionItemKinds.size() && |
1094 | SupportedCompletionItemKinds[KindVal]) |
1095 | return Kind; |
1096 | |
1097 | switch (Kind) { |
1098 | // Provide some fall backs for common kinds that are close enough. |
1099 | case CompletionItemKind::Folder: |
1100 | return CompletionItemKind::File; |
1101 | case CompletionItemKind::EnumMember: |
1102 | return CompletionItemKind::Enum; |
1103 | case CompletionItemKind::Struct: |
1104 | return CompletionItemKind::Class; |
1105 | default: |
1106 | return CompletionItemKind::Text; |
1107 | } |
1108 | } |
1109 | |
1110 | bool fromJSON(const llvm::json::Value &E, CompletionItemKindBitset &Out, |
1111 | llvm::json::Path P) { |
1112 | if (auto *A = E.getAsArray()) { |
1113 | for (size_t I = 0; I < A->size(); ++I) { |
1114 | CompletionItemKind KindOut; |
1115 | if (fromJSON(E: (*A)[I], Out&: KindOut, P: P.index(Index: I))) |
1116 | Out.set(position: size_t(KindOut)); |
1117 | } |
1118 | return true; |
1119 | } |
1120 | return false; |
1121 | } |
1122 | |
1123 | llvm::json::Value toJSON(const CompletionItemLabelDetails &CD) { |
1124 | llvm::json::Object Result; |
1125 | if (!CD.detail.empty()) |
1126 | Result["detail"] = CD.detail; |
1127 | if (!CD.description.empty()) |
1128 | Result["description"] = CD.description; |
1129 | return Result; |
1130 | } |
1131 | |
1132 | void removeCompletionLabelDetails(CompletionItem &C) { |
1133 | if (!C.labelDetails) |
1134 | return; |
1135 | if (!C.labelDetails->detail.empty()) |
1136 | C.label += C.labelDetails->detail; |
1137 | if (!C.labelDetails->description.empty()) |
1138 | C.label = C.labelDetails->description + C.label; |
1139 | C.labelDetails.reset(); |
1140 | } |
1141 | |
1142 | llvm::json::Value toJSON(const CompletionItem &CI) { |
1143 | assert(!CI.label.empty() && "completion item label is required"); |
1144 | llvm::json::Object Result{{.K: "label", .V: CI.label}}; |
1145 | if (CI.kind != CompletionItemKind::Missing) |
1146 | Result["kind"] = static_cast<int>(CI.kind); |
1147 | if (!CI.detail.empty()) |
1148 | Result["detail"] = CI.detail; |
1149 | if (CI.labelDetails) |
1150 | Result["labelDetails"] = *CI.labelDetails; |
1151 | if (CI.documentation) |
1152 | Result["documentation"] = CI.documentation; |
1153 | if (!CI.sortText.empty()) |
1154 | Result["sortText"] = CI.sortText; |
1155 | if (!CI.filterText.empty()) |
1156 | Result["filterText"] = CI.filterText; |
1157 | if (!CI.insertText.empty()) |
1158 | Result["insertText"] = CI.insertText; |
1159 | if (CI.insertTextFormat != InsertTextFormat::Missing) |
1160 | Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat); |
1161 | if (CI.textEdit) |
1162 | Result["textEdit"] = *CI.textEdit; |
1163 | if (!CI.additionalTextEdits.empty()) |
1164 | Result["additionalTextEdits"] = llvm::json::Array(CI.additionalTextEdits); |
1165 | if (CI.deprecated) |
1166 | Result["deprecated"] = CI.deprecated; |
1167 | Result["score"] = CI.score; |
1168 | return std::move(Result); |
1169 | } |
1170 | |
1171 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) { |
1172 | O << I.label << " - "<< toJSON(CI: I); |
1173 | return O; |
1174 | } |
1175 | |
1176 | bool operator<(const CompletionItem &L, const CompletionItem &R) { |
1177 | return (L.sortText.empty() ? L.label : L.sortText) < |
1178 | (R.sortText.empty() ? R.label : R.sortText); |
1179 | } |
1180 | |
1181 | llvm::json::Value toJSON(const CompletionList &L) { |
1182 | return llvm::json::Object{ |
1183 | {.K: "isIncomplete", .V: L.isIncomplete}, |
1184 | {.K: "items", .V: llvm::json::Array(L.items)}, |
1185 | }; |
1186 | } |
1187 | |
1188 | llvm::json::Value toJSON(const ParameterInformation &PI) { |
1189 | assert((PI.labelOffsets || !PI.labelString.empty()) && |
1190 | "parameter information label is required"); |
1191 | llvm::json::Object Result; |
1192 | if (PI.labelOffsets) |
1193 | Result["label"] = |
1194 | llvm::json::Array({PI.labelOffsets->first, PI.labelOffsets->second}); |
1195 | else |
1196 | Result["label"] = PI.labelString; |
1197 | if (!PI.documentation.empty()) |
1198 | Result["documentation"] = PI.documentation; |
1199 | return std::move(Result); |
1200 | } |
1201 | |
1202 | llvm::json::Value toJSON(const SignatureInformation &SI) { |
1203 | assert(!SI.label.empty() && "signature information label is required"); |
1204 | llvm::json::Object Result{ |
1205 | {.K: "label", .V: SI.label}, |
1206 | {.K: "parameters", .V: llvm::json::Array(SI.parameters)}, |
1207 | }; |
1208 | if (!SI.documentation.value.empty()) |
1209 | Result["documentation"] = SI.documentation; |
1210 | return std::move(Result); |
1211 | } |
1212 | |
1213 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, |
1214 | const SignatureInformation &I) { |
1215 | O << I.label << " - "<< toJSON(SI: I); |
1216 | return O; |
1217 | } |
1218 | |
1219 | llvm::json::Value toJSON(const SignatureHelp &SH) { |
1220 | assert(SH.activeSignature >= 0 && |
1221 | "Unexpected negative value for number of active signatures."); |
1222 | assert(SH.activeParameter >= 0 && |
1223 | "Unexpected negative value for active parameter index"); |
1224 | return llvm::json::Object{ |
1225 | {.K: "activeSignature", .V: SH.activeSignature}, |
1226 | {.K: "activeParameter", .V: SH.activeParameter}, |
1227 | {.K: "signatures", .V: llvm::json::Array(SH.signatures)}, |
1228 | }; |
1229 | } |
1230 | |
1231 | bool fromJSON(const llvm::json::Value &Params, RenameParams &R, |
1232 | llvm::json::Path P) { |
1233 | llvm::json::ObjectMapper O(Params, P); |
1234 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && |
1235 | O.map(Prop: "position", Out&: R.position) && O.map(Prop: "newName", Out&: R.newName); |
1236 | } |
1237 | |
1238 | llvm::json::Value toJSON(const RenameParams &R) { |
1239 | return llvm::json::Object{ |
1240 | {.K: "textDocument", .V: R.textDocument}, |
1241 | {.K: "position", .V: R.position}, |
1242 | {.K: "newName", .V: R.newName}, |
1243 | }; |
1244 | } |
1245 | |
1246 | llvm::json::Value toJSON(const PrepareRenameResult &PRR) { |
1247 | if (PRR.placeholder.empty()) |
1248 | return toJSON(P: PRR.range); |
1249 | return llvm::json::Object{ |
1250 | {.K: "range", .V: toJSON(P: PRR.range)}, |
1251 | {.K: "placeholder", .V: PRR.placeholder}, |
1252 | }; |
1253 | } |
1254 | |
1255 | llvm::json::Value toJSON(const DocumentHighlight &DH) { |
1256 | return llvm::json::Object{ |
1257 | {.K: "range", .V: toJSON(P: DH.range)}, |
1258 | {.K: "kind", .V: static_cast<int>(DH.kind)}, |
1259 | }; |
1260 | } |
1261 | |
1262 | llvm::json::Value toJSON(const FileStatus &FStatus) { |
1263 | return llvm::json::Object{ |
1264 | {.K: "uri", .V: FStatus.uri}, |
1265 | {.K: "state", .V: FStatus.state}, |
1266 | }; |
1267 | } |
1268 | |
1269 | constexpr unsigned SemanticTokenEncodingSize = 5; |
1270 | static llvm::json::Value encodeTokens(llvm::ArrayRef<SemanticToken> Toks) { |
1271 | llvm::json::Array Result; |
1272 | Result.reserve(S: SemanticTokenEncodingSize * Toks.size()); |
1273 | for (const auto &Tok : Toks) { |
1274 | Result.push_back(E: Tok.deltaLine); |
1275 | Result.push_back(E: Tok.deltaStart); |
1276 | Result.push_back(E: Tok.length); |
1277 | Result.push_back(E: Tok.tokenType); |
1278 | Result.push_back(E: Tok.tokenModifiers); |
1279 | } |
1280 | assert(Result.size() == SemanticTokenEncodingSize * Toks.size()); |
1281 | return std::move(Result); |
1282 | } |
1283 | |
1284 | bool operator==(const SemanticToken &L, const SemanticToken &R) { |
1285 | return std::tie(args: L.deltaLine, args: L.deltaStart, args: L.length, args: L.tokenType, |
1286 | args: L.tokenModifiers) == std::tie(args: R.deltaLine, args: R.deltaStart, |
1287 | args: R.length, args: R.tokenType, |
1288 | args: R.tokenModifiers); |
1289 | } |
1290 | |
1291 | llvm::json::Value toJSON(const SemanticTokens &Tokens) { |
1292 | return llvm::json::Object{{.K: "resultId", .V: Tokens.resultId}, |
1293 | {.K: "data", .V: encodeTokens(Toks: Tokens.tokens)}}; |
1294 | } |
1295 | |
1296 | llvm::json::Value toJSON(const SemanticTokensEdit &Edit) { |
1297 | return llvm::json::Object{ |
1298 | {.K: "start", .V: SemanticTokenEncodingSize * Edit.startToken}, |
1299 | {.K: "deleteCount", .V: SemanticTokenEncodingSize * Edit.deleteTokens}, |
1300 | {.K: "data", .V: encodeTokens(Toks: Edit.tokens)}}; |
1301 | } |
1302 | |
1303 | llvm::json::Value toJSON(const SemanticTokensOrDelta &TE) { |
1304 | llvm::json::Object Result{{.K: "resultId", .V: TE.resultId}}; |
1305 | if (TE.edits) |
1306 | Result["edits"] = *TE.edits; |
1307 | if (TE.tokens) |
1308 | Result["data"] = encodeTokens(Toks: *TE.tokens); |
1309 | return std::move(Result); |
1310 | } |
1311 | |
1312 | bool fromJSON(const llvm::json::Value &Params, SemanticTokensParams &R, |
1313 | llvm::json::Path P) { |
1314 | llvm::json::ObjectMapper O(Params, P); |
1315 | return O && O.map(Prop: "textDocument", Out&: R.textDocument); |
1316 | } |
1317 | |
1318 | bool fromJSON(const llvm::json::Value &Params, SemanticTokensDeltaParams &R, |
1319 | llvm::json::Path P) { |
1320 | llvm::json::ObjectMapper O(Params, P); |
1321 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && |
1322 | O.map(Prop: "previousResultId", Out&: R.previousResultId); |
1323 | } |
1324 | |
1325 | llvm::json::Value toJSON(const InactiveRegionsParams &InactiveRegions) { |
1326 | return llvm::json::Object{ |
1327 | {.K: "textDocument", .V: InactiveRegions.TextDocument}, |
1328 | {.K: "regions", .V: std::move(InactiveRegions.InactiveRegions)}}; |
1329 | } |
1330 | |
1331 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, |
1332 | const DocumentHighlight &V) { |
1333 | O << V.range; |
1334 | if (V.kind == DocumentHighlightKind::Read) |
1335 | O << "(r)"; |
1336 | if (V.kind == DocumentHighlightKind::Write) |
1337 | O << "(w)"; |
1338 | return O; |
1339 | } |
1340 | |
1341 | bool fromJSON(const llvm::json::Value &Params, |
1342 | DidChangeConfigurationParams &CCP, llvm::json::Path P) { |
1343 | llvm::json::ObjectMapper O(Params, P); |
1344 | return O && O.map(Prop: "settings", Out&: CCP.settings); |
1345 | } |
1346 | |
1347 | bool fromJSON(const llvm::json::Value &Params, ClangdCompileCommand &CDbUpdate, |
1348 | llvm::json::Path P) { |
1349 | llvm::json::ObjectMapper O(Params, P); |
1350 | return O && O.map(Prop: "workingDirectory", Out&: CDbUpdate.workingDirectory) && |
1351 | O.map(Prop: "compilationCommand", Out&: CDbUpdate.compilationCommand); |
1352 | } |
1353 | |
1354 | bool fromJSON(const llvm::json::Value &Params, ConfigurationSettings &S, |
1355 | llvm::json::Path P) { |
1356 | llvm::json::ObjectMapper O(Params, P); |
1357 | if (!O) |
1358 | return true; // 'any' type in LSP. |
1359 | return mapOptOrNull(Params, Prop: "compilationDatabaseChanges", |
1360 | Out&: S.compilationDatabaseChanges, P); |
1361 | } |
1362 | |
1363 | bool fromJSON(const llvm::json::Value &Params, InitializationOptions &Opts, |
1364 | llvm::json::Path P) { |
1365 | llvm::json::ObjectMapper O(Params, P); |
1366 | if (!O) |
1367 | return true; // 'any' type in LSP. |
1368 | |
1369 | return fromJSON(Params, S&: Opts.ConfigSettings, P) && |
1370 | O.map(Prop: "compilationDatabasePath", Out&: Opts.compilationDatabasePath) && |
1371 | mapOptOrNull(Params, Prop: "fallbackFlags", Out&: Opts.fallbackFlags, P) && |
1372 | mapOptOrNull(Params, Prop: "clangdFileStatus", Out&: Opts.FileStatus, P); |
1373 | } |
1374 | |
1375 | bool fromJSON(const llvm::json::Value &E, TypeHierarchyDirection &Out, |
1376 | llvm::json::Path P) { |
1377 | auto T = E.getAsInteger(); |
1378 | if (!T) |
1379 | return false; |
1380 | if (*T < static_cast<int>(TypeHierarchyDirection::Children) || |
1381 | *T > static_cast<int>(TypeHierarchyDirection::Both)) |
1382 | return false; |
1383 | Out = static_cast<TypeHierarchyDirection>(*T); |
1384 | return true; |
1385 | } |
1386 | |
1387 | bool fromJSON(const llvm::json::Value &Params, TypeHierarchyPrepareParams &R, |
1388 | llvm::json::Path P) { |
1389 | llvm::json::ObjectMapper O(Params, P); |
1390 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && |
1391 | O.map(Prop: "position", Out&: R.position) && |
1392 | mapOptOrNull(Params, Prop: "resolve", Out&: R.resolve, P) && |
1393 | mapOptOrNull(Params, Prop: "direction", Out&: R.direction, P); |
1394 | } |
1395 | |
1396 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, |
1397 | const TypeHierarchyItem &I) { |
1398 | return O << I.name << " - "<< toJSON(I); |
1399 | } |
1400 | |
1401 | llvm::json::Value toJSON(const TypeHierarchyItem::ResolveParams &RP) { |
1402 | llvm::json::Object Result{{.K: "symbolID", .V: RP.symbolID}}; |
1403 | if (RP.parents) |
1404 | Result["parents"] = RP.parents; |
1405 | return std::move(Result); |
1406 | } |
1407 | bool fromJSON(const llvm::json::Value &Params, |
1408 | TypeHierarchyItem::ResolveParams &RP, llvm::json::Path P) { |
1409 | llvm::json::ObjectMapper O(Params, P); |
1410 | return O && O.map(Prop: "symbolID", Out&: RP.symbolID) && |
1411 | mapOptOrNull(Params, Prop: "parents", Out&: RP.parents, P); |
1412 | } |
1413 | |
1414 | llvm::json::Value toJSON(const TypeHierarchyItem &I) { |
1415 | llvm::json::Object Result{ |
1416 | {.K: "name", .V: I.name}, {.K: "kind", .V: static_cast<int>(I.kind)}, |
1417 | {.K: "range", .V: I.range}, {.K: "selectionRange", .V: I.selectionRange}, |
1418 | {.K: "uri", .V: I.uri}, {.K: "data", .V: I.data}, |
1419 | }; |
1420 | |
1421 | if (I.detail) |
1422 | Result["detail"] = I.detail; |
1423 | return std::move(Result); |
1424 | } |
1425 | |
1426 | bool fromJSON(const llvm::json::Value &Params, TypeHierarchyItem &I, |
1427 | llvm::json::Path P) { |
1428 | llvm::json::ObjectMapper O(Params, P); |
1429 | |
1430 | // Required fields. |
1431 | return O && O.map(Prop: "name", Out&: I.name) && O.map(Prop: "kind", Out&: I.kind) && |
1432 | O.map(Prop: "uri", Out&: I.uri) && O.map(Prop: "range", Out&: I.range) && |
1433 | O.map(Prop: "selectionRange", Out&: I.selectionRange) && |
1434 | mapOptOrNull(Params, Prop: "detail", Out&: I.detail, P) && |
1435 | mapOptOrNull(Params, Prop: "deprecated", Out&: I.deprecated, P) && |
1436 | mapOptOrNull(Params, Prop: "parents", Out&: I.parents, P) && |
1437 | mapOptOrNull(Params, Prop: "children", Out&: I.children, P) && |
1438 | mapOptOrNull(Params, Prop: "data", Out&: I.data, P); |
1439 | } |
1440 | |
1441 | bool fromJSON(const llvm::json::Value &Params, |
1442 | ResolveTypeHierarchyItemParams &R, llvm::json::Path P) { |
1443 | llvm::json::ObjectMapper O(Params, P); |
1444 | return O && O.map(Prop: "item", Out&: R.item) && |
1445 | mapOptOrNull(Params, Prop: "resolve", Out&: R.resolve, P) && |
1446 | mapOptOrNull(Params, Prop: "direction", Out&: R.direction, P); |
1447 | } |
1448 | |
1449 | bool fromJSON(const llvm::json::Value &Params, ReferenceContext &R, |
1450 | llvm::json::Path P) { |
1451 | llvm::json::ObjectMapper O(Params, P); |
1452 | return O && O.mapOptional(Prop: "includeDeclaration", Out&: R.includeDeclaration); |
1453 | } |
1454 | |
1455 | bool fromJSON(const llvm::json::Value &Params, ReferenceParams &R, |
1456 | llvm::json::Path P) { |
1457 | TextDocumentPositionParams &Base = R; |
1458 | llvm::json::ObjectMapper O(Params, P); |
1459 | return fromJSON(Params, R&: Base, P) && O && O.mapOptional(Prop: "context", Out&: R.context); |
1460 | } |
1461 | |
1462 | llvm::json::Value toJSON(SymbolTag Tag) { |
1463 | return llvm::json::Value(static_cast<int>(Tag)); |
1464 | } |
1465 | |
1466 | llvm::json::Value toJSON(const CallHierarchyItem &I) { |
1467 | llvm::json::Object Result{{.K: "name", .V: I.name}, |
1468 | {.K: "kind", .V: static_cast<int>(I.kind)}, |
1469 | {.K: "range", .V: I.range}, |
1470 | {.K: "selectionRange", .V: I.selectionRange}, |
1471 | {.K: "uri", .V: I.uri}}; |
1472 | if (!I.tags.empty()) |
1473 | Result["tags"] = I.tags; |
1474 | if (!I.detail.empty()) |
1475 | Result["detail"] = I.detail; |
1476 | if (!I.data.empty()) |
1477 | Result["data"] = I.data; |
1478 | return std::move(Result); |
1479 | } |
1480 | |
1481 | bool fromJSON(const llvm::json::Value &Params, CallHierarchyItem &I, |
1482 | llvm::json::Path P) { |
1483 | llvm::json::ObjectMapper O(Params, P); |
1484 | |
1485 | // Populate the required fields only. We don't care about the |
1486 | // optional fields `Tags` and `Detail` for the purpose of |
1487 | // client --> server communication. |
1488 | return O && O.map(Prop: "name", Out&: I.name) && O.map(Prop: "kind", Out&: I.kind) && |
1489 | O.map(Prop: "uri", Out&: I.uri) && O.map(Prop: "range", Out&: I.range) && |
1490 | O.map(Prop: "selectionRange", Out&: I.selectionRange) && |
1491 | mapOptOrNull(Params, Prop: "data", Out&: I.data, P); |
1492 | } |
1493 | |
1494 | bool fromJSON(const llvm::json::Value &Params, |
1495 | CallHierarchyIncomingCallsParams &C, llvm::json::Path P) { |
1496 | llvm::json::ObjectMapper O(Params, P); |
1497 | return O.map(Prop: "item", Out&: C.item); |
1498 | } |
1499 | |
1500 | llvm::json::Value toJSON(const CallHierarchyIncomingCall &C) { |
1501 | return llvm::json::Object{{.K: "from", .V: C.from}, {.K: "fromRanges", .V: C.fromRanges}}; |
1502 | } |
1503 | |
1504 | bool fromJSON(const llvm::json::Value &Params, |
1505 | CallHierarchyOutgoingCallsParams &C, llvm::json::Path P) { |
1506 | llvm::json::ObjectMapper O(Params, P); |
1507 | return O.map(Prop: "item", Out&: C.item); |
1508 | } |
1509 | |
1510 | llvm::json::Value toJSON(const CallHierarchyOutgoingCall &C) { |
1511 | return llvm::json::Object{{.K: "to", .V: C.to}, {.K: "fromRanges", .V: C.fromRanges}}; |
1512 | } |
1513 | |
1514 | bool fromJSON(const llvm::json::Value &Params, InlayHintsParams &R, |
1515 | llvm::json::Path P) { |
1516 | llvm::json::ObjectMapper O(Params, P); |
1517 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && O.map(Prop: "range", Out&: R.range); |
1518 | } |
1519 | |
1520 | llvm::json::Value toJSON(const InlayHintKind &Kind) { |
1521 | switch (Kind) { |
1522 | case InlayHintKind::Type: |
1523 | return 1; |
1524 | case InlayHintKind::Parameter: |
1525 | return 2; |
1526 | case InlayHintKind::Designator: |
1527 | case InlayHintKind::BlockEnd: |
1528 | case InlayHintKind::DefaultArgument: |
1529 | // This is an extension, don't serialize. |
1530 | return nullptr; |
1531 | } |
1532 | llvm_unreachable("Unknown clang.clangd.InlayHintKind"); |
1533 | } |
1534 | |
1535 | llvm::json::Value toJSON(const InlayHint &H) { |
1536 | llvm::json::Object Result{{.K: "position", .V: H.position}, |
1537 | {.K: "label", .V: H.label}, |
1538 | {.K: "paddingLeft", .V: H.paddingLeft}, |
1539 | {.K: "paddingRight", .V: H.paddingRight}}; |
1540 | auto K = toJSON(Kind: H.kind); |
1541 | if (!K.getAsNull()) |
1542 | Result["kind"] = std::move(K); |
1543 | return std::move(Result); |
1544 | } |
1545 | bool operator==(const InlayHint &A, const InlayHint &B) { |
1546 | return std::tie(args: A.position, args: A.range, args: A.kind, args: A.label) == |
1547 | std::tie(args: B.position, args: B.range, args: B.kind, args: B.label); |
1548 | } |
1549 | bool operator<(const InlayHint &A, const InlayHint &B) { |
1550 | return std::tie(args: A.position, args: A.range, args: A.kind, args: A.label) < |
1551 | std::tie(args: B.position, args: B.range, args: B.kind, args: B.label); |
1552 | } |
1553 | std::string InlayHint::joinLabels() const { |
1554 | return llvm::join(R: llvm::map_range(C: label, F: [](auto &L) { return L.value; }), |
1555 | Separator: ""); |
1556 | } |
1557 | |
1558 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) { |
1559 | auto ToString = [](InlayHintKind K) { |
1560 | switch (K) { |
1561 | case InlayHintKind::Parameter: |
1562 | return "parameter"; |
1563 | case InlayHintKind::Type: |
1564 | return "type"; |
1565 | case InlayHintKind::Designator: |
1566 | return "designator"; |
1567 | case InlayHintKind::BlockEnd: |
1568 | return "block-end"; |
1569 | case InlayHintKind::DefaultArgument: |
1570 | return "default-argument"; |
1571 | } |
1572 | llvm_unreachable("Unknown clang.clangd.InlayHintKind"); |
1573 | }; |
1574 | return OS << ToString(Kind); |
1575 | } |
1576 | |
1577 | llvm::json::Value toJSON(const InlayHintLabelPart &L) { |
1578 | llvm::json::Object Result{{.K: "value", .V: L.value}}; |
1579 | if (L.tooltip) |
1580 | Result["tooltip"] = *L.tooltip; |
1581 | if (L.location) |
1582 | Result["location"] = *L.location; |
1583 | if (L.command) |
1584 | Result["command"] = *L.command; |
1585 | return Result; |
1586 | } |
1587 | |
1588 | bool operator==(const InlayHintLabelPart &LHS, const InlayHintLabelPart &RHS) { |
1589 | return std::tie(args: LHS.value, args: LHS.location) == std::tie(args: RHS.value, args: RHS.location); |
1590 | } |
1591 | |
1592 | bool operator<(const InlayHintLabelPart &LHS, const InlayHintLabelPart &RHS) { |
1593 | return std::tie(args: LHS.value, args: LHS.location) < std::tie(args: RHS.value, args: RHS.location); |
1594 | } |
1595 | |
1596 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
1597 | const InlayHintLabelPart &L) { |
1598 | OS << L.value; |
1599 | if (L.location) |
1600 | OS << " ("<< L.location << ")"; |
1601 | return OS; |
1602 | } |
1603 | |
1604 | static const char *toString(OffsetEncoding OE) { |
1605 | switch (OE) { |
1606 | case OffsetEncoding::UTF8: |
1607 | return "utf-8"; |
1608 | case OffsetEncoding::UTF16: |
1609 | return "utf-16"; |
1610 | case OffsetEncoding::UTF32: |
1611 | return "utf-32"; |
1612 | case OffsetEncoding::UnsupportedEncoding: |
1613 | return "unknown"; |
1614 | } |
1615 | llvm_unreachable("Unknown clang.clangd.OffsetEncoding"); |
1616 | } |
1617 | llvm::json::Value toJSON(const OffsetEncoding &OE) { return toString(OE); } |
1618 | bool fromJSON(const llvm::json::Value &V, OffsetEncoding &OE, |
1619 | llvm::json::Path P) { |
1620 | auto Str = V.getAsString(); |
1621 | if (!Str) |
1622 | return false; |
1623 | OE = llvm::StringSwitch<OffsetEncoding>(*Str) |
1624 | .Case(S: "utf-8", Value: OffsetEncoding::UTF8) |
1625 | .Case(S: "utf-16", Value: OffsetEncoding::UTF16) |
1626 | .Case(S: "utf-32", Value: OffsetEncoding::UTF32) |
1627 | .Default(Value: OffsetEncoding::UnsupportedEncoding); |
1628 | return true; |
1629 | } |
1630 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OffsetEncoding Enc) { |
1631 | return OS << toString(OE: Enc); |
1632 | } |
1633 | |
1634 | bool fromJSON(const llvm::json::Value &Params, SelectionRangeParams &S, |
1635 | llvm::json::Path P) { |
1636 | llvm::json::ObjectMapper O(Params, P); |
1637 | return O && O.map(Prop: "textDocument", Out&: S.textDocument) && |
1638 | O.map(Prop: "positions", Out&: S.positions); |
1639 | } |
1640 | |
1641 | llvm::json::Value toJSON(const SelectionRange &Out) { |
1642 | if (Out.parent) { |
1643 | return llvm::json::Object{{.K: "range", .V: Out.range}, |
1644 | {.K: "parent", .V: toJSON(Out: *Out.parent)}}; |
1645 | } |
1646 | return llvm::json::Object{{.K: "range", .V: Out.range}}; |
1647 | } |
1648 | |
1649 | bool fromJSON(const llvm::json::Value &Params, DocumentLinkParams &R, |
1650 | llvm::json::Path P) { |
1651 | llvm::json::ObjectMapper O(Params, P); |
1652 | return O && O.map(Prop: "textDocument", Out&: R.textDocument); |
1653 | } |
1654 | |
1655 | llvm::json::Value toJSON(const DocumentLink &DocumentLink) { |
1656 | return llvm::json::Object{ |
1657 | {.K: "range", .V: DocumentLink.range}, |
1658 | {.K: "target", .V: DocumentLink.target}, |
1659 | }; |
1660 | } |
1661 | |
1662 | bool fromJSON(const llvm::json::Value &Params, FoldingRangeParams &R, |
1663 | llvm::json::Path P) { |
1664 | llvm::json::ObjectMapper O(Params, P); |
1665 | return O && O.map(Prop: "textDocument", Out&: R.textDocument); |
1666 | } |
1667 | |
1668 | const llvm::StringLiteral FoldingRange::REGION_KIND = "region"; |
1669 | const llvm::StringLiteral FoldingRange::COMMENT_KIND = "comment"; |
1670 | const llvm::StringLiteral FoldingRange::IMPORT_KIND = "import"; |
1671 | |
1672 | llvm::json::Value toJSON(const FoldingRange &Range) { |
1673 | llvm::json::Object Result{ |
1674 | {.K: "startLine", .V: Range.startLine}, |
1675 | {.K: "endLine", .V: Range.endLine}, |
1676 | }; |
1677 | if (Range.startCharacter) |
1678 | Result["startCharacter"] = Range.startCharacter; |
1679 | if (Range.endCharacter) |
1680 | Result["endCharacter"] = Range.endCharacter; |
1681 | if (!Range.kind.empty()) |
1682 | Result["kind"] = Range.kind; |
1683 | return Result; |
1684 | } |
1685 | |
1686 | llvm::json::Value toJSON(const MemoryTree &MT) { |
1687 | llvm::json::Object Out; |
1688 | int64_t Total = MT.self(); |
1689 | Out["_self"] = Total; |
1690 | for (const auto &Entry : MT.children()) { |
1691 | auto Child = toJSON(MT: Entry.getSecond()); |
1692 | Total += *Child.getAsObject()->getInteger(K: "_total"); |
1693 | Out[Entry.first] = std::move(Child); |
1694 | } |
1695 | Out["_total"] = Total; |
1696 | return Out; |
1697 | } |
1698 | |
1699 | bool fromJSON(const llvm::json::Value &Params, ASTParams &R, |
1700 | llvm::json::Path P) { |
1701 | llvm::json::ObjectMapper O(Params, P); |
1702 | return O && O.map(Prop: "textDocument", Out&: R.textDocument) && O.map(Prop: "range", Out&: R.range); |
1703 | } |
1704 | |
1705 | llvm::json::Value toJSON(const ASTNode &N) { |
1706 | llvm::json::Object Result{ |
1707 | {.K: "role", .V: N.role}, |
1708 | {.K: "kind", .V: N.kind}, |
1709 | }; |
1710 | if (!N.children.empty()) |
1711 | Result["children"] = N.children; |
1712 | if (!N.detail.empty()) |
1713 | Result["detail"] = N.detail; |
1714 | if (!N.arcana.empty()) |
1715 | Result["arcana"] = N.arcana; |
1716 | if (N.range) |
1717 | Result["range"] = *N.range; |
1718 | return Result; |
1719 | } |
1720 | |
1721 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const ASTNode &Root) { |
1722 | std::function<void(const ASTNode &, unsigned)> Print = [&](const ASTNode &N, |
1723 | unsigned Level) { |
1724 | OS.indent(NumSpaces: 2 * Level) << N.role << ": "<< N.kind; |
1725 | if (!N.detail.empty()) |
1726 | OS << " - "<< N.detail; |
1727 | OS << "\n"; |
1728 | for (const ASTNode &C : N.children) |
1729 | Print(C, Level + 1); |
1730 | }; |
1731 | Print(Root, 0); |
1732 | return OS; |
1733 | } |
1734 | |
1735 | bool fromJSON(const llvm::json::Value &E, SymbolID &S, llvm::json::Path P) { |
1736 | auto Str = E.getAsString(); |
1737 | if (!Str) { |
1738 | P.report(Message: "expected a string"); |
1739 | return false; |
1740 | } |
1741 | auto ID = SymbolID::fromStr(*Str); |
1742 | if (!ID) { |
1743 | elog(Fmt: "Malformed symbolid: {0}", Vals: ID.takeError()); |
1744 | P.report(Message: "malformed symbolid"); |
1745 | return false; |
1746 | } |
1747 | S = *ID; |
1748 | return true; |
1749 | } |
1750 | llvm::json::Value toJSON(const SymbolID &S) { return S.str(); } |
1751 | |
1752 | } // namespace clangd |
1753 | } // namespace clang |
1754 |
Definitions
- mapOptOrNull
- ID
- canonicalize
- fromURI
- fromJSON
- toJSON
- operator<<
- toJSON
- fromJSON
- toJSON
- fromJSON
- fromJSON
- toJSON
- operator<<
- fromJSON
- toJSON
- operator<<
- toJSON
- operator<<
- toJSON
- operator<<
- fromJSON
- fromJSON
- toJSON
- fromJSON
- toJSON
- fromJSON
- toJSON
- operator<<
- fromJSON
- fromJSON
- fromJSON
- adjustKindToCapability
- indexSymbolKindToSymbolKind
- fromJSON
- fromJSON
- toJSON
- toJSON
- toJSON
- toJSON
- toJSON
- toJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- toJSON
- toJSON
- toJSON
- toJSON
- fromJSON
- toJSON
- fromJSON
- operator<<
- fromJSON
- fromJSON
- fromJSON
- toJSON
- operator<<
- operator==
- toJSON
- operator<<
- fromJSON
- toJSON
- QUICKFIX_KIND
- REFACTOR_KIND
- INFO_KIND
- toJSON
- operator<<
- toJSON
- toJSON
- fromJSON
- toJSON
- toJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- toTextKind
- fromJSON
- operator<<
- toJSON
- toJSON
- fromJSON
- adjustKindToCapability
- fromJSON
- toJSON
- removeCompletionLabelDetails
- toJSON
- operator<<
- operator<
- toJSON
- toJSON
- toJSON
- operator<<
- toJSON
- fromJSON
- toJSON
- toJSON
- toJSON
- toJSON
- SemanticTokenEncodingSize
- encodeTokens
- operator==
- toJSON
- toJSON
- toJSON
- fromJSON
- fromJSON
- toJSON
- operator<<
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- operator<<
- toJSON
- fromJSON
- toJSON
- fromJSON
- fromJSON
- fromJSON
- fromJSON
- toJSON
- toJSON
- fromJSON
- fromJSON
- toJSON
- fromJSON
- toJSON
- fromJSON
- toJSON
- toJSON
- operator==
- operator<
- joinLabels
- operator<<
- toJSON
- operator==
- operator<
- operator<<
- toString
- toJSON
- fromJSON
- operator<<
- fromJSON
- toJSON
- fromJSON
- toJSON
- fromJSON
- REGION_KIND
- COMMENT_KIND
- IMPORT_KIND
- toJSON
- toJSON
- fromJSON
- toJSON
- operator<<
- fromJSON
Learn to use CMake with our Intro Training
Find out more