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 "ConfigProvider.h" 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 = {}) RangeLocated51 : Range(Range), Value(std::move(Value)) {} 52 53 llvm::SMRange Range; 54 T *operator->() { return &Value; } 55 const T *operator->() const { return &Value; } 56 T &operator*() { return Value; } 57 const T &operator*() const { return Value; } 58 59 private: 60 T Value; 61 }; 62 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 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 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; 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; 97 }; 98 SourceInfo Source; 99 100 /// Conditions in the If block restrict when a Fragment applies. 101 /// 102 /// Each separate condition must match (combined with AND). 103 /// When one condition has multiple values, any may match (combined with OR). 104 /// e.g. `PathMatch: [foo/.*, bar/.*]` matches files in either directory. 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. 111 struct IfBlock { 112 /// The file being processed must fully match a regular expression. 113 std::vector<Located<std::string>> PathMatch; 114 /// The file being processed must *not* fully match a regular expression. 115 std::vector<Located<std::string>> PathExclude; 116 117 /// An unrecognized key was found while parsing the condition. 118 /// The condition will evaluate to false. 119 bool HasUnrecognizedCondition = false; 120 }; 121 IfBlock If; 122 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. 133 struct CompileFlagsBlock { 134 /// List of flags to append to the compile command. 135 std::vector<Located<std::string>> Add; 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; 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; 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; 181 }; 182 IndexBlock Index; 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; 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; 216 }; 217 218 } // namespace config 219 } // namespace clangd 220 } // namespace clang 221 222 #endif 223