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