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 |
34 | |
35 | #include "Config.h" |
36 | #include "ConfigProvider.h" |
37 | #include "llvm/Support/SMLoc.h" |
38 | #include "llvm/Support/SourceMgr.h" |
39 | #include <optional> |
40 | #include <string> |
41 | #include <vector> |
42 | |
43 | namespace clang { |
44 | namespace clangd { |
45 | namespace config { |
46 | |
47 | /// An entity written in config along, with its optional location in the file. |
48 | template <typename T> struct Located { |
49 | Located(T Value, llvm::SMRange Range = {}) |
50 | : Range(Range), Value(std::move(Value)) {} |
51 | |
52 | llvm::SMRange Range; |
53 | T *operator->() { return &Value; } |
54 | const T *operator->() const { return &Value; } |
55 | T &operator*() { return Value; } |
56 | const T &operator*() const { return Value; } |
57 | |
58 | private: |
59 | T Value; |
60 | }; |
61 | |
62 | /// A chunk of configuration obtained from a config file, LSP, or elsewhere. |
63 | struct Fragment { |
64 | /// Parses fragments from a YAML file (one from each --- delimited document). |
65 | /// Documents that contained fatal errors are omitted from the results. |
66 | /// BufferName is used for the SourceMgr and diagnostics. |
67 | static std::vector<Fragment> parseYAML(llvm::StringRef YAML, |
68 | llvm::StringRef BufferName, |
69 | DiagnosticCallback); |
70 | |
71 | /// Analyzes and consumes this fragment, possibly yielding more diagnostics. |
72 | /// This always produces a usable result (errors are recovered). |
73 | /// |
74 | /// Typically, providers will compile a Fragment once when it's first loaded, |
75 | /// caching the result for reuse. |
76 | /// Like a compiled program, this is good for performance and also encourages |
77 | /// errors to be reported early and only once. |
78 | /// |
79 | /// The returned function is a cheap-copyable wrapper of refcounted internals. |
80 | CompiledFragment compile(DiagnosticCallback) &&; |
81 | |
82 | /// These fields are not part of the user-specified configuration, but |
83 | /// instead are populated by the parser to describe the configuration source. |
84 | struct SourceInfo { |
85 | /// Retains a buffer of the original source this fragment was parsed from. |
86 | /// Locations within Located<T> objects point into this SourceMgr. |
87 | /// Shared because multiple fragments are often parsed from one (YAML) file. |
88 | /// May be null, then all locations should be ignored. |
89 | std::shared_ptr<llvm::SourceMgr> Manager; |
90 | /// The start of the original source for this fragment. |
91 | /// Only valid if SourceManager is set. |
92 | llvm::SMLoc Location; |
93 | /// Absolute path to directory the fragment is associated with. Relative |
94 | /// paths mentioned in the fragment are resolved against this. |
95 | std::string Directory; |
96 | /// Whether this fragment is allowed to make critical security/privacy |
97 | /// decisions. |
98 | bool Trusted = false; |
99 | }; |
100 | SourceInfo Source; |
101 | |
102 | /// Conditions in the If block restrict when a Fragment applies. |
103 | /// |
104 | /// Each separate condition must match (combined with AND). |
105 | /// When one condition has multiple values, any may match (combined with OR). |
106 | /// e.g. `PathMatch: [foo/.*, bar/.*]` matches files in either directory. |
107 | /// |
108 | /// Conditions based on a file's path use the following form: |
109 | /// - if the fragment came from a project directory, the path is relative |
110 | /// - if the fragment is global (e.g. user config), the path is absolute |
111 | /// - paths always use forward-slashes (UNIX-style) |
112 | /// If no file is being processed, these conditions will not match. |
113 | struct IfBlock { |
114 | /// The file being processed must fully match a regular expression. |
115 | std::vector<Located<std::string>> PathMatch; |
116 | /// The file being processed must *not* fully match a regular expression. |
117 | std::vector<Located<std::string>> PathExclude; |
118 | |
119 | /// An unrecognized key was found while parsing the condition. |
120 | /// The condition will evaluate to false. |
121 | bool HasUnrecognizedCondition = false; |
122 | }; |
123 | IfBlock If; |
124 | |
125 | /// Conditions in the CompileFlags block affect how a file is parsed. |
126 | /// |
127 | /// clangd emulates how clang would interpret a file. |
128 | /// By default, it behaves roughly like `clang $FILENAME`, but real projects |
129 | /// usually require setting the include path (with the `-I` flag), defining |
130 | /// preprocessor symbols, configuring warnings etc. |
131 | /// Often, a compilation database specifies these compile commands. clangd |
132 | /// searches for compile_commands.json in parents of the source file. |
133 | /// |
134 | /// This section modifies how the compile command is constructed. |
135 | struct CompileFlagsBlock { |
136 | /// Override the compiler executable name to simulate. |
137 | /// |
138 | /// The name can affect how flags are parsed (clang++ vs clang). |
139 | /// If the executable name is in the --query-driver allowlist, then it will |
140 | /// be invoked to extract include paths. |
141 | /// |
142 | /// (That this simply replaces argv[0], and may mangle commands that use |
143 | /// more complicated drivers like ccache). |
144 | std::optional<Located<std::string>> Compiler; |
145 | |
146 | /// List of flags to append to the compile command. |
147 | std::vector<Located<std::string>> Add; |
148 | /// List of flags to remove from the compile command. |
149 | /// |
150 | /// - If the value is a recognized clang flag (like "-I") then it will be |
151 | /// removed along with any arguments. Synonyms like --include-dir= will |
152 | /// also be removed. |
153 | /// - Otherwise, if the value ends in * (like "-DFOO=*") then any argument |
154 | /// with the prefix will be removed. |
155 | /// - Otherwise any argument exactly matching the value is removed. |
156 | /// |
157 | /// In all cases, -Xclang is also removed where needed. |
158 | /// |
159 | /// Example: |
160 | /// Command: clang++ --include-directory=/usr/include -DFOO=42 foo.cc |
161 | /// Remove: [-I, -DFOO=*] |
162 | /// Result: clang++ foo.cc |
163 | /// |
164 | /// Flags added by the same CompileFlags entry will not be removed. |
165 | std::vector<Located<std::string>> Remove; |
166 | |
167 | /// Directory to search for compilation database (compile_commands.json |
168 | /// etc). Valid values are: |
169 | /// - A single path to a directory (absolute, or relative to the fragment) |
170 | /// - Ancestors: search all parent directories (the default) |
171 | /// - std::nullopt: do not use a compilation database, just default flags. |
172 | std::optional<Located<std::string>> CompilationDatabase; |
173 | |
174 | /// Controls whether Clangd should use its own built-in system headers (like |
175 | /// stddef.h), or use the system headers from the query driver. Use the |
176 | /// option value 'Clangd' (default) to indicate Clangd's headers, and use |
177 | /// 'QueryDriver' to indicate QueryDriver's headers. `Clangd` is the |
178 | /// fallback if no query driver is supplied or if the query driver regex |
179 | /// string fails to match the compiler used in the CDB. |
180 | std::optional<Located<std::string>> ; |
181 | }; |
182 | CompileFlagsBlock CompileFlags; |
183 | |
184 | /// Controls how clangd understands code outside the current file. |
185 | /// clangd's indexes provide information about symbols that isn't available |
186 | /// to clang's parser, such as incoming references. |
187 | struct IndexBlock { |
188 | /// Whether files are built in the background to produce a project index. |
189 | /// This is checked for translation units only, not headers they include. |
190 | /// Legal values are "Build" or "Skip". |
191 | std::optional<Located<std::string>> Background; |
192 | /// An external index uses data source outside of clangd itself. This is |
193 | /// usually prepared using clangd-indexer. |
194 | /// Exactly one source (File/Server) should be configured. |
195 | struct ExternalBlock { |
196 | /// Whether the block is explicitly set to `None`. Can be used to clear |
197 | /// any external index specified before. |
198 | Located<bool> IsNone = false; |
199 | /// Path to an index file generated by clangd-indexer. Relative paths may |
200 | /// be used, if config fragment is associated with a directory. |
201 | std::optional<Located<std::string>> File; |
202 | /// Address and port number for a clangd-index-server. e.g. |
203 | /// `123.1.1.1:13337`. |
204 | std::optional<Located<std::string>> Server; |
205 | /// Source root governed by this index. Default is the directory |
206 | /// associated with the config fragment. Absolute in case of user config |
207 | /// and relative otherwise. Should always use forward-slashes. |
208 | std::optional<Located<std::string>> MountPoint; |
209 | }; |
210 | std::optional<Located<ExternalBlock>> External; |
211 | // Whether the standard library visible from this file should be indexed. |
212 | // This makes all standard library symbols available, included or not. |
213 | std::optional<Located<bool>> StandardLibrary; |
214 | }; |
215 | IndexBlock Index; |
216 | |
217 | /// Controls behavior of diagnostics (errors and warnings). |
218 | struct DiagnosticsBlock { |
219 | /// Diagnostic codes that should be suppressed. |
220 | /// |
221 | /// Valid values are: |
222 | /// - *, to disable all diagnostics |
223 | /// - diagnostic codes exposed by clangd (e.g unknown_type, -Wunused-result) |
224 | /// - clang internal diagnostic codes (e.g. err_unknown_type) |
225 | /// - warning categories (e.g. unused-result) |
226 | /// - clang-tidy check names (e.g. bugprone-narrowing-conversions) |
227 | /// |
228 | /// This is a simple filter. Diagnostics can be controlled in other ways |
229 | /// (e.g. by disabling a clang-tidy check, or the -Wunused compile flag). |
230 | /// This often has other advantages, such as skipping some analysis. |
231 | std::vector<Located<std::string>> Suppress; |
232 | |
233 | /// Controls how clangd will correct "unnecessary" #include directives. |
234 | /// clangd can warn if a header is `#include`d but not used, and suggest |
235 | /// removing it. |
236 | // |
237 | /// Strict means a header is unused if it does not *directly* provide any |
238 | /// symbol used in the file. Removing it may still break compilation if it |
239 | /// transitively includes headers that are used. This should be fixed by |
240 | /// including those headers directly. |
241 | /// |
242 | /// Valid values are: |
243 | /// - Strict |
244 | /// - std::nullopt |
245 | std::optional<Located<std::string>> UnusedIncludes; |
246 | |
247 | /// Controls if clangd should analyze missing #include directives. |
248 | /// clangd will warn if no header providing a symbol is `#include`d |
249 | /// (missing) directly, and suggest adding it. |
250 | /// |
251 | /// Strict means a header providing a symbol is missing if it is not |
252 | /// *directly #include'd. The file might still compile if the header is |
253 | /// included transitively. |
254 | /// |
255 | /// Valid values are: |
256 | /// - Strict |
257 | /// - std::nullopt |
258 | std::optional<Located<std::string>> MissingIncludes; |
259 | |
260 | /// Controls IncludeCleaner diagnostics. |
261 | struct IncludesBlock { |
262 | /// Regexes that will be used to avoid diagnosing certain includes as |
263 | /// unused or missing. These can match any suffix of the header file in |
264 | /// question. |
265 | std::vector<Located<std::string>> ; |
266 | |
267 | /// If false (default), unused system headers will be ignored. |
268 | /// Standard library headers are analyzed regardless of this option. |
269 | std::optional<Located<bool>> AnalyzeAngledIncludes; |
270 | }; |
271 | IncludesBlock Includes; |
272 | |
273 | /// Controls how clang-tidy will run over the code base. |
274 | /// |
275 | /// The settings are merged with any settings found in .clang-tidy |
276 | /// configuration files with these ones taking precedence. |
277 | struct ClangTidyBlock { |
278 | std::vector<Located<std::string>> Add; |
279 | /// List of checks to disable. |
280 | /// Takes precedence over Add. To enable all llvm checks except include |
281 | /// order: |
282 | /// Add: llvm-* |
283 | /// Remove: llvm-include-order |
284 | std::vector<Located<std::string>> Remove; |
285 | |
286 | /// A Key-Value pair list of options to pass to clang-tidy checks |
287 | /// These take precedence over options specified in clang-tidy |
288 | /// configuration files. Example: |
289 | /// CheckOptions: |
290 | /// readability-braces-around-statements.ShortStatementLines: 2 |
291 | std::vector<std::pair<Located<std::string>, Located<std::string>>> |
292 | CheckOptions; |
293 | |
294 | /// Whether to run checks that may slow down clangd. |
295 | /// Strict: Run only checks measured to be fast. (Default) |
296 | /// This excludes recently-added checks we have not timed yet. |
297 | /// Loose: Run checks unless they are known to be slow. |
298 | /// None: Run checks regardless of their speed. |
299 | std::optional<Located<std::string>> FastCheckFilter; |
300 | }; |
301 | ClangTidyBlock ClangTidy; |
302 | }; |
303 | DiagnosticsBlock Diagnostics; |
304 | |
305 | // Describes the style of the codebase, beyond formatting. |
306 | struct StyleBlock { |
307 | // Namespaces that should always be fully qualified, meaning no "using" |
308 | // declarations, always spell out the whole name (with or without leading |
309 | // ::). All nested namespaces are affected as well. |
310 | // Affects availability of the AddUsing tweak. |
311 | std::vector<Located<std::string>> FullyQualifiedNamespaces; |
312 | |
313 | /// List of regexes for headers that should always be included with a |
314 | /// ""-style include. By default, and in case of a conflict with |
315 | /// AngledHeaders (i.e. a header matches a regex in both QuotedHeaders and |
316 | /// AngledHeaders), system headers use <> and non-system headers use "". |
317 | /// These can match any suffix of the header file in question. |
318 | /// Matching is performed against the header text, not its absolute path |
319 | /// within the project. |
320 | std::vector<Located<std::string>> ; |
321 | /// List of regexes for headers that should always be included with a |
322 | /// <>-style include. By default, and in case of a conflict with |
323 | /// AngledHeaders (i.e. a header matches a regex in both QuotedHeaders and |
324 | /// AngledHeaders), system headers use <> and non-system headers use "". |
325 | /// These can match any suffix of the header file in question. |
326 | /// Matching is performed against the header text, not its absolute path |
327 | /// within the project. |
328 | std::vector<Located<std::string>> ; |
329 | }; |
330 | StyleBlock Style; |
331 | |
332 | /// Describes code completion preferences. |
333 | struct CompletionBlock { |
334 | /// Whether code completion should include suggestions from scopes that are |
335 | /// not visible. The required scope prefix will be inserted. |
336 | std::optional<Located<bool>> AllScopes; |
337 | /// How to present the argument list between '()' and '<>': |
338 | /// valid values are enum Config::ArgumentListsPolicy values: |
339 | /// None: Nothing at all |
340 | /// OpenDelimiter: only opening delimiter "(" or "<" |
341 | /// Delimiters: empty pair of delimiters "()" or "<>" |
342 | /// FullPlaceholders: full name of both type and parameter |
343 | std::optional<Located<std::string>> ArgumentLists; |
344 | /// Add #include directives when accepting code completions. Config |
345 | /// equivalent of the CLI option '--header-insertion' |
346 | /// Valid values are enum Config::HeaderInsertionPolicy values: |
347 | /// "IWYU": Include what you use. Insert the owning header for top-level |
348 | /// symbols, unless the header is already directly included or the |
349 | /// symbol is forward-declared |
350 | /// "Never": Never insert headers |
351 | std::optional<Located<std::string>> ; |
352 | /// Will suggest code patterns & snippets. |
353 | /// Values are Config::CodePatternsPolicy: |
354 | /// All => enable all code patterns and snippets suggestion |
355 | /// None => disable all code patterns and snippets suggestion |
356 | std::optional<Located<std::string>> CodePatterns; |
357 | }; |
358 | CompletionBlock Completion; |
359 | |
360 | /// Describes hover preferences. |
361 | struct HoverBlock { |
362 | /// Whether hover show a.k.a type. |
363 | std::optional<Located<bool>> ShowAKA; |
364 | }; |
365 | HoverBlock Hover; |
366 | |
367 | /// Configures labels shown inline with the code. |
368 | struct InlayHintsBlock { |
369 | /// Enables/disables the inlay-hints feature. |
370 | std::optional<Located<bool>> Enabled; |
371 | |
372 | /// Show parameter names before function arguments. |
373 | std::optional<Located<bool>> ParameterNames; |
374 | /// Show deduced types for `auto`. |
375 | std::optional<Located<bool>> DeducedTypes; |
376 | /// Show designators in aggregate initialization. |
377 | std::optional<Located<bool>> Designators; |
378 | /// Show defined symbol names at the end of a definition block. |
379 | std::optional<Located<bool>> BlockEnd; |
380 | /// Show parameter names and default values of default arguments after all |
381 | /// of the explicit arguments. |
382 | std::optional<Located<bool>> DefaultArguments; |
383 | /// Limit the length of type name hints. (0 means no limit) |
384 | std::optional<Located<uint32_t>> TypeNameLimit; |
385 | }; |
386 | InlayHintsBlock InlayHints; |
387 | |
388 | /// Configures semantic tokens that are produced by clangd. |
389 | struct SemanticTokensBlock { |
390 | /// Disables clangd to produce semantic tokens for the given kinds. |
391 | std::vector<Located<std::string>> DisabledKinds; |
392 | /// Disables clangd to assign semantic tokens with the given modifiers. |
393 | std::vector<Located<std::string>> DisabledModifiers; |
394 | }; |
395 | SemanticTokensBlock SemanticTokens; |
396 | }; |
397 | |
398 | } // namespace config |
399 | } // namespace clangd |
400 | } // namespace clang |
401 | |
402 | #endif |
403 | |