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 | bool fromJSON(const llvm::json::Value &Params, |
678 | DocumentOnTypeFormattingParams &R, llvm::json::Path P) { |
679 | llvm::json::ObjectMapper O(Params, P); |
680 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument) && |
681 | O.map(Prop: "position" , Out&: R.position) && O.map(Prop: "ch" , Out&: R.ch); |
682 | } |
683 | |
684 | bool fromJSON(const llvm::json::Value &Params, DocumentFormattingParams &R, |
685 | llvm::json::Path P) { |
686 | llvm::json::ObjectMapper O(Params, P); |
687 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument); |
688 | } |
689 | |
690 | bool fromJSON(const llvm::json::Value &Params, DocumentSymbolParams &R, |
691 | llvm::json::Path P) { |
692 | llvm::json::ObjectMapper O(Params, P); |
693 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument); |
694 | } |
695 | |
696 | llvm::json::Value toJSON(const DiagnosticRelatedInformation &DRI) { |
697 | return llvm::json::Object{ |
698 | {.K: "location" , .V: DRI.location}, |
699 | {.K: "message" , .V: DRI.message}, |
700 | }; |
701 | } |
702 | |
703 | llvm::json::Value toJSON(DiagnosticTag Tag) { return static_cast<int>(Tag); } |
704 | |
705 | llvm::json::Value toJSON(const CodeDescription &D) { |
706 | return llvm::json::Object{{.K: "href" , .V: D.href}}; |
707 | } |
708 | |
709 | llvm::json::Value toJSON(const Diagnostic &D) { |
710 | llvm::json::Object Diag{ |
711 | {.K: "range" , .V: D.range}, |
712 | {.K: "severity" , .V: D.severity}, |
713 | {.K: "message" , .V: D.message}, |
714 | }; |
715 | if (D.category) |
716 | Diag["category" ] = *D.category; |
717 | if (D.codeActions) |
718 | Diag["codeActions" ] = D.codeActions; |
719 | if (!D.code.empty()) |
720 | Diag["code" ] = D.code; |
721 | if (D.codeDescription) |
722 | Diag["codeDescription" ] = *D.codeDescription; |
723 | if (!D.source.empty()) |
724 | Diag["source" ] = D.source; |
725 | if (D.relatedInformation) |
726 | Diag["relatedInformation" ] = *D.relatedInformation; |
727 | if (!D.data.empty()) |
728 | Diag["data" ] = llvm::json::Object(D.data); |
729 | if (!D.tags.empty()) |
730 | Diag["tags" ] = llvm::json::Array{D.tags}; |
731 | // FIXME: workaround for older gcc/clang |
732 | return std::move(Diag); |
733 | } |
734 | |
735 | bool fromJSON(const llvm::json::Value &Params, Diagnostic &R, |
736 | llvm::json::Path P) { |
737 | llvm::json::ObjectMapper O(Params, P); |
738 | if (!O) |
739 | return false; |
740 | if (auto *Data = Params.getAsObject()->getObject(K: "data" )) |
741 | R.data = *Data; |
742 | return O.map(Prop: "range" , Out&: R.range) && O.map(Prop: "message" , Out&: R.message) && |
743 | mapOptOrNull(Params, Prop: "severity" , Out&: R.severity, P) && |
744 | mapOptOrNull(Params, Prop: "category" , Out&: R.category, P) && |
745 | mapOptOrNull(Params, Prop: "code" , Out&: R.code, P) && |
746 | mapOptOrNull(Params, Prop: "source" , Out&: R.source, P); |
747 | } |
748 | |
749 | llvm::json::Value toJSON(const PublishDiagnosticsParams &PDP) { |
750 | llvm::json::Object Result{ |
751 | {.K: "uri" , .V: PDP.uri}, |
752 | {.K: "diagnostics" , .V: PDP.diagnostics}, |
753 | }; |
754 | if (PDP.version) |
755 | Result["version" ] = PDP.version; |
756 | return std::move(Result); |
757 | } |
758 | |
759 | bool fromJSON(const llvm::json::Value &Params, CodeActionContext &R, |
760 | llvm::json::Path P) { |
761 | llvm::json::ObjectMapper O(Params, P); |
762 | if (!O || !O.map(Prop: "diagnostics" , Out&: R.diagnostics)) |
763 | return false; |
764 | O.map(Prop: "only" , Out&: R.only); |
765 | return true; |
766 | } |
767 | |
768 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) { |
769 | OS << D.range << " [" ; |
770 | switch (D.severity) { |
771 | case 1: |
772 | OS << "error" ; |
773 | break; |
774 | case 2: |
775 | OS << "warning" ; |
776 | break; |
777 | case 3: |
778 | OS << "note" ; |
779 | break; |
780 | case 4: |
781 | OS << "remark" ; |
782 | break; |
783 | default: |
784 | OS << "diagnostic" ; |
785 | break; |
786 | } |
787 | return OS << '(' << D.severity << "): " << D.message << "]" ; |
788 | } |
789 | |
790 | bool fromJSON(const llvm::json::Value &Params, CodeActionParams &R, |
791 | llvm::json::Path P) { |
792 | llvm::json::ObjectMapper O(Params, P); |
793 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument) && |
794 | O.map(Prop: "range" , Out&: R.range) && O.map(Prop: "context" , Out&: R.context); |
795 | } |
796 | |
797 | bool fromJSON(const llvm::json::Value &Params, WorkspaceEdit &R, |
798 | llvm::json::Path P) { |
799 | llvm::json::ObjectMapper O(Params, P); |
800 | return O && O.map(Prop: "changes" , Out&: R.changes) && |
801 | O.map(Prop: "documentChanges" , Out&: R.documentChanges) && |
802 | O.mapOptional(Prop: "changeAnnotations" , Out&: R.changeAnnotations); |
803 | } |
804 | |
805 | bool fromJSON(const llvm::json::Value &Params, ExecuteCommandParams &R, |
806 | llvm::json::Path P) { |
807 | llvm::json::ObjectMapper O(Params, P); |
808 | if (!O || !O.map(Prop: "command" , Out&: R.command)) |
809 | return false; |
810 | |
811 | const auto *Args = Params.getAsObject()->get(K: "arguments" ); |
812 | if (!Args) |
813 | return true; // Missing args is ok, argument is null. |
814 | const auto *ArgsArray = Args->getAsArray(); |
815 | if (!ArgsArray) { |
816 | P.field(Field: "arguments" ).report(Message: "expected array" ); |
817 | return false; |
818 | } |
819 | if (ArgsArray->size() > 1) { |
820 | P.field(Field: "arguments" ).report(Message: "Command should have 0 or 1 argument" ); |
821 | return false; |
822 | } |
823 | if (ArgsArray->size() == 1) { |
824 | R.argument = ArgsArray->front(); |
825 | } |
826 | return true; |
827 | } |
828 | |
829 | llvm::json::Value toJSON(const SymbolInformation &P) { |
830 | llvm::json::Object O{ |
831 | {.K: "name" , .V: P.name}, |
832 | {.K: "kind" , .V: static_cast<int>(P.kind)}, |
833 | {.K: "location" , .V: P.location}, |
834 | {.K: "containerName" , .V: P.containerName}, |
835 | }; |
836 | if (P.score) |
837 | O["score" ] = *P.score; |
838 | return std::move(O); |
839 | } |
840 | |
841 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, |
842 | const SymbolInformation &SI) { |
843 | O << SI.containerName << "::" << SI.name << " - " << toJSON(P: SI); |
844 | return O; |
845 | } |
846 | |
847 | bool operator==(const SymbolDetails &LHS, const SymbolDetails &RHS) { |
848 | return LHS.name == RHS.name && LHS.containerName == RHS.containerName && |
849 | LHS.USR == RHS.USR && LHS.ID == RHS.ID && |
850 | LHS.declarationRange == RHS.declarationRange && |
851 | LHS.definitionRange == RHS.definitionRange; |
852 | } |
853 | |
854 | llvm::json::Value toJSON(const SymbolDetails &P) { |
855 | llvm::json::Object Result{{.K: "name" , .V: llvm::json::Value(nullptr)}, |
856 | {.K: "containerName" , .V: llvm::json::Value(nullptr)}, |
857 | {.K: "usr" , .V: llvm::json::Value(nullptr)}, |
858 | {.K: "id" , .V: llvm::json::Value(nullptr)}}; |
859 | |
860 | if (!P.name.empty()) |
861 | Result["name" ] = P.name; |
862 | |
863 | if (!P.containerName.empty()) |
864 | Result["containerName" ] = P.containerName; |
865 | |
866 | if (!P.USR.empty()) |
867 | Result["usr" ] = P.USR; |
868 | |
869 | if (P.ID) |
870 | Result["id" ] = P.ID.str(); |
871 | |
872 | if (P.declarationRange) |
873 | Result["declarationRange" ] = *P.declarationRange; |
874 | |
875 | if (P.definitionRange) |
876 | Result["definitionRange" ] = *P.definitionRange; |
877 | |
878 | // FIXME: workaround for older gcc/clang |
879 | return std::move(Result); |
880 | } |
881 | |
882 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const SymbolDetails &S) { |
883 | if (!S.containerName.empty()) { |
884 | O << S.containerName; |
885 | llvm::StringRef ContNameRef; |
886 | if (!ContNameRef.ends_with(Suffix: "::" )) { |
887 | O << " " ; |
888 | } |
889 | } |
890 | O << S.name << " - " << toJSON(P: S); |
891 | return O; |
892 | } |
893 | |
894 | bool fromJSON(const llvm::json::Value &Params, WorkspaceSymbolParams &R, |
895 | llvm::json::Path P) { |
896 | llvm::json::ObjectMapper O(Params, P); |
897 | return O && O.map(Prop: "query" , Out&: R.query) && |
898 | mapOptOrNull(Params, Prop: "limit" , Out&: R.limit, P); |
899 | } |
900 | |
901 | llvm::json::Value toJSON(const Command &C) { |
902 | auto Cmd = llvm::json::Object{{.K: "title" , .V: C.title}, {.K: "command" , .V: C.command}}; |
903 | if (!C.argument.getAsNull()) |
904 | Cmd["arguments" ] = llvm::json::Array{C.argument}; |
905 | return std::move(Cmd); |
906 | } |
907 | |
908 | const llvm::StringLiteral CodeAction::QUICKFIX_KIND = "quickfix" ; |
909 | const llvm::StringLiteral CodeAction::REFACTOR_KIND = "refactor" ; |
910 | const llvm::StringLiteral CodeAction::INFO_KIND = "info" ; |
911 | |
912 | llvm::json::Value toJSON(const CodeAction &CA) { |
913 | auto CodeAction = llvm::json::Object{{.K: "title" , .V: CA.title}}; |
914 | if (CA.kind) |
915 | CodeAction["kind" ] = *CA.kind; |
916 | if (CA.diagnostics) |
917 | CodeAction["diagnostics" ] = llvm::json::Array(*CA.diagnostics); |
918 | if (CA.isPreferred) |
919 | CodeAction["isPreferred" ] = true; |
920 | if (CA.edit) |
921 | CodeAction["edit" ] = *CA.edit; |
922 | if (CA.command) |
923 | CodeAction["command" ] = *CA.command; |
924 | return std::move(CodeAction); |
925 | } |
926 | |
927 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const DocumentSymbol &S) { |
928 | return O << S.name << " - " << toJSON(S); |
929 | } |
930 | |
931 | llvm::json::Value toJSON(const DocumentSymbol &S) { |
932 | llvm::json::Object Result{{.K: "name" , .V: S.name}, |
933 | {.K: "kind" , .V: static_cast<int>(S.kind)}, |
934 | {.K: "range" , .V: S.range}, |
935 | {.K: "selectionRange" , .V: S.selectionRange}}; |
936 | |
937 | if (!S.detail.empty()) |
938 | Result["detail" ] = S.detail; |
939 | if (!S.children.empty()) |
940 | Result["children" ] = S.children; |
941 | if (S.deprecated) |
942 | Result["deprecated" ] = true; |
943 | // FIXME: workaround for older gcc/clang |
944 | return std::move(Result); |
945 | } |
946 | |
947 | llvm::json::Value toJSON(const WorkspaceEdit &WE) { |
948 | llvm::json::Object Result; |
949 | if (WE.changes) { |
950 | llvm::json::Object FileChanges; |
951 | for (auto &Change : *WE.changes) |
952 | FileChanges[Change.first] = llvm::json::Array(Change.second); |
953 | Result["changes" ] = std::move(FileChanges); |
954 | } |
955 | if (WE.documentChanges) |
956 | Result["documentChanges" ] = *WE.documentChanges; |
957 | if (!WE.changeAnnotations.empty()) { |
958 | llvm::json::Object ChangeAnnotations; |
959 | for (auto &Annotation : WE.changeAnnotations) |
960 | ChangeAnnotations[Annotation.first] = Annotation.second; |
961 | Result["changeAnnotations" ] = std::move(ChangeAnnotations); |
962 | } |
963 | return Result; |
964 | } |
965 | |
966 | bool fromJSON(const llvm::json::Value &Params, TweakArgs &A, |
967 | llvm::json::Path P) { |
968 | llvm::json::ObjectMapper O(Params, P); |
969 | return O && O.map(Prop: "file" , Out&: A.file) && O.map(Prop: "selection" , Out&: A.selection) && |
970 | O.map(Prop: "tweakID" , Out&: A.tweakID); |
971 | } |
972 | |
973 | llvm::json::Value toJSON(const TweakArgs &A) { |
974 | return llvm::json::Object{ |
975 | {.K: "tweakID" , .V: A.tweakID}, {.K: "selection" , .V: A.selection}, {.K: "file" , .V: A.file}}; |
976 | } |
977 | |
978 | llvm::json::Value toJSON(const ApplyWorkspaceEditParams &Params) { |
979 | return llvm::json::Object{{.K: "edit" , .V: Params.edit}}; |
980 | } |
981 | |
982 | bool fromJSON(const llvm::json::Value &Response, ApplyWorkspaceEditResponse &R, |
983 | llvm::json::Path P) { |
984 | llvm::json::ObjectMapper O(Response, P); |
985 | return O && O.map(Prop: "applied" , Out&: R.applied) && |
986 | O.map(Prop: "failureReason" , Out&: R.failureReason); |
987 | } |
988 | |
989 | bool fromJSON(const llvm::json::Value &Params, TextDocumentPositionParams &R, |
990 | llvm::json::Path P) { |
991 | llvm::json::ObjectMapper O(Params, P); |
992 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument) && |
993 | O.map(Prop: "position" , Out&: R.position); |
994 | } |
995 | |
996 | bool fromJSON(const llvm::json::Value &Params, CompletionContext &R, |
997 | llvm::json::Path P) { |
998 | llvm::json::ObjectMapper O(Params, P); |
999 | int TriggerKind; |
1000 | if (!O || !O.map(Prop: "triggerKind" , Out&: TriggerKind) || |
1001 | !mapOptOrNull(Params, Prop: "triggerCharacter" , Out&: R.triggerCharacter, P)) |
1002 | return false; |
1003 | R.triggerKind = static_cast<CompletionTriggerKind>(TriggerKind); |
1004 | return true; |
1005 | } |
1006 | |
1007 | bool fromJSON(const llvm::json::Value &Params, CompletionParams &R, |
1008 | llvm::json::Path P) { |
1009 | if (!fromJSON(Params, R&: static_cast<TextDocumentPositionParams &>(R), P) || |
1010 | !mapOptOrNull(Params, Prop: "limit" , Out&: R.limit, P)) |
1011 | return false; |
1012 | if (auto *Context = Params.getAsObject()->get(K: "context" )) |
1013 | return fromJSON(Params: *Context, R&: R.context, P: P.field(Field: "context" )); |
1014 | return true; |
1015 | } |
1016 | |
1017 | static llvm::StringRef toTextKind(MarkupKind Kind) { |
1018 | switch (Kind) { |
1019 | case MarkupKind::PlainText: |
1020 | return "plaintext" ; |
1021 | case MarkupKind::Markdown: |
1022 | return "markdown" ; |
1023 | } |
1024 | llvm_unreachable("Invalid MarkupKind" ); |
1025 | } |
1026 | |
1027 | bool fromJSON(const llvm::json::Value &V, MarkupKind &K, llvm::json::Path P) { |
1028 | auto Str = V.getAsString(); |
1029 | if (!Str) { |
1030 | P.report(Message: "expected string" ); |
1031 | return false; |
1032 | } |
1033 | if (*Str == "plaintext" ) |
1034 | K = MarkupKind::PlainText; |
1035 | else if (*Str == "markdown" ) |
1036 | K = MarkupKind::Markdown; |
1037 | else { |
1038 | P.report(Message: "unknown markup kind" ); |
1039 | return false; |
1040 | } |
1041 | return true; |
1042 | } |
1043 | |
1044 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind K) { |
1045 | return OS << toTextKind(Kind: K); |
1046 | } |
1047 | |
1048 | llvm::json::Value toJSON(const MarkupContent &MC) { |
1049 | if (MC.value.empty()) |
1050 | return nullptr; |
1051 | |
1052 | return llvm::json::Object{ |
1053 | {.K: "kind" , .V: toTextKind(Kind: MC.kind)}, |
1054 | {.K: "value" , .V: MC.value}, |
1055 | }; |
1056 | } |
1057 | |
1058 | llvm::json::Value toJSON(const Hover &H) { |
1059 | llvm::json::Object Result{{.K: "contents" , .V: toJSON(MC: H.contents)}}; |
1060 | |
1061 | if (H.range) |
1062 | Result["range" ] = toJSON(P: *H.range); |
1063 | |
1064 | return std::move(Result); |
1065 | } |
1066 | |
1067 | bool fromJSON(const llvm::json::Value &E, CompletionItemKind &Out, |
1068 | llvm::json::Path P) { |
1069 | if (auto T = E.getAsInteger()) { |
1070 | if (*T < static_cast<int>(CompletionItemKind::Text) || |
1071 | *T > static_cast<int>(CompletionItemKind::TypeParameter)) |
1072 | return false; |
1073 | Out = static_cast<CompletionItemKind>(*T); |
1074 | return true; |
1075 | } |
1076 | return false; |
1077 | } |
1078 | |
1079 | CompletionItemKind |
1080 | adjustKindToCapability(CompletionItemKind Kind, |
1081 | CompletionItemKindBitset &SupportedCompletionItemKinds) { |
1082 | auto KindVal = static_cast<size_t>(Kind); |
1083 | if (KindVal >= CompletionItemKindMin && |
1084 | KindVal <= SupportedCompletionItemKinds.size() && |
1085 | SupportedCompletionItemKinds[KindVal]) |
1086 | return Kind; |
1087 | |
1088 | switch (Kind) { |
1089 | // Provide some fall backs for common kinds that are close enough. |
1090 | case CompletionItemKind::Folder: |
1091 | return CompletionItemKind::File; |
1092 | case CompletionItemKind::EnumMember: |
1093 | return CompletionItemKind::Enum; |
1094 | case CompletionItemKind::Struct: |
1095 | return CompletionItemKind::Class; |
1096 | default: |
1097 | return CompletionItemKind::Text; |
1098 | } |
1099 | } |
1100 | |
1101 | bool fromJSON(const llvm::json::Value &E, CompletionItemKindBitset &Out, |
1102 | llvm::json::Path P) { |
1103 | if (auto *A = E.getAsArray()) { |
1104 | for (size_t I = 0; I < A->size(); ++I) { |
1105 | CompletionItemKind KindOut; |
1106 | if (fromJSON(E: (*A)[I], Out&: KindOut, P: P.index(Index: I))) |
1107 | Out.set(position: size_t(KindOut)); |
1108 | } |
1109 | return true; |
1110 | } |
1111 | return false; |
1112 | } |
1113 | |
1114 | llvm::json::Value toJSON(const CompletionItemLabelDetails &CD) { |
1115 | llvm::json::Object Result; |
1116 | if (!CD.detail.empty()) |
1117 | Result["detail" ] = CD.detail; |
1118 | if (!CD.description.empty()) |
1119 | Result["description" ] = CD.description; |
1120 | return Result; |
1121 | } |
1122 | |
1123 | void removeCompletionLabelDetails(CompletionItem &C) { |
1124 | if (!C.labelDetails) |
1125 | return; |
1126 | if (!C.labelDetails->detail.empty()) |
1127 | C.label += C.labelDetails->detail; |
1128 | if (!C.labelDetails->description.empty()) |
1129 | C.label = C.labelDetails->description + C.label; |
1130 | C.labelDetails.reset(); |
1131 | } |
1132 | |
1133 | llvm::json::Value toJSON(const CompletionItem &CI) { |
1134 | assert(!CI.label.empty() && "completion item label is required" ); |
1135 | llvm::json::Object Result{{.K: "label" , .V: CI.label}}; |
1136 | if (CI.kind != CompletionItemKind::Missing) |
1137 | Result["kind" ] = static_cast<int>(CI.kind); |
1138 | if (!CI.detail.empty()) |
1139 | Result["detail" ] = CI.detail; |
1140 | if (CI.labelDetails) |
1141 | Result["labelDetails" ] = *CI.labelDetails; |
1142 | if (CI.documentation) |
1143 | Result["documentation" ] = CI.documentation; |
1144 | if (!CI.sortText.empty()) |
1145 | Result["sortText" ] = CI.sortText; |
1146 | if (!CI.filterText.empty()) |
1147 | Result["filterText" ] = CI.filterText; |
1148 | if (!CI.insertText.empty()) |
1149 | Result["insertText" ] = CI.insertText; |
1150 | if (CI.insertTextFormat != InsertTextFormat::Missing) |
1151 | Result["insertTextFormat" ] = static_cast<int>(CI.insertTextFormat); |
1152 | if (CI.textEdit) |
1153 | Result["textEdit" ] = *CI.textEdit; |
1154 | if (!CI.additionalTextEdits.empty()) |
1155 | Result["additionalTextEdits" ] = llvm::json::Array(CI.additionalTextEdits); |
1156 | if (CI.deprecated) |
1157 | Result["deprecated" ] = CI.deprecated; |
1158 | Result["score" ] = CI.score; |
1159 | return std::move(Result); |
1160 | } |
1161 | |
1162 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const CompletionItem &I) { |
1163 | O << I.label << " - " << toJSON(CI: I); |
1164 | return O; |
1165 | } |
1166 | |
1167 | bool operator<(const CompletionItem &L, const CompletionItem &R) { |
1168 | return (L.sortText.empty() ? L.label : L.sortText) < |
1169 | (R.sortText.empty() ? R.label : R.sortText); |
1170 | } |
1171 | |
1172 | llvm::json::Value toJSON(const CompletionList &L) { |
1173 | return llvm::json::Object{ |
1174 | {.K: "isIncomplete" , .V: L.isIncomplete}, |
1175 | {.K: "items" , .V: llvm::json::Array(L.items)}, |
1176 | }; |
1177 | } |
1178 | |
1179 | llvm::json::Value toJSON(const ParameterInformation &PI) { |
1180 | assert((PI.labelOffsets || !PI.labelString.empty()) && |
1181 | "parameter information label is required" ); |
1182 | llvm::json::Object Result; |
1183 | if (PI.labelOffsets) |
1184 | Result["label" ] = |
1185 | llvm::json::Array({PI.labelOffsets->first, PI.labelOffsets->second}); |
1186 | else |
1187 | Result["label" ] = PI.labelString; |
1188 | if (!PI.documentation.empty()) |
1189 | Result["documentation" ] = PI.documentation; |
1190 | return std::move(Result); |
1191 | } |
1192 | |
1193 | llvm::json::Value toJSON(const SignatureInformation &SI) { |
1194 | assert(!SI.label.empty() && "signature information label is required" ); |
1195 | llvm::json::Object Result{ |
1196 | {.K: "label" , .V: SI.label}, |
1197 | {.K: "parameters" , .V: llvm::json::Array(SI.parameters)}, |
1198 | }; |
1199 | if (!SI.documentation.value.empty()) |
1200 | Result["documentation" ] = SI.documentation; |
1201 | return std::move(Result); |
1202 | } |
1203 | |
1204 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, |
1205 | const SignatureInformation &I) { |
1206 | O << I.label << " - " << toJSON(SI: I); |
1207 | return O; |
1208 | } |
1209 | |
1210 | llvm::json::Value toJSON(const SignatureHelp &SH) { |
1211 | assert(SH.activeSignature >= 0 && |
1212 | "Unexpected negative value for number of active signatures." ); |
1213 | assert(SH.activeParameter >= 0 && |
1214 | "Unexpected negative value for active parameter index" ); |
1215 | return llvm::json::Object{ |
1216 | {.K: "activeSignature" , .V: SH.activeSignature}, |
1217 | {.K: "activeParameter" , .V: SH.activeParameter}, |
1218 | {.K: "signatures" , .V: llvm::json::Array(SH.signatures)}, |
1219 | }; |
1220 | } |
1221 | |
1222 | bool fromJSON(const llvm::json::Value &Params, RenameParams &R, |
1223 | llvm::json::Path P) { |
1224 | llvm::json::ObjectMapper O(Params, P); |
1225 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument) && |
1226 | O.map(Prop: "position" , Out&: R.position) && O.map(Prop: "newName" , Out&: R.newName); |
1227 | } |
1228 | |
1229 | llvm::json::Value toJSON(const RenameParams &R) { |
1230 | return llvm::json::Object{ |
1231 | {.K: "textDocument" , .V: R.textDocument}, |
1232 | {.K: "position" , .V: R.position}, |
1233 | {.K: "newName" , .V: R.newName}, |
1234 | }; |
1235 | } |
1236 | |
1237 | llvm::json::Value toJSON(const PrepareRenameResult &PRR) { |
1238 | if (PRR.placeholder.empty()) |
1239 | return toJSON(P: PRR.range); |
1240 | return llvm::json::Object{ |
1241 | {.K: "range" , .V: toJSON(P: PRR.range)}, |
1242 | {.K: "placeholder" , .V: PRR.placeholder}, |
1243 | }; |
1244 | } |
1245 | |
1246 | llvm::json::Value toJSON(const DocumentHighlight &DH) { |
1247 | return llvm::json::Object{ |
1248 | {.K: "range" , .V: toJSON(P: DH.range)}, |
1249 | {.K: "kind" , .V: static_cast<int>(DH.kind)}, |
1250 | }; |
1251 | } |
1252 | |
1253 | llvm::json::Value toJSON(const FileStatus &FStatus) { |
1254 | return llvm::json::Object{ |
1255 | {.K: "uri" , .V: FStatus.uri}, |
1256 | {.K: "state" , .V: FStatus.state}, |
1257 | }; |
1258 | } |
1259 | |
1260 | constexpr unsigned SemanticTokenEncodingSize = 5; |
1261 | static llvm::json::Value encodeTokens(llvm::ArrayRef<SemanticToken> Toks) { |
1262 | llvm::json::Array Result; |
1263 | Result.reserve(S: SemanticTokenEncodingSize * Toks.size()); |
1264 | for (const auto &Tok : Toks) { |
1265 | Result.push_back(E: Tok.deltaLine); |
1266 | Result.push_back(E: Tok.deltaStart); |
1267 | Result.push_back(E: Tok.length); |
1268 | Result.push_back(E: Tok.tokenType); |
1269 | Result.push_back(E: Tok.tokenModifiers); |
1270 | } |
1271 | assert(Result.size() == SemanticTokenEncodingSize * Toks.size()); |
1272 | return std::move(Result); |
1273 | } |
1274 | |
1275 | bool operator==(const SemanticToken &L, const SemanticToken &R) { |
1276 | return std::tie(args: L.deltaLine, args: L.deltaStart, args: L.length, args: L.tokenType, |
1277 | args: L.tokenModifiers) == std::tie(args: R.deltaLine, args: R.deltaStart, |
1278 | args: R.length, args: R.tokenType, |
1279 | args: R.tokenModifiers); |
1280 | } |
1281 | |
1282 | llvm::json::Value toJSON(const SemanticTokens &Tokens) { |
1283 | return llvm::json::Object{{.K: "resultId" , .V: Tokens.resultId}, |
1284 | {.K: "data" , .V: encodeTokens(Toks: Tokens.tokens)}}; |
1285 | } |
1286 | |
1287 | llvm::json::Value toJSON(const SemanticTokensEdit &Edit) { |
1288 | return llvm::json::Object{ |
1289 | {.K: "start" , .V: SemanticTokenEncodingSize * Edit.startToken}, |
1290 | {.K: "deleteCount" , .V: SemanticTokenEncodingSize * Edit.deleteTokens}, |
1291 | {.K: "data" , .V: encodeTokens(Toks: Edit.tokens)}}; |
1292 | } |
1293 | |
1294 | llvm::json::Value toJSON(const SemanticTokensOrDelta &TE) { |
1295 | llvm::json::Object Result{{.K: "resultId" , .V: TE.resultId}}; |
1296 | if (TE.edits) |
1297 | Result["edits" ] = *TE.edits; |
1298 | if (TE.tokens) |
1299 | Result["data" ] = encodeTokens(Toks: *TE.tokens); |
1300 | return std::move(Result); |
1301 | } |
1302 | |
1303 | bool fromJSON(const llvm::json::Value &Params, SemanticTokensParams &R, |
1304 | llvm::json::Path P) { |
1305 | llvm::json::ObjectMapper O(Params, P); |
1306 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument); |
1307 | } |
1308 | |
1309 | bool fromJSON(const llvm::json::Value &Params, SemanticTokensDeltaParams &R, |
1310 | llvm::json::Path P) { |
1311 | llvm::json::ObjectMapper O(Params, P); |
1312 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument) && |
1313 | O.map(Prop: "previousResultId" , Out&: R.previousResultId); |
1314 | } |
1315 | |
1316 | llvm::json::Value toJSON(const InactiveRegionsParams &InactiveRegions) { |
1317 | return llvm::json::Object{ |
1318 | {.K: "textDocument" , .V: InactiveRegions.TextDocument}, |
1319 | {.K: "regions" , .V: std::move(InactiveRegions.InactiveRegions)}}; |
1320 | } |
1321 | |
1322 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, |
1323 | const DocumentHighlight &V) { |
1324 | O << V.range; |
1325 | if (V.kind == DocumentHighlightKind::Read) |
1326 | O << "(r)" ; |
1327 | if (V.kind == DocumentHighlightKind::Write) |
1328 | O << "(w)" ; |
1329 | return O; |
1330 | } |
1331 | |
1332 | bool fromJSON(const llvm::json::Value &Params, |
1333 | DidChangeConfigurationParams &CCP, llvm::json::Path P) { |
1334 | llvm::json::ObjectMapper O(Params, P); |
1335 | return O && O.map(Prop: "settings" , Out&: CCP.settings); |
1336 | } |
1337 | |
1338 | bool fromJSON(const llvm::json::Value &Params, ClangdCompileCommand &CDbUpdate, |
1339 | llvm::json::Path P) { |
1340 | llvm::json::ObjectMapper O(Params, P); |
1341 | return O && O.map(Prop: "workingDirectory" , Out&: CDbUpdate.workingDirectory) && |
1342 | O.map(Prop: "compilationCommand" , Out&: CDbUpdate.compilationCommand); |
1343 | } |
1344 | |
1345 | bool fromJSON(const llvm::json::Value &Params, ConfigurationSettings &S, |
1346 | llvm::json::Path P) { |
1347 | llvm::json::ObjectMapper O(Params, P); |
1348 | if (!O) |
1349 | return true; // 'any' type in LSP. |
1350 | return mapOptOrNull(Params, Prop: "compilationDatabaseChanges" , |
1351 | Out&: S.compilationDatabaseChanges, P); |
1352 | } |
1353 | |
1354 | bool fromJSON(const llvm::json::Value &Params, InitializationOptions &Opts, |
1355 | llvm::json::Path P) { |
1356 | llvm::json::ObjectMapper O(Params, P); |
1357 | if (!O) |
1358 | return true; // 'any' type in LSP. |
1359 | |
1360 | return fromJSON(Params, S&: Opts.ConfigSettings, P) && |
1361 | O.map(Prop: "compilationDatabasePath" , Out&: Opts.compilationDatabasePath) && |
1362 | mapOptOrNull(Params, Prop: "fallbackFlags" , Out&: Opts.fallbackFlags, P) && |
1363 | mapOptOrNull(Params, Prop: "clangdFileStatus" , Out&: Opts.FileStatus, P); |
1364 | } |
1365 | |
1366 | bool fromJSON(const llvm::json::Value &E, TypeHierarchyDirection &Out, |
1367 | llvm::json::Path P) { |
1368 | auto T = E.getAsInteger(); |
1369 | if (!T) |
1370 | return false; |
1371 | if (*T < static_cast<int>(TypeHierarchyDirection::Children) || |
1372 | *T > static_cast<int>(TypeHierarchyDirection::Both)) |
1373 | return false; |
1374 | Out = static_cast<TypeHierarchyDirection>(*T); |
1375 | return true; |
1376 | } |
1377 | |
1378 | bool fromJSON(const llvm::json::Value &Params, TypeHierarchyPrepareParams &R, |
1379 | llvm::json::Path P) { |
1380 | llvm::json::ObjectMapper O(Params, P); |
1381 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument) && |
1382 | O.map(Prop: "position" , Out&: R.position) && |
1383 | mapOptOrNull(Params, Prop: "resolve" , Out&: R.resolve, P) && |
1384 | mapOptOrNull(Params, Prop: "direction" , Out&: R.direction, P); |
1385 | } |
1386 | |
1387 | llvm::raw_ostream &operator<<(llvm::raw_ostream &O, |
1388 | const TypeHierarchyItem &I) { |
1389 | return O << I.name << " - " << toJSON(I); |
1390 | } |
1391 | |
1392 | llvm::json::Value toJSON(const TypeHierarchyItem::ResolveParams &RP) { |
1393 | llvm::json::Object Result{{.K: "symbolID" , .V: RP.symbolID}}; |
1394 | if (RP.parents) |
1395 | Result["parents" ] = RP.parents; |
1396 | return std::move(Result); |
1397 | } |
1398 | bool fromJSON(const llvm::json::Value &Params, |
1399 | TypeHierarchyItem::ResolveParams &RP, llvm::json::Path P) { |
1400 | llvm::json::ObjectMapper O(Params, P); |
1401 | return O && O.map(Prop: "symbolID" , Out&: RP.symbolID) && |
1402 | mapOptOrNull(Params, Prop: "parents" , Out&: RP.parents, P); |
1403 | } |
1404 | |
1405 | llvm::json::Value toJSON(const TypeHierarchyItem &I) { |
1406 | llvm::json::Object Result{ |
1407 | {.K: "name" , .V: I.name}, {.K: "kind" , .V: static_cast<int>(I.kind)}, |
1408 | {.K: "range" , .V: I.range}, {.K: "selectionRange" , .V: I.selectionRange}, |
1409 | {.K: "uri" , .V: I.uri}, {.K: "data" , .V: I.data}, |
1410 | }; |
1411 | |
1412 | if (I.detail) |
1413 | Result["detail" ] = I.detail; |
1414 | return std::move(Result); |
1415 | } |
1416 | |
1417 | bool fromJSON(const llvm::json::Value &Params, TypeHierarchyItem &I, |
1418 | llvm::json::Path P) { |
1419 | llvm::json::ObjectMapper O(Params, P); |
1420 | |
1421 | // Required fields. |
1422 | return O && O.map(Prop: "name" , Out&: I.name) && O.map(Prop: "kind" , Out&: I.kind) && |
1423 | O.map(Prop: "uri" , Out&: I.uri) && O.map(Prop: "range" , Out&: I.range) && |
1424 | O.map(Prop: "selectionRange" , Out&: I.selectionRange) && |
1425 | mapOptOrNull(Params, Prop: "detail" , Out&: I.detail, P) && |
1426 | mapOptOrNull(Params, Prop: "deprecated" , Out&: I.deprecated, P) && |
1427 | mapOptOrNull(Params, Prop: "parents" , Out&: I.parents, P) && |
1428 | mapOptOrNull(Params, Prop: "children" , Out&: I.children, P) && |
1429 | mapOptOrNull(Params, Prop: "data" , Out&: I.data, P); |
1430 | } |
1431 | |
1432 | bool fromJSON(const llvm::json::Value &Params, |
1433 | ResolveTypeHierarchyItemParams &R, llvm::json::Path P) { |
1434 | llvm::json::ObjectMapper O(Params, P); |
1435 | return O && O.map(Prop: "item" , Out&: R.item) && |
1436 | mapOptOrNull(Params, Prop: "resolve" , Out&: R.resolve, P) && |
1437 | mapOptOrNull(Params, Prop: "direction" , Out&: R.direction, P); |
1438 | } |
1439 | |
1440 | bool fromJSON(const llvm::json::Value &Params, ReferenceContext &R, |
1441 | llvm::json::Path P) { |
1442 | llvm::json::ObjectMapper O(Params, P); |
1443 | return O && O.mapOptional(Prop: "includeDeclaration" , Out&: R.includeDeclaration); |
1444 | } |
1445 | |
1446 | bool fromJSON(const llvm::json::Value &Params, ReferenceParams &R, |
1447 | llvm::json::Path P) { |
1448 | TextDocumentPositionParams &Base = R; |
1449 | llvm::json::ObjectMapper O(Params, P); |
1450 | return fromJSON(Params, R&: Base, P) && O && O.mapOptional(Prop: "context" , Out&: R.context); |
1451 | } |
1452 | |
1453 | llvm::json::Value toJSON(SymbolTag Tag) { |
1454 | return llvm::json::Value(static_cast<int>(Tag)); |
1455 | } |
1456 | |
1457 | llvm::json::Value toJSON(const CallHierarchyItem &I) { |
1458 | llvm::json::Object Result{{.K: "name" , .V: I.name}, |
1459 | {.K: "kind" , .V: static_cast<int>(I.kind)}, |
1460 | {.K: "range" , .V: I.range}, |
1461 | {.K: "selectionRange" , .V: I.selectionRange}, |
1462 | {.K: "uri" , .V: I.uri}}; |
1463 | if (!I.tags.empty()) |
1464 | Result["tags" ] = I.tags; |
1465 | if (!I.detail.empty()) |
1466 | Result["detail" ] = I.detail; |
1467 | if (!I.data.empty()) |
1468 | Result["data" ] = I.data; |
1469 | return std::move(Result); |
1470 | } |
1471 | |
1472 | bool fromJSON(const llvm::json::Value &Params, CallHierarchyItem &I, |
1473 | llvm::json::Path P) { |
1474 | llvm::json::ObjectMapper O(Params, P); |
1475 | |
1476 | // Populate the required fields only. We don't care about the |
1477 | // optional fields `Tags` and `Detail` for the purpose of |
1478 | // client --> server communication. |
1479 | return O && O.map(Prop: "name" , Out&: I.name) && O.map(Prop: "kind" , Out&: I.kind) && |
1480 | O.map(Prop: "uri" , Out&: I.uri) && O.map(Prop: "range" , Out&: I.range) && |
1481 | O.map(Prop: "selectionRange" , Out&: I.selectionRange) && |
1482 | mapOptOrNull(Params, Prop: "data" , Out&: I.data, P); |
1483 | } |
1484 | |
1485 | bool fromJSON(const llvm::json::Value &Params, |
1486 | CallHierarchyIncomingCallsParams &C, llvm::json::Path P) { |
1487 | llvm::json::ObjectMapper O(Params, P); |
1488 | return O.map(Prop: "item" , Out&: C.item); |
1489 | } |
1490 | |
1491 | llvm::json::Value toJSON(const CallHierarchyIncomingCall &C) { |
1492 | return llvm::json::Object{{.K: "from" , .V: C.from}, {.K: "fromRanges" , .V: C.fromRanges}}; |
1493 | } |
1494 | |
1495 | bool fromJSON(const llvm::json::Value &Params, |
1496 | CallHierarchyOutgoingCallsParams &C, llvm::json::Path P) { |
1497 | llvm::json::ObjectMapper O(Params, P); |
1498 | return O.map(Prop: "item" , Out&: C.item); |
1499 | } |
1500 | |
1501 | llvm::json::Value toJSON(const CallHierarchyOutgoingCall &C) { |
1502 | return llvm::json::Object{{.K: "to" , .V: C.to}, {.K: "fromRanges" , .V: C.fromRanges}}; |
1503 | } |
1504 | |
1505 | bool fromJSON(const llvm::json::Value &Params, InlayHintsParams &R, |
1506 | llvm::json::Path P) { |
1507 | llvm::json::ObjectMapper O(Params, P); |
1508 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument) && O.map(Prop: "range" , Out&: R.range); |
1509 | } |
1510 | |
1511 | llvm::json::Value toJSON(const InlayHintKind &Kind) { |
1512 | switch (Kind) { |
1513 | case InlayHintKind::Type: |
1514 | return 1; |
1515 | case InlayHintKind::Parameter: |
1516 | return 2; |
1517 | case InlayHintKind::Designator: |
1518 | case InlayHintKind::BlockEnd: |
1519 | case InlayHintKind::DefaultArgument: |
1520 | // This is an extension, don't serialize. |
1521 | return nullptr; |
1522 | } |
1523 | llvm_unreachable("Unknown clang.clangd.InlayHintKind" ); |
1524 | } |
1525 | |
1526 | llvm::json::Value toJSON(const InlayHint &H) { |
1527 | llvm::json::Object Result{{.K: "position" , .V: H.position}, |
1528 | {.K: "label" , .V: H.label}, |
1529 | {.K: "paddingLeft" , .V: H.paddingLeft}, |
1530 | {.K: "paddingRight" , .V: H.paddingRight}}; |
1531 | auto K = toJSON(Kind: H.kind); |
1532 | if (!K.getAsNull()) |
1533 | Result["kind" ] = std::move(K); |
1534 | return std::move(Result); |
1535 | } |
1536 | bool operator==(const InlayHint &A, const InlayHint &B) { |
1537 | return std::tie(args: A.position, args: A.range, args: A.kind, args: A.label) == |
1538 | std::tie(args: B.position, args: B.range, args: B.kind, args: B.label); |
1539 | } |
1540 | bool operator<(const InlayHint &A, const InlayHint &B) { |
1541 | return std::tie(args: A.position, args: A.range, args: A.kind, args: A.label) < |
1542 | std::tie(args: B.position, args: B.range, args: B.kind, args: B.label); |
1543 | } |
1544 | std::string InlayHint::joinLabels() const { |
1545 | return llvm::join(R: llvm::map_range(C: label, F: [](auto &L) { return L.value; }), |
1546 | Separator: "" ); |
1547 | } |
1548 | |
1549 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) { |
1550 | auto ToString = [](InlayHintKind K) { |
1551 | switch (K) { |
1552 | case InlayHintKind::Parameter: |
1553 | return "parameter" ; |
1554 | case InlayHintKind::Type: |
1555 | return "type" ; |
1556 | case InlayHintKind::Designator: |
1557 | return "designator" ; |
1558 | case InlayHintKind::BlockEnd: |
1559 | return "block-end" ; |
1560 | case InlayHintKind::DefaultArgument: |
1561 | return "default-argument" ; |
1562 | } |
1563 | llvm_unreachable("Unknown clang.clangd.InlayHintKind" ); |
1564 | }; |
1565 | return OS << ToString(Kind); |
1566 | } |
1567 | |
1568 | llvm::json::Value toJSON(const InlayHintLabelPart &L) { |
1569 | llvm::json::Object Result{{.K: "value" , .V: L.value}}; |
1570 | if (L.tooltip) |
1571 | Result["tooltip" ] = *L.tooltip; |
1572 | if (L.location) |
1573 | Result["location" ] = *L.location; |
1574 | if (L.command) |
1575 | Result["command" ] = *L.command; |
1576 | return Result; |
1577 | } |
1578 | |
1579 | bool operator==(const InlayHintLabelPart &LHS, const InlayHintLabelPart &RHS) { |
1580 | return std::tie(args: LHS.value, args: LHS.location) == std::tie(args: RHS.value, args: RHS.location); |
1581 | } |
1582 | |
1583 | bool operator<(const InlayHintLabelPart &LHS, const InlayHintLabelPart &RHS) { |
1584 | return std::tie(args: LHS.value, args: LHS.location) < std::tie(args: RHS.value, args: RHS.location); |
1585 | } |
1586 | |
1587 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, |
1588 | const InlayHintLabelPart &L) { |
1589 | OS << L.value; |
1590 | if (L.location) |
1591 | OS << " (" << L.location << ")" ; |
1592 | return OS; |
1593 | } |
1594 | |
1595 | static const char *toString(OffsetEncoding OE) { |
1596 | switch (OE) { |
1597 | case OffsetEncoding::UTF8: |
1598 | return "utf-8" ; |
1599 | case OffsetEncoding::UTF16: |
1600 | return "utf-16" ; |
1601 | case OffsetEncoding::UTF32: |
1602 | return "utf-32" ; |
1603 | case OffsetEncoding::UnsupportedEncoding: |
1604 | return "unknown" ; |
1605 | } |
1606 | llvm_unreachable("Unknown clang.clangd.OffsetEncoding" ); |
1607 | } |
1608 | llvm::json::Value toJSON(const OffsetEncoding &OE) { return toString(OE); } |
1609 | bool fromJSON(const llvm::json::Value &V, OffsetEncoding &OE, |
1610 | llvm::json::Path P) { |
1611 | auto Str = V.getAsString(); |
1612 | if (!Str) |
1613 | return false; |
1614 | OE = llvm::StringSwitch<OffsetEncoding>(*Str) |
1615 | .Case(S: "utf-8" , Value: OffsetEncoding::UTF8) |
1616 | .Case(S: "utf-16" , Value: OffsetEncoding::UTF16) |
1617 | .Case(S: "utf-32" , Value: OffsetEncoding::UTF32) |
1618 | .Default(Value: OffsetEncoding::UnsupportedEncoding); |
1619 | return true; |
1620 | } |
1621 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, OffsetEncoding Enc) { |
1622 | return OS << toString(OE: Enc); |
1623 | } |
1624 | |
1625 | bool fromJSON(const llvm::json::Value &Params, SelectionRangeParams &S, |
1626 | llvm::json::Path P) { |
1627 | llvm::json::ObjectMapper O(Params, P); |
1628 | return O && O.map(Prop: "textDocument" , Out&: S.textDocument) && |
1629 | O.map(Prop: "positions" , Out&: S.positions); |
1630 | } |
1631 | |
1632 | llvm::json::Value toJSON(const SelectionRange &Out) { |
1633 | if (Out.parent) { |
1634 | return llvm::json::Object{{.K: "range" , .V: Out.range}, |
1635 | {.K: "parent" , .V: toJSON(Out: *Out.parent)}}; |
1636 | } |
1637 | return llvm::json::Object{{.K: "range" , .V: Out.range}}; |
1638 | } |
1639 | |
1640 | bool fromJSON(const llvm::json::Value &Params, DocumentLinkParams &R, |
1641 | llvm::json::Path P) { |
1642 | llvm::json::ObjectMapper O(Params, P); |
1643 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument); |
1644 | } |
1645 | |
1646 | llvm::json::Value toJSON(const DocumentLink &DocumentLink) { |
1647 | return llvm::json::Object{ |
1648 | {.K: "range" , .V: DocumentLink.range}, |
1649 | {.K: "target" , .V: DocumentLink.target}, |
1650 | }; |
1651 | } |
1652 | |
1653 | bool fromJSON(const llvm::json::Value &Params, FoldingRangeParams &R, |
1654 | llvm::json::Path P) { |
1655 | llvm::json::ObjectMapper O(Params, P); |
1656 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument); |
1657 | } |
1658 | |
1659 | const llvm::StringLiteral FoldingRange::REGION_KIND = "region" ; |
1660 | const llvm::StringLiteral FoldingRange:: = "comment" ; |
1661 | const llvm::StringLiteral FoldingRange::IMPORT_KIND = "import" ; |
1662 | |
1663 | llvm::json::Value toJSON(const FoldingRange &Range) { |
1664 | llvm::json::Object Result{ |
1665 | {.K: "startLine" , .V: Range.startLine}, |
1666 | {.K: "endLine" , .V: Range.endLine}, |
1667 | }; |
1668 | if (Range.startCharacter) |
1669 | Result["startCharacter" ] = Range.startCharacter; |
1670 | if (Range.endCharacter) |
1671 | Result["endCharacter" ] = Range.endCharacter; |
1672 | if (!Range.kind.empty()) |
1673 | Result["kind" ] = Range.kind; |
1674 | return Result; |
1675 | } |
1676 | |
1677 | llvm::json::Value toJSON(const MemoryTree &MT) { |
1678 | llvm::json::Object Out; |
1679 | int64_t Total = MT.self(); |
1680 | Out["_self" ] = Total; |
1681 | for (const auto &Entry : MT.children()) { |
1682 | auto Child = toJSON(MT: Entry.getSecond()); |
1683 | Total += *Child.getAsObject()->getInteger(K: "_total" ); |
1684 | Out[Entry.first] = std::move(Child); |
1685 | } |
1686 | Out["_total" ] = Total; |
1687 | return Out; |
1688 | } |
1689 | |
1690 | bool fromJSON(const llvm::json::Value &Params, ASTParams &R, |
1691 | llvm::json::Path P) { |
1692 | llvm::json::ObjectMapper O(Params, P); |
1693 | return O && O.map(Prop: "textDocument" , Out&: R.textDocument) && O.map(Prop: "range" , Out&: R.range); |
1694 | } |
1695 | |
1696 | llvm::json::Value toJSON(const ASTNode &N) { |
1697 | llvm::json::Object Result{ |
1698 | {.K: "role" , .V: N.role}, |
1699 | {.K: "kind" , .V: N.kind}, |
1700 | }; |
1701 | if (!N.children.empty()) |
1702 | Result["children" ] = N.children; |
1703 | if (!N.detail.empty()) |
1704 | Result["detail" ] = N.detail; |
1705 | if (!N.arcana.empty()) |
1706 | Result["arcana" ] = N.arcana; |
1707 | if (N.range) |
1708 | Result["range" ] = *N.range; |
1709 | return Result; |
1710 | } |
1711 | |
1712 | llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const ASTNode &Root) { |
1713 | std::function<void(const ASTNode &, unsigned)> Print = [&](const ASTNode &N, |
1714 | unsigned Level) { |
1715 | OS.indent(NumSpaces: 2 * Level) << N.role << ": " << N.kind; |
1716 | if (!N.detail.empty()) |
1717 | OS << " - " << N.detail; |
1718 | OS << "\n" ; |
1719 | for (const ASTNode &C : N.children) |
1720 | Print(C, Level + 1); |
1721 | }; |
1722 | Print(Root, 0); |
1723 | return OS; |
1724 | } |
1725 | |
1726 | bool fromJSON(const llvm::json::Value &E, SymbolID &S, llvm::json::Path P) { |
1727 | auto Str = E.getAsString(); |
1728 | if (!Str) { |
1729 | P.report(Message: "expected a string" ); |
1730 | return false; |
1731 | } |
1732 | auto ID = SymbolID::fromStr(*Str); |
1733 | if (!ID) { |
1734 | elog(Fmt: "Malformed symbolid: {0}" , Vals: ID.takeError()); |
1735 | P.report(Message: "malformed symbolid" ); |
1736 | return false; |
1737 | } |
1738 | S = *ID; |
1739 | return true; |
1740 | } |
1741 | llvm::json::Value toJSON(const SymbolID &S) { return S.str(); } |
1742 | |
1743 | } // namespace clangd |
1744 | } // namespace clang |
1745 | |