ilya-biryukov created this revision.
ilya-biryukov added reviewers: klimek, sammccall.
Herald added subscribers: kadircet, arphaman, jkorous, MaskRay, ioeric.

A proposal for the interface of the new build system integration.
Similar to CompilationDatabase, but will provide more functionality and live
in clangd instead of tooling until stabilized.

Main points of interest are:

- clangd::Integration is a user-facing API, it handles loading the proper build 
system integrations from the directory structure and notifying the clients 
about all changes. It implements clang::GlobalCompilationDatabase and is used 
by all of clangd to get compile commands, etc.

- clangd::BuildSystem interface is for build system implementations. It handles 
interactions with a single build system (initially only 
'compile_commands.json', but we also plan to experiment with adding direct 
CMake or ninja support).

- The clangd::GlobalCompilationDatabase now also provides a VFS instance 
alongside the compile command. The idea is to allow build systems to overlay 
generated files, if they can need (this is Bazel-specific AFAIK). It is also 
the responsibility of the buildsystem to update any dependencies (e.g. the 
generated files) it knows about before providing the compile commands.


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D54952

Files:
  clangd/BuildSystem.h
  clangd/BuildSystemPlugin.h
  clangd/FSProvider.h
  clangd/FSWatch.h
  clangd/GlobalCompilationDatabase.h

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 <memory>
 #include <mutex>
@@ -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<llvm::vfs::FileSystem> FS;
+  /// Information about the project that the file belongs to.
+  llvm::Optional<ProjectInfo> Project;
+};
+
+using CommandChanged = Event<std::vector<std::string>>;
+
 /// 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<tooling::CompileCommand>
-  getCompileCommand(PathRef File, ProjectInfo * = nullptr) const = 0;
+  virtual llvm::Optional<CompileInputs>
+  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<std::vector<std::string>>;
   /// 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
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 <memory>
+
+namespace clang {
+namespace clangd {
+
+enum class FSEventKind { Added, Modified, Removed };
+
+/// An event that fires when the file has changed.
+using FileChangedEvent = Event<FSEventKind>;
+
+/// 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<FileSystemWatcher>
+createPollingWatcher(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
+                     std::chrono::duration<double> PollIntervalSecs);
+
+/// Never reports any changes.
+std::unique_ptr<FileSystemWatcher> createSilentWatcher();
+} // 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<llvm::vfs::FileSystem>
   getFileSystem() const = 0;
+
+  virtual FileSystemWatcher &watcher() = 0;
 };
 
 class RealFileSystemProvider : public FileSystemProvider {
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<BuildSystem> tryLoad(FileSystemProvider &FS,
+                                               llvm::StringRef Dir) = 0;
+};
+
+using BuildSystemPluginRegistry = llvm::Registry<BuildSystemPlugin>;
+
+} // namespace clangd
+} // namespace clang
+
+#endif
\ No newline at end of file
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 <memory>
+#include <mutex>
+
+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<Integration> PluginBased(FileSystemProvider &FS);
+
+  using GlobalLoaderFunc =
+      llvm::unique_function<std::shared_ptr<BuildSystem>()>;
+  /// Will load a single build system once and reuse it for all files that are
+  /// required.
+  static std::unique_ptr<Integration> Global(FileSystemProvider &FS,
+                                             GlobalLoaderFunc Loader);
+
+  ~Integration();
+
+  FileSystemProvider &fs() const override;
+
+  llvm::Optional<CompileInputs> getCompileCommand(PathRef File) const override;
+
+  CommandChanged::Subscription watch(CommandChanged::Listener L) const override;
+
+  class Discovery;
+
+private:
+  Integration(std::unique_ptr<Discovery> D, FileSystemProvider &FS);
+
+  FileSystemProvider &FS;
+  std::unique_ptr<Discovery> D;
+
+  /// An event firing when the build system is loaded.
+  using BSLoadedEvent = Event<std::shared_ptr<BuildSystem>>;
+  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<CompileInputs> 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<BuildSystem> loadWithPlugins(FileSystemProvider &FS,
+                                             llvm::StringRef Dir);
+
+} // namespace clangd
+} // namespace clang
+
+#endif
\ No newline at end of file
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to