blob: 1be3dbbb5bc8a286091e19c50cfb7d8b7fc05ce9 [file] [log] [blame]
Ilya Biryukov38d79772017-05-16 09:38:59 +00001//===--- ClangdServer.h - Main clangd server code ----------------*- C++-*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H
11#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H
12
Eric Liub99d5e82017-12-14 21:22:03 +000013#include "ClangdUnit.h"
Eric Liub99d5e82017-12-14 21:22:03 +000014#include "CodeComplete.h"
Ilya Biryukov929697b2018-01-25 14:19:21 +000015#include "CompileArgsCache.h"
Ilya Biryukov38d79772017-05-16 09:38:59 +000016#include "DraftStore.h"
Eric Liub99d5e82017-12-14 21:22:03 +000017#include "Function.h"
Ilya Biryukov38d79772017-05-16 09:38:59 +000018#include "GlobalCompilationDatabase.h"
Eric Liub99d5e82017-12-14 21:22:03 +000019#include "Protocol.h"
Ilya Biryukov75f1dd92018-01-31 08:51:16 +000020#include "TUScheduler.h"
Eric Liubfac8f72017-12-19 18:00:37 +000021#include "index/FileIndex.h"
Ilya Biryukov38d79772017-05-16 09:38:59 +000022#include "clang/Tooling/CompilationDatabase.h"
23#include "clang/Tooling/Core/Replacement.h"
24#include "llvm/ADT/IntrusiveRefCntPtr.h"
25#include "llvm/ADT/Optional.h"
26#include "llvm/ADT/StringRef.h"
Ilya Biryukovf01af682017-05-23 13:42:59 +000027#include <functional>
Ilya Biryukov44ba9e02018-02-09 10:17:23 +000028#include <future>
Ilya Biryukov38d79772017-05-16 09:38:59 +000029#include <string>
Ilya Biryukov22602992017-05-30 15:11:02 +000030#include <type_traits>
Ilya Biryukov38d79772017-05-16 09:38:59 +000031#include <utility>
32
33namespace clang {
34class PCHContainerOperations;
35
36namespace clangd {
37
Ilya Biryukov22602992017-05-30 15:11:02 +000038/// A tag supplied by the FileSytemProvider.
Ilya Biryukove36035b2017-06-13 08:24:48 +000039typedef std::string VFSTag;
Ilya Biryukov22602992017-05-30 15:11:02 +000040
41/// A value of an arbitrary type and VFSTag that was supplied by the
42/// FileSystemProvider when this value was computed.
43template <class T> class Tagged {
44public:
Ilya Biryukove81b7622017-10-05 22:15:15 +000045 // MSVC requires future<> arguments to be default-constructible.
46 Tagged() = default;
47
Ilya Biryukov22602992017-05-30 15:11:02 +000048 template <class U>
Ilya Biryukove36035b2017-06-13 08:24:48 +000049 Tagged(U &&Value, VFSTag Tag)
50 : Value(std::forward<U>(Value)), Tag(std::move(Tag)) {}
Ilya Biryukov22602992017-05-30 15:11:02 +000051
52 template <class U>
53 Tagged(const Tagged<U> &Other) : Value(Other.Value), Tag(Other.Tag) {}
54
55 template <class U>
Ilya Biryukove36035b2017-06-13 08:24:48 +000056 Tagged(Tagged<U> &&Other)
57 : Value(std::move(Other.Value)), Tag(std::move(Other.Tag)) {}
Ilya Biryukov22602992017-05-30 15:11:02 +000058
Ilya Biryukove81b7622017-10-05 22:15:15 +000059 T Value = T();
60 VFSTag Tag = VFSTag();
Ilya Biryukov22602992017-05-30 15:11:02 +000061};
62
63template <class T>
64Tagged<typename std::decay<T>::type> make_tagged(T &&Value, VFSTag Tag) {
Ilya Biryukovc22824a2017-08-09 12:55:13 +000065 return Tagged<typename std::decay<T>::type>(std::forward<T>(Value), Tag);
Ilya Biryukov22602992017-05-30 15:11:02 +000066}
67
Ilya Biryukov38d79772017-05-16 09:38:59 +000068class DiagnosticsConsumer {
69public:
70 virtual ~DiagnosticsConsumer() = default;
71
72 /// Called by ClangdServer when \p Diagnostics for \p File are ready.
Ilya Biryukov22602992017-05-30 15:11:02 +000073 virtual void
Sam McCalld1a7a372018-01-31 13:40:48 +000074 onDiagnosticsReady(PathRef File,
Ilya Biryukov22602992017-05-30 15:11:02 +000075 Tagged<std::vector<DiagWithFixIts>> Diagnostics) = 0;
Ilya Biryukov38d79772017-05-16 09:38:59 +000076};
77
Ilya Biryukov0f62ed22017-05-26 12:26:51 +000078class FileSystemProvider {
79public:
80 virtual ~FileSystemProvider() = default;
Ilya Biryukovaf0c04b2017-06-14 09:46:44 +000081 /// Called by ClangdServer to obtain a vfs::FileSystem to be used for parsing.
82 /// Name of the file that will be parsed is passed in \p File.
83 ///
Ilya Biryukov22602992017-05-30 15:11:02 +000084 /// \return A filesystem that will be used for all file accesses in clangd.
85 /// A Tag returned by this method will be propagated to all results of clangd
86 /// that will use this filesystem.
Ilya Biryukovaf0c04b2017-06-14 09:46:44 +000087 virtual Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
88 getTaggedFileSystem(PathRef File) = 0;
Ilya Biryukov0f62ed22017-05-26 12:26:51 +000089};
90
91class RealFileSystemProvider : public FileSystemProvider {
92public:
Ilya Biryukov22602992017-05-30 15:11:02 +000093 /// \return getRealFileSystem() tagged with default tag, i.e. VFSTag()
Ilya Biryukovaf0c04b2017-06-14 09:46:44 +000094 Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
95 getTaggedFileSystem(PathRef File) override;
Ilya Biryukov0f62ed22017-05-26 12:26:51 +000096};
97
Ilya Biryukov38d79772017-05-16 09:38:59 +000098/// Provides API to manage ASTs for a collection of C++ files and request
Ilya Biryukov75337e82017-08-22 09:16:46 +000099/// various language features.
100/// Currently supports async diagnostics, code completion, formatting and goto
101/// definition.
Ilya Biryukov38d79772017-05-16 09:38:59 +0000102class ClangdServer {
103public:
Ilya Biryukov75337e82017-08-22 09:16:46 +0000104 /// Creates a new ClangdServer instance.
105 /// To process parsing requests asynchronously, ClangdServer will spawn \p
106 /// AsyncThreadsCount worker threads. However, if \p AsyncThreadsCount is 0,
107 /// all requests will be processed on the calling thread.
108 ///
109 /// ClangdServer uses \p FSProvider to get an instance of vfs::FileSystem for
110 /// each parsing request. Results of code completion and diagnostics also
111 /// include a tag, that \p FSProvider returns along with the vfs::FileSystem.
112 ///
113 /// The value of \p ResourceDir will be used to search for internal headers
114 /// (overriding defaults and -resource-dir compiler flag). If \p ResourceDir
115 /// is None, ClangdServer will call CompilerInvocation::GetResourcePath() to
116 /// obtain the standard resource directory.
117 ///
118 /// ClangdServer uses \p CDB to obtain compilation arguments for parsing. Note
119 /// that ClangdServer only obtains compilation arguments once for each newly
120 /// added file (i.e., when processing a first call to addDocument) and reuses
121 /// those arguments for subsequent reparses. However, ClangdServer will check
122 /// if compilation arguments changed on calls to forceReparse().
123 ///
124 /// After each parsing request finishes, ClangdServer reports diagnostics to
125 /// \p DiagConsumer. Note that a callback to \p DiagConsumer happens on a
126 /// worker thread. Therefore, instances of \p DiagConsumer must properly
127 /// synchronize access to shared state.
Ilya Biryukove5128f72017-09-20 07:24:15 +0000128 ///
Ilya Biryukove9eb7f02017-11-16 16:25:18 +0000129 /// \p StorePreamblesInMemory defines whether the Preambles generated by
130 /// clangd are stored in-memory or on disk.
Eric Liubfac8f72017-12-19 18:00:37 +0000131 ///
132 /// If \p BuildDynamicSymbolIndex is true, ClangdServer builds a dynamic
133 /// in-memory index for symbols in all opened files and uses the index to
134 /// augment code completion results.
Haojian Wuba28e9a2018-01-10 14:44:34 +0000135 ///
136 /// If \p StaticIdx is set, ClangdServer uses the index for global code
137 /// completion.
Ilya Biryukov103c9512017-06-13 15:59:43 +0000138 ClangdServer(GlobalCompilationDatabase &CDB,
139 DiagnosticsConsumer &DiagConsumer,
Ilya Biryukovdb8b2d72017-08-14 08:45:47 +0000140 FileSystemProvider &FSProvider, unsigned AsyncThreadsCount,
Ilya Biryukov940901e2017-12-13 12:51:22 +0000141 bool StorePreamblesInMemory,
Eric Liubfac8f72017-12-19 18:00:37 +0000142 bool BuildDynamicSymbolIndex = false,
Haojian Wuba28e9a2018-01-10 14:44:34 +0000143 SymbolIndex *StaticIdx = nullptr,
Ilya Biryukova46f7a92017-06-28 10:34:50 +0000144 llvm::Optional<StringRef> ResourceDir = llvm::None);
Ilya Biryukov38d79772017-05-16 09:38:59 +0000145
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000146 /// Set the root path of the workspace.
147 void setRootPath(PathRef RootPath);
148
Ilya Biryukov38d79772017-05-16 09:38:59 +0000149 /// Add a \p File to the list of tracked C++ files or update the contents if
150 /// \p File is already tracked. Also schedules parsing of the AST for it on a
151 /// separate thread. When the parsing is complete, DiagConsumer passed in
152 /// constructor will receive onDiagnosticsReady callback.
Sam McCall568e17f2018-02-22 13:11:12 +0000153 void addDocument(PathRef File, StringRef Contents,
154 WantDiagnostics WD = WantDiagnostics::Auto);
Sam McCalld1a7a372018-01-31 13:40:48 +0000155
Ilya Biryukov38d79772017-05-16 09:38:59 +0000156 /// Remove \p File from list of tracked files, schedule a request to free
157 /// resources associated with it.
Ilya Biryukov7e5ee262018-02-08 07:37:35 +0000158 void removeDocument(PathRef File);
Sam McCalld1a7a372018-01-31 13:40:48 +0000159
Ilya Biryukov0f62ed22017-05-26 12:26:51 +0000160 /// Force \p File to be reparsed using the latest contents.
Ilya Biryukov91dbf5b2017-08-14 08:37:32 +0000161 /// Will also check if CompileCommand, provided by GlobalCompilationDatabase
162 /// for \p File has changed. If it has, will remove currently stored Preamble
163 /// and AST and rebuild them from scratch.
Sam McCall0bb24cd2018-02-13 08:59:23 +0000164 void forceReparse(PathRef File);
Ilya Biryukov38d79772017-05-16 09:38:59 +0000165
Ilya Biryukovdcd21692017-10-05 17:04:13 +0000166 /// Run code completion for \p File at \p Pos.
Sam McCalld1a7a372018-01-31 13:40:48 +0000167 /// Request is processed asynchronously.
Ilya Biryukovdcd21692017-10-05 17:04:13 +0000168 ///
169 /// If \p OverridenContents is not None, they will used only for code
170 /// completion, i.e. no diagnostics update will be scheduled and a draft for
171 /// \p File will not be updated. If \p OverridenContents is None, contents of
172 /// the current draft for \p File will be used. If \p UsedFS is non-null, it
173 /// will be overwritten by vfs::FileSystem used for completion.
174 ///
175 /// This method should only be called for currently tracked files. However, it
176 /// is safe to call removeDocument for \p File after this method returns, even
177 /// while returned future is not yet ready.
Ilya Biryukov90bbcfd2017-10-25 09:35:10 +0000178 /// A version of `codeComplete` that runs \p Callback on the processing thread
179 /// when codeComplete results become available.
Sam McCalld1a7a372018-01-31 13:40:48 +0000180 void codeComplete(PathRef File, Position Pos,
181 const clangd::CodeCompleteOptions &Opts,
182 UniqueFunction<void(Tagged<CompletionList>)> Callback,
183 llvm::Optional<StringRef> OverridenContents = llvm::None,
184 IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
185
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000186 /// Provide signature help for \p File at \p Pos. If \p OverridenContents is
187 /// not None, they will used only for signature help, i.e. no diagnostics
188 /// update will be scheduled and a draft for \p File will not be updated. If
189 /// \p OverridenContents is None, contents of the current draft for \p File
190 /// will be used. If \p UsedFS is non-null, it will be overwritten by
191 /// vfs::FileSystem used for signature help. This method should only be called
192 /// for currently tracked files.
Ilya Biryukov2c5e8e82018-02-15 13:15:47 +0000193 void signatureHelp(
194 PathRef File, Position Pos,
195 UniqueFunction<void(llvm::Expected<Tagged<SignatureHelp>>)> Callback,
196 llvm::Optional<StringRef> OverridenContents = llvm::None,
197 IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
Ilya Biryukovd9bdfe02017-10-06 11:54:17 +0000198
Marc-Andre Laperle2cbf0372017-06-28 16:12:10 +0000199 /// Get definition of symbol at a specified \p Line and \p Column in \p File.
Ilya Biryukov2c5e8e82018-02-15 13:15:47 +0000200 void findDefinitions(
201 PathRef File, Position Pos,
202 UniqueFunction<void(llvm::Expected<Tagged<std::vector<Location>>>)>
203 Callback);
Ilya Biryukov38d79772017-05-16 09:38:59 +0000204
Marc-Andre Laperle6571b3e2017-09-28 03:14:40 +0000205 /// Helper function that returns a path to the corresponding source file when
206 /// given a header file and vice versa.
207 llvm::Optional<Path> switchSourceHeader(PathRef Path);
208
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000209 /// Get document highlights for a given position.
Ilya Biryukov2c5e8e82018-02-15 13:15:47 +0000210 void findDocumentHighlights(
211 PathRef File, Position Pos,
212 UniqueFunction<
213 void(llvm::Expected<Tagged<std::vector<DocumentHighlight>>>)>
214 Callback);
Ilya Biryukov0e6a51f2017-12-12 12:27:47 +0000215
Marc-Andre Laperle3e618ed2018-02-16 21:38:15 +0000216 /// Get code hover for a given position.
217 void findHover(PathRef File, Position Pos,
218 UniqueFunction<void(llvm::Expected<Tagged<Hover>>)> Callback);
219
Raoul Wols212bcf82017-12-12 20:25:06 +0000220 /// Run formatting for \p Rng inside \p File with content \p Code.
221 llvm::Expected<tooling::Replacements> formatRange(StringRef Code,
222 PathRef File, Range Rng);
223
224 /// Run formatting for the whole \p File with content \p Code.
225 llvm::Expected<tooling::Replacements> formatFile(StringRef Code,
226 PathRef File);
227
228 /// Run formatting after a character was typed at \p Pos in \p File with
229 /// content \p Code.
230 llvm::Expected<tooling::Replacements>
231 formatOnType(StringRef Code, PathRef File, Position Pos);
232
Haojian Wu345099c2017-11-09 11:30:04 +0000233 /// Rename all occurrences of the symbol at the \p Pos in \p File to
234 /// \p NewName.
Ilya Biryukov2c5e8e82018-02-15 13:15:47 +0000235 void rename(PathRef File, Position Pos, llvm::StringRef NewName,
236 UniqueFunction<void(Expected<std::vector<tooling::Replacement>>)>
237 Callback);
Ilya Biryukovafb55542017-05-16 14:40:30 +0000238
Eric Liuc5105f92018-02-16 14:15:55 +0000239 /// Inserts a new #include of \p Header into \p File, if it's not present.
240 /// \p Header is either an URI that can be resolved to an #include path that
241 /// is suitable to be inserted or a literal string quoted with <> or "" that
242 /// can be #included directly.
243 Expected<tooling::Replacements> insertInclude(PathRef File, StringRef Code,
244 StringRef Header);
245
Ilya Biryukov261c72e2018-01-17 12:30:24 +0000246 /// Gets current document contents for \p File. Returns None if \p File is not
247 /// currently tracked.
Ilya Biryukovafb55542017-05-16 14:40:30 +0000248 /// FIXME(ibiryukov): This function is here to allow offset-to-Position
249 /// conversions in outside code, maybe there's a way to get rid of it.
Ilya Biryukov261c72e2018-01-17 12:30:24 +0000250 llvm::Optional<std::string> getDocument(PathRef File);
Ilya Biryukov38d79772017-05-16 09:38:59 +0000251
Ilya Biryukovf01af682017-05-23 13:42:59 +0000252 /// Only for testing purposes.
253 /// Waits until all requests to worker thread are finished and dumps AST for
254 /// \p File. \p File must be in the list of added documents.
Ilya Biryukov2c5e8e82018-02-15 13:15:47 +0000255 void dumpAST(PathRef File, UniqueFunction<void(std::string)> Callback);
Marc-Andre Laperlebf114242017-10-02 18:00:37 +0000256 /// Called when an event occurs for a watched file in the workspace.
257 void onFileEvent(const DidChangeWatchedFilesParams &Params);
Ilya Biryukovf01af682017-05-23 13:42:59 +0000258
Ilya Biryukovdf842342018-01-25 14:32:21 +0000259 /// Returns estimated memory usage for each of the currently open files.
260 /// The order of results is unspecified.
261 /// Overall memory usage of clangd may be significantly more than reported
262 /// here, as this metric does not account (at least) for:
263 /// - memory occupied by static and dynamic index,
264 /// - memory required for in-flight requests,
265 /// FIXME: those metrics might be useful too, we should add them.
266 std::vector<std::pair<Path, std::size_t>> getUsedBytesPerFile() const;
267
Sam McCall0bb24cd2018-02-13 08:59:23 +0000268 // Blocks the main thread until the server is idle. Only for use in tests.
269 // Returns false if the timeout expires.
270 LLVM_NODISCARD bool
271 blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds = 10);
272
Ilya Biryukov38d79772017-05-16 09:38:59 +0000273private:
Raoul Wols212bcf82017-12-12 20:25:06 +0000274 /// FIXME: This stats several files to find a .clang-format file. I/O can be
275 /// slow. Think of a way to cache this.
276 llvm::Expected<tooling::Replacements>
277 formatCode(llvm::StringRef Code, PathRef File,
278 ArrayRef<tooling::Range> Ranges);
279
Sam McCall0bb24cd2018-02-13 08:59:23 +0000280 void
Sam McCalld1a7a372018-01-31 13:40:48 +0000281 scheduleReparseAndDiags(PathRef File, VersionedDraft Contents,
Sam McCall568e17f2018-02-22 13:11:12 +0000282 WantDiagnostics WD,
Ilya Biryukov929697b2018-01-25 14:19:21 +0000283 Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS);
Ilya Biryukovc5ad35f2017-08-14 08:17:24 +0000284
Ilya Biryukov929697b2018-01-25 14:19:21 +0000285 CompileArgsCache CompileArgs;
Ilya Biryukov103c9512017-06-13 15:59:43 +0000286 DiagnosticsConsumer &DiagConsumer;
287 FileSystemProvider &FSProvider;
Ilya Biryukov38d79772017-05-16 09:38:59 +0000288 DraftStore DraftMgr;
Sam McCall0faecf02018-01-15 12:33:00 +0000289 // The index used to look up symbols. This could be:
290 // - null (all index functionality is optional)
291 // - the dynamic index owned by ClangdServer (FileIdx)
292 // - the static index passed to the constructor
293 // - a merged view of a static and dynamic index (MergedIndex)
294 SymbolIndex *Index;
295 // If present, an up-to-date of symbols in open files. Read via Index.
Eric Liubfac8f72017-12-19 18:00:37 +0000296 std::unique_ptr<FileIndex> FileIdx;
Sam McCall0faecf02018-01-15 12:33:00 +0000297 // If present, a merged view of FileIdx and an external index. Read via Index.
298 std::unique_ptr<SymbolIndex> MergedIndex;
Marc-Andre Laperle37de9712017-09-27 15:31:17 +0000299 // If set, this represents the workspace path.
300 llvm::Optional<std::string> RootPath;
Ilya Biryukov38d79772017-05-16 09:38:59 +0000301 std::shared_ptr<PCHContainerOperations> PCHs;
Ilya Biryukov47f22022017-09-20 12:58:55 +0000302 /// Used to serialize diagnostic callbacks.
303 /// FIXME(ibiryukov): get rid of an extra map and put all version counters
304 /// into CppFile.
305 std::mutex DiagnosticsMutex;
306 /// Maps from a filename to the latest version of reported diagnostics.
307 llvm::StringMap<DocVersion> ReportedDiagnosticVersions;
Ilya Biryukovf4e95d72017-09-20 19:32:06 +0000308 // WorkScheduler has to be the last member, because its destructor has to be
309 // called before all other members to stop the worker thread that references
Ilya Biryukov75f1dd92018-01-31 08:51:16 +0000310 // ClangdServer.
311 TUScheduler WorkScheduler;
Ilya Biryukov38d79772017-05-16 09:38:59 +0000312};
313
314} // namespace clangd
315} // namespace clang
316
317#endif