19 #include "clang/Tooling/Core/Replacement.h" 20 #include "llvm/ADT/ArrayRef.h" 21 #include "llvm/ADT/Optional.h" 22 #include "llvm/ADT/ScopeExit.h" 23 #include "llvm/Support/Errc.h" 24 #include "llvm/Support/Error.h" 25 #include "llvm/Support/FormatVariadic.h" 26 #include "llvm/Support/Path.h" 27 #include "llvm/Support/ScopedPrinter.h" 34 CodeAction
toCodeAction(
const ClangdServer::TweakRef &T,
const URIForFile &File,
52 CA.command->title = T.Title;
53 CA.command->command = Command::CLANGD_APPLY_TWEAK;
54 CA.command->tweakArgs.emplace();
55 CA.command->tweakArgs->file = File;
56 CA.command->tweakArgs->tweakID = T.ID;
57 CA.command->tweakArgs->selection = Selection;
61 void adjustSymbolKinds(llvm::MutableArrayRef<DocumentSymbol> Syms,
63 for (
auto &S : Syms) {
65 adjustSymbolKinds(S.children, Kinds);
87 std::vector<std::vector<std::string>> buildHighlightScopeLookupTable() {
88 std::vector<std::vector<std::string>> LookupTable;
92 LookupTable.push_back({toTextMateScope((HighlightingKind)(KindValue))});
111 log(
"<-- {0}", Method);
112 if (Method ==
"exit")
115 elog(
"Notification {0} before initialization", Method);
116 else if (Method ==
"$/cancelRequest")
117 onCancel(std::move(Params));
118 else if (
auto Handler = Notifications.lookup(Method))
119 Handler(std::move(Params));
121 log(
"unhandled notification {0}", Method);
126 llvm::json::Value ID)
override {
129 WithContext WithCancel(cancelableRequestContext(ID));
132 ReplyOnce Reply(ID, Method, &Server, Tracer.
Args);
133 log(
"<-- {0}({1})", Method, ID);
134 if (!Server.Server && Method !=
"initialize") {
135 elog(
"Call {0} before initialization.", Method);
136 Reply(llvm::make_error<LSPError>(
"server not initialized",
138 }
else if (
auto Handler = Calls.lookup(Method))
139 Handler(std::move(Params), std::move(Reply));
141 Reply(llvm::make_error<LSPError>(
"method not found",
147 llvm::Expected<llvm::json::Value>
Result)
override {
151 log(
"<-- reply({0})", ID);
158 template <
typename Param,
typename Result>
161 Calls[
Method] = [
Method, Handler,
this](llvm::json::Value RawParams,
165 (Server.*Handler)(P, std::move(Reply));
167 elog(
"Failed to decode {0} request.", Method);
168 Reply(llvm::make_error<LSPError>(
"failed to decode request",
175 template <
typename Param>
179 this](llvm::json::Value RawParams) {
182 elog(
"Failed to decode {0} request.", Method);
187 (Server.*Handler)(P);
198 std::atomic<bool> Replied = {
false};
199 std::chrono::steady_clock::time_point Start;
200 llvm::json::Value ID;
203 llvm::json::Object *TraceArgs;
206 ReplyOnce(
const llvm::json::Value &ID, llvm::StringRef Method,
208 : Start(std::chrono::steady_clock::now()), ID(ID),
Method(Method),
209 Server(Server), TraceArgs(TraceArgs) {
212 ReplyOnce(ReplyOnce &&Other)
213 : Replied(Other.Replied.load()), Start(Other.Start),
214 ID(std::move(Other.ID)),
Method(std::move(Other.Method)),
215 Server(Other.Server), TraceArgs(Other.TraceArgs) {
216 Other.Server =
nullptr;
218 ReplyOnce &operator=(ReplyOnce &&) =
delete;
219 ReplyOnce(
const ReplyOnce &) =
delete;
220 ReplyOnce &operator=(
const ReplyOnce &) =
delete;
223 if (Server && !Replied) {
224 elog(
"No reply to message {0}({1})", Method, ID);
225 assert(
false &&
"must reply to all calls!");
226 (*this)(llvm::make_error<LSPError>(
"server failed to reply",
231 void operator()(llvm::Expected<llvm::json::Value> Reply) {
232 assert(Server &&
"moved-from!");
233 if (Replied.exchange(
true)) {
234 elog(
"Replied twice to message {0}({1})", Method, ID);
235 assert(
false &&
"must reply to each call only once!");
238 auto Duration = std::chrono::steady_clock::now() - Start;
240 log(
"--> reply:{0}({1}) {2:ms}", Method, ID, Duration);
242 (*TraceArgs)[
"Reply"] = *Reply;
243 std::lock_guard<std::mutex> Lock(Server->TranspWriter);
244 Server->Transp.
reply(std::move(ID), std::move(Reply));
247 log(
"--> reply:{0}({1}) {2:ms}, error: {3}", Method, ID, Duration, Err);
249 (*TraceArgs)[
"Error"] = llvm::to_string(Err);
250 std::lock_guard<std::mutex> Lock(Server->TranspWriter);
251 Server->Transp.
reply(std::move(ID), std::move(Err));
256 llvm::StringMap<std::function<void(llvm::json::Value)>> Notifications;
257 llvm::StringMap<std::function<void(llvm::json::Value, ReplyOnce)>> Calls;
262 mutable std::mutex RequestCancelersMutex;
263 llvm::StringMap<std::pair<
Canceler,
unsigned>> RequestCancelers;
264 unsigned NextRequestCookie = 0;
265 void onCancel(
const llvm::json::Value &Params) {
266 const llvm::json::Value *ID =
nullptr;
267 if (
auto *O = Params.getAsObject())
270 elog(
"Bad cancellation request: {0}", Params);
273 auto StrID = llvm::to_string(*ID);
274 std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
275 auto It = RequestCancelers.find(StrID);
276 if (It != RequestCancelers.end())
280 Context handlerContext()
const {
290 Context cancelableRequestContext(
const llvm::json::Value &ID) {
292 auto StrID = llvm::to_string(ID);
293 auto Cookie = NextRequestCookie++;
295 std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
296 RequestCancelers[StrID] = {std::move(Task.second), Cookie};
301 return Task.first.derive(llvm::make_scope_exit([
this, StrID, Cookie] {
302 std::lock_guard<std::mutex> Lock(RequestCancelersMutex);
303 auto It = RequestCancelers.find(StrID);
304 if (It != RequestCancelers.end() && It->second.second == Cookie)
305 RequestCancelers.erase(It);
313 void ClangdLSPServer::call(llvm::StringRef Method, llvm::json::Value Params) {
314 auto ID = NextCallID++;
315 log(
"--> {0}({1})", Method, ID);
317 std::lock_guard<std::mutex> Lock(TranspWriter);
318 Transp.call(Method, std::move(Params), ID);
321 void ClangdLSPServer::notify(llvm::StringRef Method, llvm::json::Value Params) {
322 log(
"--> {0}", Method);
323 std::lock_guard<std::mutex> Lock(TranspWriter);
324 Transp.notify(Method, std::move(Params));
334 NegotiatedOffsetEncoding = Supported;
338 llvm::Optional<WithContextValue> WithOffsetEncoding;
339 if (NegotiatedOffsetEncoding)
341 *NegotiatedOffsetEncoding);
343 ClangdServerOpts.SemanticHighlighting =
346 ClangdServerOpts.WorkspaceRoot = Params.
rootUri->file();
348 ClangdServerOpts.WorkspaceRoot = *Params.
rootPath;
350 return Reply(llvm::make_error<LSPError>(
"server already initialized",
353 CompileCommandsDir = Dir;
354 if (UseDirBasedCDB) {
355 BaseCDB = llvm::make_unique<DirectoryBasedGlobalCompilationDatabase>(
358 llvm::makeArrayRef(ClangdServerOpts.QueryDriverGlobs),
362 ClangdServerOpts.ResourceDir);
369 if (!CCOpts.BundleOverloads.hasValue())
373 DiagOpts.EmitRelatedLocations =
380 SupportsHierarchicalDocumentSymbol =
385 llvm::json::Object
Result{
389 {
"documentFormattingProvider",
true},
390 {
"documentRangeFormattingProvider",
true},
391 {
"documentOnTypeFormattingProvider",
393 {
"firstTriggerCharacter",
"\n"},
394 {
"moreTriggerCharacter", {}},
396 {
"codeActionProvider",
true},
397 {
"completionProvider",
399 {
"resolveProvider",
false},
402 {
"triggerCharacters", {
".",
">",
":"}},
404 {
"signatureHelpProvider",
406 {
"triggerCharacters", {
"(",
","}},
408 {
"declarationProvider",
true},
409 {
"definitionProvider",
true},
410 {
"documentHighlightProvider",
true},
411 {
"hoverProvider",
true},
412 {
"renameProvider",
true},
413 {
"documentSymbolProvider",
true},
414 {
"workspaceSymbolProvider",
true},
415 {
"referencesProvider",
true},
416 {
"executeCommandProvider",
422 {
"typeHierarchyProvider",
true},
424 if (NegotiatedOffsetEncoding)
425 Result[
"offsetEncoding"] = *NegotiatedOffsetEncoding;
427 Result.getObject(
"capabilities")
429 {
"semanticHighlighting",
430 llvm::json::Object{{
"scopes", buildHighlightScopeLookupTable()}}});
437 ShutdownRequestReceived =
true;
443 void ClangdLSPServer::onSync(
const NoParams &Params,
445 if (
Server->blockUntilIdleForTest(60))
448 Reply(llvm::createStringError(llvm::inconvertibleErrorCode(),
449 "Not idle after a minute"));
452 void ClangdLSPServer::onDocumentDidOpen(
458 DraftMgr.addDraft(File, Contents);
462 void ClangdLSPServer::onDocumentDidChange(
470 llvm::Expected<std::string>
Contents =
476 DraftMgr.removeDraft(File);
477 Server->removeDocument(File);
478 elog(
"Failed to update {0}: {1}", File, Contents.takeError());
482 Server->addDocument(File, *Contents, WantDiags);
486 Server->onFileEvent(Params);
493 Edit.
edit = std::move(WE);
496 call(
"workspace/applyEdit", Edit);
509 Reply(
"Fix applied.");
513 auto Code = DraftMgr.getDraft(Params.
tweakArgs->file.file());
515 return Reply(llvm::createStringError(
516 llvm::inconvertibleErrorCode(),
517 "trying to apply a code action for a non-added file"));
521 llvm::Expected<Tweak::Effect> R) {
523 return Reply(R.takeError());
529 ApplyEdit(std::move(WE));
531 if (R->ShowMessage) {
535 notify(
"window/showMessage", Msg);
537 Reply(
"Tweak applied.");
547 Reply(llvm::make_error<LSPError>(
548 llvm::formatv(
"Unsupported command \"{0}\".", Params.
command).str(),
553 void ClangdLSPServer::onWorkspaceSymbol(
555 Callback<std::vector<SymbolInformation>> Reply) {
557 Params.
query, CCOpts.Limit,
559 [
this](decltype(Reply) Reply,
562 return Reply(Items.takeError());
563 for (
auto &Sym : *Items)
566 Reply(std::move(*Items));
571 void ClangdLSPServer::onRename(
const RenameParams &Params,
574 llvm::Optional<std::string> Code = DraftMgr.getDraft(File);
576 return Reply(llvm::make_error<LSPError>(
582 [File, Code, Params](decltype(Reply) Reply,
585 return Reply(Edits.takeError());
594 void ClangdLSPServer::onDocumentDidClose(
597 DraftMgr.removeDraft(File);
598 Server->removeDocument(File);
601 std::lock_guard<std::mutex> Lock(FixItsMutex);
602 FixItsMap.erase(File);
612 void ClangdLSPServer::onDocumentOnTypeFormatting(
614 Callback<std::vector<TextEdit>> Reply) {
616 auto Code = DraftMgr.getDraft(File);
618 return Reply(llvm::make_error<LSPError>(
619 "onDocumentOnTypeFormatting called for non-added file",
625 void ClangdLSPServer::onDocumentRangeFormatting(
627 Callback<std::vector<TextEdit>> Reply) {
629 auto Code = DraftMgr.getDraft(File);
631 return Reply(llvm::make_error<LSPError>(
632 "onDocumentRangeFormatting called for non-added file",
635 auto ReplacementsOrError =
Server->formatRange(*Code, File, Params.
range);
636 if (ReplacementsOrError)
639 Reply(ReplacementsOrError.takeError());
642 void ClangdLSPServer::onDocumentFormatting(
644 Callback<std::vector<TextEdit>> Reply) {
646 auto Code = DraftMgr.getDraft(File);
648 return Reply(llvm::make_error<LSPError>(
649 "onDocumentFormatting called for non-added file",
652 auto ReplacementsOrError =
Server->formatFile(*Code, File);
653 if (ReplacementsOrError)
656 Reply(ReplacementsOrError.takeError());
661 static std::vector<SymbolInformation>
665 std::vector<SymbolInformation>
Results;
666 std::function<void(const DocumentSymbol &, llvm::StringRef)> Process =
667 [&](
const DocumentSymbol &S, llvm::Optional<llvm::StringRef> ParentName) {
675 Results.push_back(std::move(SI));
676 std::string FullName =
677 !ParentName ? S.
name : (ParentName->str() +
"::" + S.
name);
679 Process(C, FullName);
681 for (
auto &S : Symbols)
692 [
this, FileURI](decltype(Reply) Reply,
695 return Reply(Items.takeError());
696 adjustSymbolKinds(*Items, SupportedSymbolKinds);
697 if (SupportsHierarchicalDocumentSymbol)
698 return Reply(std::move(*Items));
711 }
else if (Action.
edit) {
712 Cmd.command = Command::CLANGD_APPLY_FIX_COMMAND;
713 Cmd.workspaceEdit = *Action.
edit;
717 Cmd.title = Action.
title;
719 Cmd.title =
"Apply fix: " + Cmd.title;
726 auto Code = DraftMgr.getDraft(File.
file());
728 return Reply(llvm::make_error<LSPError>(
731 std::vector<CodeAction> FixIts;
733 for (
auto &F : getFixes(File.
file(),
D)) {
735 FixIts.back().diagnostics = {D};
740 auto ConsumeActions =
742 Range Selection, std::vector<CodeAction> FixIts,
743 llvm::Expected<std::vector<ClangdServer::TweakRef>> Tweaks) {
745 return Reply(Tweaks.takeError());
747 std::vector<CodeAction> Actions = std::move(FixIts);
748 Actions.reserve(Actions.size() + Tweaks->size());
749 for (
const auto &T : *Tweaks)
752 if (SupportsCodeAction)
753 return Reply(llvm::json::Array(Actions));
755 for (
const auto &
Action : Actions) {
757 Commands.push_back(std::move(*
Command));
759 return Reply(llvm::json::Array(Commands));
763 Bind(ConsumeActions, std::move(Reply), File,
764 std::move(*Code), Params.
range,
770 if (!shouldRunCompletion(Params)) {
773 vlog(
"ignored auto-triggered completion, preceding char did not match");
778 [
this](decltype(Reply) Reply,
779 llvm::Expected<CodeCompleteResult> List) {
781 return Reply(List.takeError());
784 for (
const auto &R : List->Completions) {
787 C.
kind, SupportedCompletionItemKinds);
788 LSPList.
items.push_back(std::move(C));
790 return Reply(std::move(LSPList));
799 [
this](decltype(Reply) Reply,
800 llvm::Expected<SignatureHelp>
Signature) {
802 return Reply(Signature.takeError());
803 if (SupportsOffsetsInSignatureHelp)
804 return Reply(std::move(*Signature));
807 for (
auto &SigInfo : Signature->signatures) {
808 for (
auto &Param : SigInfo.parameters)
809 Param.labelOffsets.reset();
811 return Reply(std::move(*Signature));
836 void ClangdLSPServer::onGoToDefinition(
const TextDocumentPositionParams &Params,
837 Callback<std::vector<Location>> Reply) {
839 Params.textDocument.uri.file(), Params.position,
841 [&, Params](decltype(Reply) Reply,
844 return Reply(
Symbols.takeError());
845 std::vector<Location> Defs;
848 return Reply(std::vector<Location>{std::move(*Toggle)});
849 Defs.push_back(S.Definition.getValueOr(S.PreferredDeclaration));
851 Reply(std::move(Defs));
856 void ClangdLSPServer::onGoToDeclaration(
857 const TextDocumentPositionParams &Params,
858 Callback<std::vector<Location>> Reply) {
860 Params.textDocument.uri.file(), Params.position,
862 [&, Params](decltype(Reply) Reply,
865 return Reply(Symbols.takeError());
866 std::vector<Location> Decls;
867 for (
auto &S : *Symbols) {
869 return Reply(std::vector<Location>{std::move(*Toggle)});
870 Decls.push_back(std::move(S.PreferredDeclaration));
872 Reply(std::move(Decls));
877 void ClangdLSPServer::onSwitchSourceHeader(
878 const TextDocumentIdentifier &Params,
879 Callback<llvm::Optional<URIForFile>> Reply) {
880 if (
auto Result =
Server->switchSourceHeader(Params.uri.file()))
886 void ClangdLSPServer::onDocumentHighlight(
887 const TextDocumentPositionParams &Params,
888 Callback<std::vector<DocumentHighlight>> Reply) {
889 Server->findDocumentHighlights(Params.textDocument.uri.file(),
890 Params.position, std::move(Reply));
893 void ClangdLSPServer::onHover(
const TextDocumentPositionParams &Params,
894 Callback<llvm::Optional<Hover>> Reply) {
895 Server->findHover(Params.textDocument.uri.file(), Params.position,
897 [
this](decltype(Reply) Reply,
900 return Reply(H.takeError());
905 R.contents.kind = HoverContentFormat;
906 R.range = (*H)->SymRange;
907 switch (HoverContentFormat) {
910 (*H)->present().renderAsPlainText();
911 return Reply(std::move(R));
914 (*H)->present().renderAsMarkdown();
915 return Reply(std::move(R));
917 llvm_unreachable(
"unhandled MarkupKind");
922 void ClangdLSPServer::onTypeHierarchy(
923 const TypeHierarchyParams &Params,
924 Callback<Optional<TypeHierarchyItem>> Reply) {
925 Server->typeHierarchy(Params.textDocument.uri.file(), Params.position,
926 Params.resolve, Params.direction, std::move(Reply));
929 void ClangdLSPServer::onResolveTypeHierarchy(
930 const ResolveTypeHierarchyItemParams &Params,
931 Callback<Optional<TypeHierarchyItem>> Reply) {
932 Server->resolveTypeHierarchy(Params.item, Params.resolve, Params.direction,
936 void ClangdLSPServer::applyConfiguration(
937 const ConfigurationSettings &Settings) {
939 bool ShouldReparseOpenFiles =
false;
940 for (
auto &
Entry : Settings.compilationDatabaseChanges) {
944 auto Old = CDB->getCompileCommand(File);
946 tooling::CompileCommand(std::move(
Entry.second.workingDirectory), File,
947 std::move(
Entry.second.compilationCommand),
950 CDB->setCompileCommand(File, std::move(New));
951 ShouldReparseOpenFiles =
true;
954 if (ShouldReparseOpenFiles)
955 reparseOpenedFiles();
958 void ClangdLSPServer::publishSemanticHighlighting(
959 SemanticHighlightingParams Params) {
960 notify(
"textDocument/semanticHighlighting", Params);
963 void ClangdLSPServer::publishDiagnostics(
964 const URIForFile &File, std::vector<clangd::Diagnostic> Diagnostics) {
966 notify(
"textDocument/publishDiagnostics",
969 {
"diagnostics", std::move(Diagnostics)},
974 void ClangdLSPServer::onChangeConfiguration(
975 const DidChangeConfigurationParams &Params) {
976 applyConfiguration(Params.settings);
979 void ClangdLSPServer::onReference(
const ReferenceParams &Params,
980 Callback<std::vector<Location>> Reply) {
981 Server->findReferences(Params.textDocument.uri.file(), Params.position,
982 CCOpts.Limit, std::move(Reply));
985 void ClangdLSPServer::onSymbolInfo(
const TextDocumentPositionParams &Params,
986 Callback<std::vector<SymbolDetails>> Reply) {
987 Server->symbolInfo(Params.textDocument.uri.file(), Params.position,
994 llvm::Optional<Path> CompileCommandsDir,
bool UseDirBasedCDB,
995 llvm::Optional<OffsetEncoding> ForcedOffsetEncoding,
998 FSProvider(FSProvider), CCOpts(CCOpts),
999 SupportedSymbolKinds(defaultSymbolKinds()),
1000 SupportedCompletionItemKinds(defaultCompletionItemKinds()),
1001 UseDirBasedCDB(UseDirBasedCDB),
1002 CompileCommandsDir(std::move(CompileCommandsDir)), ClangdServerOpts(Opts),
1003 NegotiatedOffsetEncoding(ForcedOffsetEncoding) {
1005 MsgHandler->bind(
"initialize", &ClangdLSPServer::onInitialize);
1006 MsgHandler->bind(
"shutdown", &ClangdLSPServer::onShutdown);
1007 MsgHandler->bind(
"sync", &ClangdLSPServer::onSync);
1008 MsgHandler->bind(
"textDocument/rangeFormatting", &ClangdLSPServer::onDocumentRangeFormatting);
1009 MsgHandler->bind(
"textDocument/onTypeFormatting", &ClangdLSPServer::onDocumentOnTypeFormatting);
1010 MsgHandler->bind(
"textDocument/formatting", &ClangdLSPServer::onDocumentFormatting);
1011 MsgHandler->bind(
"textDocument/codeAction", &ClangdLSPServer::onCodeAction);
1012 MsgHandler->bind(
"textDocument/completion", &ClangdLSPServer::onCompletion);
1013 MsgHandler->bind(
"textDocument/signatureHelp", &ClangdLSPServer::onSignatureHelp);
1014 MsgHandler->bind(
"textDocument/definition", &ClangdLSPServer::onGoToDefinition);
1015 MsgHandler->bind(
"textDocument/declaration", &ClangdLSPServer::onGoToDeclaration);
1016 MsgHandler->bind(
"textDocument/references", &ClangdLSPServer::onReference);
1017 MsgHandler->bind(
"textDocument/switchSourceHeader", &ClangdLSPServer::onSwitchSourceHeader);
1018 MsgHandler->bind(
"textDocument/rename", &ClangdLSPServer::onRename);
1019 MsgHandler->bind(
"textDocument/hover", &ClangdLSPServer::onHover);
1020 MsgHandler->bind(
"textDocument/documentSymbol", &ClangdLSPServer::onDocumentSymbol);
1021 MsgHandler->bind(
"workspace/executeCommand", &ClangdLSPServer::onCommand);
1022 MsgHandler->bind(
"textDocument/documentHighlight", &ClangdLSPServer::onDocumentHighlight);
1023 MsgHandler->bind(
"workspace/symbol", &ClangdLSPServer::onWorkspaceSymbol);
1024 MsgHandler->bind(
"textDocument/didOpen", &ClangdLSPServer::onDocumentDidOpen);
1025 MsgHandler->bind(
"textDocument/didClose", &ClangdLSPServer::onDocumentDidClose);
1026 MsgHandler->bind(
"textDocument/didChange", &ClangdLSPServer::onDocumentDidChange);
1027 MsgHandler->bind(
"workspace/didChangeWatchedFiles", &ClangdLSPServer::onFileEvent);
1028 MsgHandler->bind(
"workspace/didChangeConfiguration", &ClangdLSPServer::onChangeConfiguration);
1029 MsgHandler->bind(
"textDocument/symbolInfo", &ClangdLSPServer::onSymbolInfo);
1030 MsgHandler->bind(
"textDocument/typeHierarchy", &ClangdLSPServer::onTypeHierarchy);
1031 MsgHandler->bind(
"typeHierarchy/resolve", &ClangdLSPServer::onResolveTypeHierarchy);
1039 bool CleanExit =
true;
1040 if (
auto Err = Transp.
loop(*MsgHandler)) {
1041 elog(
"Transport error: {0}", std::move(Err));
1047 return CleanExit && ShutdownRequestReceived;
1050 std::vector<Fix> ClangdLSPServer::getFixes(llvm::StringRef File,
1052 std::lock_guard<std::mutex> Lock(FixItsMutex);
1053 auto DiagToFixItsIter = FixItsMap.find(File);
1054 if (DiagToFixItsIter == FixItsMap.end())
1057 const auto &DiagToFixItsMap = DiagToFixItsIter->second;
1058 auto FixItsIter = DiagToFixItsMap.find(D);
1059 if (FixItsIter == DiagToFixItsMap.end())
1062 return FixItsIter->second;
1065 bool ClangdLSPServer::shouldRunCompletion(
1069 (Trigger !=
">" && Trigger !=
":"))
1085 vlog(
"could not convert position '{0}' to offset for file '{1}'",
1093 return (*Code)[*
Offset - 2] ==
'-';
1095 return (*Code)[*
Offset - 2] ==
':';
1096 assert(
false &&
"unhandled trigger character");
1100 void ClangdLSPServer::onHighlightingsReady(
1101 PathRef File, std::vector<HighlightingToken> Highlightings) {
1102 publishSemanticHighlighting(
1107 void ClangdLSPServer::onDiagnosticsReady(
PathRef File,
1108 std::vector<Diag> Diagnostics) {
1110 std::vector<Diagnostic> LSPDiagnostics;
1111 DiagnosticToReplacementMap LocalFixIts;
1112 for (
auto &
Diag : Diagnostics) {
1115 auto &FixItsForDiagnostic = LocalFixIts[Diag];
1116 llvm::copy(Fixes, std::back_inserter(FixItsForDiagnostic));
1117 LSPDiagnostics.push_back(std::move(Diag));
1123 std::lock_guard<std::mutex> Lock(FixItsMutex);
1124 FixItsMap[
File] = LocalFixIts;
1128 publishDiagnostics(
URI, std::move(LSPDiagnostics));
1131 void ClangdLSPServer::onFileUpdated(
PathRef File,
const TUStatus &Status) {
1132 if (!SupportFileStatus)
1141 notify(
"textDocument/clangd.fileStatus", Status.
render(File));
1144 void ClangdLSPServer::reparseOpenedFiles() {
1146 Server->addDocument(FilePath, *DraftMgr.
getDraft(FilePath),
const tooling::CompileCommand & Command
Exact commands are not specified in the protocol so we define the ones supported by Clangd here...
llvm::Optional< SymbolKindBitset > WorkspaceSymbolKinds
The supported set of SymbolKinds for workspace/symbol.
llvm::Optional< URIForFile > rootUri
The rootUri of the workspace.
std::unique_ptr< GlobalCompilationDatabase > getQueryDriverDatabase(llvm::ArrayRef< std::string > QueryDriverGlobs, std::unique_ptr< GlobalCompilationDatabase > Base)
Extracts system include search path from drivers matching QueryDriverGlobs and adds them to the compi...
static std::vector< SymbolInformation > flattenSymbolHierarchy(llvm::ArrayRef< DocumentSymbol > Symbols, const URIForFile &FileURI)
The functions constructs a flattened view of the DocumentSymbol hierarchy.
Represents a collection of completion items to be presented in the editor.
Diagnostics must be generated for this snapshot.
llvm::Optional< bool > wantDiagnostics
Forces diagnostics to be generated, or to not be generated, for this version of the file...
Range range
The range for which the command was invoked.
std::function< void()> Canceler
A canceller requests cancellation of a task, when called.
FileStatus render(PathRef File) const
Serialize this to an LSP file status item.
CodeActionContext context
Context carrying additional information.
bool onReply(llvm::json::Value ID, llvm::Expected< llvm::json::Value > Result) override
static const llvm::StringLiteral CLANGD_APPLY_FIX_COMMAND
CompletionItemKind kind
The kind of this completion item.
bool CompletionSnippets
Client supports snippets as insert text.
Apply changes that preserve the behavior of the code.
std::vector< CompletionItem > items
The completion items.
void bind(const char *Method, void(ClangdLSPServer::*Handler)(const Param &))
CodeAction toCodeAction(const Fix &F, const URIForFile &File)
Convert from Fix to LSP CodeAction.
Documents are synced by sending the full content on open.
llvm::Optional< std::map< std::string, std::vector< TextEdit > > > changes
Holds changes to existing resources.
static cl::list< std::string > Commands("c", cl::desc("Specify command to run"), cl::value_desc("command"), cl::cat(ClangQueryCategory))
llvm::Optional< std::string > kind
The kind of the code action.
std::string title
A short, human-readable, title for this code action.
Provide information to the user.
TextDocumentIdentifier textDocument
The document that was closed.
bool run()
Run LSP server loop, communicating with the Transport provided in the constructor.
llvm::Optional< Location > Definition
A code action represents a change that can be performed in code, e.g.
URIForFile uri
The text document's URI.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
llvm::Optional< WorkspaceEdit > edit
The workspace edit this code action performs.
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
std::vector< CodeCompletionResult > Results
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
constexpr auto SymbolKindMin
The show message notification is sent from a server to a client to ask the client to display a partic...
llvm::Optional< std::string > compilationDatabasePath
constexpr auto CompletionItemKindMin
std::bitset< CompletionItemKindMax+1 > CompletionItemKindBitset
Documents should not be synced at all.
bool isIncomplete
The list is not complete.
Range range
The range enclosing this symbol not including leading/trailing whitespace but everything else like co...
void vlog(const char *Fmt, Ts &&... Vals)
void elog(const char *Fmt, Ts &&... Vals)
Represents programming constructs like variables, classes, interfaces etc.
static const llvm::StringLiteral CLANGD_APPLY_TWEAK
bool onCall(llvm::StringRef Method, llvm::json::Value Params, llvm::json::Value ID) override
MarkupKind HoverContentFormat
The content format that should be used for Hover requests.
MockFSProvider FSProvider
ConfigurationSettings ConfigSettings
A top-level diagnostic that may have Notes and Fixes.
bool OffsetsInSignatureHelp
Client supports processing label offsets instead of a simple label string.
URIForFile uri
The text document's URI.
bool CompletionFixes
Client supports completions with additionalTextEdit near the cursor.
llvm::Optional< TweakArgs > tweakArgs
TextDocumentIdentifier textDocument
The document that was opened.
void toLSPDiags(const Diag &D, const URIForFile &File, const ClangdDiagnosticOptions &Opts, llvm::function_ref< void(clangd::Diagnostic, llvm::ArrayRef< Fix >)> OutFn)
Conversion to LSP diagnostics.
bool DiagnosticCategory
Whether the client accepts diagnostics with category attached to it using the "category" extension...
std::string newName
The new name of the symbol.
std::string command
The command identifier, e.g. CLANGD_APPLY_FIX_COMMAND.
InitializationOptions initializationOptions
User-provided initialization options.
TextDocumentIdentifier textDocument
MessageHandler(ClangdLSPServer &Server)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
ForwardBinder< Func, Args... > Bind(Func F, Args &&... As)
Creates an object that stores a callable (F) and first arguments to the callable (As) and allows to c...
TextDocumentIdentifier textDocument
The document in which the command was invoked.
static Location * getToggle(const TextDocumentPositionParams &Point, LocatedSymbol &Sym)
llvm::unique_function< void()> Action
std::vector< std::string > fallbackFlags
void log(const char *Fmt, Ts &&... Vals)
MessageType type
The message type.
std::string Path
A typedef to represent a file path.
static const Context & current()
Returns the context for the current thread, creating it if needed.
CompletionTriggerKind triggerKind
How the completion was triggered.
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Position position
The position inside the text document.
Key< OffsetEncoding > kCurrentOffsetEncoding
bool SemanticHighlighting
Client supports semantic highlighting.
Location PreferredDeclaration
std::vector< DocumentSymbol > children
Children of this symbol, e.g. properties of a class.
static const llvm::StringLiteral REFACTOR_KIND
bool FileStatus
Clients supports show file status for textDocument/clangd.fileStatus.
std::string name
The name of this symbol.
std::pair< Context, Canceler > cancelableTask()
Defines a new task whose cancellation may be requested.
static llvm::Optional< Command > asCommand(const CodeAction &Action)
std::vector< SemanticHighlightingInformation > toSemanticHighlightingInformation(llvm::ArrayRef< HighlightingToken > Tokens)
bool DiagnosticFixes
Whether the client accepts diagnostics with codeActions attached inline.
ClientCapabilities capabilities
The capabilities provided by the client (editor or tool)
TextDocumentItem textDocument
The document that was opened.
A context is an immutable container for per-request data that must be propagated through layers that ...
TextDocumentIdentifier textDocument
The document that did change.
Completion was triggered by a trigger character specified by the triggerCharacters properties of the ...
bool onNotify(llvm::StringRef Method, llvm::json::Value Params) override
llvm::Optional< CompletionItemKindBitset > CompletionItemKinds
The supported set of CompletionItemKinds for textDocument/completion.
llvm::Optional< std::string > rootPath
The rootPath of the workspace.
virtual llvm::Error loop(MessageHandler &)=0
bool CodeActionStructure
Client supports CodeAction return value for textDocument/codeAction.
WithContext replaces Context::current() with a provided scope.
bool fromJSON(const llvm::json::Value &Parameters, FuzzyFindRequest &Request)
void bind(const char *Method, void(ClangdLSPServer::*Handler)(const Param &, Callback< Result >))
std::vector< TextDocumentContentChangeEvent > contentChanges
The actual content changes.
CompletionContext context
bool contains(Position Pos) const
std::string query
A non-empty query string.
SymbolKind kind
The kind of this symbol.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::bitset< SymbolKindMax+1 > SymbolKindBitset
std::string triggerCharacter
The trigger character (a single character) that has trigger code complete.
TextDocumentIdentifier textDocument
The text document.
static const llvm::StringLiteral INFO_KIND
Context derive(const Key< Type > &Key, typename std::decay< Type >::type Value) const &
Derives a child context It is safe to move or destroy a parent context after calling derive()...
virtual void reply(llvm::json::Value ID, llvm::Expected< llvm::json::Value > Result)=0
CharSourceRange Range
SourceRange for the file name.
SymbolKind adjustKindToCapability(SymbolKind Kind, SymbolKindBitset &SupportedSymbolKinds)
static const llvm::StringLiteral QUICKFIX_KIND
A URI describes the location of a source file.
std::vector< Diagnostic > diagnostics
An array of diagnostics.
llvm::Optional< Command > command
A command this code action executes.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
std::vector< TextEdit > replacementsToEdits(llvm::StringRef Code, const tooling::Replacements &Repls)
The parameters of a Workspace Symbol Request.
std::vector< const char * > Expected
std::string text
The content of the opened text document.
Position position
The position at which this request was sent.
URIForFile uri
The text document's URI.
std::string message
The actual message.
bool HasSignatureHelp
Client supports signature help.
bool DiagnosticRelatedInformation
Whether the client accepts diagnostics with related locations.
std::vector< Path > getActiveFiles() const
llvm::Optional< WorkspaceEdit > workspaceEdit
This class exposes ClangdServer's capabilities via Language Server Protocol.
llvm::json::Object *const Args
Mutable metadata, if this span is interested.
Records an event whose duration is the lifetime of the Span object.
ClangdLSPServer(Transport &Transp, const FileSystemProvider &FSProvider, const clangd::CodeCompleteOptions &CCOpts, llvm::Optional< Path > CompileCommandsDir, bool UseDirBasedCDB, llvm::Optional< OffsetEncoding > ForcedOffsetEncoding, const ClangdServer::Options &Opts)
If CompileCommandsDir has a value, compile_commands.json will be loaded only from CompileCommandsDir...
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
Diagnostics must not be generated for this snapshot.
llvm::Optional< std::vector< OffsetEncoding > > offsetEncoding
Supported encodings for LSP character offsets. (clangd extension).
llvm::Optional< std::string > getDraft(PathRef File) const
bool HierarchicalDocumentSymbol
Client supports hierarchical document symbols.
llvm::StringRef file() const
Retrieves absolute path to the file.