1 //===--- ConfigFragment.h - Unit of user-specified 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 //
14 // This file defines the config::Fragment structure which models one piece of
15 // configuration as obtained from a source like a file.
16 //
17 // This is distinct from how the config is interpreted (CompiledFragment),
18 // combined (Provider) and exposed to the rest of clangd (Config).
19 //
20 //===----------------------------------------------------------------------===//
21 //
22 // To add a new configuration option, you must:
23 //  - add its syntactic form to Fragment
24 //  - update ConfigYAML.cpp to parse it
25 //  - add its semantic form to Config (in Config.h)
26 //  - update ConfigCompile.cpp to map Fragment -> Config
27 //  - make use of the option inside clangd
28 //  - document the new option (config.md in the llvm/clangd-www repository)
29 //
30 //===----------------------------------------------------------------------===//
31 
32 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONFIGFRAGMENT_H
33 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONFIGFRAGMENT_H
34 
35 #include "ConfigProvider.h"
36 #include "llvm/ADT/Optional.h"
37 #include "llvm/Support/SMLoc.h"
38 #include "llvm/Support/SourceMgr.h"
39 #include <string>
40 #include <vector>
41 
42 namespace clang {
43 namespace clangd {
44 namespace config {
45 
46 /// An entity written in config along, with its optional location in the file.
47 template <typename T> struct Located {
48   Located(T Value, llvm::SMRange Range = {})
RangeLocated49       : Range(Range), Value(std::move(Value)) {}
50 
51   llvm::SMRange Range;
52   T *operator->() { return &Value; }
53   const T *operator->() const { return &Value; }
54   T &operator*() { return Value; }
55   const T &operator*() const { return Value; }
56 
57 private:
58   T Value;
59 };
60 
61 /// A chunk of configuration obtained from a config file, LSP, or elsewhere.
62 struct Fragment {
63   /// Parses fragments from a YAML file (one from each --- delimited document).
64   /// Documents that contained fatal errors are omitted from the results.
65   /// BufferName is used for the SourceMgr and diagnostics.
66   static std::vector<Fragment> parseYAML(llvm::StringRef YAML,
67                                          llvm::StringRef BufferName,
68                                          DiagnosticCallback);
69 
70   /// Analyzes and consumes this fragment, possibly yielding more diagnostics.
71   /// This always produces a usable result (errors are recovered).
72   ///
73   /// Typically, providers will compile a Fragment once when it's first loaded,
74   /// caching the result for reuse.
75   /// Like a compiled program, this is good for performance and also encourages
76   /// errors to be reported early and only once.
77   ///
78   /// The returned function is a cheap-copyable wrapper of refcounted internals.
79   CompiledFragment compile(DiagnosticCallback) &&;
80 
81   /// These fields are not part of the user-specified configuration, but
82   /// instead are populated by the parser to describe the configuration source.
83   struct SourceInfo {
84     /// Retains a buffer of the original source this fragment was parsed from.
85     /// Locations within Located<T> objects point into this SourceMgr.
86     /// Shared because multiple fragments are often parsed from one (YAML) file.
87     /// May be null, then all locations should be ignored.
88     std::shared_ptr<llvm::SourceMgr> Manager;
89     /// The start of the original source for this fragment.
90     /// Only valid if SourceManager is set.
91     llvm::SMLoc Location;
92     /// Absolute path to directory the fragment is associated with. Relative
93     /// paths mentioned in the fragment are resolved against this.
94     std::string Directory;
95     /// Whether this fragment is allowed to make critical security/privacy
96     /// decisions.
97     bool Trusted = false;
98   };
99   SourceInfo Source;
100 
101   /// Conditions in the If block restrict when a Fragment applies.
102   ///
103   /// Each separate condition must match (combined with AND).
104   /// When one condition has multiple values, any may match (combined with OR).
105   /// e.g. `PathMatch: [foo/.*, bar/.*]` matches files in either directory.
106   ///
107   /// Conditions based on a file's path use the following form:
108   /// - if the fragment came from a project directory, the path is relative
109   /// - if the fragment is global (e.g. user config), the path is absolute
110   /// - paths always use forward-slashes (UNIX-style)
111   /// If no file is being processed, these conditions will not match.
112   struct IfBlock {
113     /// The file being processed must fully match a regular expression.
114     std::vector<Located<std::string>> PathMatch;
115     /// The file being processed must *not* fully match a regular expression.
116     std::vector<Located<std::string>> PathExclude;
117 
118     /// An unrecognized key was found while parsing the condition.
119     /// The condition will evaluate to false.
120     bool HasUnrecognizedCondition = false;
121   };
122   IfBlock If;
123 
124   /// Conditions in the CompileFlags block affect how a file is parsed.
125   ///
126   /// clangd emulates how clang would interpret a file.
127   /// By default, it behaves roughly like `clang $FILENAME`, but real projects
128   /// usually require setting the include path (with the `-I` flag), defining
129   /// preprocessor symbols, configuring warnings etc.
130   /// Often, a compilation database specifies these compile commands. clangd
131   /// searches for compile_commands.json in parents of the source file.
132   ///
133   /// This section modifies how the compile command is constructed.
134   struct CompileFlagsBlock {
135     /// Override the compiler executable name to simulate.
136     ///
137     /// The name can affect how flags are parsed (clang++ vs clang).
138     /// If the executable name is in the --query-driver allowlist, then it will
139     /// be invoked to extract include paths.
140     ///
141     /// (That this simply replaces argv[0], and may mangle commands that use
142     /// more complicated drivers like ccache).
143     llvm::Optional<Located<std::string>> Compiler;
144 
145     /// List of flags to append to the compile command.
146     std::vector<Located<std::string>> Add;
147     /// List of flags to remove from the compile command.
148     ///
149     /// - If the value is a recognized clang flag (like "-I") then it will be
150     ///   removed along with any arguments. Synonyms like --include-dir= will
151     ///   also be removed.
152     /// - Otherwise, if the value ends in * (like "-DFOO=*") then any argument
153     ///   with the prefix will be removed.
154     /// - Otherwise any argument exactly matching the value is removed.
155     ///
156     /// In all cases, -Xclang is also removed where needed.
157     ///
158     /// Example:
159     ///   Command: clang++ --include-directory=/usr/include -DFOO=42 foo.cc
160     ///   Remove: [-I, -DFOO=*]
161     ///   Result: clang++ foo.cc
162     ///
163     /// Flags added by the same CompileFlags entry will not be removed.
164     std::vector<Located<std::string>> Remove;
165 
166     /// Directory to search for compilation database (compile_comands.json etc).
167     /// Valid values are:
168     /// - A single path to a directory (absolute, or relative to the fragment)
169     /// - Ancestors: search all parent directories (the default)
170     /// - None: do not use a compilation database, just default flags.
171     llvm::Optional<Located<std::string>> CompilationDatabase;
172   };
173   CompileFlagsBlock CompileFlags;
174 
175   /// Controls how clangd understands code outside the current file.
176   /// clangd's indexes provide information about symbols that isn't available
177   /// to clang's parser, such as incoming references.
178   struct IndexBlock {
179     /// Whether files are built in the background to produce a project index.
180     /// This is checked for translation units only, not headers they include.
181     /// Legal values are "Build" or "Skip".
182     llvm::Optional<Located<std::string>> Background;
183     /// An external index uses data source outside of clangd itself. This is
184     /// usually prepared using clangd-indexer.
185     /// Exactly one source (File/Server) should be configured.
186     struct ExternalBlock {
187       /// Whether the block is explicitly set to `None`. Can be used to clear
188       /// any external index specified before.
189       Located<bool> IsNone = false;
190       /// Path to an index file generated by clangd-indexer. Relative paths may
191       /// be used, if config fragment is associated with a directory.
192       llvm::Optional<Located<std::string>> File;
193       /// Address and port number for a clangd-index-server. e.g.
194       /// `123.1.1.1:13337`.
195       llvm::Optional<Located<std::string>> Server;
196       /// Source root governed by this index. Default is the directory
197       /// associated with the config fragment. Absolute in case of user config
198       /// and relative otherwise. Should always use forward-slashes.
199       llvm::Optional<Located<std::string>> MountPoint;
200     };
201     llvm::Optional<Located<ExternalBlock>> External;
202     // Whether the standard library visible from this file should be indexed.
203     // This makes all standard library symbols available, included or not.
204     llvm::Optional<Located<bool>> StandardLibrary;
205   };
206   IndexBlock Index;
207 
208   /// Controls behavior of diagnostics (errors and warnings).
209   struct DiagnosticsBlock {
210     /// Diagnostic codes that should be suppressed.
211     ///
212     /// Valid values are:
213     /// - *, to disable all diagnostics
214     /// - diagnostic codes exposed by clangd (e.g unknown_type, -Wunused-result)
215     /// - clang internal diagnostic codes (e.g. err_unknown_type)
216     /// - warning categories (e.g. unused-result)
217     /// - clang-tidy check names (e.g. bugprone-narrowing-conversions)
218     ///
219     /// This is a simple filter. Diagnostics can be controlled in other ways
220     /// (e.g. by disabling a clang-tidy check, or the -Wunused compile flag).
221     /// This often has other advantages, such as skipping some analysis.
222     std::vector<Located<std::string>> Suppress;
223 
224     /// Controls how clangd will correct "unnecessary #include directives.
225     /// clangd can warn if a header is `#include`d but not used, and suggest
226     /// removing it.
227     //
228     /// Strict means a header is unused if it does not *directly* provide any
229     /// symbol used in the file. Removing it may still break compilation if it
230     /// transitively includes headers that are used. This should be fixed by
231     /// including those headers directly.
232     ///
233     /// Valid values are:
234     /// - Strict
235     /// - None
236     llvm::Optional<Located<std::string>> UnusedIncludes;
237 
238     /// Controls IncludeCleaner diagnostics.
239     struct IncludesBlock {
240       /// Regexes that will be used to avoid diagnosing certain includes as
241       /// unused or missing. These can match any suffix of the header file in
242       /// question.
243       std::vector<Located<std::string>> IgnoreHeader;
244     };
245     IncludesBlock Includes;
246 
247     /// Controls how clang-tidy will run over the code base.
248     ///
249     /// The settings are merged with any settings found in .clang-tidy
250     /// configuration files with these ones taking precedence.
251     struct ClangTidyBlock {
252       std::vector<Located<std::string>> Add;
253       /// List of checks to disable.
254       /// Takes precedence over Add. To enable all llvm checks except include
255       /// order:
256       ///   Add: llvm-*
257       ///   Remove: llvm-include-order
258       std::vector<Located<std::string>> Remove;
259 
260       /// A Key-Value pair list of options to pass to clang-tidy checks
261       /// These take precedence over options specified in clang-tidy
262       /// configuration files. Example:
263       ///   CheckOptions:
264       ///     readability-braces-around-statements.ShortStatementLines: 2
265       std::vector<std::pair<Located<std::string>, Located<std::string>>>
266           CheckOptions;
267     };
268     ClangTidyBlock ClangTidy;
269   };
270   DiagnosticsBlock Diagnostics;
271 
272   // Describes the style of the codebase, beyond formatting.
273   struct StyleBlock {
274     // Namespaces that should always be fully qualified, meaning no "using"
275     // declarations, always spell out the whole name (with or without leading
276     // ::). All nested namespaces are affected as well.
277     // Affects availability of the AddUsing tweak.
278     std::vector<Located<std::string>> FullyQualifiedNamespaces;
279   };
280   StyleBlock Style;
281 
282   /// Describes code completion preferences.
283   struct CompletionBlock {
284     /// Whether code completion should include suggestions from scopes that are
285     /// not visible. The required scope prefix will be inserted.
286     llvm::Optional<Located<bool>> AllScopes;
287   };
288   CompletionBlock Completion;
289 
290   /// Describes hover preferences.
291   struct HoverBlock {
292     /// Whether hover show a.k.a type.
293     llvm::Optional<Located<bool>> ShowAKA;
294   };
295   HoverBlock Hover;
296 
297   /// Configures labels shown inline with the code.
298   struct InlayHintsBlock {
299     /// Enables/disables the inlay-hints feature.
300     llvm::Optional<Located<bool>> Enabled;
301 
302     /// Show parameter names before function arguments.
303     llvm::Optional<Located<bool>> ParameterNames;
304     /// Show deduced types for `auto`.
305     llvm::Optional<Located<bool>> DeducedTypes;
306     /// Show designators in aggregate initialization.
307     llvm::Optional<Located<bool>> Designators;
308   };
309   InlayHintsBlock InlayHints;
310 };
311 
312 } // namespace config
313 } // namespace clangd
314 } // namespace clang
315 
316 #endif
317