• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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