clang-tools  15.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 <memory>
19 #include <type_traits>
20 #include <vector>
21 
22 namespace clang {
23 class CompilerInstance;
24 namespace clangd {
25 struct Diag;
26 class LSPBinder;
27 class SymbolIndex;
28 class ThreadsafeFS;
29 class TUScheduler;
30 class Tweak;
31 
32 /// A FeatureModule contributes a vertical feature to clangd.
33 ///
34 /// The lifetime of a module is roughly:
35 /// - feature modules are created before the LSP server, in ClangdMain.cpp
36 /// - these modules are then passed to ClangdLSPServer in a FeatureModuleSet
37 /// - initializeLSP() is called when the editor calls initialize.
38 // - initialize() is then called by ClangdServer as it is constructed.
39 /// - module hooks can be called by the server at this point.
40 /// Server facilities (scheduler etc) are available.
41 /// - ClangdServer will not be destroyed until all the requests are done.
42 /// FIXME: Block server shutdown until all the modules are idle.
43 /// - When shutting down, ClangdServer will wait for all requests to
44 /// finish, call stop(), and then blockUntilIdle().
45 /// - feature modules will be destroyed after ClangdLSPServer is destroyed.
46 ///
47 /// FeatureModules are not threadsafe in general. A module's entrypoints are:
48 /// - method handlers registered in initializeLSP()
49 /// - public methods called directly via ClangdServer.featureModule<T>()->...
50 /// - specific overridable "hook" methods inherited from FeatureModule
51 /// Unless otherwise specified, these are only called on the main thread.
52 ///
53 /// Conventionally, standard feature modules live in the `clangd` namespace,
54 /// and other exposed details live in a sub-namespace.
56 public:
57  virtual ~FeatureModule() {
58  /// Perform shutdown sequence on destruction in case the ClangdServer was
59  /// never initialized. Usually redundant, but shutdown is idempotent.
60  stop();
62  }
63 
64  /// Called by the server to connect this feature module to LSP.
65  /// The module should register the methods/notifications/commands it handles,
66  /// and update the server capabilities to advertise them.
67  ///
68  /// This is only called if the module is running in ClangdLSPServer!
69  /// FeatureModules with a public interface should work without LSP bindings.
70  virtual void initializeLSP(LSPBinder &Bind,
71  const llvm::json::Object &ClientCaps,
72  llvm::json::Object &ServerCaps) {}
73 
74  /// Shared server facilities needed by the module to get its work done.
75  struct Facilities {
78  const ThreadsafeFS &FS;
79  };
80  /// Called by the server to prepare this module for use.
81  void initialize(const Facilities &F);
82 
83  /// Requests that the module cancel background work and go idle soon.
84  /// Does not block, the caller will call blockUntilIdle() instead.
85  /// After a module is stop()ed, it should not receive any more requests.
86  /// Called by the server when shutting down.
87  /// May be called multiple times, should be idempotent.
88  virtual void stop() {}
89 
90  /// Waits until the module is idle (no background work) or a deadline expires.
91  /// In general all modules should eventually go idle, though it may take a
92  /// long time (e.g. background indexing).
93  /// FeatureModules should go idle quickly if stop() has been called.
94  /// Called by the server when shutting down, and also by tests.
95  virtual bool blockUntilIdle(Deadline) { return true; }
96 
97  /// Tweaks implemented by this module. Can be called asynchronously when
98  /// enumerating or applying code actions.
99  virtual void contributeTweaks(std::vector<std::unique_ptr<Tweak>> &Out) {}
100 
101  /// Extension point that allows modules to observe and modify an AST build.
102  /// One instance is created each time clangd produces a ParsedAST or
103  /// PrecompiledPreamble. For a given instance, lifecycle methods are always
104  /// called on a single thread.
105  struct ASTListener {
106  /// Listeners are destroyed once the AST is built.
107  virtual ~ASTListener() = default;
108 
109  /// Called before every AST build, both for main file and preamble. The call
110  /// happens immediately before FrontendAction::Execute(), with Preprocessor
111  /// set up already and after BeginSourceFile() on main file was called.
112  virtual void beforeExecute(CompilerInstance &CI) {}
113 
114  /// Called everytime a diagnostic is encountered. Modules can use this
115  /// modify the final diagnostic, or store some information to surface code
116  /// actions later on.
117  virtual void sawDiagnostic(const clang::Diagnostic &, clangd::Diag &) {}
118  };
119  /// Can be called asynchronously before building an AST.
120  virtual std::unique_ptr<ASTListener> astListeners() { return nullptr; }
121 
122 protected:
123  /// Accessors for modules to access shared server facilities they depend on.
124  Facilities &facilities();
125  /// The scheduler is used to run tasks on worker threads and access ASTs.
127  /// The index is used to get information about the whole codebase.
128  const SymbolIndex *index() { return facilities().Index; }
129  /// The filesystem is used to read source files on disk.
130  const ThreadsafeFS &fs() { return facilities().FS; }
131 
132  /// Types of function objects that feature modules use for outgoing calls.
133  /// (Bound throuh LSPBinder, made available here for convenience).
134  template <typename P>
135  using OutgoingNotification = llvm::unique_function<void(const P &)>;
136  template <typename P, typename R>
137  using OutgoingMethod = llvm::unique_function<void(const P &, Callback<R>)>;
138 
139 private:
140  llvm::Optional<Facilities> Fac;
141 };
142 
143 /// A FeatureModuleSet is a collection of feature modules installed in clangd.
144 ///
145 /// Modules can be looked up by type, or used via the FeatureModule interface.
146 /// This allows individual modules to expose a public API.
147 /// For this reason, there can be only one feature module of each type.
148 ///
149 /// The set owns the modules. It is itself owned by main, not ClangdServer.
151  std::vector<std::unique_ptr<FeatureModule>> Modules;
152  llvm::DenseMap<void *, FeatureModule *> Map;
153 
154  template <typename Mod> struct ID {
155  static_assert(std::is_base_of<FeatureModule, Mod>::value &&
156  std::is_final<Mod>::value,
157  "Modules must be final classes derived from clangd::Module");
158  static int Key;
159  };
160 
161  bool addImpl(void *Key, std::unique_ptr<FeatureModule>, const char *Source);
162 
163 public:
164  FeatureModuleSet() = default;
165 
166  using iterator = llvm::pointee_iterator<decltype(Modules)::iterator>;
167  using const_iterator =
168  llvm::pointee_iterator<decltype(Modules)::const_iterator>;
169  iterator begin() { return iterator(Modules.begin()); }
170  iterator end() { return iterator(Modules.end()); }
171  const_iterator begin() const { return const_iterator(Modules.begin()); }
172  const_iterator end() const { return const_iterator(Modules.end()); }
173 
174  template <typename Mod> bool add(std::unique_ptr<Mod> M) {
175  return addImpl(&ID<Mod>::Key, std::move(M), LLVM_PRETTY_FUNCTION);
176  }
177  template <typename Mod> Mod *get() {
178  return static_cast<Mod *>(Map.lookup(&ID<Mod>::Key));
179  }
180  template <typename Mod> const Mod *get() const {
181  return const_cast<FeatureModuleSet *>(this)->get<Mod>();
182  }
183 };
184 
185 template <typename Mod> int FeatureModuleSet::ID<Mod>::Key;
186 
187 } // namespace clangd
188 } // namespace clang
189 #endif
clang::clangd::FeatureModuleSet::begin
const_iterator begin() const
Definition: FeatureModule.h:171
clang::clangd::FeatureModule::initializeLSP
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.
Definition: FeatureModule.h:70
clang::clangd::FeatureModuleSet::get
Mod * get()
Definition: FeatureModule.h:177
clang::clangd::FeatureModuleSet
A FeatureModuleSet is a collection of feature modules installed in clangd.
Definition: FeatureModule.h:150
clang::clangd::Deadline::infinity
static Deadline infinity()
Definition: Threading.h:50
clang::clangd::FeatureModule::ASTListener::beforeExecute
virtual void beforeExecute(CompilerInstance &CI)
Called before every AST build, both for main file and preamble.
Definition: FeatureModule.h:112
clang::clangd::FeatureModuleSet::end
iterator end()
Definition: FeatureModule.h:170
clang::clangd::FeatureModule
A FeatureModule contributes a vertical feature to clangd.
Definition: FeatureModule.h:55
clang::clangd::FeatureModuleSet::const_iterator
llvm::pointee_iterator< decltype(Modules)::const_iterator > const_iterator
Definition: FeatureModule.h:168
clang::clangd::FeatureModule::index
const SymbolIndex * index()
The index is used to get information about the whole codebase.
Definition: FeatureModule.h:128
clang::clangd::FeatureModule::ASTListener
Extension point that allows modules to observe and modify an AST build.
Definition: FeatureModule.h:105
CI
std::unique_ptr< CompilerInvocation > CI
Definition: TUScheduler.cpp:491
clang::clangd::FeatureModule::stop
virtual void stop()
Requests that the module cancel background work and go idle soon.
Definition: FeatureModule.h:88
clang::clangd::FeatureModule::Facilities
Shared server facilities needed by the module to get its work done.
Definition: FeatureModule.h:75
clang::clangd::FeatureModule::scheduler
TUScheduler & scheduler()
The scheduler is used to run tasks on worker threads and access ASTs.
Definition: FeatureModule.h:126
clang::clangd::FeatureModuleSet::get
const Mod * get() const
Definition: FeatureModule.h:180
clang::clangd::Deadline
A point in time we can wait for.
Definition: Threading.h:45
M
const google::protobuf::Message & M
Definition: Server.cpp:309
clang::clangd::FeatureModule::~FeatureModule
virtual ~FeatureModule()
Definition: FeatureModule.h:57
Diagnostic
DiagnosticCallback Diagnostic
Definition: ConfigCompile.cpp:100
clang::clangd::FeatureModule::fs
const ThreadsafeFS & fs()
The filesystem is used to read source files on disk.
Definition: FeatureModule.h:130
clang::clangd::Diag
A top-level diagnostic that may have Notes and Fixes.
Definition: Diagnostics.h:94
Threading.h
clang::clangd::FeatureModuleSet::end
const_iterator end() const
Definition: FeatureModule.h:172
clang::clangd::FeatureModule::blockUntilIdle
virtual bool blockUntilIdle(Deadline)
Waits until the module is idle (no background work) or a deadline expires.
Definition: FeatureModule.h:95
clang::clangd::FeatureModule::ASTListener::~ASTListener
virtual ~ASTListener()=default
Listeners are destroyed once the AST is built.
clang::clangd::FeatureModule::OutgoingMethod
llvm::unique_function< void(const P &, Callback< R >)> OutgoingMethod
Definition: FeatureModule.h:137
clang::clangd::FeatureModule::Facilities::Index
const SymbolIndex * Index
Definition: FeatureModule.h:77
clang::clangd::Key
Values in a Context are indexed by typed keys.
Definition: Context.h:40
clang::clangd::FeatureModule::OutgoingNotification
llvm::unique_function< void(const P &)> OutgoingNotification
Types of function objects that feature modules use for outgoing calls.
Definition: FeatureModule.h:135
clang::clangd::FeatureModule::ASTListener::sawDiagnostic
virtual void sawDiagnostic(const clang::Diagnostic &, clangd::Diag &)
Called everytime a diagnostic is encountered.
Definition: FeatureModule.h:117
clang::clangd::SymbolIndex
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:110
clang::clangd::FeatureModule::contributeTweaks
virtual void contributeTweaks(std::vector< std::unique_ptr< Tweak >> &Out)
Tweaks implemented by this module.
Definition: FeatureModule.h:99
ID
static char ID
Definition: Logger.cpp:74
clang::clangd::LSPBinder
LSPBinder collects a table of functions that handle LSP calls.
Definition: LSPBinder.h:34
clang::clangd::ThreadsafeFS
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
Definition: ThreadsafeFS.h:27
clang::clangd::FeatureModule::Facilities::FS
const ThreadsafeFS & FS
Definition: FeatureModule.h:78
clang::clangd::FeatureModuleSet::iterator
llvm::pointee_iterator< decltype(Modules)::iterator > iterator
Definition: FeatureModule.h:166
clang::clangd::FeatureModuleSet::FeatureModuleSet
FeatureModuleSet()=default
clang::clangd::FeatureModuleSet::begin
iterator begin()
Definition: FeatureModule.h:169
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
Function.h
clang::clangd::FeatureModuleSet::add
bool add(std::unique_ptr< Mod > M)
Definition: FeatureModule.h:174
clang::clangd::FeatureModule::astListeners
virtual std::unique_ptr< ASTListener > astListeners()
Can be called asynchronously before building an AST.
Definition: FeatureModule.h:120
clang::clangd::TUScheduler
Handles running tasks for ClangdServer and managing the resources (e.g., preambles and ASTs) for open...
Definition: TUScheduler.h:184
clang::clangd::Callback
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:28
Out
CompiledFragmentImpl & Out
Definition: ConfigCompile.cpp:99
clang::clangd::FeatureModule::facilities
Facilities & facilities()
Accessors for modules to access shared server facilities they depend on.
Definition: FeatureModule.cpp:20
clang::clangd::FeatureModule::initialize
void initialize(const Facilities &F)
Called by the server to prepare this module for use.
Definition: FeatureModule.cpp:15
clang::clangd::FeatureModule::Facilities::Scheduler
TUScheduler & Scheduler
Definition: FeatureModule.h:76