Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 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 | |
Sam McCall | f12cd99 | 2020-06-26 01:49:53 +0200 | [diff] [blame] | 35 | #include "ConfigProvider.h" |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 36 | #include "llvm/ADT/Optional.h" |
| 37 | #include "llvm/ADT/STLExtras.h" |
| 38 | #include "llvm/Support/Error.h" |
| 39 | #include "llvm/Support/SMLoc.h" |
| 40 | #include "llvm/Support/SourceMgr.h" |
| 41 | #include <string> |
| 42 | #include <vector> |
| 43 | |
| 44 | namespace clang { |
| 45 | namespace clangd { |
| 46 | namespace config { |
| 47 | |
| 48 | /// An entity written in config along, with its optional location in the file. |
| 49 | template <typename T> struct Located { |
| 50 | Located(T Value, llvm::SMRange Range = {}) |
| 51 | : Range(Range), Value(std::move(Value)) {} |
| 52 | |
| 53 | llvm::SMRange Range; |
Nathan James | cb9d0e8 | 2020-11-04 01:36:13 +0000 | [diff] [blame] | 54 | T *operator->() { return &Value; } |
| 55 | const T *operator->() const { return &Value; } |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 56 | T &operator*() { return Value; } |
| 57 | const T &operator*() const { return Value; } |
| 58 | |
| 59 | private: |
| 60 | T Value; |
| 61 | }; |
| 62 | |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 63 | /// A chunk of configuration obtained from a config file, LSP, or elsewhere. |
| 64 | struct Fragment { |
| 65 | /// Parses fragments from a YAML file (one from each --- delimited document). |
| 66 | /// Documents that contained fatal errors are omitted from the results. |
| 67 | /// BufferName is used for the SourceMgr and diagnostics. |
| 68 | static std::vector<Fragment> parseYAML(llvm::StringRef YAML, |
| 69 | llvm::StringRef BufferName, |
| 70 | DiagnosticCallback); |
| 71 | |
Sam McCall | f12cd99 | 2020-06-26 01:49:53 +0200 | [diff] [blame] | 72 | /// Analyzes and consumes this fragment, possibly yielding more diagnostics. |
| 73 | /// This always produces a usable result (errors are recovered). |
| 74 | /// |
| 75 | /// Typically, providers will compile a Fragment once when it's first loaded, |
| 76 | /// caching the result for reuse. |
| 77 | /// Like a compiled program, this is good for performance and also encourages |
| 78 | /// errors to be reported early and only once. |
| 79 | /// |
| 80 | /// The returned function is a cheap-copyable wrapper of refcounted internals. |
| 81 | CompiledFragment compile(DiagnosticCallback) &&; |
| 82 | |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 83 | /// These fields are not part of the user-specified configuration, but |
| 84 | /// instead are populated by the parser to describe the configuration source. |
| 85 | struct SourceInfo { |
| 86 | /// Retains a buffer of the original source this fragment was parsed from. |
| 87 | /// Locations within Located<T> objects point into this SourceMgr. |
| 88 | /// Shared because multiple fragments are often parsed from one (YAML) file. |
| 89 | /// May be null, then all locations should be ignored. |
| 90 | std::shared_ptr<llvm::SourceMgr> Manager; |
| 91 | /// The start of the original source for this fragment. |
| 92 | /// Only valid if SourceManager is set. |
| 93 | llvm::SMLoc Location; |
Kadir Cetinkaya | 7f059a2 | 2020-10-27 23:03:41 +0100 | [diff] [blame] | 94 | /// Absolute path to directory the fragment is associated with. Relative |
| 95 | /// paths mentioned in the fragment are resolved against this. |
| 96 | std::string Directory; |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 97 | }; |
| 98 | SourceInfo Source; |
| 99 | |
Sam McCall | f12cd99 | 2020-06-26 01:49:53 +0200 | [diff] [blame] | 100 | /// Conditions in the If block restrict when a Fragment applies. |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 101 | /// |
| 102 | /// Each separate condition must match (combined with AND). |
| 103 | /// When one condition has multiple values, any may match (combined with OR). |
Sam McCall | f12cd99 | 2020-06-26 01:49:53 +0200 | [diff] [blame] | 104 | /// e.g. `PathMatch: [foo/.*, bar/.*]` matches files in either directory. |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 105 | /// |
| 106 | /// Conditions based on a file's path use the following form: |
| 107 | /// - if the fragment came from a project directory, the path is relative |
| 108 | /// - if the fragment is global (e.g. user config), the path is absolute |
| 109 | /// - paths always use forward-slashes (UNIX-style) |
| 110 | /// If no file is being processed, these conditions will not match. |
Sam McCall | f12cd99 | 2020-06-26 01:49:53 +0200 | [diff] [blame] | 111 | struct IfBlock { |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 112 | /// The file being processed must fully match a regular expression. |
| 113 | std::vector<Located<std::string>> PathMatch; |
Sam McCall | 86f1313 | 2020-07-09 23:33:46 +0200 | [diff] [blame] | 114 | /// The file being processed must *not* fully match a regular expression. |
| 115 | std::vector<Located<std::string>> PathExclude; |
| 116 | |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 117 | /// An unrecognized key was found while parsing the condition. |
| 118 | /// The condition will evaluate to false. |
| 119 | bool HasUnrecognizedCondition = false; |
| 120 | }; |
Sam McCall | f12cd99 | 2020-06-26 01:49:53 +0200 | [diff] [blame] | 121 | IfBlock If; |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 122 | |
Sam McCall | 6c16fbd | 2020-07-13 20:37:54 +0200 | [diff] [blame] | 123 | /// Conditions in the CompileFlags block affect how a file is parsed. |
| 124 | /// |
| 125 | /// clangd emulates how clang would interpret a file. |
| 126 | /// By default, it behaves roughly like `clang $FILENAME`, but real projects |
| 127 | /// usually require setting the include path (with the `-I` flag), defining |
| 128 | /// preprocessor symbols, configuring warnings etc. |
| 129 | /// Often, a compilation database specifies these compile commands. clangd |
| 130 | /// searches for compile_commands.json in parents of the source file. |
| 131 | /// |
| 132 | /// This section modifies how the compile command is constructed. |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 133 | struct CompileFlagsBlock { |
Sam McCall | 6c16fbd | 2020-07-13 20:37:54 +0200 | [diff] [blame] | 134 | /// List of flags to append to the compile command. |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 135 | std::vector<Located<std::string>> Add; |
Sam McCall | 6c16fbd | 2020-07-13 20:37:54 +0200 | [diff] [blame] | 136 | /// List of flags to remove from the compile command. |
| 137 | /// |
| 138 | /// - If the value is a recognized clang flag (like "-I") then it will be |
| 139 | /// removed along with any arguments. Synonyms like --include-dir= will |
| 140 | /// also be removed. |
| 141 | /// - Otherwise, if the value ends in * (like "-DFOO=*") then any argument |
| 142 | /// with the prefix will be removed. |
| 143 | /// - Otherwise any argument exactly matching the value is removed. |
| 144 | /// |
| 145 | /// In all cases, -Xclang is also removed where needed. |
| 146 | /// |
| 147 | /// Example: |
| 148 | /// Command: clang++ --include-directory=/usr/include -DFOO=42 foo.cc |
| 149 | /// Remove: [-I, -DFOO=*] |
| 150 | /// Result: clang++ foo.cc |
| 151 | /// |
| 152 | /// Flags added by the same CompileFlags entry will not be removed. |
| 153 | std::vector<Located<std::string>> Remove; |
| 154 | }; |
| 155 | CompileFlagsBlock CompileFlags; |
Sam McCall | dbf486c | 2020-07-14 15:17:16 +0200 | [diff] [blame] | 156 | |
| 157 | /// Controls how clangd understands code outside the current file. |
| 158 | /// clangd's indexes provide information about symbols that isn't available |
| 159 | /// to clang's parser, such as incoming references. |
| 160 | struct IndexBlock { |
| 161 | /// Whether files are built in the background to produce a project index. |
| 162 | /// This is checked for translation units only, not headers they include. |
| 163 | /// Legal values are "Build" or "Skip". |
| 164 | llvm::Optional<Located<std::string>> Background; |
Kadir Cetinkaya | 359e2f9 | 2020-10-01 12:29:55 +0100 | [diff] [blame] | 165 | /// An external index uses data source outside of clangd itself. This is |
| 166 | /// usually prepared using clangd-indexer. |
| 167 | /// Exactly one source (File/Server) should be configured. |
| 168 | struct ExternalBlock { |
| 169 | /// Path to an index file generated by clangd-indexer. Relative paths may |
| 170 | /// be used, if config fragment is associated with a directory. |
| 171 | llvm::Optional<Located<std::string>> File; |
| 172 | /// Address and port number for a clangd-index-server. e.g. |
| 173 | /// `123.1.1.1:13337`. |
| 174 | llvm::Optional<Located<std::string>> Server; |
| 175 | /// Source root governed by this index. Default is the directory |
| 176 | /// associated with the config fragment. Absolute in case of user config |
| 177 | /// and relative otherwise. Should always use forward-slashes. |
| 178 | llvm::Optional<Located<std::string>> MountPoint; |
| 179 | }; |
| 180 | llvm::Optional<Located<ExternalBlock>> External; |
Sam McCall | dbf486c | 2020-07-14 15:17:16 +0200 | [diff] [blame] | 181 | }; |
| 182 | IndexBlock Index; |
Adam Czachorowski | c894bfd | 2020-09-15 19:47:50 +0200 | [diff] [blame] | 183 | |
| 184 | // Describes the style of the codebase, beyond formatting. |
| 185 | struct StyleBlock { |
| 186 | // Namespaces that should always be fully qualified, meaning no "using" |
| 187 | // declarations, always spell out the whole name (with or without leading |
| 188 | // ::). All nested namespaces are affected as well. |
| 189 | // Affects availability of the AddUsing tweak. |
| 190 | std::vector<Located<std::string>> FullyQualifiedNamespaces; |
| 191 | }; |
| 192 | StyleBlock Style; |
Nathan James | 20b69af | 2020-11-22 10:04:00 +0000 | [diff] [blame] | 193 | |
| 194 | /// Controls how clang-tidy will run over the code base. |
| 195 | /// |
| 196 | /// The settings are merged with any settings found in .clang-tidy |
| 197 | /// configiration files with these ones taking precedence. |
| 198 | struct ClangTidyBlock { |
| 199 | std::vector<Located<std::string>> Add; |
| 200 | /// List of checks to disable. |
| 201 | /// Takes precedence over Add. To enable all llvm checks except include |
| 202 | /// order: |
| 203 | /// Add: llvm-* |
| 204 | /// Remove: llvm-include-onder |
| 205 | std::vector<Located<std::string>> Remove; |
| 206 | |
| 207 | /// A Key-Value pair list of options to pass to clang-tidy checks |
| 208 | /// These take precedence over options specified in clang-tidy configuration |
| 209 | /// files. Example: |
| 210 | /// CheckOptions: |
| 211 | /// readability-braces-around-statements.ShortStatementLines: 2 |
| 212 | std::vector<std::pair<Located<std::string>, Located<std::string>>> |
| 213 | CheckOptions; |
| 214 | }; |
| 215 | ClangTidyBlock ClangTidy; |
Sam McCall | e9fb150 | 2020-06-23 17:21:56 +0200 | [diff] [blame] | 216 | }; |
| 217 | |
| 218 | } // namespace config |
| 219 | } // namespace clangd |
| 220 | } // namespace clang |
| 221 | |
| 222 | #endif |