diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -167,6 +167,16 @@ } if (DynamicIdx) AddIndex(DynamicIdx.get()); + + if (Opts.Modules) { + Module::Facilities F{ + this->WorkScheduler, + this->Index, + this->TFS, + }; + for (auto &Mod : *Opts.Modules) + Mod.initialize(F); + } } void ClangdServer::addDocument(PathRef File, llvm::StringRef Contents, diff --git a/clang-tools-extra/clangd/Module.h b/clang-tools-extra/clangd/Module.h --- a/clang-tools-extra/clangd/Module.h +++ b/clang-tools-extra/clangd/Module.h @@ -1,7 +1,14 @@ +//===--- Module.h - Plugging features into clangd -----------------*-C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_MODULE_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_MODULE_H -#include "LSPBinder.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/JSON.h" @@ -11,6 +18,10 @@ namespace clang { namespace clangd { +class LSPBinder; +class SymbolIndex; +class ThreadsafeFS; +class TUScheduler; /// A Module contributes a vertical feature to clangd. /// @@ -18,10 +29,11 @@ /// /// The lifetime of a module is roughly: /// - modules are created before the LSP server, in ClangdMain.cpp -/// - these modules are then passed to ClangdLSPServer and ClangdServer -/// - module hooks can be called at this point. -/// FIXME: We should make some server facilities like TUScheduler and index -/// available to those modules after ClangdServer is initalized. +/// - these modules are then passed to ClangdLSPServer in a ModuleSet +/// - initializeLSP() is called when the editor calls initialize. +// - initialize() is then called by ClangdServer as it is constructed. +/// - module hooks can be called by the server at this point. +/// Server facilities (scheduler etc) are available. /// - ClangdServer will not be destroyed until all the requests are done. /// FIXME: Block server shutdown until all the modules are idle. /// - modules will be destroyed after ClangdLSPServer is destroyed. @@ -41,6 +53,28 @@ virtual void initializeLSP(LSPBinder &Bind, const llvm::json::Object &ClientCaps, llvm::json::Object &ServerCaps) {} + + /// Shared server facilities needed by the module to get its work done. + struct Facilities { + TUScheduler &Scheduler; + const SymbolIndex *Index; + const ThreadsafeFS &FS; + }; + /// Called by the server to prepare this module for use. + void initialize(const Facilities &F); + +protected: + /// Accessors for modules to access shared server facilities they depend on. + Facilities &facilities(); + /// The scheduler is used to run tasks on worker threads and access ASTs. + TUScheduler &scheduler() { return facilities().Scheduler; } + /// The index is used to get information about the whole codebase. + const SymbolIndex *index() { return facilities().Index; } + /// The filesystem is used to read source files on disk. + const ThreadsafeFS &fs() { return facilities().FS; } + +private: + llvm::Optional Fac; }; /// A ModuleSet is a collection of modules installed in clangd. diff --git a/clang-tools-extra/clangd/Module.cpp b/clang-tools-extra/clangd/Module.cpp --- a/clang-tools-extra/clangd/Module.cpp +++ b/clang-tools-extra/clangd/Module.cpp @@ -1,8 +1,27 @@ +//===--- Module.cpp - Plugging features into clangd -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #include "Module.h" +#include "support/Logger.h" namespace clang { namespace clangd { +void Module::initialize(const Facilities &F) { + assert(!Fac.hasValue() && "Initialized twice"); + Fac.emplace(F); +} + +Module::Facilities &Module::facilities() { + assert(Fac.hasValue() && "Not initialized yet"); + return *Fac; +} + bool ModuleSet::addImpl(void *Key, std::unique_ptr M, const char *Source) { if (!Map.try_emplace(Key, M.get()).second) { diff --git a/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp b/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp --- a/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdLSPServerTests.cpp @@ -233,7 +233,11 @@ public: void add(const int &X) { Value += X; } - void get(const std::nullptr_t &, Callback Reply) { Reply(Value); } + void get(const std::nullptr_t &, Callback Reply) { + scheduler().runQuick( + "get", "", + [Reply(std::move(Reply)), Value(Value)]() mutable { Reply(Value); }); + } }; ModuleSet Mods; Mods.add(std::make_unique());