brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.1 KiB · 1d636d7 Raw
226 lines · c
1//===--- GlobalCompilationDatabase.h -----------------------------*- C++-*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_GLOBALCOMPILATIONDATABASE_H10#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_GLOBALCOMPILATIONDATABASE_H11 12#include "ProjectModules.h"13#include "support/Function.h"14#include "support/Path.h"15#include "support/Threading.h"16#include "support/ThreadsafeFS.h"17#include "clang/Tooling/ArgumentsAdjusters.h"18#include "clang/Tooling/CompilationDatabase.h"19#include "llvm/ADT/FunctionExtras.h"20#include "llvm/ADT/StringMap.h"21#include <memory>22#include <mutex>23#include <optional>24#include <vector>25 26namespace clang {27namespace clangd {28 29struct ProjectInfo {30  // The directory in which the compilation database was discovered.31  // Empty if directory-based compilation database discovery was not used.32  std::string SourceRoot;33};34 35/// Provides compilation arguments used for parsing C and C++ files.36class GlobalCompilationDatabase {37public:38  virtual ~GlobalCompilationDatabase() = default;39 40  /// If there are any known-good commands for building this file, returns one.41  virtual std::optional<tooling::CompileCommand>42  getCompileCommand(PathRef File) const = 0;43 44  /// Finds the closest project to \p File.45  virtual std::optional<ProjectInfo> getProjectInfo(PathRef File) const {46    return std::nullopt;47  }48 49  /// Get the modules in the closest project to \p File50  virtual std::unique_ptr<ProjectModules>51  getProjectModules(PathRef File) const {52    return nullptr;53  }54 55  /// Makes a guess at how to build a file.56  /// The default implementation just runs clang on the file.57  /// Clangd should treat the results as unreliable.58  virtual tooling::CompileCommand getFallbackCommand(PathRef File) const;59 60  /// If the CDB does any asynchronous work, wait for it to complete.61  /// For use in tests.62  virtual bool blockUntilIdle(Deadline D) const { return true; }63 64  using CommandChanged = Event<std::vector<std::string>>;65  /// The callback is notified when files may have new compile commands.66  /// The argument is a list of full file paths.67  CommandChanged::Subscription watch(CommandChanged::Listener L) const {68    return OnCommandChanged.observe(std::move(L));69  }70 71protected:72  mutable CommandChanged OnCommandChanged;73};74 75// Helper class for implementing GlobalCompilationDatabases that wrap others.76class DelegatingCDB : public GlobalCompilationDatabase {77public:78  DelegatingCDB(const GlobalCompilationDatabase *Base);79  DelegatingCDB(std::unique_ptr<GlobalCompilationDatabase> Base);80 81  std::optional<tooling::CompileCommand>82  getCompileCommand(PathRef File) const override;83 84  std::optional<ProjectInfo> getProjectInfo(PathRef File) const override;85 86  std::unique_ptr<ProjectModules>87  getProjectModules(PathRef File) const override;88 89  tooling::CompileCommand getFallbackCommand(PathRef File) const override;90 91  bool blockUntilIdle(Deadline D) const override;92 93private:94  const GlobalCompilationDatabase *Base;95  std::unique_ptr<GlobalCompilationDatabase> BaseOwner;96  CommandChanged::Subscription BaseChanged;97};98 99/// Gets compile args from tooling::CompilationDatabases built for parent100/// directories.101class DirectoryBasedGlobalCompilationDatabase102    : public GlobalCompilationDatabase {103public:104  struct Options {105    Options(const ThreadsafeFS &TFS) : TFS(TFS) {}106 107    const ThreadsafeFS &TFS;108    // Frequency to check whether e.g. compile_commands.json has changed.109    std::chrono::steady_clock::duration RevalidateAfter =110        std::chrono::seconds(5);111    // Frequency to check whether e.g. compile_commands.json has been created.112    // (This is more expensive to check frequently, as we check many locations).113    std::chrono::steady_clock::duration RevalidateMissingAfter =114        std::chrono::seconds(30);115    // Used to provide per-file configuration.116    std::function<Context(llvm::StringRef)> ContextProvider;117    // Only look for a compilation database in this one fixed directory.118    // FIXME: fold this into config/context mechanism.119    std::optional<Path> CompileCommandsDir;120  };121 122  DirectoryBasedGlobalCompilationDatabase(const Options &Opts);123  ~DirectoryBasedGlobalCompilationDatabase() override;124 125  /// Scans File's parents looking for compilation databases.126  /// Any extra flags will be added.127  /// Might trigger OnCommandChanged, if CDB wasn't broadcasted yet.128  std::optional<tooling::CompileCommand>129  getCompileCommand(PathRef File) const override;130 131  /// Returns the path to first directory containing a compilation database in132  /// \p File's parents.133  std::optional<ProjectInfo> getProjectInfo(PathRef File) const override;134 135  std::unique_ptr<ProjectModules>136  getProjectModules(PathRef File) const override;137 138  bool blockUntilIdle(Deadline Timeout) const override;139 140private:141  Options Opts;142 143  class DirectoryCache;144  // Keyed by possibly-case-folded directory path.145  // We can hand out pointers as they're stable and entries are never removed.146  mutable llvm::StringMap<DirectoryCache> DirCaches;147  mutable std::mutex DirCachesMutex;148 149  std::vector<DirectoryCache *>150  getDirectoryCaches(llvm::ArrayRef<llvm::StringRef> Dirs) const;151 152  struct CDBLookupRequest {153    PathRef FileName;154    // Whether this lookup should trigger discovery of the CDB found.155    bool ShouldBroadcast = false;156    // Cached results newer than this are considered fresh and not checked157    // against disk.158    std::chrono::steady_clock::time_point FreshTime;159    std::chrono::steady_clock::time_point FreshTimeMissing;160  };161  struct CDBLookupResult {162    std::shared_ptr<const tooling::CompilationDatabase> CDB;163    ProjectInfo PI;164  };165  std::optional<CDBLookupResult> lookupCDB(CDBLookupRequest Request) const;166 167  class BroadcastThread;168  std::unique_ptr<BroadcastThread> Broadcaster;169 170  // Performs broadcast on governed files.171  void broadcastCDB(CDBLookupResult Res) const;172 173  // cache test calls lookupCDB directly to ensure valid/invalid times.174  friend class DirectoryBasedGlobalCompilationDatabaseCacheTest;175};176 177/// Extracts system include search path from drivers matching QueryDriverGlobs178/// and adds them to the compile flags.179/// Returns null when \p QueryDriverGlobs is empty.180using SystemIncludeExtractorFn = llvm::unique_function<void(181    tooling::CompileCommand &, llvm::StringRef) const>;182SystemIncludeExtractorFn183getSystemIncludeExtractor(llvm::ArrayRef<std::string> QueryDriverGlobs);184 185/// Wraps another compilation database, and supports overriding the commands186/// using an in-memory mapping.187class OverlayCDB : public DelegatingCDB {188public:189  // Makes adjustments to a tooling::CompileCommand which will be used to190  // process a file (possibly different from the one in the command).191  using CommandMangler = llvm::unique_function<void(tooling::CompileCommand &,192                                                    StringRef File) const>;193 194  // Base may be null, in which case no entries are inherited.195  // FallbackFlags are added to the fallback compile command.196  // Adjuster is applied to all commands, fallback or not.197  OverlayCDB(const GlobalCompilationDatabase *Base,198             std::vector<std::string> FallbackFlags = {},199             CommandMangler Mangler = nullptr);200 201  std::optional<tooling::CompileCommand>202  getCompileCommand(PathRef File) const override;203  tooling::CompileCommand getFallbackCommand(PathRef File) const override;204 205  /// Sets or clears the compilation command for a particular file.206  /// Returns true if the command was changed (including insertion and removal),207  /// false if it was unchanged.208  bool209  setCompileCommand(PathRef File,210                    std::optional<tooling::CompileCommand> CompilationCommand);211 212  std::unique_ptr<ProjectModules>213  getProjectModules(PathRef File) const override;214 215private:216  mutable std::mutex Mutex;217  llvm::StringMap<tooling::CompileCommand> Commands; /* GUARDED_BY(Mut) */218  CommandMangler Mangler;219  std::vector<std::string> FallbackFlags;220};221 222} // namespace clangd223} // namespace clang224 225#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_GLOBALCOMPILATIONDATABASE_H226