clang-tools  15.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/StringMap.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/Path.h"
20 #include <chrono>
21 #include <mutex>
22 #include <string>
23 
24 namespace clang {
25 namespace clangd {
26 namespace config {
27 
28 // Threadsafe cache around reading a YAML config file from disk.
29 class FileConfigCache : public FileCache {
30  mutable llvm::SmallVector<CompiledFragment, 1> CachedValue;
31  std::string Directory;
32 
33 public:
34  FileConfigCache(llvm::StringRef Path, llvm::StringRef Directory)
36 
37  void get(const ThreadsafeFS &TFS, DiagnosticCallback DC,
38  std::chrono::steady_clock::time_point FreshTime, bool Trusted,
39  std::vector<CompiledFragment> &Out) const {
40  read(
41  TFS, FreshTime,
42  [&](llvm::Optional<llvm::StringRef> Data) {
43  CachedValue.clear();
44  if (Data)
45  for (auto &Fragment : Fragment::parseYAML(*Data, path(), DC)) {
48  CachedValue.push_back(std::move(Fragment).compile(DC));
49  }
50  },
51  [&]() { llvm::copy(CachedValue, std::back_inserter(Out)); });
52  }
53 };
54 
55 std::unique_ptr<Provider> Provider::fromYAMLFile(llvm::StringRef AbsPath,
56  llvm::StringRef Directory,
57  const ThreadsafeFS &FS,
58  bool Trusted) {
59  class AbsFileProvider : public Provider {
60  mutable FileConfigCache Cache; // threadsafe
61  const ThreadsafeFS &FS;
62  bool Trusted;
63 
64  std::vector<CompiledFragment>
65  getFragments(const Params &P, DiagnosticCallback DC) const override {
66  std::vector<CompiledFragment> Result;
67  Cache.get(FS, DC, P.FreshTime, Trusted, Result);
68  return Result;
69  };
70 
71  public:
72  AbsFileProvider(llvm::StringRef Path, llvm::StringRef Directory,
73  const ThreadsafeFS &FS, bool Trusted)
74  : Cache(Path, Directory), FS(FS), Trusted(Trusted) {
75  assert(llvm::sys::path::is_absolute(Path));
76  }
77  };
78 
79  return std::make_unique<AbsFileProvider>(AbsPath, Directory, FS, Trusted);
80 }
81 
82 std::unique_ptr<Provider>
84  const ThreadsafeFS &FS, bool Trusted) {
85  class RelFileProvider : public Provider {
86  std::string RelPath;
87  const ThreadsafeFS &FS;
88  bool Trusted;
89 
90  mutable std::mutex Mu;
91  // Keys are the (posix-style) ancestor directory, not the config within it.
92  // We only insert into this map, so pointers to values are stable forever.
93  // Mutex guards the map itself, not the values (which are threadsafe).
94  mutable llvm::StringMap<FileConfigCache> Cache;
95 
96  std::vector<CompiledFragment>
97  getFragments(const Params &P, DiagnosticCallback DC) const override {
98  namespace path = llvm::sys::path;
99 
100  if (P.Path.empty())
101  return {};
102 
103  // Compute absolute paths to all ancestors (substrings of P.Path).
104  llvm::SmallVector<llvm::StringRef, 8> Ancestors;
105  for (auto Ancestor = absoluteParent(P.Path); !Ancestor.empty();
106  Ancestor = absoluteParent(Ancestor)) {
107  Ancestors.emplace_back(Ancestor);
108  }
109  // Ensure corresponding cache entries exist in the map.
110  llvm::SmallVector<FileConfigCache *, 8> Caches;
111  {
112  std::lock_guard<std::mutex> Lock(Mu);
113  for (llvm::StringRef Ancestor : Ancestors) {
114  auto It = Cache.find(Ancestor);
115  // Assemble the actual config file path only once.
116  if (It == Cache.end()) {
117  llvm::SmallString<256> ConfigPath = Ancestor;
118  path::append(ConfigPath, RelPath);
119  // Use native slashes for reading the file, affects diagnostics.
120  llvm::sys::path::native(ConfigPath);
121  It = Cache.try_emplace(Ancestor, ConfigPath.str(), Ancestor).first;
122  }
123  Caches.push_back(&It->second);
124  }
125  }
126  // Finally query each individual file.
127  // This will take a (per-file) lock for each file that actually exists.
128  std::vector<CompiledFragment> Result;
129  for (FileConfigCache *Cache : llvm::reverse(Caches))
130  Cache->get(FS, DC, P.FreshTime, Trusted, Result);
131  return Result;
132  };
133 
134  public:
135  RelFileProvider(llvm::StringRef RelPath, const ThreadsafeFS &FS,
136  bool Trusted)
137  : RelPath(RelPath), FS(FS), Trusted(Trusted) {
138  assert(llvm::sys::path::is_relative(RelPath));
139  }
140  };
141 
142  return std::make_unique<RelFileProvider>(RelPath, FS, Trusted);
143 }
144 
145 std::unique_ptr<Provider>
146 Provider::combine(std::vector<const Provider *> Providers) {
147  class CombinedProvider : public Provider {
148  std::vector<const Provider *> Providers;
149 
150  std::vector<CompiledFragment>
151  getFragments(const Params &P, DiagnosticCallback DC) const override {
152  std::vector<CompiledFragment> Result;
153  for (const auto &Provider : Providers) {
154  for (auto &Fragment : Provider->getFragments(P, DC))
155  Result.push_back(std::move(Fragment));
156  }
157  return Result;
158  }
159 
160  public:
161  CombinedProvider(std::vector<const Provider *> Providers)
162  : Providers(std::move(Providers)) {}
163  };
164 
165  return std::make_unique<CombinedProvider>(std::move(Providers));
166 }
167 
169  trace::Span Tracer("getConfig");
170  if (!P.Path.empty())
171  SPAN_ATTACH(Tracer, "path", P.Path);
172  Config C;
173  for (const auto &Fragment : getFragments(P, DC))
174  Fragment(P, C);
175  return C;
176 }
177 
178 } // namespace config
179 } // namespace clangd
180 } // 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:413
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:161
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:40
Path.h
FileCache.h
ConfigProvider.h
Trace.h
clang::clangd::Config
Settings that express user/project preferences and control clangd behavior.
Definition: Config.h:45
clang::clangd::config::Provider
A source of configuration fragments.
Definition: ConfigProvider.h:62
Trusted
bool Trusted
Definition: ConfigCompile.cpp:104
clang::clangd::config::FileConfigCache
Definition: ConfigProvider.cpp:29
ThreadsafeFS.h
clang::clangd::config::FileConfigCache::FileConfigCache
FileConfigCache(llvm::StringRef Path, llvm::StringRef Directory)
Definition: ConfigProvider.cpp:34
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:37
clang::clangd::config::Fragment::Source
SourceInfo Source
Definition: ConfigFragment.h:99
Directory
llvm::StringRef Directory
Definition: Serialization.cpp:420
clang::clangd::config::Provider::getConfig
Config getConfig(const Params &, DiagnosticCallback) const
Build a config based on this provider.
Definition: ConfigProvider.cpp:168
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:83
clang::clangd::config::Fragment::SourceInfo::Directory
std::string Directory
Absolute path to directory the fragment is associated with.
Definition: ConfigFragment.h:94
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:55
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:146
clang::clangd::ThreadsafeFS
Wrapper for vfs::FileSystem for use in multithreaded programs like clangd.
Definition: ThreadsafeFS.h:27
clang::clangd::FileCache::path
PathRef path() const
Definition: FileCache.h:62
C
const Criteria C
Definition: FunctionCognitiveComplexityCheck.cpp:93
clang::clangd::config::Params
Describes the context used to evaluate configuration fragments.
Definition: ConfigProvider.h:33
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:36
clang::clangd::FileCache
Base class for threadsafe cache of data read from a file on disk.
Definition: FileCache.h:39
clang::clangd::config::Fragment
A chunk of configuration obtained from a config file, LSP, or elsewhere.
Definition: ConfigFragment.h:62
clang::clangd::config::Fragment::SourceInfo::Trusted
bool Trusted
Whether this fragment is allowed to make critical security/privacy decisions.
Definition: ConfigFragment.h:97
Out
CompiledFragmentImpl & Out
Definition: ConfigCompile.cpp:99
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:30
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:49
clang::clangd::trace::Span
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:143