Index: clangd/BuildSystem.h =================================================================== --- /dev/null +++ clangd/BuildSystem.h @@ -0,0 +1,91 @@ +//===--- BuildSystem.h --------------------------------------------*-C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Interfaces for buildsystem integration. + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_BUILD_SYSTEM_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_BUILD_SYSTEM_H + +#include "FSProvider.h" +#include "Function.h" +#include "GlobalCompilationDatabase.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "llvm/ADT/FunctionExtras.h" +#include "llvm/Support/VirtualFileSystem.h" +#include +#include + +namespace clang { +namespace clangd { + +class BuildSystem; + +/// Default compilation database used by clangd, based on the build system. +class Integration : public GlobalCompilationDatabase { +public: + /// Loads the build systems by consulting the registry of available + /// BuildSystemPlugin instances. + static std::unique_ptr PluginBased(FileSystemProvider &FS); + + using GlobalLoaderFunc = + llvm::unique_function()>; + /// Will load a single build system once and reuse it for all files that are + /// required. + static std::unique_ptr Global(FileSystemProvider &FS, + GlobalLoaderFunc Loader); + + ~Integration(); + + FileSystemProvider &fs() const override; + + llvm::Optional getCompileCommand(PathRef File) const override; + + CommandChanged::Subscription watch(CommandChanged::Listener L) const override; + + class Discovery; + +private: + Integration(std::unique_ptr D, FileSystemProvider &FS); + + FileSystemProvider &FS; + std::unique_ptr D; + + /// An event firing when the build system is loaded. + using BSLoadedEvent = Event>; + BSLoadedEvent::Subscription Subscription; + + mutable CommandChanged OnFilesAdded; +}; + +/// Handles interaction between clangd and a build system. +/// Similar to a CompilationDatabase, but additionally supports change tracking +/// facilities. +/// The abstraction is highly experimental, we expect to change the interface in +/// the future. +class BuildSystem { +public: + virtual ~BuildSystem() = default; + + /// Provide compilation command for the provided \p Path, possibly building + /// all prerequisites if the build system supports it. + virtual llvm::Optional buildInputs(FileSystemProvider &FS, + llvm::StringRef Path) = 0; + + /// Notification that fires when inputs for a set of files might have changed. + virtual CommandChanged::Subscription watch(CommandChanged::Listener L) = 0; +}; + +/// Attempt to load a build system under \p Dir with a set of plugins. +/// Does not traverse parent directories. +std::unique_ptr loadWithPlugins(FileSystemProvider &FS, + llvm::StringRef Dir); + +} // namespace clangd +} // namespace clang + +#endif \ No newline at end of file Index: clangd/BuildSystemPlugin.h =================================================================== --- /dev/null +++ clangd/BuildSystemPlugin.h @@ -0,0 +1,43 @@ +//===--- BuildSystemPlugin.h --------------------------------------*-C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Interfaces for buildsystem integration. + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_BUILD_SYSTEM_PLUGIN_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_BUILD_SYSTEM_PLUGIN_H + +#include "FSProvider.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Registry.h" + +namespace clang { +namespace clangd { + +class BuildSystem; + +/// A plugin to provide a build system integration for clangd. +class BuildSystemPlugin { +public: + virtual ~BuildSystemPlugin() = default; + + /// Registered plugins are consulted in the decreasing order of their weights. + /// The first plugin that produces a non-null BuildSystem wins. + /// The 'compile_commands.json' has a weight of 1. + virtual float weight() = 0; + /// Attempt to detect and load the build system that resides in \p Dir. + /// Should return null if detection failed. + virtual std::unique_ptr tryLoad(FileSystemProvider &FS, + llvm::StringRef Dir) = 0; +}; + +using BuildSystemPluginRegistry = llvm::Registry; + +} // namespace clangd +} // namespace clang + +#endif \ No newline at end of file Index: clangd/FSProvider.h =================================================================== --- clangd/FSProvider.h +++ clangd/FSProvider.h @@ -10,6 +10,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FSPROVIDER_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FSPROVIDER_H +#include "FSWatch.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/VirtualFileSystem.h" @@ -21,12 +22,15 @@ class FileSystemProvider { public: virtual ~FileSystemProvider() = default; + /// Called by ClangdServer to obtain a vfs::FileSystem to be used for parsing. /// Context::current() will be the context passed to the clang entrypoint, /// such as addDocument(), and will also be propagated to result callbacks. /// Embedders may use this to isolate filesystem accesses. virtual llvm::IntrusiveRefCntPtr getFileSystem() const = 0; + + virtual FileSystemWatcher &watcher() = 0; }; class RealFileSystemProvider : public FileSystemProvider { Index: clangd/FSWatch.h =================================================================== --- /dev/null +++ clangd/FSWatch.h @@ -0,0 +1,48 @@ +//===--- FSWatch.h ------------------------------------------------*-C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FS_WATCH_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FS_WATCH_H + +#include "Function.h" +#include "llvm/ADT/FunctionExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VirtualFileSystem.h" +#include + +namespace clang { +namespace clangd { + +enum class FSEventKind { Added, Modified, Removed }; + +/// An event that fires when the file has changed. +using FileChangedEvent = Event; + +/// An interface to allow watching for changes in the filesystem. +class FileSystemWatcher { +public: + virtual ~FileSystemWatcher() = default; + + /// Add a watch for a single file or directory. + virtual FileChangedEvent::Subscription + watchFile(llvm::StringRef Path, FileChangedEvent::Listener L) = 0; +}; + +/// Polls the underlying VFS for changes every \p PollIntervalSecs seconds on a +/// separate thread. Should only be used when a small number of files. +std::unique_ptr +createPollingWatcher(llvm::IntrusiveRefCntPtr FS, + std::chrono::duration PollIntervalSecs); + +/// Never reports any changes. +std::unique_ptr createSilentWatcher(); +} // namespace clangd +} // namespace clang + +#endif \ No newline at end of file Index: clangd/GlobalCompilationDatabase.h =================================================================== --- clangd/GlobalCompilationDatabase.h +++ clangd/GlobalCompilationDatabase.h @@ -10,8 +10,10 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_GLOBALCOMPILATIONDATABASE_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_GLOBALCOMPILATIONDATABASE_H +#include "FSProvider.h" #include "Function.h" #include "Path.h" +#include "clang/Tooling/CompilationDatabase.h" #include "llvm/ADT/StringMap.h" #include #include @@ -34,15 +36,30 @@ std::string SourceRoot; }; +/// Full information required to run clang frontend on the file. +struct CompileInputs { + /// Command used to build the AST. + tooling::CompileCommand Command; + /// An instance of VFS that should be used for compilations. Must have proper + /// working directory set in advance, can contain overlays that include the + /// generated files. + IntrusiveRefCntPtr FS; + /// Information about the project that the file belongs to. + llvm::Optional Project; +}; + +using CommandChanged = Event>; + /// Provides compilation arguments used for parsing C and C++ files. class GlobalCompilationDatabase { public: virtual ~GlobalCompilationDatabase() = default; + virtual FileSystemProvider &fs() const = 0; + /// If there are any known-good commands for building this file, returns one. - /// If the ProjectInfo pointer is set, it will also be populated. - virtual llvm::Optional - getCompileCommand(PathRef File, ProjectInfo * = nullptr) const = 0; + virtual llvm::Optional + getCompileCommand(PathRef File) const = 0; /// Makes a guess at how to build a file. /// The default implementation just runs clang on the file. @@ -52,12 +69,7 @@ using CommandChanged = Event>; /// The callback is notified when files may have new compile commands. /// The argument is a list of full file paths. - CommandChanged::Subscription watch(CommandChanged::Listener L) const { - return OnCommandChanged.observe(std::move(L)); - } - -protected: - mutable CommandChanged OnCommandChanged; + virtual CommandChanged::Subscription watch(CommandChanged::Listener L) const; }; /// Gets compile args from tooling::CompilationDatabases built for parent