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 "CodeComplete.h"
13 #include "ConfigProvider.h"
14 #include "Diagnostics.h"
15 #include "DraftStore.h"
16 #include "FeatureModule.h"
17 #include "GlobalCompilationDatabase.h"
18 #include "Hover.h"
19 #include "Protocol.h"
20 #include "SemanticHighlighting.h"
21 #include "TUScheduler.h"
22 #include "XRefs.h"
23 #include "index/Background.h"
24 #include "index/FileIndex.h"
25 #include "index/Index.h"
26 #include "refactor/Rename.h"
27 #include "refactor/Tweak.h"
28 #include "support/Function.h"
29 #include "support/MemoryTree.h"
30 #include "support/Path.h"
31 #include "support/ThreadsafeFS.h"
32 #include "clang/Tooling/Core/Replacement.h"
33 #include "llvm/ADT/FunctionExtras.h"
34 #include "llvm/ADT/Optional.h"
35 #include "llvm/ADT/StringRef.h"
36 #include <functional>
37 #include <memory>
38 #include <string>
39 #include <type_traits>
40 #include <utility>
41 #include <vector>
42 
43 namespace clang {
44 namespace clangd {
45 /// Manages a collection of source files and derived data (ASTs, indexes),
46 /// and provides language-aware features such as code completion.
47 ///
48 /// The primary client is ClangdLSPServer which exposes these features via
49 /// the Language Server protocol. ClangdServer may also be embedded directly,
50 /// though its API is not stable over time.
51 ///
52 /// ClangdServer should be used from a single thread. Many potentially-slow
53 /// operations have asynchronous APIs and deliver their results on another
54 /// thread.
55 /// Such operations support cancellation: if the caller sets up a cancelable
56 /// context, many operations will notice cancellation and fail early.
57 /// (ClangdLSPServer uses this to implement $/cancelRequest).
58 class ClangdServer {
59 public:
60   /// Interface with hooks for users of ClangdServer to be notified of events.
61   class Callbacks {
62   public:
63     virtual ~Callbacks() = default;
64 
65     /// Called by ClangdServer when \p Diagnostics for \p File are ready.
66     /// These pushed diagnostics might correspond to an older version of the
67     /// file, they do not interfere with "pull-based" ClangdServer::diagnostics.
68     /// May be called concurrently for separate files, not for a single file.
onDiagnosticsReady(PathRef File,llvm::StringRef Version,std::vector<Diag> Diagnostics)69     virtual void onDiagnosticsReady(PathRef File, llvm::StringRef Version,
70                                     std::vector<Diag> Diagnostics) {}
71     /// Called whenever the file status is updated.
72     /// May be called concurrently for separate files, not for a single file.
onFileUpdated(PathRef File,const TUStatus & Status)73     virtual void onFileUpdated(PathRef File, const TUStatus &Status) {}
74 
75     /// Called when background indexing tasks are enqueued/started/completed.
76     /// Not called concurrently.
77     virtual void
onBackgroundIndexProgress(const BackgroundQueue::Stats & Stats)78     onBackgroundIndexProgress(const BackgroundQueue::Stats &Stats) {}
79 
80     /// Called when the meaning of a source code may have changed without an
81     /// edit. Usually clients assume that responses to requests are valid until
82     /// they next edit the file. If they're invalidated at other times, we
83     /// should tell the client. In particular, when an asynchronous preamble
84     /// build finishes, we can provide more accurate semantic tokens, so we
85     /// should tell the client to refresh.
onSemanticsMaybeChanged(PathRef File)86     virtual void onSemanticsMaybeChanged(PathRef File) {}
87   };
88   /// Creates a context provider that loads and installs config.
89   /// Errors in loading config are reported as diagnostics via Callbacks.
90   /// (This is typically used as ClangdServer::Options::ContextProvider).
91   static std::function<Context(PathRef)>
92   createConfiguredContextProvider(const config::Provider *Provider,
93                                   ClangdServer::Callbacks *);
94 
95   struct Options {
96     /// To process requests asynchronously, ClangdServer spawns worker threads.
97     /// If this is zero, no threads are spawned. All work is done on the calling
98     /// thread, and callbacks are invoked before "async" functions return.
99     unsigned AsyncThreadsCount = getDefaultAsyncThreadsCount();
100 
101     /// AST caching policy. The default is to keep up to 3 ASTs in memory.
102     ASTRetentionPolicy RetentionPolicy;
103 
104     /// Cached preambles are potentially large. If false, store them on disk.
105     bool StorePreamblesInMemory = true;
106 
107     /// This throttler controls which preambles may be built at a given time.
108     clangd::PreambleThrottler *PreambleThrottler = nullptr;
109 
110     /// If true, ClangdServer builds a dynamic in-memory index for symbols in
111     /// opened files and uses the index to augment code completion results.
112     bool BuildDynamicSymbolIndex = false;
113     /// If true, ClangdServer automatically indexes files in the current project
114     /// on background threads. The index is stored in the project root.
115     bool BackgroundIndex = false;
116     llvm::ThreadPriority BackgroundIndexPriority = llvm::ThreadPriority::Low;
117 
118     /// If set, use this index to augment code completion results.
119     SymbolIndex *StaticIndex = nullptr;
120 
121     /// If set, queried to derive a processing context for some work.
122     /// Usually used to inject Config (see createConfiguredContextProvider).
123     ///
124     /// When the provider is called, the active context will be that inherited
125     /// from the request (e.g. addDocument()), or from the ClangdServer
126     /// constructor if there is no such request (e.g. background indexing).
127     ///
128     /// The path is an absolute path of the file being processed.
129     /// If there is no particular file (e.g. project loading) then it is empty.
130     std::function<Context(PathRef)> ContextProvider;
131 
132     /// The Options provider to use when running clang-tidy. If null, clang-tidy
133     /// checks will be disabled.
134     TidyProviderRef ClangTidyProvider;
135 
136     /// Clangd's workspace root. Relevant for "workspace" operations not bound
137     /// to a particular file.
138     /// FIXME: If not set, should use the current working directory.
139     llvm::Optional<std::string> WorkspaceRoot;
140 
141     /// The resource directory is used to find internal headers, overriding
142     /// defaults and -resource-dir compiler flag).
143     /// If None, ClangdServer calls CompilerInvocation::GetResourcePath() to
144     /// obtain the standard resource directory.
145     llvm::Optional<std::string> ResourceDir = llvm::None;
146 
147     /// Time to wait after a new file version before computing diagnostics.
148     DebouncePolicy UpdateDebounce = DebouncePolicy{
149         /*Min=*/std::chrono::milliseconds(50),
150         /*Max=*/std::chrono::milliseconds(500),
151         /*RebuildRatio=*/1,
152     };
153 
154     /// Cancel certain requests if the file changes before they begin running.
155     /// This is useful for "transient" actions like enumerateTweaks that were
156     /// likely implicitly generated, and avoids redundant work if clients forget
157     /// to cancel. Clients that always cancel stale requests should clear this.
158     bool ImplicitCancellation = true;
159 
160     /// Clangd will execute compiler drivers matching one of these globs to
161     /// fetch system include path.
162     std::vector<std::string> QueryDriverGlobs;
163 
164     /// Enable preview of FoldingRanges feature.
165     bool FoldingRanges = false;
166 
167     FeatureModuleSet *FeatureModules = nullptr;
168     /// If true, use the dirty buffer contents when building Preambles.
169     bool UseDirtyHeaders = false;
170 
171     // If true, parse emplace-like functions in the preamble.
172     bool PreambleParseForwardingFunctions = false;
173 
174     explicit operator TUScheduler::Options() const;
175   };
176   // Sensible default options for use in tests.
177   // Features like indexing must be enabled if desired.
178   static Options optsForTest();
179 
180   /// Creates a new ClangdServer instance.
181   ///
182   /// ClangdServer uses \p CDB to obtain compilation arguments for parsing. Note
183   /// that ClangdServer only obtains compilation arguments once for each newly
184   /// added file (i.e., when processing a first call to addDocument) and reuses
185   /// those arguments for subsequent reparses. However, ClangdServer will check
186   /// if compilation arguments changed on calls to forceReparse().
187   ClangdServer(const GlobalCompilationDatabase &CDB, const ThreadsafeFS &TFS,
188                const Options &Opts, Callbacks *Callbacks = nullptr);
189   ~ClangdServer();
190 
191   /// Gets the installed feature module of a given type, if any.
192   /// This exposes access the public interface of feature modules that have one.
featureModule()193   template <typename Mod> Mod *featureModule() {
194     return FeatureModules ? FeatureModules->get<Mod>() : nullptr;
195   }
featureModule()196   template <typename Mod> const Mod *featureModule() const {
197     return FeatureModules ? FeatureModules->get<Mod>() : nullptr;
198   }
199 
200   /// Add a \p File to the list of tracked C++ files or update the contents if
201   /// \p File is already tracked. Also schedules parsing of the AST for it on a
202   /// separate thread. When the parsing is complete, DiagConsumer passed in
203   /// constructor will receive onDiagnosticsReady callback.
204   /// Version identifies this snapshot and is propagated to ASTs, preambles,
205   /// diagnostics etc built from it. If empty, a version number is generated.
206   void addDocument(PathRef File, StringRef Contents,
207                    llvm::StringRef Version = "null",
208                    WantDiagnostics WD = WantDiagnostics::Auto,
209                    bool ForceRebuild = false);
210 
211   /// Remove \p File from list of tracked files, schedule a request to free
212   /// resources associated with it. Pending diagnostics for closed files may not
213   /// be delivered, even if requested with WantDiags::Auto or WantDiags::Yes.
214   /// An empty set of diagnostics will be delivered, with Version = "".
215   void removeDocument(PathRef File);
216 
217   /// Requests a reparse of currently opened files using their latest source.
218   /// This will typically only rebuild if something other than the source has
219   /// changed (e.g. the CDB yields different flags, or files included in the
220   /// preamble have been modified).
221   void reparseOpenFilesIfNeeded(
222       llvm::function_ref<bool(llvm::StringRef File)> Filter);
223 
224   /// Run code completion for \p File at \p Pos.
225   ///
226   /// This method should only be called for currently tracked files.
227   void codeComplete(PathRef File, Position Pos,
228                     const clangd::CodeCompleteOptions &Opts,
229                     Callback<CodeCompleteResult> CB);
230 
231   /// Provide signature help for \p File at \p Pos.  This method should only be
232   /// called for tracked files.
233   void signatureHelp(PathRef File, Position Pos, MarkupKind DocumentationFormat,
234                      Callback<SignatureHelp> CB);
235 
236   /// Find declaration/definition locations of symbol at a specified position.
237   void locateSymbolAt(PathRef File, Position Pos,
238                       Callback<std::vector<LocatedSymbol>> CB);
239 
240   /// Switch to a corresponding source file when given a header file, and vice
241   /// versa.
242   void switchSourceHeader(PathRef Path,
243                           Callback<llvm::Optional<clangd::Path>> CB);
244 
245   /// Get document highlights for a given position.
246   void findDocumentHighlights(PathRef File, Position Pos,
247                               Callback<std::vector<DocumentHighlight>> CB);
248 
249   /// Get code hover for a given position.
250   void findHover(PathRef File, Position Pos,
251                  Callback<llvm::Optional<HoverInfo>> CB);
252 
253   /// Get information about type hierarchy for a given position.
254   void typeHierarchy(PathRef File, Position Pos, int Resolve,
255                      TypeHierarchyDirection Direction,
256                      Callback<std::vector<TypeHierarchyItem>> CB);
257   /// Get direct parents of a type hierarchy item.
258   void superTypes(const TypeHierarchyItem &Item,
259                   Callback<llvm::Optional<std::vector<TypeHierarchyItem>>> CB);
260   /// Get direct children of a type hierarchy item.
261   void subTypes(const TypeHierarchyItem &Item,
262                 Callback<std::vector<TypeHierarchyItem>> CB);
263 
264   /// Resolve type hierarchy item in the given direction.
265   void resolveTypeHierarchy(TypeHierarchyItem Item, int Resolve,
266                             TypeHierarchyDirection Direction,
267                             Callback<llvm::Optional<TypeHierarchyItem>> CB);
268 
269   /// Get information about call hierarchy for a given position.
270   void prepareCallHierarchy(PathRef File, Position Pos,
271                             Callback<std::vector<CallHierarchyItem>> CB);
272 
273   /// Resolve incoming calls for a given call hierarchy item.
274   void incomingCalls(const CallHierarchyItem &Item,
275                      Callback<std::vector<CallHierarchyIncomingCall>>);
276 
277   /// Resolve inlay hints for a given document.
278   void inlayHints(PathRef File, llvm::Optional<Range> RestrictRange,
279                   Callback<std::vector<InlayHint>>);
280 
281   /// Retrieve the top symbols from the workspace matching a query.
282   void workspaceSymbols(StringRef Query, int Limit,
283                         Callback<std::vector<SymbolInformation>> CB);
284 
285   /// Retrieve the symbols within the specified file.
286   void documentSymbols(StringRef File,
287                        Callback<std::vector<DocumentSymbol>> CB);
288 
289   /// Retrieve ranges that can be used to fold code within the specified file.
290   void foldingRanges(StringRef File, Callback<std::vector<FoldingRange>> CB);
291 
292   /// Retrieve implementations for virtual method.
293   void findImplementations(PathRef File, Position Pos,
294                            Callback<std::vector<LocatedSymbol>> CB);
295 
296   /// Retrieve symbols for types referenced at \p Pos.
297   void findType(PathRef File, Position Pos,
298                 Callback<std::vector<LocatedSymbol>> CB);
299 
300   /// Retrieve locations for symbol references.
301   void findReferences(PathRef File, Position Pos, uint32_t Limit,
302                       Callback<ReferencesResult> CB);
303 
304   /// Run formatting for the \p File with content \p Code.
305   /// If \p Rng is non-null, formats only that region.
306   void formatFile(PathRef File, llvm::Optional<Range> Rng,
307                   Callback<tooling::Replacements> CB);
308 
309   /// Run formatting after \p TriggerText was typed at \p Pos in \p File with
310   /// content \p Code.
311   void formatOnType(PathRef File, Position Pos, StringRef TriggerText,
312                     Callback<std::vector<TextEdit>> CB);
313 
314   /// Test the validity of a rename operation.
315   ///
316   /// If NewName is provided, it performs a name validation.
317   void prepareRename(PathRef File, Position Pos,
318                      llvm::Optional<std::string> NewName,
319                      const RenameOptions &RenameOpts,
320                      Callback<RenameResult> CB);
321 
322   /// Rename all occurrences of the symbol at the \p Pos in \p File to
323   /// \p NewName.
324   /// If WantFormat is false, the final TextEdit will be not formatted,
325   /// embedders could use this method to get all occurrences of the symbol (e.g.
326   /// highlighting them in prepare stage).
327   void rename(PathRef File, Position Pos, llvm::StringRef NewName,
328               const RenameOptions &Opts, Callback<RenameResult> CB);
329 
330   struct TweakRef {
331     std::string ID;    /// ID to pass for applyTweak.
332     std::string Title; /// A single-line message to show in the UI.
333     llvm::StringLiteral Kind;
334   };
335   /// Enumerate the code tweaks available to the user at a specified point.
336   /// Tweaks where Filter returns false will not be checked or included.
337   void enumerateTweaks(PathRef File, Range Sel,
338                        llvm::unique_function<bool(const Tweak &)> Filter,
339                        Callback<std::vector<TweakRef>> CB);
340 
341   /// Apply the code tweak with a specified \p ID.
342   void applyTweak(PathRef File, Range Sel, StringRef ID,
343                   Callback<Tweak::Effect> CB);
344 
345   /// Called when an event occurs for a watched file in the workspace.
346   void onFileEvent(const DidChangeWatchedFilesParams &Params);
347 
348   /// Get symbol info for given position.
349   /// Clangd extension - not part of official LSP.
350   void symbolInfo(PathRef File, Position Pos,
351                   Callback<std::vector<SymbolDetails>> CB);
352 
353   /// Get semantic ranges around a specified position in a file.
354   void semanticRanges(PathRef File, const std::vector<Position> &Pos,
355                       Callback<std::vector<SelectionRange>> CB);
356 
357   /// Get all document links in a file.
358   void documentLinks(PathRef File, Callback<std::vector<DocumentLink>> CB);
359 
360   void semanticHighlights(PathRef File,
361                           Callback<std::vector<HighlightingToken>>);
362 
363   /// Describe the AST subtree for a piece of code.
364   void getAST(PathRef File, llvm::Optional<Range> R,
365               Callback<llvm::Optional<ASTNode>> CB);
366 
367   /// Runs an arbitrary action that has access to the AST of the specified file.
368   /// The action will execute on one of ClangdServer's internal threads.
369   /// The AST is only valid for the duration of the callback.
370   /// As with other actions, the file must have been opened.
371   void customAction(PathRef File, llvm::StringRef Name,
372                     Callback<InputsAndAST> Action);
373 
374   /// Fetches diagnostics for current version of the \p File. This might fail if
375   /// server is busy (building a preamble) and would require a long time to
376   /// prepare diagnostics. If it fails, clients should wait for
377   /// onSemanticsMaybeChanged and then retry.
378   /// These 'pulled' diagnostics do not interfere with the diagnostics 'pushed'
379   /// to Callbacks::onDiagnosticsReady, and clients may use either or both.
380   void diagnostics(PathRef File, Callback<std::vector<Diag>> CB);
381 
382   /// Returns estimated memory usage and other statistics for each of the
383   /// currently open files.
384   /// Overall memory usage of clangd may be significantly more than reported
385   /// here, as this metric does not account (at least) for:
386   ///   - memory occupied by static and dynamic index,
387   ///   - memory required for in-flight requests,
388   /// FIXME: those metrics might be useful too, we should add them.
389   llvm::StringMap<TUScheduler::FileStats> fileStats() const;
390 
391   /// Gets the contents of a currently tracked file. Returns nullptr if the file
392   /// isn't being tracked.
393   std::shared_ptr<const std::string> getDraft(PathRef File) const;
394 
395   // Blocks the main thread until the server is idle. Only for use in tests.
396   // Returns false if the timeout expires.
397   // FIXME: various subcomponents each get the full timeout, so it's more of
398   // an order of magnitude than a hard deadline.
399   LLVM_NODISCARD bool
400   blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds = 10);
401 
402   /// Builds a nested representation of memory used by components.
403   void profile(MemoryTree &MT) const;
404 
405 private:
406   FeatureModuleSet *FeatureModules;
407   const GlobalCompilationDatabase &CDB;
getHeaderFS()408   const ThreadsafeFS &getHeaderFS() const {
409     return UseDirtyHeaders ? *DirtyFS : TFS;
410   }
411   const ThreadsafeFS &TFS;
412 
413   Path ResourceDir;
414   // The index used to look up symbols. This could be:
415   //   - null (all index functionality is optional)
416   //   - the dynamic index owned by ClangdServer (DynamicIdx)
417   //   - the static index passed to the constructor
418   //   - a merged view of a static and dynamic index (MergedIndex)
419   const SymbolIndex *Index = nullptr;
420   // If present, an index of symbols in open files. Read via *Index.
421   std::unique_ptr<FileIndex> DynamicIdx;
422   // If present, the new "auto-index" maintained in background threads.
423   std::unique_ptr<BackgroundIndex> BackgroundIdx;
424   // Storage for merged views of the various indexes.
425   std::vector<std::unique_ptr<SymbolIndex>> MergedIdx;
426 
427   // When set, provides clang-tidy options for a specific file.
428   TidyProviderRef ClangTidyProvider;
429 
430   bool UseDirtyHeaders = false;
431 
432   bool PreambleParseForwardingFunctions = false;
433 
434   // GUARDED_BY(CachedCompletionFuzzyFindRequestMutex)
435   llvm::StringMap<llvm::Optional<FuzzyFindRequest>>
436       CachedCompletionFuzzyFindRequestByFile;
437   mutable std::mutex CachedCompletionFuzzyFindRequestMutex;
438 
439   llvm::Optional<std::string> WorkspaceRoot;
440   llvm::Optional<AsyncTaskRunner> IndexTasks; // for stdlib indexing.
441   llvm::Optional<TUScheduler> WorkScheduler;
442   // Invalidation policy used for actions that we assume are "transient".
443   TUScheduler::ASTActionInvalidation Transient;
444 
445   // Store of the current versions of the open documents.
446   // Only written from the main thread (despite being threadsafe).
447   DraftStore DraftMgr;
448 
449   std::unique_ptr<ThreadsafeFS> DirtyFS;
450 };
451 
452 } // namespace clangd
453 } // namespace clang
454 
455 #endif
456