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 "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 CompileFlagsBlock CompileFlags; 175 176 /// Controls how clangd understands code outside the current file. 177 /// clangd's indexes provide information about symbols that isn't available 178 /// to clang's parser, such as incoming references. 179 struct IndexBlock { 180 /// Whether files are built in the background to produce a project index. 181 /// This is checked for translation units only, not headers they include. 182 /// Legal values are "Build" or "Skip". 183 std::optional<Located<std::string>> Background; 184 /// An external index uses data source outside of clangd itself. This is 185 /// usually prepared using clangd-indexer. 186 /// Exactly one source (File/Server) should be configured. 187 struct ExternalBlock { 188 /// Whether the block is explicitly set to `None`. Can be used to clear 189 /// any external index specified before. 190 Located<bool> IsNone = false; 191 /// Path to an index file generated by clangd-indexer. Relative paths may 192 /// be used, if config fragment is associated with a directory. 193 std::optional<Located<std::string>> File; 194 /// Address and port number for a clangd-index-server. e.g. 195 /// `123.1.1.1:13337`. 196 std::optional<Located<std::string>> Server; 197 /// Source root governed by this index. Default is the directory 198 /// associated with the config fragment. Absolute in case of user config 199 /// and relative otherwise. Should always use forward-slashes. 200 std::optional<Located<std::string>> MountPoint; 201 }; 202 std::optional<Located<ExternalBlock>> External; 203 // Whether the standard library visible from this file should be indexed. 204 // This makes all standard library symbols available, included or not. 205 std::optional<Located<bool>> StandardLibrary; 206 }; 207 IndexBlock Index; 208 209 /// Controls behavior of diagnostics (errors and warnings). 210 struct DiagnosticsBlock { 211 /// Diagnostic codes that should be suppressed. 212 /// 213 /// Valid values are: 214 /// - *, to disable all diagnostics 215 /// - diagnostic codes exposed by clangd (e.g unknown_type, -Wunused-result) 216 /// - clang internal diagnostic codes (e.g. err_unknown_type) 217 /// - warning categories (e.g. unused-result) 218 /// - clang-tidy check names (e.g. bugprone-narrowing-conversions) 219 /// 220 /// This is a simple filter. Diagnostics can be controlled in other ways 221 /// (e.g. by disabling a clang-tidy check, or the -Wunused compile flag). 222 /// This often has other advantages, such as skipping some analysis. 223 std::vector<Located<std::string>> Suppress; 224 225 /// Controls how clangd will correct "unnecessary" #include directives. 226 /// clangd can warn if a header is `#include`d but not used, and suggest 227 /// removing it. 228 // 229 /// Strict means a header is unused if it does not *directly* provide any 230 /// symbol used in the file. Removing it may still break compilation if it 231 /// transitively includes headers that are used. This should be fixed by 232 /// including those headers directly. 233 /// 234 /// Valid values are: 235 /// - Strict 236 /// - std::nullopt 237 std::optional<Located<std::string>> UnusedIncludes; 238 239 /// Controls if clangd should analyze missing #include directives. 240 /// clangd will warn if no header providing a symbol is `#include`d 241 /// (missing) directly, and suggest adding it. 242 /// 243 /// Strict means a header providing a symbol is missing if it is not 244 /// *directly #include'd. The file might still compile if the header is 245 /// included transitively. 246 /// 247 /// Valid values are: 248 /// - Strict 249 /// - std::nullopt 250 std::optional<Located<std::string>> MissingIncludes; 251 252 /// Controls IncludeCleaner diagnostics. 253 struct IncludesBlock { 254 /// Regexes that will be used to avoid diagnosing certain includes as 255 /// unused or missing. These can match any suffix of the header file in 256 /// question. 257 std::vector<Located<std::string>> IgnoreHeader; 258 259 /// If false (default), unused system headers will be ignored. 260 /// Standard library headers are analyzed regardless of this option. 261 std::optional<Located<bool>> AnalyzeAngledIncludes; 262 }; 263 IncludesBlock Includes; 264 265 /// Controls how clang-tidy will run over the code base. 266 /// 267 /// The settings are merged with any settings found in .clang-tidy 268 /// configuration files with these ones taking precedence. 269 struct ClangTidyBlock { 270 std::vector<Located<std::string>> Add; 271 /// List of checks to disable. 272 /// Takes precedence over Add. To enable all llvm checks except include 273 /// order: 274 /// Add: llvm-* 275 /// Remove: llvm-include-order 276 std::vector<Located<std::string>> Remove; 277 278 /// A Key-Value pair list of options to pass to clang-tidy checks 279 /// These take precedence over options specified in clang-tidy 280 /// configuration files. Example: 281 /// CheckOptions: 282 /// readability-braces-around-statements.ShortStatementLines: 2 283 std::vector<std::pair<Located<std::string>, Located<std::string>>> 284 CheckOptions; 285 286 /// Whether to run checks that may slow down clangd. 287 /// Strict: Run only checks measured to be fast. (Default) 288 /// This excludes recently-added checks we have not timed yet. 289 /// Loose: Run checks unless they are known to be slow. 290 /// None: Run checks regardless of their speed. 291 std::optional<Located<std::string>> FastCheckFilter; 292 }; 293 ClangTidyBlock ClangTidy; 294 }; 295 DiagnosticsBlock Diagnostics; 296 297 // Describes the style of the codebase, beyond formatting. 298 struct StyleBlock { 299 // Namespaces that should always be fully qualified, meaning no "using" 300 // declarations, always spell out the whole name (with or without leading 301 // ::). All nested namespaces are affected as well. 302 // Affects availability of the AddUsing tweak. 303 std::vector<Located<std::string>> FullyQualifiedNamespaces; 304 305 /// List of regexes for headers that should always be included with a 306 /// ""-style include. By default, and in case of a conflict with 307 /// AngledHeaders (i.e. a header matches a regex in both QuotedHeaders and 308 /// AngledHeaders), system headers use <> and non-system headers use "". 309 /// These can match any suffix of the header file in question. 310 /// Matching is performed against the header text, not its absolute path 311 /// within the project. 312 std::vector<Located<std::string>> QuotedHeaders; 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>> AngledHeaders; 321 }; 322 StyleBlock Style; 323 324 /// Describes code completion preferences. 325 struct CompletionBlock { 326 /// Whether code completion should include suggestions from scopes that are 327 /// not visible. The required scope prefix will be inserted. 328 std::optional<Located<bool>> AllScopes; 329 /// How to present the argument list between '()' and '<>': 330 /// valid values are enum Config::ArgumentListsPolicy values: 331 /// None: Nothing at all 332 /// OpenDelimiter: only opening delimiter "(" or "<" 333 /// Delimiters: empty pair of delimiters "()" or "<>" 334 /// FullPlaceholders: full name of both type and parameter 335 std::optional<Located<std::string>> ArgumentLists; 336 }; 337 CompletionBlock Completion; 338 339 /// Describes hover preferences. 340 struct HoverBlock { 341 /// Whether hover show a.k.a type. 342 std::optional<Located<bool>> ShowAKA; 343 }; 344 HoverBlock Hover; 345 346 /// Configures labels shown inline with the code. 347 struct InlayHintsBlock { 348 /// Enables/disables the inlay-hints feature. 349 std::optional<Located<bool>> Enabled; 350 351 /// Show parameter names before function arguments. 352 std::optional<Located<bool>> ParameterNames; 353 /// Show deduced types for `auto`. 354 std::optional<Located<bool>> DeducedTypes; 355 /// Show designators in aggregate initialization. 356 std::optional<Located<bool>> Designators; 357 /// Show defined symbol names at the end of a definition block. 358 std::optional<Located<bool>> BlockEnd; 359 /// Show parameter names and default values of default arguments after all 360 /// of the explicit arguments. 361 std::optional<Located<bool>> DefaultArguments; 362 /// Limit the length of type name hints. (0 means no limit) 363 std::optional<Located<uint32_t>> TypeNameLimit; 364 }; 365 InlayHintsBlock InlayHints; 366 367 /// Configures semantic tokens that are produced by clangd. 368 struct SemanticTokensBlock { 369 /// Disables clangd to produce semantic tokens for the given kinds. 370 std::vector<Located<std::string>> DisabledKinds; 371 /// Disables clangd to assign semantic tokens with the given modifiers. 372 std::vector<Located<std::string>> DisabledModifiers; 373 }; 374 SemanticTokensBlock SemanticTokens; 375 }; 376 377 } // namespace config 378 } // namespace clangd 379 } // namespace clang 380 381 #endif 382