1 //===--- ClangdServer.h - Main clangd server code ----------------*- 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_CLANGDSERVER_H 10 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H 11 12 #include "../clang-tidy/ClangTidyOptions.h" 13 #include "CodeComplete.h" 14 #include "ConfigProvider.h" 15 #include "GlobalCompilationDatabase.h" 16 #include "Hover.h" 17 #include "Protocol.h" 18 #include "SemanticHighlighting.h" 19 #include "TUScheduler.h" 20 #include "XRefs.h" 21 #include "index/Background.h" 22 #include "index/FileIndex.h" 23 #include "index/Index.h" 24 #include "refactor/Rename.h" 25 #include "refactor/Tweak.h" 26 #include "support/Cancellation.h" 27 #include "support/Function.h" 28 #include "support/MemoryTree.h" 29 #include "support/ThreadsafeFS.h" 30 #include "clang/Tooling/CompilationDatabase.h" 31 #include "clang/Tooling/Core/Replacement.h" 32 #include "llvm/ADT/FunctionExtras.h" 33 #include "llvm/ADT/IntrusiveRefCntPtr.h" 34 #include "llvm/ADT/Optional.h" 35 #include "llvm/ADT/StringRef.h" 36 #include <functional> 37 #include <future> 38 #include <string> 39 #include <type_traits> 40 #include <utility> 41 42 namespace clang { 43 namespace clangd { 44 /// Manages a collection of source files and derived data (ASTs, indexes), 45 /// and provides language-aware features such as code completion. 46 /// 47 /// The primary client is ClangdLSPServer which exposes these features via 48 /// the Language Server protocol. ClangdServer may also be embedded directly, 49 /// though its API is not stable over time. 50 /// 51 /// ClangdServer should be used from a single thread. Many potentially-slow 52 /// operations have asynchronous APIs and deliver their results on another 53 /// thread. 54 /// Such operations support cancellation: if the caller sets up a cancelable 55 /// context, many operations will notice cancellation and fail early. 56 /// (ClangdLSPServer uses this to implement $/cancelRequest). 57 class ClangdServer { 58 public: 59 /// Interface with hooks for users of ClangdServer to be notified of events. 60 class Callbacks { 61 public: 62 virtual ~Callbacks() = default; 63 64 /// Called by ClangdServer when \p Diagnostics for \p File are ready. 65 /// May be called concurrently for separate files, not for a single file. onDiagnosticsReady(PathRef File,llvm::StringRef Version,std::vector<Diag> Diagnostics)66 virtual void onDiagnosticsReady(PathRef File, llvm::StringRef Version, 67 std::vector<Diag> Diagnostics) {} 68 /// Called whenever the file status is updated. 69 /// May be called concurrently for separate files, not for a single file. onFileUpdated(PathRef File,const TUStatus & Status)70 virtual void onFileUpdated(PathRef File, const TUStatus &Status) {} 71 72 /// Called by ClangdServer when some \p Highlightings for \p File are ready. 73 /// May be called concurrently for separate files, not for a single file. 74 virtual void onHighlightingsReady(PathRef File,llvm::StringRef Version,std::vector<HighlightingToken> Highlightings)75 onHighlightingsReady(PathRef File, llvm::StringRef Version, 76 std::vector<HighlightingToken> Highlightings) {} 77 78 /// Called when background indexing tasks are enqueued/started/completed. 79 /// Not called concurrently. 80 virtual void onBackgroundIndexProgress(const BackgroundQueue::Stats & Stats)81 onBackgroundIndexProgress(const BackgroundQueue::Stats &Stats) {} 82 }; 83 84 struct Options { 85 /// To process requests asynchronously, ClangdServer spawns worker threads. 86 /// If this is zero, no threads are spawned. All work is done on the calling 87 /// thread, and callbacks are invoked before "async" functions return. 88 unsigned AsyncThreadsCount = getDefaultAsyncThreadsCount(); 89 90 /// AST caching policy. The default is to keep up to 3 ASTs in memory. 91 ASTRetentionPolicy RetentionPolicy; 92 93 /// Cached preambles are potentially large. If false, store them on disk. 94 bool StorePreamblesInMemory = true; 95 /// Reuse even stale preambles, and rebuild them in the background. 96 /// This improves latency at the cost of accuracy. 97 bool AsyncPreambleBuilds = true; 98 99 /// If true, ClangdServer builds a dynamic in-memory index for symbols in 100 /// opened files and uses the index to augment code completion results. 101 bool BuildDynamicSymbolIndex = false; 102 /// Use a heavier and faster in-memory index implementation. 103 bool HeavyweightDynamicSymbolIndex = true; 104 /// If true, ClangdServer automatically indexes files in the current project 105 /// on background threads. The index is stored in the project root. 106 bool BackgroundIndex = false; 107 108 /// Store refs to main-file symbols in the index. 109 bool CollectMainFileRefs = true; 110 111 /// If set, use this index to augment code completion results. 112 SymbolIndex *StaticIndex = nullptr; 113 114 /// If set, queried to obtain the configuration to handle each request. 115 config::Provider *ConfigProvider = nullptr; 116 117 /// The Options provider to use when running clang-tidy. If null, clang-tidy 118 /// checks will be disabled. 119 TidyProviderRef ClangTidyProvider; 120 121 /// If true, force -frecovery-ast flag. 122 /// If false, respect the value in clang. 123 bool BuildRecoveryAST = false; 124 125 /// If true, force -frecovery-ast-type flag. 126 /// If false, respect the value in clang. 127 bool PreserveRecoveryASTType = false; 128 129 /// Clangd's workspace root. Relevant for "workspace" operations not bound 130 /// to a particular file. 131 /// FIXME: If not set, should use the current working directory. 132 llvm::Optional<std::string> WorkspaceRoot; 133 134 /// The resource directory is used to find internal headers, overriding 135 /// defaults and -resource-dir compiler flag). 136 /// If None, ClangdServer calls CompilerInvocation::GetResourcePath() to 137 /// obtain the standard resource directory. 138 llvm::Optional<std::string> ResourceDir = llvm::None; 139 140 /// Time to wait after a new file version before computing diagnostics. 141 DebouncePolicy UpdateDebounce = DebouncePolicy{ 142 /*Min=*/std::chrono::milliseconds(50), 143 /*Max=*/std::chrono::milliseconds(500), 144 /*RebuildRatio=*/1, 145 }; 146 147 bool SuggestMissingIncludes = false; 148 149 /// Clangd will execute compiler drivers matching one of these globs to 150 /// fetch system include path. 151 std::vector<std::string> QueryDriverGlobs; 152 153 /// Enable notification-based semantic highlighting. 154 bool TheiaSemanticHighlighting = false; 155 156 /// Enable preview of FoldingRanges feature. 157 bool FoldingRanges = false; 158 159 explicit operator TUScheduler::Options() const; 160 }; 161 // Sensible default options for use in tests. 162 // Features like indexing must be enabled if desired. 163 static Options optsForTest(); 164 165 /// Creates a new ClangdServer instance. 166 /// 167 /// ClangdServer uses \p CDB to obtain compilation arguments for parsing. Note 168 /// that ClangdServer only obtains compilation arguments once for each newly 169 /// added file (i.e., when processing a first call to addDocument) and reuses 170 /// those arguments for subsequent reparses. However, ClangdServer will check 171 /// if compilation arguments changed on calls to forceReparse(). 172 ClangdServer(const GlobalCompilationDatabase &CDB, const ThreadsafeFS &TFS, 173 const Options &Opts, Callbacks *Callbacks = nullptr); 174 175 /// Add a \p File to the list of tracked C++ files or update the contents if 176 /// \p File is already tracked. Also schedules parsing of the AST for it on a 177 /// separate thread. When the parsing is complete, DiagConsumer passed in 178 /// constructor will receive onDiagnosticsReady callback. 179 /// Version identifies this snapshot and is propagated to ASTs, preambles, 180 /// diagnostics etc built from it. 181 void addDocument(PathRef File, StringRef Contents, 182 llvm::StringRef Version = "null", 183 WantDiagnostics WD = WantDiagnostics::Auto, 184 bool ForceRebuild = false); 185 186 /// Remove \p File from list of tracked files, schedule a request to free 187 /// resources associated with it. Pending diagnostics for closed files may not 188 /// be delivered, even if requested with WantDiags::Auto or WantDiags::Yes. 189 /// An empty set of diagnostics will be delivered, with Version = "". 190 void removeDocument(PathRef File); 191 192 /// Run code completion for \p File at \p Pos. 193 /// Request is processed asynchronously. 194 /// 195 /// This method should only be called for currently tracked files. However, it 196 /// is safe to call removeDocument for \p File after this method returns, even 197 /// while returned future is not yet ready. 198 /// A version of `codeComplete` that runs \p Callback on the processing thread 199 /// when codeComplete results become available. 200 void codeComplete(PathRef File, Position Pos, 201 const clangd::CodeCompleteOptions &Opts, 202 Callback<CodeCompleteResult> CB); 203 204 /// Provide signature help for \p File at \p Pos. This method should only be 205 /// called for tracked files. 206 void signatureHelp(PathRef File, Position Pos, Callback<SignatureHelp> CB); 207 208 /// Find declaration/definition locations of symbol at a specified position. 209 void locateSymbolAt(PathRef File, Position Pos, 210 Callback<std::vector<LocatedSymbol>> CB); 211 212 /// Switch to a corresponding source file when given a header file, and vice 213 /// versa. 214 void switchSourceHeader(PathRef Path, 215 Callback<llvm::Optional<clangd::Path>> CB); 216 217 /// Get document highlights for a given position. 218 void findDocumentHighlights(PathRef File, Position Pos, 219 Callback<std::vector<DocumentHighlight>> CB); 220 221 /// Get code hover for a given position. 222 void findHover(PathRef File, Position Pos, 223 Callback<llvm::Optional<HoverInfo>> CB); 224 225 /// Get information about type hierarchy for a given position. 226 void typeHierarchy(PathRef File, Position Pos, int Resolve, 227 TypeHierarchyDirection Direction, 228 Callback<llvm::Optional<TypeHierarchyItem>> CB); 229 230 /// Resolve type hierarchy item in the given direction. 231 void resolveTypeHierarchy(TypeHierarchyItem Item, int Resolve, 232 TypeHierarchyDirection Direction, 233 Callback<llvm::Optional<TypeHierarchyItem>> CB); 234 235 /// Get information about call hierarchy for a given position. 236 void prepareCallHierarchy(PathRef File, Position Pos, 237 Callback<std::vector<CallHierarchyItem>> CB); 238 239 /// Resolve incoming calls for a given call hierarchy item. 240 void incomingCalls(const CallHierarchyItem &Item, 241 Callback<std::vector<CallHierarchyIncomingCall>>); 242 243 /// Retrieve the top symbols from the workspace matching a query. 244 void workspaceSymbols(StringRef Query, int Limit, 245 Callback<std::vector<SymbolInformation>> CB); 246 247 /// Retrieve the symbols within the specified file. 248 void documentSymbols(StringRef File, 249 Callback<std::vector<DocumentSymbol>> CB); 250 251 /// Retrieve ranges that can be used to fold code within the specified file. 252 void foldingRanges(StringRef File, Callback<std::vector<FoldingRange>> CB); 253 254 /// Retrieve implementations for virtual method. 255 void findImplementations(PathRef File, Position Pos, 256 Callback<std::vector<LocatedSymbol>> CB); 257 258 /// Retrieve locations for symbol references. 259 void findReferences(PathRef File, Position Pos, uint32_t Limit, 260 Callback<ReferencesResult> CB); 261 262 /// Run formatting for \p Rng inside \p File with content \p Code. 263 void formatRange(PathRef File, StringRef Code, Range Rng, 264 Callback<tooling::Replacements> CB); 265 266 /// Run formatting for the whole \p File with content \p Code. 267 void formatFile(PathRef File, StringRef Code, 268 Callback<tooling::Replacements> CB); 269 270 /// Run formatting after \p TriggerText was typed at \p Pos in \p File with 271 /// content \p Code. 272 void formatOnType(PathRef File, StringRef Code, Position Pos, 273 StringRef TriggerText, Callback<std::vector<TextEdit>> CB); 274 275 /// Test the validity of a rename operation. 276 /// 277 /// If NewName is provided, it performs a name validation. 278 void prepareRename(PathRef File, Position Pos, 279 llvm::Optional<std::string> NewName, 280 const RenameOptions &RenameOpts, 281 Callback<RenameResult> CB); 282 283 /// Rename all occurrences of the symbol at the \p Pos in \p File to 284 /// \p NewName. 285 /// If WantFormat is false, the final TextEdit will be not formatted, 286 /// embedders could use this method to get all occurrences of the symbol (e.g. 287 /// highlighting them in prepare stage). 288 void rename(PathRef File, Position Pos, llvm::StringRef NewName, 289 const RenameOptions &Opts, Callback<RenameResult> CB); 290 291 struct TweakRef { 292 std::string ID; /// ID to pass for applyTweak. 293 std::string Title; /// A single-line message to show in the UI. 294 llvm::StringLiteral Kind; 295 }; 296 /// Enumerate the code tweaks available to the user at a specified point. 297 /// Tweaks where Filter returns false will not be checked or included. 298 void enumerateTweaks(PathRef File, Range Sel, 299 llvm::unique_function<bool(const Tweak &)> Filter, 300 Callback<std::vector<TweakRef>> CB); 301 302 /// Apply the code tweak with a specified \p ID. 303 void applyTweak(PathRef File, Range Sel, StringRef ID, 304 Callback<Tweak::Effect> CB); 305 306 /// Called when an event occurs for a watched file in the workspace. 307 void onFileEvent(const DidChangeWatchedFilesParams &Params); 308 309 /// Get symbol info for given position. 310 /// Clangd extension - not part of official LSP. 311 void symbolInfo(PathRef File, Position Pos, 312 Callback<std::vector<SymbolDetails>> CB); 313 314 /// Get semantic ranges around a specified position in a file. 315 void semanticRanges(PathRef File, const std::vector<Position> &Pos, 316 Callback<std::vector<SelectionRange>> CB); 317 318 /// Get all document links in a file. 319 void documentLinks(PathRef File, Callback<std::vector<DocumentLink>> CB); 320 321 void semanticHighlights(PathRef File, 322 Callback<std::vector<HighlightingToken>>); 323 324 /// Describe the AST subtree for a piece of code. 325 void getAST(PathRef File, Range R, Callback<llvm::Optional<ASTNode>> CB); 326 327 /// Runs an arbitrary action that has access to the AST of the specified file. 328 /// The action will execute on one of ClangdServer's internal threads. 329 /// The AST is only valid for the duration of the callback. 330 /// As with other actions, the file must have been opened. 331 void customAction(PathRef File, llvm::StringRef Name, 332 Callback<InputsAndAST> Action); 333 334 /// Returns estimated memory usage and other statistics for each of the 335 /// currently open files. 336 /// Overall memory usage of clangd may be significantly more than reported 337 /// here, as this metric does not account (at least) for: 338 /// - memory occupied by static and dynamic index, 339 /// - memory required for in-flight requests, 340 /// FIXME: those metrics might be useful too, we should add them. 341 llvm::StringMap<TUScheduler::FileStats> fileStats() const; 342 343 // Blocks the main thread until the server is idle. Only for use in tests. 344 // Returns false if the timeout expires. 345 LLVM_NODISCARD bool 346 blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds = 10); 347 348 /// Builds a nested representation of memory used by components. 349 void profile(MemoryTree &MT) const; 350 351 private: 352 void formatCode(PathRef File, llvm::StringRef Code, 353 ArrayRef<tooling::Range> Ranges, 354 Callback<tooling::Replacements> CB); 355 356 /// Derives a context for a task processing the specified source file. 357 /// This includes the current configuration (see Options::ConfigProvider). 358 /// The empty string means no particular file is the target. 359 /// Rather than called by each feature, this is exposed to the components 360 /// that control worker threads, like TUScheduler and BackgroundIndex. 361 /// This means it's OK to do some IO here, and it cuts across all features. 362 Context createProcessingContext(PathRef) const; 363 config::Provider *ConfigProvider = nullptr; 364 365 const ThreadsafeFS &TFS; 366 Callbacks *ServerCallbacks = nullptr; 367 mutable std::mutex ConfigDiagnosticsMu; 368 369 Path ResourceDir; 370 // The index used to look up symbols. This could be: 371 // - null (all index functionality is optional) 372 // - the dynamic index owned by ClangdServer (DynamicIdx) 373 // - the static index passed to the constructor 374 // - a merged view of a static and dynamic index (MergedIndex) 375 const SymbolIndex *Index = nullptr; 376 // If present, an index of symbols in open files. Read via *Index. 377 std::unique_ptr<FileIndex> DynamicIdx; 378 // If present, the new "auto-index" maintained in background threads. 379 std::unique_ptr<BackgroundIndex> BackgroundIdx; 380 // Storage for merged views of the various indexes. 381 std::vector<std::unique_ptr<SymbolIndex>> MergedIdx; 382 383 // When set, provides clang-tidy options for a specific file. 384 TidyProviderRef ClangTidyProvider; 385 386 // If this is true, suggest include insertion fixes for diagnostic errors that 387 // can be caused by missing includes (e.g. member access in incomplete type). 388 bool SuggestMissingIncludes = false; 389 390 // If true, preserve expressions in AST for broken code. 391 bool BuildRecoveryAST = true; 392 // If true, preserve the type for recovery AST. 393 bool PreserveRecoveryASTType = false; 394 395 // GUARDED_BY(CachedCompletionFuzzyFindRequestMutex) 396 llvm::StringMap<llvm::Optional<FuzzyFindRequest>> 397 CachedCompletionFuzzyFindRequestByFile; 398 mutable std::mutex CachedCompletionFuzzyFindRequestMutex; 399 400 llvm::Optional<std::string> WorkspaceRoot; 401 // WorkScheduler has to be the last member, because its destructor has to be 402 // called before all other members to stop the worker thread that references 403 // ClangdServer. 404 TUScheduler WorkScheduler; 405 }; 406 407 } // namespace clangd 408 } // namespace clang 409 410 #endif 411