[clang-tools-extra] 40cc63e - [clangd] Modules can have a public API. NFC

Sam McCall via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 16 06:23:16 PST 2021


Author: Sam McCall
Date: 2021-02-16T15:22:57+01:00
New Revision: 40cc63ea6eec7874d3a358f9fa549ef2f6543512

URL: https://github.com/llvm/llvm-project/commit/40cc63ea6eec7874d3a358f9fa549ef2f6543512
DIFF: https://github.com/llvm/llvm-project/commit/40cc63ea6eec7874d3a358f9fa549ef2f6543512.diff

LOG: [clangd] Modules can have a public API. NFC

Differential Revision: https://reviews.llvm.org/D96730

Added: 
    clang-tools-extra/clangd/Module.cpp

Modified: 
    clang-tools-extra/clangd/CMakeLists.txt
    clang-tools-extra/clangd/ClangdServer.cpp
    clang-tools-extra/clangd/ClangdServer.h
    clang-tools-extra/clangd/Module.h
    clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt
index 3de510665723..bf654a23e00c 100644
--- a/clang-tools-extra/clangd/CMakeLists.txt
+++ b/clang-tools-extra/clangd/CMakeLists.txt
@@ -75,6 +75,7 @@ add_clang_library(clangDaemon
   Hover.cpp
   IncludeFixer.cpp
   JSONTransport.cpp
+  Module.cpp
   PathMapping.cpp
   Protocol.cpp
   Quality.cpp

diff  --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index b39e582d84a1..49f01cd0b59a 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -127,7 +127,7 @@ ClangdServer::Options::operator TUScheduler::Options() const {
 ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
                            const ThreadsafeFS &TFS, const Options &Opts,
                            Callbacks *Callbacks)
-    : CDB(CDB), TFS(TFS),
+    : Modules(Opts.Modules), CDB(CDB), TFS(TFS),
       DynamicIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex() : nullptr),
       ClangTidyProvider(Opts.ClangTidyProvider),
       WorkspaceRoot(Opts.WorkspaceRoot),

diff  --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
index 83c8567461ec..9581a558ea31 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -161,6 +161,15 @@ class ClangdServer {
   ClangdServer(const GlobalCompilationDatabase &CDB, const ThreadsafeFS &TFS,
                const Options &Opts, Callbacks *Callbacks = nullptr);
 
+  /// Gets the installed module of a given type, if any.
+  /// This exposes access the public interface of modules that have one.
+  template <typename Mod> Mod *getModule() {
+    return Modules ? Modules->get<Mod>() : nullptr;
+  }
+  template <typename Mod> const Mod *getModule() const {
+    return Modules ? Modules->get<Mod>() : nullptr;
+  }
+
   /// Add a \p File to the list of tracked C++ files or update the contents if
   /// \p File is already tracked. Also schedules parsing of the AST for it on a
   /// separate thread. When the parsing is complete, DiagConsumer passed in
@@ -337,6 +346,7 @@ class ClangdServer {
                   ArrayRef<tooling::Range> Ranges,
                   Callback<tooling::Replacements> CB);
 
+  ModuleSet *Modules;
   const GlobalCompilationDatabase &CDB;
   const ThreadsafeFS &TFS;
 

diff  --git a/clang-tools-extra/clangd/Module.cpp b/clang-tools-extra/clangd/Module.cpp
new file mode 100644
index 000000000000..1152ae4e7fb2
--- /dev/null
+++ b/clang-tools-extra/clangd/Module.cpp
@@ -0,0 +1,18 @@
+#include "Module.h"
+
+namespace clang {
+namespace clangd {
+
+bool ModuleSet::addImpl(void *Key, std::unique_ptr<Module> M,
+                        const char *Source) {
+  if (!Map.try_emplace(Key, M.get()).second) {
+    // Source should (usually) include the name of the concrete module type.
+    elog("Tried to register duplicate modules via {0}", Source);
+    return false;
+  }
+  Modules.push_back(std::move(M));
+  return true;
+}
+
+} // namespace clangd
+} // namespace clang

diff  --git a/clang-tools-extra/clangd/Module.h b/clang-tools-extra/clangd/Module.h
index a99b78d51c44..1db228000a6e 100644
--- a/clang-tools-extra/clangd/Module.h
+++ b/clang-tools-extra/clangd/Module.h
@@ -3,8 +3,10 @@
 
 #include "LSPBinder.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
 #include "llvm/Support/JSON.h"
 #include <memory>
+#include <type_traits>
 #include <vector>
 
 namespace clang {
@@ -41,12 +43,28 @@ class Module {
                              llvm::json::Object &ServerCaps) {}
 };
 
+/// A ModuleSet is a collection of modules installed in clangd.
+///
+/// Modules can be looked up by type, or used through the Module interface.
+/// This allows individual modules to expose a public API.
+/// For this reason, there can be only one module of each type.
+///
+/// ModuleSet owns the modules. It is itself owned by main, not ClangdServer.
 class ModuleSet {
   std::vector<std::unique_ptr<Module>> Modules;
+  llvm::DenseMap<void *, Module *> Map;
+
+  template <typename Mod> struct ID {
+    static_assert(std::is_base_of<Module, Mod>::value &&
+                      std::is_final<Mod>::value,
+                  "Modules must be final classes derived from clangd::Module");
+    static int Key;
+  };
+
+  bool addImpl(void *Key, std::unique_ptr<Module>, const char *Source);
 
 public:
-  explicit ModuleSet(std::vector<std::unique_ptr<Module>> Modules)
-      : Modules(std::move(Modules)) {}
+  ModuleSet() = default;
 
   using iterator = llvm::pointee_iterator<decltype(Modules)::iterator>;
   using const_iterator =
@@ -55,7 +73,20 @@ class ModuleSet {
   iterator end() { return iterator(Modules.end()); }
   const_iterator begin() const { return const_iterator(Modules.begin()); }
   const_iterator end() const { return const_iterator(Modules.end()); }
+
+  template <typename Mod> bool add(std::unique_ptr<Mod> M) {
+    return addImpl(&ID<Mod>::Key, std::move(M), LLVM_PRETTY_FUNCTION);
+  }
+  template <typename Mod> Mod *get() {
+    return static_cast<Mod *>(Map.lookup(&ID<Mod>::Key));
+  }
+  template <typename Mod> const Mod *get() const {
+    return const_cast<ModuleSet *>(this)->get<Mod>();
+  }
 };
+
+template <typename Mod> int ModuleSet::ID<Mod>::Key;
+
 } // namespace clangd
 } // namespace clang
 #endif

diff  --git a/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp b/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp
index d8674d601bc8..0d073fad48ed 100644
--- a/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp
@@ -222,25 +222,26 @@ TEST_F(LSPTest, CDBConfigIntegration) {
 }
 
 TEST_F(LSPTest, ModulesTest) {
-  class MathModule : public Module {
+  class MathModule final : public Module {
     void initializeLSP(LSPBinder &Bind, const llvm::json::Object &ClientCaps,
                        llvm::json::Object &ServerCaps) override {
       Bind.notification("add", this, &MathModule::add);
       Bind.method("get", this, &MathModule::get);
     }
 
+    int Value = 0;
+
+  public:
     void add(const int &X) { Value += X; }
     void get(const std::nullptr_t &, Callback<int> Reply) { Reply(Value); }
-    int Value = 0;
   };
-  std::vector<std::unique_ptr<Module>> Mods;
-  Mods.push_back(std::make_unique<MathModule>());
-  ModuleSet ModSet(std::move(Mods));
-  Opts.Modules = &ModSet;
+  ModuleSet Mods;
+  Mods.add(std::make_unique<MathModule>());
+  Opts.Modules = &Mods;
 
   auto &Client = start();
   Client.notify("add", 2);
-  Client.notify("add", 8);
+  Mods.get<MathModule>()->add(8);
   EXPECT_EQ(10, Client.call("get", nullptr).takeValue());
 }
 


        


More information about the cfe-commits mailing list