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