clang-tools 22.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, both for main file and preamble. The call
112 /// happens immediately before FrontendAction::Execute(), with Preprocessor
113 /// set up already and after BeginSourceFile() on main file was called.
114 virtual void beforeExecute(CompilerInstance &CI) {}
115
116 /// Called everytime a diagnostic is encountered. Modules can use this
117 /// modify the final diagnostic, or store some information to surface code
118 /// actions later on.
119 virtual void sawDiagnostic(const clang::Diagnostic &, clangd::Diag &) {}
120 };
121 /// Can be called asynchronously before building an AST.
122 virtual std::unique_ptr<ASTListener> astListeners() { return nullptr; }
123
124protected:
125 /// Accessors for modules to access shared server facilities they depend on.
126 Facilities &facilities();
127 /// The scheduler is used to run tasks on worker threads and access ASTs.
129 /// The index is used to get information about the whole codebase.
130 const SymbolIndex *index() { return facilities().Index; }
131 /// The filesystem is used to read source files on disk.
132 const ThreadsafeFS &fs() { return facilities().FS; }
133
134 /// Types of function objects that feature modules use for outgoing calls.
135 /// (Bound throuh LSPBinder, made available here for convenience).
136 template <typename P>
137 using OutgoingNotification = llvm::unique_function<void(const P &)>;
138 template <typename P, typename R>
139 using OutgoingMethod = llvm::unique_function<void(const P &, Callback<R>)>;
140
141private:
142 std::optional<Facilities> Fac;
143};
144
145/// A FeatureModuleSet is a collection of feature modules installed in clangd.
146///
147/// Modules added with explicit type specification can be looked up by type, or
148/// used via the FeatureModule interface. This allows individual modules to
149/// expose a public API. For this reason, there can be only one feature module
150/// of each type.
151///
152/// Modules added using a base class pointer can be used only via the
153/// FeatureModule interface and can't be looked up by type, thus custom public
154/// API (if provided by the module) can't be used.
155///
156/// The set owns the modules. It is itself owned by main, not ClangdServer.
158 std::vector<std::unique_ptr<FeatureModule>> Modules;
159 llvm::DenseMap<void *, FeatureModule *> Map;
160
161 template <typename Mod> struct ID {
162 static_assert(std::is_base_of<FeatureModule, Mod>::value &&
163 std::is_final<Mod>::value,
164 "Modules must be final classes derived from clangd::Module");
165 static int Key;
166 };
167
168 bool addImpl(void *Key, std::unique_ptr<FeatureModule>, const char *Source);
169
170public:
171 FeatureModuleSet() = default;
172
174
175 using iterator = llvm::pointee_iterator<decltype(Modules)::iterator>;
177 llvm::pointee_iterator<decltype(Modules)::const_iterator>;
178 iterator begin() { return iterator(Modules.begin()); }
179 iterator end() { return iterator(Modules.end()); }
180 const_iterator begin() const { return const_iterator(Modules.begin()); }
181 const_iterator end() const { return const_iterator(Modules.end()); }
182
183 void add(std::unique_ptr<FeatureModule> M);
184 template <typename Mod> bool add(std::unique_ptr<Mod> M) {
185 return addImpl(&ID<Mod>::Key, std::move(M), LLVM_PRETTY_FUNCTION);
186 }
187 template <typename Mod> Mod *get() {
188 return static_cast<Mod *>(Map.lookup(&ID<Mod>::Key));
189 }
190 template <typename Mod> const Mod *get() const {
191 return const_cast<FeatureModuleSet *>(this)->get<Mod>();
192 }
193};
194
195template <typename Mod> int FeatureModuleSet::ID<Mod>::Key;
196
197using FeatureModuleRegistry = llvm::Registry<FeatureModule>;
198
199} // namespace clangd
200} // namespace clang
201
202namespace llvm {
203extern template class Registry<clang::clangd::FeatureModule>;
204} // namespace llvm
205
206#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:45
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:66
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.
Shared server facilities needed by the module to get its work done.