brintos

brintos / llvm-project-archived public Read only

0
0
Text · 18.3 KiB · 2afeb36 Raw
416 lines · c
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-exception6//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 flags12//  - specifying different settings for different files13//14// This file defines the config::Fragment structure which models one piece of15// 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 Fragment24//  - update ConfigYAML.cpp to parse it25//  - add its semantic form to Config (in Config.h)26//  - update ConfigCompile.cpp to map Fragment -> Config27//  - make use of the option inside clangd28//  - document the new option (config.md in the llvm/clangd-www repository)29//30//===----------------------------------------------------------------------===//31 32#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONFIGFRAGMENT_H33#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CONFIGFRAGMENT_H34 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 43namespace clang {44namespace clangd {45namespace config {46 47/// An entity written in config along, with its optional location in the file.48template <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 58private:59  T Value;60};61 62/// A chunk of configuration obtained from a config file, LSP, or elsewhere.63struct 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 encourages77  /// 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, but83  /// 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. Relative94    /// paths mentioned in the fragment are resolved against this.95    std::string Directory;96    /// Whether this fragment is allowed to make critical security/privacy97    /// 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 relative110  /// - if the fragment is global (e.g. user config), the path is absolute111  /// - 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 projects129  /// usually require setting the include path (with the `-I` flag), defining130  /// preprocessor symbols, configuring warnings etc.131  /// Often, a compilation database specifies these compile commands. clangd132  /// 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 will140    /// be invoked to extract include paths.141    ///142    /// (That this simply replaces argv[0], and may mangle commands that use143    /// 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 be151    ///   removed along with any arguments. Synonyms like --include-dir= will152    ///   also be removed.153    /// - Otherwise, if the value ends in * (like "-DFOO=*") then any argument154    ///   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.cc161    ///   Remove: [-I, -DFOO=*]162    ///   Result: clang++ foo.cc163    ///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.json168    /// 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 (like175    /// stddef.h), or use the system headers from the query driver. Use the176    /// option value 'Clangd' (default) to indicate Clangd's headers, and use177    /// 'QueryDriver' to indicate QueryDriver's headers. `Clangd` is the178    /// fallback if no query driver is supplied or if the query driver regex179    /// string fails to match the compiler used in the CDB.180    std::optional<Located<std::string>> BuiltinHeaders;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 available186  /// 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 is193    /// 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 clear197      /// any external index specified before.198      Located<bool> IsNone = false;199      /// Path to an index file generated by clangd-indexer. Relative paths may200      /// 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 directory206      /// associated with the config fragment. Absolute in case of user config207      /// 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 diagnostics223    /// - 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 ways229    /// (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 suggest235    /// removing it.236    //237    /// Strict means a header is unused if it does not *directly* provide any238    /// symbol used in the file. Removing it may still break compilation if it239    /// transitively includes headers that are used. This should be fixed by240    /// including those headers directly.241    ///242    /// Valid values are:243    /// - Strict244    /// - std::nullopt245    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`d249    /// (missing) directly, and suggest adding it.250    ///251    /// Strict means a header providing a symbol is missing if it is not252    /// *directly #include'd. The file might still compile if the header is253    /// included transitively.254    ///255    /// Valid values are:256    /// - Strict257    /// - std::nullopt258    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 as263      /// unused or missing. These can match any suffix of the header file in264      /// question.265      std::vector<Located<std::string>> IgnoreHeader;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-tidy276    /// 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 include281      /// order:282      ///   Add: llvm-*283      ///   Remove: llvm-include-order284      std::vector<Located<std::string>> Remove;285 286      /// A Key-Value pair list of options to pass to clang-tidy checks287      /// These take precedence over options specified in clang-tidy288      /// configuration files. Example:289      ///   CheckOptions:290      ///     readability-braces-around-statements.ShortStatementLines: 2291      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 leading309    // ::). 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 a314    /// ""-style include. By default, and in case of a conflict with315    /// AngledHeaders (i.e. a header matches a regex in both QuotedHeaders and316    /// 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 absolute path of the header319    /// within the project.320    std::vector<Located<std::string>> QuotedHeaders;321    /// List of regexes for headers that should always be included with a322    /// <>-style include. By default, and in case of a conflict with323    /// AngledHeaders (i.e. a header matches a regex in both QuotedHeaders and324    /// 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 absolute path of the header327    /// within the project.328    std::vector<Located<std::string>> AngledHeaders;329  };330  StyleBlock Style;331 332  /// Describes code completion preferences.333  struct CompletionBlock {334    /// Whether code completion should include suggestions from scopes that are335    /// 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 all340    ///   OpenDelimiter: only opening delimiter "(" or "<"341    ///   Delimiters: empty pair of delimiters "()" or "<>"342    ///   FullPlaceholders: full name of both type and parameter343    std::optional<Located<std::string>> ArgumentLists;344    /// Add #include directives when accepting code completions. Config345    /// 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-level348    ///     symbols, unless the header is already directly included or the349    ///     symbol is forward-declared350    ///   "Never": Never insert headers351    std::optional<Located<std::string>> HeaderInsertion;352    /// Will suggest code patterns & snippets.353    /// Values are Config::CodePatternsPolicy:354    ///   All  => enable all code patterns and snippets suggestion355    ///   None => disable all code patterns and snippets suggestion356    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    /// Limit the number of characters returned when hovering a macro.365    std::optional<Located<uint32_t>> MacroContentsLimit;366  };367  HoverBlock Hover;368 369  /// Configures labels shown inline with the code.370  struct InlayHintsBlock {371    /// Enables/disables the inlay-hints feature.372    std::optional<Located<bool>> Enabled;373 374    /// Show parameter names before function arguments.375    std::optional<Located<bool>> ParameterNames;376    /// Show deduced types for `auto`.377    std::optional<Located<bool>> DeducedTypes;378    /// Show designators in aggregate initialization.379    std::optional<Located<bool>> Designators;380    /// Show defined symbol names at the end of a definition block.381    std::optional<Located<bool>> BlockEnd;382    /// Show parameter names and default values of default arguments after all383    /// of the explicit arguments.384    std::optional<Located<bool>> DefaultArguments;385    /// Limit the length of type name hints. (0 means no limit)386    std::optional<Located<uint32_t>> TypeNameLimit;387  };388  InlayHintsBlock InlayHints;389 390  /// Configures semantic tokens that are produced by clangd.391  struct SemanticTokensBlock {392    /// Disables clangd to produce semantic tokens for the given kinds.393    std::vector<Located<std::string>> DisabledKinds;394    /// Disables clangd to assign semantic tokens with the given modifiers.395    std::vector<Located<std::string>> DisabledModifiers;396  };397  SemanticTokensBlock SemanticTokens;398 399  /// Configures documentation style and behaviour.400  struct DocumentationBlock {401    /// Specifies the format of comments in the code.402    /// Valid values are enum Config::CommentFormatPolicy values:403    /// - Plaintext: Treat comments as plain text.404    /// - Markdown: Treat comments as Markdown.405    /// - Doxygen: Treat comments as doxygen.406    std::optional<Located<std::string>> CommentFormat;407  };408  DocumentationBlock Documentation;409};410 411} // namespace config412} // namespace clangd413} // namespace clang414 415#endif416