clang-tools  14.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/ADT/StringRef.h"
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/JSON.h"
19 #include <memory>
20 #include <type_traits>
21 #include <vector>
22 
23 namespace clang {
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 everytime a diagnostic is encountered. Modules can use this
110  /// modify the final diagnostic, or store some information to surface code
111  /// actions later on.
112  virtual void sawDiagnostic(const clang::Diagnostic &, clangd::Diag &) {}
113  };
114  /// Can be called asynchronously before building an AST.
115  virtual std::unique_ptr<ASTListener> astListeners() { return nullptr; }
116 
117 protected:
118  /// Accessors for modules to access shared server facilities they depend on.
119  Facilities &facilities();
120  /// The scheduler is used to run tasks on worker threads and access ASTs.
122  /// The index is used to get information about the whole codebase.
123  const SymbolIndex *index() { return facilities().Index; }
124  /// The filesystem is used to read source files on disk.
125  const ThreadsafeFS &fs() { return facilities().FS; }
126 
127  /// Types of function objects that feature modules use for outgoing calls.
128  /// (Bound throuh LSPBinder, made available here for convenience).
129  template <typename P>
130  using OutgoingNotification = llvm::unique_function<void(const P &)>;
131  template <typename P, typename R>
132  using OutgoingMethod = llvm::unique_function<void(const P &, Callback<R>)>;
133 
134 private:
135  llvm::Optional<Facilities> Fac;
136 };
137 
138 /// A FeatureModuleSet is a collection of feature modules installed in clangd.
139 ///
140 /// Modules can be looked up by type, or used via the FeatureModule interface.
141 /// This allows individual modules to expose a public API.
142 /// For this reason, there can be only one feature module of each type.
143 ///
144 /// The set owns the modules. It is itself owned by main, not ClangdServer.
146  std::vector<std::unique_ptr<FeatureModule>> Modules;
147  llvm::DenseMap<void *, FeatureModule *> Map;
148 
149  template <typename Mod> struct ID {
150  static_assert(std::is_base_of<FeatureModule, Mod>::value &&
151  std::is_final<Mod>::value,
152  "Modules must be final classes derived from clangd::Module");
153  static int Key;
154  };
155 
156  bool addImpl(void *Key, std::unique_ptr<FeatureModule>, const char *Source);
157 
158 public:
159  FeatureModuleSet() = default;
160 
161  using iterator = llvm::pointee_iterator<decltype(Modules)::iterator>;
162  using const_iterator =
163  llvm::pointee_iterator<decltype(Modules)::const_iterator>;
164  iterator begin() { return iterator(Modules.begin()); }
165  iterator end() { return iterator(Modules.end()); }
166  const_iterator begin() const { return const_iterator(Modules.begin()); }
167  const_iterator end() const { return const_iterator(Modules.end()); }
168 
169  template <typename Mod> bool add(std::unique_ptr<Mod> M) {
170  return addImpl(&ID<Mod>::Key, std::move(M), LLVM_PRETTY_FUNCTION);
171  }
172  template <typename Mod> Mod *get() {
173  return static_cast<Mod *>(Map.lookup(&ID<Mod>::Key));
174  }
175  template <typename Mod> const Mod *get() const {
176  return const_cast<FeatureModuleSet *>(this)->get<Mod>();
177  }
178 };
179 
180 template <typename Mod> int FeatureModuleSet::ID<Mod>::Key;
181 
182 } // namespace clangd
183 } // namespace clang
184 #endif
clang::clangd::FeatureModuleSet::begin
const_iterator begin() const
Definition: FeatureModule.h:166
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:172
clang::clangd::FeatureModuleSet
A FeatureModuleSet is a collection of feature modules installed in clangd.
Definition: FeatureModule.h:145
clang::clangd::Deadline::infinity
static Deadline infinity()
Definition: Threading.h:64
clang::clangd::FeatureModuleSet::end
iterator end()
Definition: FeatureModule.h:165
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:163
clang::clangd::FeatureModule::index
const SymbolIndex * index()
The index is used to get information about the whole codebase.
Definition: FeatureModule.h:123
clang::clangd::FeatureModule::ASTListener
Extension point that allows modules to observe and modify an AST build.
Definition: FeatureModule.h:105
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:121
clang::clangd::FeatureModuleSet::get
const Mod * get() const
Definition: FeatureModule.h:175
clang::clangd::Deadline
A point in time we can wait for.
Definition: Threading.h:59
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:101
clang::clangd::FeatureModule::fs
const ThreadsafeFS & fs()
The filesystem is used to read source files on disk.
Definition: FeatureModule.h:125
clang::clangd::Diag
A top-level diagnostic that may have Notes and Fixes.
Definition: Diagnostics.h:97
Threading.h
clang::clangd::FeatureModuleSet::end
const_iterator end() const
Definition: FeatureModule.h:167
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:132
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:130
clang::clangd::FeatureModule::ASTListener::sawDiagnostic
virtual void sawDiagnostic(const clang::Diagnostic &, clangd::Diag &)
Called everytime a diagnostic is encountered.
Definition: FeatureModule.h:112
clang::clangd::SymbolIndex
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
Definition: Index.h:111
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:28
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:161
clang::clangd::FeatureModuleSet::FeatureModuleSet
FeatureModuleSet()=default
clang::clangd::FeatureModuleSet::begin
iterator begin()
Definition: FeatureModule.h:164
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:169
clang::clangd::FeatureModule::astListeners
virtual std::unique_ptr< ASTListener > astListeners()
Can be called asynchronously before building an AST.
Definition: FeatureModule.h:115
clang::clangd::TUScheduler
Handles running tasks for ClangdServer and managing the resources (e.g., preambles and ASTs) for open...
Definition: TUScheduler.h:186
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:100
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