blob: a55b50f0c549f5aa56df39e1c724b6fc81ed445f [file] [log] [blame]
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +00001//===--- Protocol.cpp - Language Server Protocol Implementation -----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains the serialization code for the LSP structs.
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000011//
12//===----------------------------------------------------------------------===//
13
14#include "Protocol.h"
Eric Liu78ed91a72018-01-29 15:37:46 +000015#include "URI.h"
16#include "Logger.h"
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000017#include "clang/Basic/LLVM.h"
18#include "llvm/ADT/SmallString.h"
19#include "llvm/Support/Format.h"
Marc-Andre Laperle85dcce42017-09-18 15:02:59 +000020#include "llvm/Support/FormatVariadic.h"
Krasimir Georgiev50117372017-04-07 11:03:26 +000021#include "llvm/Support/Path.h"
Ilya Biryukov574b7532017-08-02 09:08:39 +000022#include "llvm/Support/raw_ostream.h"
Ilya Biryukove5128f72017-09-20 07:24:15 +000023
Sam McCallff8b8742017-11-30 21:32:29 +000024namespace clang {
25namespace clangd {
Sam McCall38a04912017-11-29 11:36:46 +000026
Eric Liu78ed91a72018-01-29 15:37:46 +000027bool fromJSON(const json::Expr &E, URIForFile &R) {
Sam McCallff8b8742017-11-30 21:32:29 +000028 if (auto S = E.asString()) {
Eric Liu78ed91a72018-01-29 15:37:46 +000029 auto U = URI::parse(*S);
30 if (!U) {
Sam McCalld1a7a372018-01-31 13:40:48 +000031 log("Failed to parse URI " + *S + ": " + llvm::toString(U.takeError()));
Eric Liu78ed91a72018-01-29 15:37:46 +000032 return false;
33 }
Eric Liu5740ff52018-01-31 16:26:27 +000034 if (U->scheme() != "file" && U->scheme() != "test") {
Sam McCalld1a7a372018-01-31 13:40:48 +000035 log("Clangd only supports 'file' URI scheme for workspace files: " + *S);
Eric Liu78ed91a72018-01-29 15:37:46 +000036 return false;
37 }
Sam McCall41d21522018-01-30 11:23:11 +000038 auto Path = URI::resolve(*U);
39 if (!Path) {
Sam McCalld1a7a372018-01-31 13:40:48 +000040 log(llvm::toString(Path.takeError()));
Sam McCall41d21522018-01-30 11:23:11 +000041 return false;
42 }
43 R.file = *Path;
Sam McCallff8b8742017-11-30 21:32:29 +000044 return true;
45 }
46 return false;
Sam McCall38a04912017-11-29 11:36:46 +000047}
48
Eric Liu78ed91a72018-01-29 15:37:46 +000049json::Expr toJSON(const URIForFile &U) {
50 return U.uri();
51}
Krasimir Georgiev50117372017-04-07 11:03:26 +000052
Eric Liu78ed91a72018-01-29 15:37:46 +000053llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const URIForFile &U) {
54 return OS << U.uri();
Sam McCallfffa8222017-12-20 10:26:53 +000055}
56
Sam McCallff8b8742017-11-30 21:32:29 +000057bool fromJSON(const json::Expr &Params, TextDocumentIdentifier &R) {
58 json::ObjectMapper O(Params);
59 return O && O.map("uri", R.uri);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000060}
61
Sam McCallff8b8742017-11-30 21:32:29 +000062bool fromJSON(const json::Expr &Params, Position &R) {
63 json::ObjectMapper O(Params);
64 return O && O.map("line", R.line) && O.map("character", R.character);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000065}
66
Sam McCallff8b8742017-11-30 21:32:29 +000067json::Expr toJSON(const Position &P) {
Sam McCalldd0566b2017-11-06 15:40:30 +000068 return json::obj{
69 {"line", P.line},
70 {"character", P.character},
71 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000072}
73
Sam McCallfffa8222017-12-20 10:26:53 +000074llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Position &P) {
75 return OS << P.line << ':' << P.character;
76}
77
Sam McCallff8b8742017-11-30 21:32:29 +000078bool fromJSON(const json::Expr &Params, Range &R) {
79 json::ObjectMapper O(Params);
80 return O && O.map("start", R.start) && O.map("end", R.end);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000081}
82
Sam McCallff8b8742017-11-30 21:32:29 +000083json::Expr toJSON(const Range &P) {
Sam McCalldd0566b2017-11-06 15:40:30 +000084 return json::obj{
85 {"start", P.start},
86 {"end", P.end},
87 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000088}
89
Sam McCallfffa8222017-12-20 10:26:53 +000090llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Range &R) {
91 return OS << R.start << '-' << R.end;
92}
93
Sam McCallff8b8742017-11-30 21:32:29 +000094json::Expr toJSON(const Location &P) {
Sam McCalldd0566b2017-11-06 15:40:30 +000095 return json::obj{
96 {"uri", P.uri},
97 {"range", P.range},
98 };
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +000099}
100
Sam McCallfffa8222017-12-20 10:26:53 +0000101llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Location &L) {
102 return OS << L.range << '@' << L.uri;
103}
104
Sam McCallff8b8742017-11-30 21:32:29 +0000105bool fromJSON(const json::Expr &Params, TextDocumentItem &R) {
106 json::ObjectMapper O(Params);
107 return O && O.map("uri", R.uri) && O.map("languageId", R.languageId) &&
108 O.map("version", R.version) && O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000109}
110
Sam McCallff8b8742017-11-30 21:32:29 +0000111bool fromJSON(const json::Expr &Params, Metadata &R) {
112 json::ObjectMapper O(Params);
Sam McCallec109022017-11-28 09:37:43 +0000113 if (!O)
Sam McCallff8b8742017-11-30 21:32:29 +0000114 return false;
115 O.map("extraFlags", R.extraFlags);
116 return true;
Krasimir Georgievc2a16a32017-07-06 08:44:54 +0000117}
118
Sam McCallff8b8742017-11-30 21:32:29 +0000119bool fromJSON(const json::Expr &Params, TextEdit &R) {
120 json::ObjectMapper O(Params);
121 return O && O.map("range", R.range) && O.map("newText", R.newText);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000122}
123
Sam McCallff8b8742017-11-30 21:32:29 +0000124json::Expr toJSON(const TextEdit &P) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000125 return json::obj{
126 {"range", P.range},
127 {"newText", P.newText},
128 };
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000129}
130
Sam McCall034e11a2018-01-25 17:29:17 +0000131llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const TextEdit &TE) {
132 OS << TE.range << " => \"";
133 PrintEscapedString(TE.newText, OS);
134 return OS << '"';
135}
136
Sam McCallff8b8742017-11-30 21:32:29 +0000137bool fromJSON(const json::Expr &E, TraceLevel &Out) {
138 if (auto S = E.asString()) {
139 if (*S == "off") {
140 Out = TraceLevel::Off;
141 return true;
142 } else if (*S == "messages") {
143 Out = TraceLevel::Messages;
144 return true;
145 } else if (*S == "verbose") {
146 Out = TraceLevel::Verbose;
147 return true;
148 }
149 }
150 return false;
151}
152
153bool fromJSON(const json::Expr &Params, InitializeParams &R) {
154 json::ObjectMapper O(Params);
Sam McCallec109022017-11-28 09:37:43 +0000155 if (!O)
Sam McCallff8b8742017-11-30 21:32:29 +0000156 return false;
Sam McCall38a04912017-11-29 11:36:46 +0000157 // We deliberately don't fail if we can't parse individual fields.
158 // Failing to handle a slightly malformed initialize would be a disaster.
Sam McCallff8b8742017-11-30 21:32:29 +0000159 O.map("processId", R.processId);
160 O.map("rootUri", R.rootUri);
161 O.map("rootPath", R.rootPath);
162 O.map("trace", R.trace);
Sam McCallec109022017-11-28 09:37:43 +0000163 // initializationOptions, capabilities unused
Sam McCallff8b8742017-11-30 21:32:29 +0000164 return true;
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000165}
166
Sam McCallff8b8742017-11-30 21:32:29 +0000167bool fromJSON(const json::Expr &Params, DidOpenTextDocumentParams &R) {
168 json::ObjectMapper O(Params);
169 return O && O.map("textDocument", R.textDocument) &&
170 O.map("metadata", R.metadata);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000171}
172
Sam McCallff8b8742017-11-30 21:32:29 +0000173bool fromJSON(const json::Expr &Params, DidCloseTextDocumentParams &R) {
174 json::ObjectMapper O(Params);
175 return O && O.map("textDocument", R.textDocument);
Krasimir Georgiev561ba5e2017-04-10 13:31:39 +0000176}
177
Sam McCallff8b8742017-11-30 21:32:29 +0000178bool fromJSON(const json::Expr &Params, DidChangeTextDocumentParams &R) {
179 json::ObjectMapper O(Params);
180 return O && O.map("textDocument", R.textDocument) &&
181 O.map("contentChanges", R.contentChanges);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000182}
183
Sam McCallff8b8742017-11-30 21:32:29 +0000184bool fromJSON(const json::Expr &E, FileChangeType &Out) {
185 if (auto T = E.asInteger()) {
186 if (*T < static_cast<int>(FileChangeType::Created) ||
187 *T > static_cast<int>(FileChangeType::Deleted))
188 return false;
189 Out = static_cast<FileChangeType>(*T);
190 return true;
191 }
192 return false;
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000193}
194
Sam McCallff8b8742017-11-30 21:32:29 +0000195bool fromJSON(const json::Expr &Params, FileEvent &R) {
196 json::ObjectMapper O(Params);
197 return O && O.map("uri", R.uri) && O.map("type", R.type);
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000198}
199
Sam McCallff8b8742017-11-30 21:32:29 +0000200bool fromJSON(const json::Expr &Params, DidChangeWatchedFilesParams &R) {
201 json::ObjectMapper O(Params);
202 return O && O.map("changes", R.changes);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000203}
204
Sam McCallff8b8742017-11-30 21:32:29 +0000205bool fromJSON(const json::Expr &Params, TextDocumentContentChangeEvent &R) {
206 json::ObjectMapper O(Params);
207 return O && O.map("text", R.text);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000208}
209
Sam McCallff8b8742017-11-30 21:32:29 +0000210bool fromJSON(const json::Expr &Params, FormattingOptions &R) {
211 json::ObjectMapper O(Params);
212 return O && O.map("tabSize", R.tabSize) &&
213 O.map("insertSpaces", R.insertSpaces);
214}
215
216json::Expr toJSON(const FormattingOptions &P) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000217 return json::obj{
218 {"tabSize", P.tabSize},
219 {"insertSpaces", P.insertSpaces},
220 };
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000221}
222
Sam McCallff8b8742017-11-30 21:32:29 +0000223bool fromJSON(const json::Expr &Params, DocumentRangeFormattingParams &R) {
224 json::ObjectMapper O(Params);
225 return O && O.map("textDocument", R.textDocument) &&
226 O.map("range", R.range) && O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000227}
228
Sam McCallff8b8742017-11-30 21:32:29 +0000229bool fromJSON(const json::Expr &Params, DocumentOnTypeFormattingParams &R) {
230 json::ObjectMapper O(Params);
231 return O && O.map("textDocument", R.textDocument) &&
232 O.map("position", R.position) && O.map("ch", R.ch) &&
233 O.map("options", R.options);
Krasimir Georgiev1b8bfd42017-02-16 10:49:46 +0000234}
235
Sam McCallff8b8742017-11-30 21:32:29 +0000236bool fromJSON(const json::Expr &Params, DocumentFormattingParams &R) {
237 json::ObjectMapper O(Params);
238 return O && O.map("textDocument", R.textDocument) &&
239 O.map("options", R.options);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000240}
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000241
Sam McCallff8b8742017-11-30 21:32:29 +0000242bool fromJSON(const json::Expr &Params, Diagnostic &R) {
243 json::ObjectMapper O(Params);
244 if (!O || !O.map("range", R.range) || !O.map("message", R.message))
245 return false;
246 O.map("severity", R.severity);
247 return true;
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000248}
249
Sam McCallff8b8742017-11-30 21:32:29 +0000250bool fromJSON(const json::Expr &Params, CodeActionContext &R) {
251 json::ObjectMapper O(Params);
252 return O && O.map("diagnostics", R.diagnostics);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +0000253}
254
Sam McCall034e11a2018-01-25 17:29:17 +0000255llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diagnostic &D) {
256 OS << D.range << " [";
257 switch (D.severity) {
258 case 1:
259 OS << "error";
260 break;
261 case 2:
262 OS << "warning";
263 break;
264 case 3:
265 OS << "note";
266 break;
267 case 4:
268 OS << "remark";
269 break;
270 default:
271 OS << "diagnostic";
272 break;
273 }
274 return OS << '(' << D.severity << "): " << D.message << "]";
275}
276
Sam McCallff8b8742017-11-30 21:32:29 +0000277bool fromJSON(const json::Expr &Params, CodeActionParams &R) {
278 json::ObjectMapper O(Params);
279 return O && O.map("textDocument", R.textDocument) &&
280 O.map("range", R.range) && O.map("context", R.context);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000281}
282
Sam McCallff8b8742017-11-30 21:32:29 +0000283bool fromJSON(const json::Expr &Params, WorkspaceEdit &R) {
284 json::ObjectMapper O(Params);
285 return O && O.map("changes", R.changes);
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000286}
287
Benjamin Kramerb4c5c2d2017-12-28 15:03:02 +0000288const llvm::StringLiteral ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND =
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000289 "clangd.applyFix";
290
Sam McCallff8b8742017-11-30 21:32:29 +0000291bool fromJSON(const json::Expr &Params, ExecuteCommandParams &R) {
292 json::ObjectMapper O(Params);
293 if (!O || !O.map("command", R.command))
294 return false;
Sam McCallec109022017-11-28 09:37:43 +0000295
Sam McCallff8b8742017-11-30 21:32:29 +0000296 auto Args = Params.asObject()->getArray("arguments");
297 if (R.command == ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND) {
298 return Args && Args->size() == 1 &&
299 fromJSON(Args->front(), R.workspaceEdit);
300 }
301 return false; // Unrecognized command.
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000302}
303
Sam McCallff8b8742017-11-30 21:32:29 +0000304json::Expr toJSON(const WorkspaceEdit &WE) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000305 if (!WE.changes)
306 return json::obj{};
307 json::obj FileChanges;
308 for (auto &Change : *WE.changes)
309 FileChanges[Change.first] = json::ary(Change.second);
310 return json::obj{{"changes", std::move(FileChanges)}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000311}
312
Sam McCallff8b8742017-11-30 21:32:29 +0000313json::Expr toJSON(const ApplyWorkspaceEditParams &Params) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000314 return json::obj{{"edit", Params.edit}};
Marc-Andre Laperlee7ec16a2017-11-03 13:39:15 +0000315}
316
Sam McCallff8b8742017-11-30 21:32:29 +0000317bool fromJSON(const json::Expr &Params, TextDocumentPositionParams &R) {
318 json::ObjectMapper O(Params);
319 return O && O.map("textDocument", R.textDocument) &&
320 O.map("position", R.position);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000321}
322
Sam McCallff8b8742017-11-30 21:32:29 +0000323json::Expr toJSON(const CompletionItem &CI) {
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000324 assert(!CI.label.empty() && "completion item label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +0000325 json::obj Result{{"label", CI.label}};
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000326 if (CI.kind != CompletionItemKind::Missing)
Sam McCalldd0566b2017-11-06 15:40:30 +0000327 Result["kind"] = static_cast<int>(CI.kind);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000328 if (!CI.detail.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000329 Result["detail"] = CI.detail;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000330 if (!CI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000331 Result["documentation"] = CI.documentation;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000332 if (!CI.sortText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000333 Result["sortText"] = CI.sortText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000334 if (!CI.filterText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000335 Result["filterText"] = CI.filterText;
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000336 if (!CI.insertText.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000337 Result["insertText"] = CI.insertText;
338 if (CI.insertTextFormat != InsertTextFormat::Missing)
339 Result["insertTextFormat"] = static_cast<int>(CI.insertTextFormat);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000340 if (CI.textEdit)
Sam McCalldd0566b2017-11-06 15:40:30 +0000341 Result["textEdit"] = *CI.textEdit;
342 if (!CI.additionalTextEdits.empty())
343 Result["additionalTextEdits"] = json::ary(CI.additionalTextEdits);
344 return std::move(Result);
Krasimir Georgiev6d2131a2017-04-04 09:46:39 +0000345}
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000346
Sam McCallff8b8742017-11-30 21:32:29 +0000347bool operator<(const CompletionItem &L, const CompletionItem &R) {
Sam McCallc78ccbd2017-11-08 07:44:12 +0000348 return (L.sortText.empty() ? L.label : L.sortText) <
349 (R.sortText.empty() ? R.label : R.sortText);
350}
351
Sam McCallff8b8742017-11-30 21:32:29 +0000352json::Expr toJSON(const CompletionList &L) {
Sam McCalla40371b2017-11-15 09:16:29 +0000353 return json::obj{
354 {"isIncomplete", L.isIncomplete},
355 {"items", json::ary(L.items)},
356 };
357}
358
Sam McCallff8b8742017-11-30 21:32:29 +0000359json::Expr toJSON(const ParameterInformation &PI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000360 assert(!PI.label.empty() && "parameter information label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +0000361 json::obj Result{{"label", PI.label}};
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000362 if (!PI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000363 Result["documentation"] = PI.documentation;
364 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000365}
366
Sam McCallff8b8742017-11-30 21:32:29 +0000367json::Expr toJSON(const SignatureInformation &SI) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000368 assert(!SI.label.empty() && "signature information label is required");
Sam McCalldd0566b2017-11-06 15:40:30 +0000369 json::obj Result{
370 {"label", SI.label},
371 {"parameters", json::ary(SI.parameters)},
372 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000373 if (!SI.documentation.empty())
Sam McCalldd0566b2017-11-06 15:40:30 +0000374 Result["documentation"] = SI.documentation;
375 return std::move(Result);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000376}
377
Sam McCallff8b8742017-11-30 21:32:29 +0000378json::Expr toJSON(const SignatureHelp &SH) {
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000379 assert(SH.activeSignature >= 0 &&
380 "Unexpected negative value for number of active signatures.");
381 assert(SH.activeParameter >= 0 &&
382 "Unexpected negative value for active parameter index");
Sam McCalldd0566b2017-11-06 15:40:30 +0000383 return json::obj{
384 {"activeSignature", SH.activeSignature},
385 {"activeParameter", SH.activeParameter},
386 {"signatures", json::ary(SH.signatures)},
387 };
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000388}
Haojian Wu345099c2017-11-09 11:30:04 +0000389
Sam McCallff8b8742017-11-30 21:32:29 +0000390bool fromJSON(const json::Expr &Params, RenameParams &R) {
391 json::ObjectMapper O(Params);
392 return O && O.map("textDocument", R.textDocument) &&
393 O.map("position", R.position) && O.map("newName", R.newName);
Haojian Wu345099c2017-11-09 11:30:04 +0000394}
Sam McCallff8b8742017-11-30 21:32:29 +0000395
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000396json::Expr toJSON(const DocumentHighlight &DH) {
397 return json::obj{
398 {"range", toJSON(DH.range)},
399 {"kind", static_cast<int>(DH.kind)},
400 };
401}
402
Sam McCallff8b8742017-11-30 21:32:29 +0000403} // namespace clangd
404} // namespace clang