clang-tools  14.0.0git
ConfigProvider.cpp
Go to the documentation of this file.
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-exception
6 //
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/ScopeExit.h"
18 #include "llvm/ADT/StringMap.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Support/Path.h"
21 #include <chrono>
22 #include <mutex>
23 #include <string>
24 
25 namespace clang {
26 namespace clangd {
27 namespace config {
28 
29 // Threadsafe cache around reading a YAML config file from disk.
30 class FileConfigCache : public FileCache {
31  mutable llvm::SmallVector<CompiledFragment, 1> CachedValue;
32  std::string Directory;
33 
34 public:
35  FileConfigCache(llvm::StringRef Path, llvm::StringRef 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  [&](llvm::Optional<llvm::StringRef> Data) {
44  CachedValue.clear();
45  if (Data)
46  for (auto &Fragment : Fragment::parseYAML(*Data, path(), DC)) {
49  CachedValue.push_back(std::move(Fragment).compile(DC));
50  }
51  },
52  [&]() { llvm::copy(CachedValue, std::back_inserter(Out)); });
53  }
54 };
55 
56 std::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; // threadsafe
62  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 
83 std::unique_ptr<Provider>
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 
146 std::unique_ptr<Provider>
147 Provider::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 
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 config
180 } // namespace clangd
181 } // namespace clang
clang::clangd::config::Fragment::parseYAML
static std::vector< Fragment > parseYAML(llvm::StringRef YAML, llvm::StringRef BufferName, DiagnosticCallback)
Parses fragments from a YAML file (one from each — delimited document).
Definition: ConfigYAML.cpp:354
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:26
Tracer
std::unique_ptr< trace::EventTracer > Tracer
Definition: TraceTests.cpp:164
clang::clangd::config::Params::FreshTime
std::chrono::steady_clock::time_point FreshTime
Hint that stale data is OK to improve performance (e.g.
Definition: ConfigProvider.h:42
Path.h
FileCache.h
ConfigProvider.h
Trace.h
clang::clangd::Config
Settings that express user/project preferences and control clangd behavior.
Definition: Config.h:43
clang::clangd::config::Provider
A source of configuration fragments.
Definition: ConfigProvider.h:64
Trusted
bool Trusted
Definition: ConfigCompile.cpp:105
clang::clangd::config::FileConfigCache
Definition: ConfigProvider.cpp:30
ThreadsafeFS.h
clang::clangd::config::FileConfigCache::FileConfigCache
FileConfigCache(llvm::StringRef Path, llvm::StringRef Directory)
Definition: ConfigProvider.cpp:35
clang::clangd::config::FileConfigCache::get
void get(const ThreadsafeFS &TFS, DiagnosticCallback DC, std::chrono::steady_clock::time_point FreshTime, bool Trusted, std::vector< CompiledFragment > &Out) const
Definition: ConfigProvider.cpp:38
clang::clangd::config::Fragment::Source
SourceInfo Source
Definition: ConfigFragment.h:101
Directory
llvm::StringRef Directory
Definition: Serialization.cpp:419
clang::clangd::config::Provider::getConfig
Config getConfig(const Params &, DiagnosticCallback) const
Build a config based on this provider.
Definition: ConfigProvider.cpp:169
SPAN_ATTACH
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
Definition: Trace.h:164
clang::clangd::config::Provider::fromAncestorRelativeYAMLFiles
static std::unique_ptr< Provider > fromAncestorRelativeYAMLFiles(llvm::StringRef RelPath, const ThreadsafeFS &, bool Trusted=false)
Definition: ConfigProvider.cpp:84
clang::clangd::config::Fragment::SourceInfo::Directory
std::string Directory
Absolute path to directory the fragment is associated with.
Definition: ConfigFragment.h:96
Config.h
clang::clangd::config::Provider::fromYAMLFile
static std::unique_ptr< Provider > fromYAMLFile(llvm::StringRef AbsPath, llvm::StringRef Directory, const ThreadsafeFS &, bool Trusted=false)
Reads fragments from a single YAML file with a fixed path.
Definition: ConfigProvider.cpp:56
clang::clangd::config::Provider::combine
static std::unique_ptr< Provider > combine(std::vector< const Provider * >)
A provider that includes fragments from all the supplied providers.
Definition: ConfigProvider.cpp:147
clang::clangd::ThreadsafeFS
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
Definition: ThreadsafeFS.h:28
clang::clangd::FileCache::path
PathRef path() const
Definition: FileCache.h:64
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang::clangd::config::Params
Describes the context used to evaluate configuration fragments.
Definition: ConfigProvider.h:35
clang::clangd::absoluteParent
PathRef absoluteParent(PathRef Path)
Variant of parent_path that operates only on absolute paths.
Definition: Path.cpp:22
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::config::Params::Path
llvm::StringRef Path
Absolute path to a source file we're applying the config to.
Definition: ConfigProvider.h:38
clang::clangd::FileCache
Base class for threadsafe cache of data read from a file on disk.
Definition: FileCache.h:41
clang::clangd::config::Fragment
A chunk of configuration obtained from a config file, LSP, or elsewhere.
Definition: ConfigFragment.h:64
clang::clangd::config::Fragment::SourceInfo::Trusted
bool Trusted
Whether this fragment is allowed to make critical security/privacy decisions.
Definition: ConfigFragment.h:99
Out
CompiledFragmentImpl & Out
Definition: ConfigCompile.cpp:100
ConfigFragment.h
clang::clangd::FileCache::read
void read(const ThreadsafeFS &TFS, std::chrono::steady_clock::time_point FreshTime, llvm::function_ref< void(llvm::Optional< llvm::StringRef >)> Parse, llvm::function_ref< void()> Read) const
Definition: FileCache.cpp:29
clang::clangd::config::DiagnosticCallback
llvm::function_ref< void(const llvm::SMDiagnostic &)> DiagnosticCallback
Used to report problems in parsing or interpreting a config.
Definition: ConfigProvider.h:51
clang::clangd::trace::Span
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:143