1 //===--- ClangdLSPServer.h - LSP server --------------------------*- C++-*-===// 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 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H 10 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H 11 12 #include "ClangdServer.h" 13 #include "DraftStore.h" 14 #include "Features.inc" 15 #include "FindSymbols.h" 16 #include "GlobalCompilationDatabase.h" 17 #include "Path.h" 18 #include "Protocol.h" 19 #include "Transport.h" 20 #include "clang/Tooling/Core/Replacement.h" 21 #include "llvm/ADT/Optional.h" 22 #include <memory> 23 24 namespace clang { 25 namespace clangd { 26 27 class SymbolIndex; 28 29 /// This class exposes ClangdServer's capabilities via Language Server Protocol. 30 /// 31 /// MessageHandler binds the implemented LSP methods (e.g. onInitialize) to 32 /// corresponding JSON-RPC methods ("initialize"). 33 /// The server also supports $/cancelRequest (MessageHandler provides this). 34 class ClangdLSPServer : private DiagnosticsConsumer { 35 public: 36 /// If \p CompileCommandsDir has a value, compile_commands.json will be 37 /// loaded only from \p CompileCommandsDir. Otherwise, clangd will look 38 /// for compile_commands.json in all parent directories of each file. 39 /// If UseDirBasedCDB is false, compile commands are not read from disk. 40 // FIXME: Clean up signature around CDBs. 41 ClangdLSPServer(Transport &Transp, const FileSystemProvider &FSProvider, 42 const clangd::CodeCompleteOptions &CCOpts, 43 llvm::Optional<Path> CompileCommandsDir, bool UseDirBasedCDB, 44 llvm::Optional<OffsetEncoding> ForcedOffsetEncoding, 45 const ClangdServer::Options &Opts); 46 ~ClangdLSPServer(); 47 48 /// Run LSP server loop, communicating with the Transport provided in the 49 /// constructor. This method must not be executed more than once. 50 /// 51 /// \return Whether we shut down cleanly with a 'shutdown' -> 'exit' sequence. 52 bool run(); 53 54 private: 55 // Implement DiagnosticsConsumer. 56 void onDiagnosticsReady(PathRef File, std::vector<Diag> Diagnostics) override; 57 void onFileUpdated(PathRef File, const TUStatus &Status) override; 58 void 59 onHighlightingsReady(PathRef File, 60 std::vector<HighlightingToken> Highlightings) override; 61 62 // LSP methods. Notifications have signature void(const Params&). 63 // Calls have signature void(const Params&, Callback<Response>). 64 void onInitialize(const InitializeParams &, Callback<llvm::json::Value>); 65 void onShutdown(const ShutdownParams &, Callback<std::nullptr_t>); 66 void onSync(const NoParams &, Callback<std::nullptr_t>); 67 void onDocumentDidOpen(const DidOpenTextDocumentParams &); 68 void onDocumentDidChange(const DidChangeTextDocumentParams &); 69 void onDocumentDidClose(const DidCloseTextDocumentParams &); 70 void onDocumentOnTypeFormatting(const DocumentOnTypeFormattingParams &, 71 Callback<std::vector<TextEdit>>); 72 void onDocumentRangeFormatting(const DocumentRangeFormattingParams &, 73 Callback<std::vector<TextEdit>>); 74 void onDocumentFormatting(const DocumentFormattingParams &, 75 Callback<std::vector<TextEdit>>); 76 // The results are serialized 'vector<DocumentSymbol>' if 77 // SupportsHierarchicalDocumentSymbol is true and 'vector<SymbolInformation>' 78 // otherwise. 79 void onDocumentSymbol(const DocumentSymbolParams &, 80 Callback<llvm::json::Value>); 81 void onCodeAction(const CodeActionParams &, Callback<llvm::json::Value>); 82 void onCompletion(const CompletionParams &, Callback<CompletionList>); 83 void onSignatureHelp(const TextDocumentPositionParams &, 84 Callback<SignatureHelp>); 85 void onGoToDeclaration(const TextDocumentPositionParams &, 86 Callback<std::vector<Location>>); 87 void onGoToDefinition(const TextDocumentPositionParams &, 88 Callback<std::vector<Location>>); 89 void onReference(const ReferenceParams &, Callback<std::vector<Location>>); 90 void onSwitchSourceHeader(const TextDocumentIdentifier &, 91 Callback<llvm::Optional<URIForFile>>); 92 void onDocumentHighlight(const TextDocumentPositionParams &, 93 Callback<std::vector<DocumentHighlight>>); 94 void onFileEvent(const DidChangeWatchedFilesParams &); 95 void onCommand(const ExecuteCommandParams &, Callback<llvm::json::Value>); 96 void onWorkspaceSymbol(const WorkspaceSymbolParams &, 97 Callback<std::vector<SymbolInformation>>); 98 void onRename(const RenameParams &, Callback<WorkspaceEdit>); 99 void onHover(const TextDocumentPositionParams &, 100 Callback<llvm::Optional<Hover>>); 101 void onTypeHierarchy(const TypeHierarchyParams &, 102 Callback<llvm::Optional<TypeHierarchyItem>>); 103 void onResolveTypeHierarchy(const ResolveTypeHierarchyItemParams &, 104 Callback<llvm::Optional<TypeHierarchyItem>>); 105 void onChangeConfiguration(const DidChangeConfigurationParams &); 106 void onSymbolInfo(const TextDocumentPositionParams &, 107 Callback<std::vector<SymbolDetails>>); 108 109 std::vector<Fix> getFixes(StringRef File, const clangd::Diagnostic &D); 110 111 /// Checks if completion request should be ignored. We need this due to the 112 /// limitation of the LSP. Per LSP, a client sends requests for all "trigger 113 /// character" we specify, but for '>' and ':' we need to check they actually 114 /// produce '->' and '::', respectively. 115 bool shouldRunCompletion(const CompletionParams &Params) const; 116 117 /// Forces a reparse of all currently opened files. As a result, this method 118 /// may be very expensive. This method is normally called when the 119 /// compilation database is changed. 120 void reparseOpenedFiles(); 121 void applyConfiguration(const ConfigurationSettings &Settings); 122 123 /// Sends a "publishSemanticHighlighting" notification to the LSP client. 124 void publishSemanticHighlighting(SemanticHighlightingParams Params); 125 126 /// Sends a "publishDiagnostics" notification to the LSP client. 127 void publishDiagnostics(const URIForFile &File, 128 std::vector<clangd::Diagnostic> Diagnostics); 129 130 /// Used to indicate that the 'shutdown' request was received from the 131 /// Language Server client. 132 bool ShutdownRequestReceived = false; 133 134 std::mutex FixItsMutex; 135 typedef std::map<clangd::Diagnostic, std::vector<Fix>, LSPDiagnosticCompare> 136 DiagnosticToReplacementMap; 137 /// Caches FixIts per file and diagnostics 138 llvm::StringMap<DiagnosticToReplacementMap> FixItsMap; 139 140 // Most code should not deal with Transport directly. 141 // MessageHandler deals with incoming messages, use call() etc for outgoing. 142 clangd::Transport &Transp; 143 class MessageHandler; 144 std::unique_ptr<MessageHandler> MsgHandler; 145 std::atomic<int> NextCallID = {0}; 146 std::mutex TranspWriter; 147 void call(StringRef Method, llvm::json::Value Params); 148 void notify(StringRef Method, llvm::json::Value Params); 149 150 const FileSystemProvider &FSProvider; 151 /// Options used for code completion 152 clangd::CodeCompleteOptions CCOpts; 153 /// Options used for diagnostics. 154 ClangdDiagnosticOptions DiagOpts; 155 /// The supported kinds of the client. 156 SymbolKindBitset SupportedSymbolKinds; 157 /// The supported completion item kinds of the client. 158 CompletionItemKindBitset SupportedCompletionItemKinds; 159 /// Whether the client supports CodeAction response objects. 160 bool SupportsCodeAction = false; 161 /// From capabilities of textDocument/documentSymbol. 162 bool SupportsHierarchicalDocumentSymbol = false; 163 /// Whether the client supports showing file status. 164 bool SupportFileStatus = false; 165 /// Which kind of markup should we use in textDocument/hover responses. 166 MarkupKind HoverContentFormat = MarkupKind::PlainText; 167 /// Whether the client supports offsets for parameter info labels. 168 bool SupportsOffsetsInSignatureHelp = false; 169 // Store of the current versions of the open documents. 170 DraftStore DraftMgr; 171 172 // The CDB is created by the "initialize" LSP method. 173 bool UseDirBasedCDB; // FIXME: make this a capability. 174 llvm::Optional<Path> CompileCommandsDir; // FIXME: merge with capability? 175 std::unique_ptr<GlobalCompilationDatabase> BaseCDB; 176 // CDB is BaseCDB plus any comands overridden via LSP extensions. 177 llvm::Optional<OverlayCDB> CDB; 178 // The ClangdServer is created by the "initialize" LSP method. 179 // It is destroyed before run() returns, to ensure worker threads exit. 180 ClangdServer::Options ClangdServerOpts; 181 llvm::Optional<ClangdServer> Server; 182 llvm::Optional<OffsetEncoding> NegotiatedOffsetEncoding; 183 }; 184 } // namespace clangd 185 } // namespace clang 186 187 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H 188