diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt --- a/clang-tools-extra/clangd/CMakeLists.txt +++ b/clang-tools-extra/clangd/CMakeLists.txt @@ -74,6 +74,7 @@ Hover.cpp IncludeFixer.cpp JSONTransport.cpp + Module.cpp PathMapping.cpp Protocol.cpp Quality.cpp diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -14,6 +14,7 @@ #include "ConfigProvider.h" #include "GlobalCompilationDatabase.h" #include "Hover.h" +#include "Module.h" #include "Protocol.h" #include "SemanticHighlighting.h" #include "TUScheduler.h" @@ -29,14 +30,17 @@ #include "support/ThreadsafeFS.h" #include "clang/Tooling/CompilationDatabase.h" #include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include +#include #include #include #include +#include namespace clang { namespace clangd { @@ -151,6 +155,8 @@ /// Enable preview of FoldingRanges feature. bool FoldingRanges = false; + ModuleSet *Modules = nullptr; + explicit operator TUScheduler::Options() const; }; // Sensible default options for use in tests. @@ -345,6 +351,7 @@ const GlobalCompilationDatabase &CDB; const ThreadsafeFS &TFS; + ModuleSet *Modules = nullptr; Path ResourceDir; // The index used to look up symbols. This could be: 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 @@ -138,7 +138,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB, const ThreadsafeFS &TFS, const Options &Opts, Callbacks *Callbacks) - : CDB(CDB), TFS(TFS), + : CDB(CDB), TFS(TFS), Modules(Opts.Modules), DynamicIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex() : nullptr), ClangTidyProvider(Opts.ClangTidyProvider), WorkspaceRoot(Opts.WorkspaceRoot), diff --git a/clang-tools-extra/clangd/Headers.cpp b/clang-tools-extra/clangd/Headers.cpp --- a/clang-tools-extra/clangd/Headers.cpp +++ b/clang-tools-extra/clangd/Headers.cpp @@ -36,7 +36,7 @@ CharSourceRange /*FilenameRange*/, const FileEntry *File, llvm::StringRef /*SearchPath*/, llvm::StringRef /*RelativePath*/, - const Module * /*Imported*/, + const clang::Module * /*Imported*/, SrcMgr::CharacteristicKind FileKind) override { auto MainFID = SM.getMainFileID(); // If an include is part of the preamble patch, translate #line directives. diff --git a/clang-tools-extra/clangd/Module.h b/clang-tools-extra/clangd/Module.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/Module.h @@ -0,0 +1,60 @@ +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_MODULE_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_MODULE_H + +#include "llvm/ADT/StringRef.h" +#include +#include + +namespace clang { +namespace clangd { + +/// A Module contributes a vertical feature to clangd. Currently this consists +/// of only a public interface to access the functionality from C++ embedders, +/// ClangdServer::getModule()->foo(...) +/// +/// FIXME: Extend this with LSP bindings to support updating capabilities and +/// implementing LSP endpoints. +/// +/// 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 +/// FIXME: LSP bindings should be registered at ClangdLSPServer creation, and +/// we should make some server facilities like TUScheduler and index +/// available to those modules after ClangdServer is initalized. +/// - module hooks can be called afterwards. +/// - modules can be destroyed before/after ClangdServer and ClangdLSPServer +/// FIXME: Once we make server facilities available to modules, we'll need to +/// ensure ClangdServer is destroyed after all the modules are done/gone. +/// +/// Conventionally, standard modules live in the `clangd` namespace, and other +/// exposed details live in a sub-namespace. +class Module { +public: + virtual ~Module() = default; + + /// Identifier for the plugin, should be unique. + virtual llvm::StringLiteral id() = 0; + + /// Some modules might own background tasks. They should override this method + /// to indicate status of these tasks. + virtual void blockUntilIdle() {} +}; + +/// Wrapper around a set of modules to provide type based grouping. +// Ideas for implementing this: +// - dyn_cast (with possibly some caching on top to only traverse once) +// - have a plugin registry for each individual module type? +// - make constructor of derived modules register themselves to a +// singleton-list, and provide an endpoint to iterate over. +// I am leaning towards dyn_cast option and precomputing the grouping at +// construction time in ModuleSet. WDYT? +class ModuleSet { +public: + explicit ModuleSet(std::vector> Modules); + // Returns all the modules of type T. + template std::vector getModules() { return {}; } +}; + +} // namespace clangd +} // namespace clang +#endif diff --git a/clang-tools-extra/clangd/Module.cpp b/clang-tools-extra/clangd/Module.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clangd/Module.cpp @@ -0,0 +1,13 @@ +//===--- Module.cpp - Main clangd server code --------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "Module.h" + +namespace clang { +namespace clangd {} // namespace clangd +} // namespace clang diff --git a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp --- a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp +++ b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp @@ -376,7 +376,7 @@ void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, CharSourceRange FilenameRange, const FileEntry *, - StringRef, StringRef, const Module *, + StringRef, StringRef, const clang::Module *, SrcMgr::CharacteristicKind) override { Includes.emplace_back(SM, HashLoc, IncludeTok, FileName, IsAngled, FilenameRange);