1 //===--- ConfigProvider.h - Loading of user configuration --------*- 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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Various clangd features have configurable behaviour (or can be disabled).
10 // The configuration system allows users to control this:
11 //  - in a user config file, a project config file, via LSP, or via flags
12 //  - specifying different settings for different files
13 // This file defines the structures used for this, that produce a Config.
14 //
15 //===----------------------------------------------------------------------===//
16 
17 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONFIGPROVIDER_H
18 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONFIGPROVIDER_H
19 
20 #include "llvm/ADT/FunctionExtras.h"
21 #include "llvm/Support/SMLoc.h"
22 #include "llvm/Support/SourceMgr.h"
23 #include <chrono>
24 #include <string>
25 #include <vector>
26 
27 namespace clang {
28 namespace clangd {
29 struct Config;
30 class ThreadsafeFS;
31 namespace config {
32 
33 /// Describes the context used to evaluate configuration fragments.
34 struct Params {
35   /// Absolute path to a source file we're applying the config to. Unix slashes.
36   /// Empty if not configuring a particular file.
37   llvm::StringRef Path;
38   /// Hint that stale data is OK to improve performance (e.g. avoid IO).
39   /// FreshTime sets a bound for how old the data can be.
40   /// If not set, providers should validate caches against the data source.
41   llvm::Optional<std::chrono::steady_clock::time_point> FreshTime;
42 };
43 
44 /// Used to report problems in parsing or interpreting a config.
45 /// Errors reflect structurally invalid config that should be user-visible.
46 /// Warnings reflect e.g. unknown properties that are recoverable.
47 using DiagnosticCallback = llvm::function_ref<void(const llvm::SMDiagnostic &)>;
48 
49 /// A chunk of configuration that has been fully analyzed and is ready to apply.
50 /// Typically this is obtained from a Fragment by calling Fragment::compile().
51 ///
52 /// Calling it updates the configuration to reflect settings from the fragment.
53 /// Returns true if the condition was met and the settings were used.
54 using CompiledFragment = std::function<bool(const Params &, Config &)>;
55 
56 /// A source of configuration fragments.
57 /// Generally these providers reflect a fixed policy for obtaining config,
58 /// but return different concrete configuration over time.
59 /// e.g. a provider that reads config from files is responsive to file changes.
60 class Provider {
61 public:
62   virtual ~Provider() = default;
63 
64   // Reads fragments from a single YAML file with a fixed path.
65   static std::unique_ptr<Provider> fromYAMLFile(llvm::StringRef AbsPathPath,
66                                                 const ThreadsafeFS &);
67   // Reads fragments from YAML files found relative to ancestors of Params.Path.
68   //
69   // All fragments that exist are returned, starting from distant ancestors.
70   // For instance, given RelPath of ".clangd", then for source file /foo/bar.cc,
71   // the searched fragments are [/.clangd, /foo/.clangd].
72   //
73   // If Params does not specify a path, no fragments are returned.
74   static std::unique_ptr<Provider>
75   fromAncestorRelativeYAMLFiles(llvm::StringRef RelPath, const ThreadsafeFS &);
76 
77   /// A provider that includes fragments from all the supplied providers.
78   /// Order is preserved; later providers take precedence over earlier ones.
79   static std::unique_ptr<Provider> combine(std::vector<const Provider *>);
80 
81   /// Build a config based on this provider.
82   Config getConfig(const Params &, DiagnosticCallback) const;
83 
84 private:
85   /// Provide fragments that may be relevant to the file.
86   /// The configuration provider is not responsible for testing conditions.
87   ///
88   /// Providers are expected to cache compiled fragments, and only
89   /// reparse/recompile when the source data has changed.
90   /// Despite the need for caching, this function must be threadsafe.
91   ///
92   /// When parsing/compiling, the DiagnosticCallback is used to report errors.
93   virtual std::vector<CompiledFragment>
94   getFragments(const Params &, DiagnosticCallback) const = 0;
95 };
96 
97 } // namespace config
98 } // namespace clangd
99 } // namespace clang
100 
101 #endif
102