clang-tools 24.0.0git
FeatureModule.h
Go to the documentation of this file.
1//===--- FeatureModule.h - Plugging features into clangd ----------*-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_FEATUREMODULE_H
10#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FEATUREMODULE_H
11
12#include "support/Function.h"
13#include "support/Threading.h"
14#include "clang/Basic/Diagnostic.h"
15#include "llvm/ADT/FunctionExtras.h"
16#include "llvm/Support/Compiler.h"
17#include "llvm/Support/JSON.h"
18#include "llvm/Support/Registry.h"
19#include <memory>
20#include <optional>
21#include <type_traits>
22#include <vector>
23
24namespace clang {
25class CompilerInstance;
26namespace clangd {
27struct Diag;
28class LSPBinder;
29class SymbolIndex;
30class ThreadsafeFS;
31class TUScheduler;
32class Tweak;
33
34/// A FeatureModule contributes a vertical feature to clangd.
35///
36/// The lifetime of a module is roughly:
37/// - feature modules are created before the LSP server, in ClangdMain.cpp
38/// - these modules are then passed to ClangdLSPServer in a FeatureModuleSet
39/// - initializeLSP() is called when the editor calls initialize.
40// - initialize() is then called by ClangdServer as it is constructed.
41/// - module hooks can be called by the server at this point.
42/// Server facilities (scheduler etc) are available.
43/// - ClangdServer will not be destroyed until all the requests are done.
44/// FIXME: Block server shutdown until all the modules are idle.
45/// - When shutting down, ClangdServer will wait for all requests to
46/// finish, call stop(), and then blockUntilIdle().
47/// - feature modules will be destroyed after ClangdLSPServer is destroyed.
48///
49/// FeatureModules are not threadsafe in general. A module's entrypoints are:
50/// - method handlers registered in initializeLSP()
51/// - public methods called directly via ClangdServer.featureModule<T>()->...
52/// - specific overridable "hook" methods inherited from FeatureModule
53/// Unless otherwise specified, these are only called on the main thread.
54///
55/// Conventionally, standard feature modules live in the `clangd` namespace,
56/// and other exposed details live in a sub-namespace.
58public:
59 virtual ~FeatureModule() {
60 /// Perform shutdown sequence on destruction in case the ClangdServer was
61 /// never initialized. Usually redundant, but shutdown is idempotent.
62 stop();
64 }
65
66 /// Called by the server to connect this feature module to LSP.
67 /// The module should register the methods/notifications/commands it handles,
68 /// and update the server capabilities to advertise them.
69 ///
70 /// This is only called if the module is running in ClangdLSPServer!
71 /// FeatureModules with a public interface should work without LSP bindings.
72 virtual void initializeLSP(LSPBinder &Bind,
73 const llvm::json::Object &ClientCaps,
74 llvm::json::Object &ServerCaps) {}
75
76 /// Shared server facilities needed by the module to get its work done.
82 /// Called by the server to prepare this module for use.
83 void initialize(const Facilities &F);
84
85 /// Requests that the module cancel background work and go idle soon.
86 /// Does not block, the caller will call blockUntilIdle() instead.
87 /// After a module is stop()ed, it should not receive any more requests.
88 /// Called by the server when shutting down.
89 /// May be called multiple times, should be idempotent.
90 virtual void stop() {}
91
92 /// Waits until the module is idle (no background work) or a deadline expires.
93 /// In general all modules should eventually go idle, though it may take a
94 /// long time (e.g. background indexing).
95 /// FeatureModules should go idle quickly if stop() has been called.
96 /// Called by the server when shutting down, and also by tests.
97 virtual bool blockUntilIdle(Deadline) { return true; }
98
99 /// Tweaks implemented by this module. Can be called asynchronously when
100 /// enumerating or applying code actions.
101 virtual void contributeTweaks(std::vector<std::unique_ptr<Tweak>> &Out) {}
102
103 /// Extension point that allows modules to observe and modify an AST build.
104 /// One instance is created each time clangd produces a ParsedAST or
105 /// PrecompiledPreamble. For a given instance, lifecycle methods are always
106 /// called on a single thread.
107 struct ASTListener {
108 /// Listeners are destroyed once the AST is built.
109 virtual ~ASTListener() = default;
110
111 /// Called before every AST build, after the Preprocessor and ASTConsumer
112 /// are set up, but before clangd installs its include and macro collectors.
113 /// Modules should only use this when their PPCallbacks must observe
114 /// preamble events replayed during a main-file build.
115 /// Reusing a preamble skips the main file's initial preprocessing
116 /// directives. ReplayPreamble synthesizes callbacks for selected events
117 /// from that region and captures their recipients before beforeExecute() is
118 /// called.
119 virtual void beforePPCallbacks(CompilerInstance &CI) {}
120
121 /// Called before every AST build, both for main file and preamble. The call
122 /// happens immediately before FrontendAction::Execute(), with Preprocessor
123 /// set up already and after BeginSourceFile() on main file was called.
124 virtual void beforeExecute(CompilerInstance &CI) {}
125
126 /// Called after FrontendAction::Execute() for a main-file build, once
127 /// clangd has collected tokens and restricted the AST traversal scope.
128 /// The preprocessor has not received EndSourceFile() yet.
129 virtual void afterExecute(CompilerInstance &CI) {}
130
131 /// Called everytime a diagnostic is encountered. Modules can use this
132 /// modify the final diagnostic, or store some information to surface code
133 /// actions later on.
134 virtual void sawDiagnostic(const clang::Diagnostic &, clangd::Diag &) {}
135
136 /// Called after a diagnostic is fully assembled, including notes and
137 /// fixes, and before it is returned to the caller.
139 };
140 /// Can be called asynchronously before building an AST.
141 virtual std::unique_ptr<ASTListener> astListeners() { return nullptr; }
142
143protected:
144 /// Accessors for modules to access shared server facilities they depend on.
145 Facilities &facilities();
146 /// The scheduler is used to run tasks on worker threads and access ASTs.
148 /// The index is used to get information about the whole codebase.
149 const SymbolIndex *index() { return facilities().Index; }
150 /// The filesystem is used to read source files on disk.
151 const ThreadsafeFS &fs() { return facilities().FS; }
152
153 /// Types of function objects that feature modules use for outgoing calls.
154 /// (Bound throuh LSPBinder, made available here for convenience).
155 template <typename P>
156 using OutgoingNotification = llvm::unique_function<void(const P &)>;
157 template <typename P, typename R>
158 using OutgoingMethod = llvm::unique_function<void(const P &, Callback<R>)>;
159
160private:
161 std::optional<Facilities> Fac;
162};
163
164/// A FeatureModuleSet is a collection of feature modules installed in clangd.
165///
166/// Modules added with explicit type specification can be looked up by type, or
167/// used via the FeatureModule interface. This allows individual modules to
168/// expose a public API. For this reason, there can be only one feature module
169/// of each type.
170///
171/// Modules added using a base class pointer can be used only via the
172/// FeatureModule interface and can't be looked up by type, thus custom public
173/// API (if provided by the module) can't be used.
174///
175/// The set owns the modules. It is itself owned by main, not ClangdServer.
177 std::vector<std::unique_ptr<FeatureModule>> Modules;
178 llvm::DenseMap<void *, FeatureModule *> Map;
179
180 template <typename Mod> struct ID {
181 static_assert(std::is_base_of<FeatureModule, Mod>::value &&
182 std::is_final<Mod>::value,
183 "Modules must be final classes derived from clangd::Module");
184 static int Key;
185 };
186
187 bool addImpl(void *Key, std::unique_ptr<FeatureModule>, const char *Source);
188
189public:
190 FeatureModuleSet() = default;
191
193
194 using iterator = llvm::pointee_iterator<decltype(Modules)::iterator>;
196 llvm::pointee_iterator<decltype(Modules)::const_iterator>;
197 iterator begin() { return iterator(Modules.begin()); }
198 iterator end() { return iterator(Modules.end()); }
199 const_iterator begin() const { return const_iterator(Modules.begin()); }
200 const_iterator end() const { return const_iterator(Modules.end()); }
201
202 void add(std::unique_ptr<FeatureModule> M);
203 template <typename Mod> bool add(std::unique_ptr<Mod> M) {
204 return addImpl(&ID<Mod>::Key, std::move(M), LLVM_PRETTY_FUNCTION);
205 }
206 template <typename Mod> Mod *get() {
207 return static_cast<Mod *>(Map.lookup(&ID<Mod>::Key));
208 }
209 template <typename Mod> const Mod *get() const {
210 return const_cast<FeatureModuleSet *>(this)->get<Mod>();
211 }
212};
213
214template <typename Mod> int FeatureModuleSet::ID<Mod>::Key;
215
216using FeatureModuleRegistry = llvm::Registry<FeatureModule>;
217
218} // namespace clangd
219} // namespace clang
220
221namespace llvm {
222extern template class Registry<clang::clangd::FeatureModule>;
223} // namespace llvm
224
225#endif
A point in time we can wait for.
Definition Threading.h:46
static Deadline infinity()
Definition Threading.h:51
llvm::pointee_iterator< decltype(Modules)::iterator > iterator
bool add(std::unique_ptr< Mod > M)
static FeatureModuleSet fromRegistry()
const_iterator begin() const
void add(std::unique_ptr< FeatureModule > M)
llvm::pointee_iterator< decltype(Modules)::const_iterator > const_iterator
const_iterator end() const
A FeatureModule contributes a vertical feature to clangd.
virtual std::unique_ptr< ASTListener > astListeners()
Can be called asynchronously before building an AST.
const SymbolIndex * index()
The index is used to get information about the whole codebase.
Facilities & facilities()
Accessors for modules to access shared server facilities they depend on.
void initialize(const Facilities &F)
Called by the server to prepare this module for use.
TUScheduler & scheduler()
The scheduler is used to run tasks on worker threads and access ASTs.
llvm::unique_function< void(const P &, Callback< R >)> OutgoingMethod
llvm::unique_function< void(const P &)> OutgoingNotification
Types of function objects that feature modules use for outgoing calls.
const ThreadsafeFS & fs()
The filesystem is used to read source files on disk.
virtual void stop()
Requests that the module cancel background work and go idle soon.
virtual bool blockUntilIdle(Deadline)
Waits until the module is idle (no background work) or a deadline expires.
virtual void initializeLSP(LSPBinder &Bind, const llvm::json::Object &ClientCaps, llvm::json::Object &ServerCaps)
Called by the server to connect this feature module to LSP.
virtual void contributeTweaks(std::vector< std::unique_ptr< Tweak > > &Out)
Tweaks implemented by this module.
Values in a Context are indexed by typed keys.
Definition Context.h:40
LSPBinder collects a table of functions that handle LSP calls.
Definition LSPBinder.h:34
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition Index.h:134
Handles running tasks for ClangdServer and managing the resources (e.g., preambles and ASTs) for open...
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
An interface base for small context-sensitive refactoring actions.
Definition Tweak.h:46
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:44
llvm::Registry< FeatureModule > FeatureModuleRegistry
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition Function.h:28
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.
Definition Generators.h:150
A top-level diagnostic that may have Notes and Fixes.
Definition Diagnostics.h:98
Extension point that allows modules to observe and modify an AST build.
virtual void sawDiagnostic(const clang::Diagnostic &, clangd::Diag &)
Called everytime a diagnostic is encountered.
virtual ~ASTListener()=default
Listeners are destroyed once the AST is built.
virtual void beforeExecute(CompilerInstance &CI)
Called before every AST build, both for main file and preamble.
virtual void afterExecute(CompilerInstance &CI)
Called after FrontendAction::Execute() for a main-file build, once clangd has collected tokens and re...
virtual void finalizeDiagnostic(clangd::Diag &)
Called after a diagnostic is fully assembled, including notes and fixes, and before it is returned to...
virtual void beforePPCallbacks(CompilerInstance &CI)
Called before every AST build, after the Preprocessor and ASTConsumer are set up, but before clangd i...
Shared server facilities needed by the module to get its work done.