brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.2 KiB · ac437ee Raw
182 lines · cpp
1//===--- ConfigProvider.cpp - Loading of user configuration ---------------===//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#include "ConfigProvider.h"10#include "Config.h"11#include "ConfigFragment.h"12#include "support/FileCache.h"13#include "support/Path.h"14#include "support/ThreadsafeFS.h"15#include "support/Trace.h"16#include "llvm/ADT/STLExtras.h"17#include "llvm/ADT/StringMap.h"18#include "llvm/ADT/StringRef.h"19#include "llvm/Support/Path.h"20#include <chrono>21#include <mutex>22#include <optional>23#include <string>24 25namespace clang {26namespace clangd {27namespace config {28 29// Threadsafe cache around reading a YAML config file from disk.30class FileConfigCache : public FileCache {31  mutable llvm::SmallVector<CompiledFragment, 1> CachedValue;32  std::string Directory;33 34public:35  FileConfigCache(llvm::StringRef Path, llvm::StringRef Directory)36      : FileCache(Path), Directory(Directory) {}37 38  void get(const ThreadsafeFS &TFS, DiagnosticCallback DC,39           std::chrono::steady_clock::time_point FreshTime, bool Trusted,40           std::vector<CompiledFragment> &Out) const {41    read(42        TFS, FreshTime,43        [&](std::optional<llvm::StringRef> Data) {44          CachedValue.clear();45          if (Data)46            for (auto &Fragment : Fragment::parseYAML(*Data, path(), DC)) {47              Fragment.Source.Directory = Directory;48              Fragment.Source.Trusted = Trusted;49              CachedValue.push_back(std::move(Fragment).compile(DC));50            }51        },52        [&]() { llvm::copy(CachedValue, std::back_inserter(Out)); });53  }54};55 56std::unique_ptr<Provider> Provider::fromYAMLFile(llvm::StringRef AbsPath,57                                                 llvm::StringRef Directory,58                                                 const ThreadsafeFS &FS,59                                                 bool Trusted) {60  class AbsFileProvider : public Provider {61    mutable FileConfigCache Cache; // threadsafe62    const ThreadsafeFS &FS;63    bool Trusted;64 65    std::vector<CompiledFragment>66    getFragments(const Params &P, DiagnosticCallback DC) const override {67      std::vector<CompiledFragment> Result;68      Cache.get(FS, DC, P.FreshTime, Trusted, Result);69      return Result;70    };71 72  public:73    AbsFileProvider(llvm::StringRef Path, llvm::StringRef Directory,74                    const ThreadsafeFS &FS, bool Trusted)75        : Cache(Path, Directory), FS(FS), Trusted(Trusted) {76      assert(llvm::sys::path::is_absolute(Path));77    }78  };79 80  return std::make_unique<AbsFileProvider>(AbsPath, Directory, FS, Trusted);81}82 83std::unique_ptr<Provider>84Provider::fromAncestorRelativeYAMLFiles(llvm::StringRef RelPath,85                                        const ThreadsafeFS &FS, bool Trusted) {86  class RelFileProvider : public Provider {87    std::string RelPath;88    const ThreadsafeFS &FS;89    bool Trusted;90 91    mutable std::mutex Mu;92    // Keys are the (posix-style) ancestor directory, not the config within it.93    // We only insert into this map, so pointers to values are stable forever.94    // Mutex guards the map itself, not the values (which are threadsafe).95    mutable llvm::StringMap<FileConfigCache> Cache;96 97    std::vector<CompiledFragment>98    getFragments(const Params &P, DiagnosticCallback DC) const override {99      namespace path = llvm::sys::path;100 101      if (P.Path.empty())102        return {};103 104      // Compute absolute paths to all ancestors (substrings of P.Path).105      llvm::SmallVector<llvm::StringRef, 8> Ancestors;106      for (auto Ancestor = absoluteParent(P.Path); !Ancestor.empty();107           Ancestor = absoluteParent(Ancestor)) {108        Ancestors.emplace_back(Ancestor);109      }110      // Ensure corresponding cache entries exist in the map.111      llvm::SmallVector<FileConfigCache *, 8> Caches;112      {113        std::lock_guard<std::mutex> Lock(Mu);114        for (llvm::StringRef Ancestor : Ancestors) {115          auto It = Cache.find(Ancestor);116          // Assemble the actual config file path only once.117          if (It == Cache.end()) {118            llvm::SmallString<256> ConfigPath = Ancestor;119            path::append(ConfigPath, RelPath);120            // Use native slashes for reading the file, affects diagnostics.121            llvm::sys::path::native(ConfigPath);122            It = Cache.try_emplace(Ancestor, ConfigPath.str(), Ancestor).first;123          }124          Caches.push_back(&It->second);125        }126      }127      // Finally query each individual file.128      // This will take a (per-file) lock for each file that actually exists.129      std::vector<CompiledFragment> Result;130      for (FileConfigCache *Cache : llvm::reverse(Caches))131        Cache->get(FS, DC, P.FreshTime, Trusted, Result);132      return Result;133    };134 135  public:136    RelFileProvider(llvm::StringRef RelPath, const ThreadsafeFS &FS,137                    bool Trusted)138        : RelPath(RelPath), FS(FS), Trusted(Trusted) {139      assert(llvm::sys::path::is_relative(RelPath));140    }141  };142 143  return std::make_unique<RelFileProvider>(RelPath, FS, Trusted);144}145 146std::unique_ptr<Provider>147Provider::combine(std::vector<const Provider *> Providers) {148  class CombinedProvider : public Provider {149    std::vector<const Provider *> Providers;150 151    std::vector<CompiledFragment>152    getFragments(const Params &P, DiagnosticCallback DC) const override {153      std::vector<CompiledFragment> Result;154      for (const auto &Provider : Providers) {155        for (auto &Fragment : Provider->getFragments(P, DC))156          Result.push_back(std::move(Fragment));157      }158      return Result;159    }160 161  public:162    CombinedProvider(std::vector<const Provider *> Providers)163        : Providers(std::move(Providers)) {}164  };165 166  return std::make_unique<CombinedProvider>(std::move(Providers));167}168 169Config Provider::getConfig(const Params &P, DiagnosticCallback DC) const {170  trace::Span Tracer("getConfig");171  if (!P.Path.empty())172    SPAN_ATTACH(Tracer, "path", P.Path);173  Config C;174  for (const auto &Fragment : getFragments(P, DC))175    Fragment(P, C);176  return C;177}178 179} // namespace config180} // namespace clangd181} // namespace clang182