brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.7 KiB · 6ada3fd Raw
344 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H10#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H11 12#include "ClangdServer.h"13#include "Diagnostics.h"14#include "GlobalCompilationDatabase.h"15#include "LSPBinder.h"16#include "Protocol.h"17#include "Transport.h"18#include "support/Context.h"19#include "support/MemoryTree.h"20#include "support/Path.h"21#include "support/Threading.h"22#include "llvm/ADT/ArrayRef.h"23#include "llvm/Support/JSON.h"24#include <chrono>25#include <cstddef>26#include <cstdint>27#include <memory>28#include <optional>29#include <vector>30 31namespace clang {32namespace clangd {33 34/// This class exposes ClangdServer's capabilities via Language Server Protocol.35///36/// MessageHandler binds the implemented LSP methods (e.g. onInitialize) to37/// corresponding JSON-RPC methods ("initialize").38/// The server also supports $/cancelRequest (MessageHandler provides this).39class ClangdLSPServer : private ClangdServer::Callbacks,40                        private LSPBinder::RawOutgoing {41public:42  struct Options : ClangdServer::Options {43    /// Supplies configuration (overrides ClangdServer::ContextProvider).44    config::Provider *ConfigProvider = nullptr;45    /// Look for compilation databases, rather than using compile commands46    /// set via LSP (extensions) only.47    bool UseDirBasedCDB = true;48    /// The offset-encoding to use, or std::nullopt to negotiate it over LSP.49    std::optional<OffsetEncoding> Encoding;50    /// If set, periodically called to release memory.51    /// Consider malloc_trim(3)52    std::function<void()> MemoryCleanup = nullptr;53 54    /// Per-feature options. Generally ClangdServer lets these vary55    /// per-request, but LSP allows limited/no customizations.56    clangd::CodeCompleteOptions CodeComplete;57    MarkupKind SignatureHelpDocumentationFormat = MarkupKind::PlainText;58    clangd::RenameOptions Rename;59    /// Returns true if the tweak should be enabled.60    std::function<bool(const Tweak &)> TweakFilter = [](const Tweak &T) {61      return !T.hidden(); // only enable non-hidden tweaks.62    };63 64    /// Limit the number of references returned (0 means no limit).65    size_t ReferencesLimit = 0;66 67    /// Flag to hint the experimental modules support is enabled.68    bool EnableExperimentalModulesSupport = false;69  };70 71  ClangdLSPServer(Transport &Transp, const ThreadsafeFS &TFS,72                  const ClangdLSPServer::Options &Opts);73  /// The destructor blocks on any outstanding background tasks.74  ~ClangdLSPServer();75 76  ClangdLSPServer(const ClangdLSPServer &other) = delete;77  ClangdLSPServer &operator=(const ClangdLSPServer &other) = delete;78 79  /// Run LSP server loop, communicating with the Transport provided in the80  /// constructor. This method must not be executed more than once.81  ///82  /// \return Whether we shut down cleanly with a 'shutdown' -> 'exit' sequence.83  bool run();84 85  /// Profiles resource-usage.86  void profile(MemoryTree &MT) const;87 88private:89  // Implement ClangdServer::Callbacks.90  void onDiagnosticsReady(PathRef File, llvm::StringRef Version,91                          llvm::ArrayRef<Diag> Diagnostics) override;92  void onFileUpdated(PathRef File, const TUStatus &Status) override;93  void onBackgroundIndexProgress(const BackgroundQueue::Stats &Stats) override;94  void onSemanticsMaybeChanged(PathRef File) override;95  void onInactiveRegionsReady(PathRef File,96                              std::vector<Range> InactiveRegions) override;97 98  // LSP methods. Notifications have signature void(const Params&).99  // Calls have signature void(const Params&, Callback<Response>).100  void onInitialize(const InitializeParams &, Callback<llvm::json::Value>);101  void onInitialized(const InitializedParams &);102  void onShutdown(const NoParams &, Callback<std::nullptr_t>);103  void onSync(const NoParams &, Callback<std::nullptr_t>);104  void onDocumentDidOpen(const DidOpenTextDocumentParams &);105  void onDocumentDidChange(const DidChangeTextDocumentParams &);106  void onDocumentDidClose(const DidCloseTextDocumentParams &);107  void onDocumentDidSave(const DidSaveTextDocumentParams &);108  void onAST(const ASTParams &, Callback<std::optional<ASTNode>>);109  void onDocumentOnTypeFormatting(const DocumentOnTypeFormattingParams &,110                                  Callback<std::vector<TextEdit>>);111  void onDocumentRangeFormatting(const DocumentRangeFormattingParams &,112                                 Callback<std::vector<TextEdit>>);113  void onDocumentRangesFormatting(const DocumentRangesFormattingParams &,114                                  Callback<std::vector<TextEdit>>);115  void onDocumentFormatting(const DocumentFormattingParams &,116                            Callback<std::vector<TextEdit>>);117  // The results are serialized 'vector<DocumentSymbol>' if118  // SupportsHierarchicalDocumentSymbol is true and 'vector<SymbolInformation>'119  // otherwise.120  void onDocumentSymbol(const DocumentSymbolParams &,121                        Callback<llvm::json::Value>);122  void onFoldingRange(const FoldingRangeParams &,123                      Callback<std::vector<FoldingRange>>);124  void onCodeAction(const CodeActionParams &, Callback<llvm::json::Value>);125  void onCompletion(const CompletionParams &, Callback<CompletionList>);126  void onSignatureHelp(const TextDocumentPositionParams &,127                       Callback<SignatureHelp>);128  void onGoToDeclaration(const TextDocumentPositionParams &,129                         Callback<std::vector<Location>>);130  void onGoToDefinition(const TextDocumentPositionParams &,131                        Callback<std::vector<Location>>);132  void onGoToType(const TextDocumentPositionParams &,133                  Callback<std::vector<Location>>);134  void onGoToImplementation(const TextDocumentPositionParams &,135                            Callback<std::vector<Location>>);136  void onReference(const ReferenceParams &, Callback<std::vector<ReferenceLocation>>);137  void onSwitchSourceHeader(const TextDocumentIdentifier &,138                            Callback<std::optional<URIForFile>>);139  void onDocumentHighlight(const TextDocumentPositionParams &,140                           Callback<std::vector<DocumentHighlight>>);141  void onFileEvent(const DidChangeWatchedFilesParams &);142  void onWorkspaceSymbol(const WorkspaceSymbolParams &,143                         Callback<std::vector<SymbolInformation>>);144  void onPrepareRename(const TextDocumentPositionParams &,145                       Callback<PrepareRenameResult>);146  void onRename(const RenameParams &, Callback<WorkspaceEdit>);147  void onHover(const TextDocumentPositionParams &,148               Callback<std::optional<Hover>>);149  void onPrepareTypeHierarchy(const TypeHierarchyPrepareParams &,150                              Callback<std::vector<TypeHierarchyItem>>);151  void onSuperTypes(const ResolveTypeHierarchyItemParams &,152                    Callback<std::optional<std::vector<TypeHierarchyItem>>>);153  void onSubTypes(const ResolveTypeHierarchyItemParams &,154                  Callback<std::vector<TypeHierarchyItem>>);155  void onTypeHierarchy(const TypeHierarchyPrepareParams &,156                       Callback<llvm::json::Value>);157  void onResolveTypeHierarchy(const ResolveTypeHierarchyItemParams &,158                              Callback<llvm::json::Value>);159  void onPrepareCallHierarchy(const CallHierarchyPrepareParams &,160                              Callback<std::vector<CallHierarchyItem>>);161  void onCallHierarchyIncomingCalls(162      const CallHierarchyIncomingCallsParams &,163      Callback<std::vector<CallHierarchyIncomingCall>>);164  void onCallHierarchyOutgoingCalls(165      const CallHierarchyOutgoingCallsParams &,166      Callback<std::vector<CallHierarchyOutgoingCall>>);167  void onClangdInlayHints(const InlayHintsParams &,168                          Callback<llvm::json::Value>);169  void onInlayHint(const InlayHintsParams &, Callback<std::vector<InlayHint>>);170  void onChangeConfiguration(const DidChangeConfigurationParams &);171  void onSymbolInfo(const TextDocumentPositionParams &,172                    Callback<std::vector<SymbolDetails>>);173  void onSelectionRange(const SelectionRangeParams &,174                        Callback<std::vector<SelectionRange>>);175  void onDocumentLink(const DocumentLinkParams &,176                      Callback<std::vector<DocumentLink>>);177  void onSemanticTokens(const SemanticTokensParams &, Callback<SemanticTokens>);178  void onSemanticTokensDelta(const SemanticTokensDeltaParams &,179                             Callback<SemanticTokensOrDelta>);180  /// This is a clangd extension. Provides a json tree representing memory usage181  /// hierarchy.182  void onMemoryUsage(const NoParams &, Callback<MemoryTree>);183  void onCommand(const ExecuteCommandParams &, Callback<llvm::json::Value>);184 185  /// Implement commands.186  void onCommandApplyEdit(const WorkspaceEdit &, Callback<llvm::json::Value>);187  void onCommandApplyTweak(const TweakArgs &, Callback<llvm::json::Value>);188  void onCommandApplyRename(const RenameParams &, Callback<llvm::json::Value>);189 190  /// Outgoing LSP calls.191  LSPBinder::OutgoingMethod<ApplyWorkspaceEditParams,192                            ApplyWorkspaceEditResponse>193      ApplyWorkspaceEdit;194  LSPBinder::OutgoingNotification<ShowMessageParams> ShowMessage;195  LSPBinder::OutgoingNotification<PublishDiagnosticsParams> PublishDiagnostics;196  LSPBinder::OutgoingNotification<FileStatus> NotifyFileStatus;197  LSPBinder::OutgoingNotification<InactiveRegionsParams> PublishInactiveRegions;198  LSPBinder::OutgoingMethod<WorkDoneProgressCreateParams, std::nullptr_t>199      CreateWorkDoneProgress;200  LSPBinder::OutgoingNotification<ProgressParams<WorkDoneProgressBegin>>201      BeginWorkDoneProgress;202  LSPBinder::OutgoingNotification<ProgressParams<WorkDoneProgressReport>>203      ReportWorkDoneProgress;204  LSPBinder::OutgoingNotification<ProgressParams<WorkDoneProgressEnd>>205      EndWorkDoneProgress;206  LSPBinder::OutgoingMethod<NoParams, std::nullptr_t> SemanticTokensRefresh;207 208  void applyEdit(WorkspaceEdit WE, llvm::json::Value Success,209                 Callback<llvm::json::Value> Reply);210 211  void bindMethods(LSPBinder &, const ClientCapabilities &Caps);212  std::optional<ClangdServer::DiagRef> getDiagRef(StringRef File,213                                                  const clangd::Diagnostic &D);214 215  /// Checks if completion request should be ignored. We need this due to the216  /// limitation of the LSP. Per LSP, a client sends requests for all "trigger217  /// character" we specify, but for '>' and ':' we need to check they actually218  /// produce '->' and '::', respectively.219  bool shouldRunCompletion(const CompletionParams &Params) const;220 221  void applyConfiguration(const ConfigurationSettings &Settings);222 223  /// Runs profiling and exports memory usage metrics if tracing is enabled and224  /// profiling hasn't happened recently.225  void maybeExportMemoryProfile();226  PeriodicThrottler ShouldProfile;227 228  /// Run the MemoryCleanup callback if it's time.229  /// This method is thread safe.230  void maybeCleanupMemory();231  PeriodicThrottler ShouldCleanupMemory;232 233  /// Since initialization of CDBs and ClangdServer is done lazily, the234  /// following context captures the one used while creating ClangdLSPServer and235  /// passes it to above mentioned object instances to make sure they share the236  /// same state.237  Context BackgroundContext;238 239  /// Used to indicate that the 'shutdown' request was received from the240  /// Language Server client.241  bool ShutdownRequestReceived = false;242 243  /// Used to indicate the ClangdLSPServer is being destroyed.244  std::atomic<bool> IsBeingDestroyed = {false};245 246  // FIXME: The caching is a temporary solution to get corresponding clangd 247  // diagnostic from a LSP diagnostic.248  // Ideally, ClangdServer can generate an identifier for each diagnostic,249  // emit them via the LSP's data field (which was newly added in LSP 3.16).250  std::mutex DiagRefMutex;251  struct DiagKey {252    clangd::Range Rng;253    std::string Message;254    bool operator<(const DiagKey &Other) const {255      return std::tie(Rng, Message) < std::tie(Other.Rng, Other.Message);256    }257  };258  DiagKey toDiagKey(const clangd::Diagnostic &LSPDiag) {259    return {LSPDiag.range, LSPDiag.message};260  }261  /// A map from LSP diagnostic to clangd-naive diagnostic.262  typedef std::map<DiagKey, ClangdServer::DiagRef>263      DiagnosticToDiagRefMap;264  /// Caches the mapping LSP and clangd-naive diagnostics per file.265  llvm::StringMap<DiagnosticToDiagRefMap>266      DiagRefMap;267 268  // Last semantic-tokens response, for incremental requests.269  std::mutex SemanticTokensMutex;270  llvm::StringMap<SemanticTokens> LastSemanticTokens;271 272  // Most code should not deal with Transport, callMethod, notify directly.273  // Use LSPBinder to handle incoming and outgoing calls.274  clangd::Transport &Transp;275  class MessageHandler;276  std::unique_ptr<MessageHandler> MsgHandler;277  std::mutex TranspWriter;278 279  void callMethod(StringRef Method, llvm::json::Value Params,280                  Callback<llvm::json::Value> CB) override;281  void notify(StringRef Method, llvm::json::Value Params) override;282 283  LSPBinder::RawHandlers Handlers;284 285  const ThreadsafeFS &TFS;286  /// Options used for diagnostics.287  ClangdDiagnosticOptions DiagOpts;288  /// The supported kinds of the client.289  SymbolKindBitset SupportedSymbolKinds;290  /// The supported completion item kinds of the client.291  CompletionItemKindBitset SupportedCompletionItemKinds;292  // Whether the client supports CompletionItem.labelDetails.293  bool SupportsCompletionLabelDetails = false;294  /// Whether the client supports CodeAction response objects.295  bool SupportsCodeAction = false;296  /// From capabilities of textDocument/documentSymbol.297  bool SupportsHierarchicalDocumentSymbol = false;298  /// Whether the client supports showing file status.299  bool SupportFileStatus = false;300  /// Whether the client supports attaching a container string to references.301  bool SupportsReferenceContainer = false;302  /// Which kind of markup should we use in textDocument/hover responses.303  MarkupKind HoverContentFormat = MarkupKind::PlainText;304  /// Whether the client supports offsets for parameter info labels.305  bool SupportsOffsetsInSignatureHelp = false;306  /// Whether the client supports the versioned document changes.307  bool SupportsDocumentChanges = false;308  /// Whether the client supports change annotations on text edits.309  bool SupportsChangeAnnotation = false;310 311  std::mutex BackgroundIndexProgressMutex;312  enum class BackgroundIndexProgress {313    // Client doesn't support reporting progress. No transitions possible.314    Unsupported,315    // The queue is idle, and the client has no progress bar.316    // Can transition to Creating when we have some activity.317    Empty,318    // We've requested the client to create a progress bar.319    // Meanwhile, the state is buffered in PendingBackgroundIndexProgress.320    Creating,321    // The client has a progress bar, and we can send it updates immediately.322    Live,323  } BackgroundIndexProgressState = BackgroundIndexProgress::Unsupported;324  // The progress to send when the progress bar is created.325  // Only valid in state Creating.326  BackgroundQueue::Stats PendingBackgroundIndexProgress;327  /// LSP extension: skip WorkDoneProgressCreate, just send progress streams.328  bool BackgroundIndexSkipCreate = false;329 330  Options Opts;331  // The CDB is created by the "initialize" LSP method.332  std::unique_ptr<GlobalCompilationDatabase> BaseCDB;333  // CDB is BaseCDB plus any commands overridden via LSP extensions.334  std::optional<OverlayCDB> CDB;335  // The ClangdServer is created by the "initialize" LSP method.336  std::optional<ClangdServer> Server;337  // Manages to build module files.338  std::optional<ModulesBuilder> ModulesManager;339};340} // namespace clangd341} // namespace clang342 343#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H344