1 //===--- ClangTidyOptions.h - clang-tidy ------------------------*- 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 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H 10 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H 11 12 #include "llvm/ADT/IntrusiveRefCntPtr.h" 13 #include "llvm/ADT/StringMap.h" 14 #include "llvm/ADT/StringRef.h" 15 #include "llvm/Support/ErrorOr.h" 16 #include "llvm/Support/MemoryBufferRef.h" 17 #include "llvm/Support/VirtualFileSystem.h" 18 #include <functional> 19 #include <optional> 20 #include <string> 21 #include <system_error> 22 #include <utility> 23 #include <vector> 24 25 namespace clang::tidy { 26 27 /// Contains a list of line ranges in a single file. 28 struct FileFilter { 29 /// File name. 30 std::string Name; 31 32 /// LineRange is a pair<start, end> (inclusive). 33 using LineRange = std::pair<unsigned int, unsigned int>; 34 35 /// A list of line ranges in this file, for which we show warnings. 36 std::vector<LineRange> LineRanges; 37 }; 38 39 /// Global options. These options are neither stored nor read from 40 /// configuration files. 41 struct ClangTidyGlobalOptions { 42 /// Output warnings from certain line ranges of certain files only. 43 /// If empty, no warnings will be filtered. 44 std::vector<FileFilter> LineFilter; 45 }; 46 47 /// Contains options for clang-tidy. These options may be read from 48 /// configuration files, and may be different for different translation units. 49 struct ClangTidyOptions { 50 /// These options are used for all settings that haven't been 51 /// overridden by the \c OptionsProvider. 52 /// 53 /// Allow no checks and no headers by default. This method initializes 54 /// check-specific options by calling \c ClangTidyModule::getModuleOptions() 55 /// of each registered \c ClangTidyModule. 56 static ClangTidyOptions getDefaults(); 57 58 /// Overwrites all fields in here by the fields of \p Other that have a value. 59 /// \p Order specifies precedence of \p Other option. 60 ClangTidyOptions &mergeWith(const ClangTidyOptions &Other, unsigned Order); 61 62 /// Creates a new \c ClangTidyOptions instance combined from all fields 63 /// of this instance overridden by the fields of \p Other that have a value. 64 /// \p Order specifies precedence of \p Other option. 65 [[nodiscard]] ClangTidyOptions merge(const ClangTidyOptions &Other, 66 unsigned Order) const; 67 68 /// Checks filter. 69 std::optional<std::string> Checks; 70 71 /// WarningsAsErrors filter. 72 std::optional<std::string> WarningsAsErrors; 73 74 /// File extensions to consider to determine if a given diagnostic is located 75 /// in a header file. 76 std::optional<std::vector<std::string>> HeaderFileExtensions; 77 78 /// File extensions to consider to determine if a given diagnostic is located 79 /// is located in an implementation file. 80 std::optional<std::vector<std::string>> ImplementationFileExtensions; 81 82 /// Output warnings from headers matching this filter. Warnings from 83 /// main files will always be displayed. 84 std::optional<std::string> HeaderFilterRegex; 85 86 /// Output warnings from system headers matching \c HeaderFilterRegex. 87 std::optional<bool> SystemHeaders; 88 89 /// Format code around applied fixes with clang-format using this 90 /// style. 91 /// 92 /// Can be one of: 93 /// * 'none' - don't format code around applied fixes; 94 /// * 'llvm', 'google', 'mozilla' or other predefined clang-format style 95 /// names; 96 /// * 'file' - use the .clang-format file in the closest parent directory of 97 /// each source file; 98 /// * '{inline-formatting-style-in-yaml-format}'. 99 /// 100 /// See clang-format documentation for more about configuring format style. 101 std::optional<std::string> FormatStyle; 102 103 /// Specifies the name or e-mail of the user running clang-tidy. 104 /// 105 /// This option is used, for example, to place the correct user name in TODO() 106 /// comments in the relevant check. 107 std::optional<std::string> User; 108 109 /// Helper structure for storing option value with priority of the value. 110 struct ClangTidyValue { 111 ClangTidyValue() = default; ClangTidyValueClangTidyOptions::ClangTidyValue112 ClangTidyValue(const char *Value) : Value(Value) {} 113 ClangTidyValue(llvm::StringRef Value, unsigned Priority = 0) ValueClangTidyOptions::ClangTidyValue114 : Value(Value), Priority(Priority) {} 115 116 std::string Value; 117 /// Priority stores relative precedence of the value loaded from config 118 /// files to disambiguate local vs global value from different levels. 119 unsigned Priority = 0; 120 }; 121 using StringPair = std::pair<std::string, std::string>; 122 using OptionMap = llvm::StringMap<ClangTidyValue>; 123 124 /// Key-value mapping used to store check-specific options. 125 OptionMap CheckOptions; 126 127 using ArgList = std::vector<std::string>; 128 129 /// Add extra compilation arguments to the end of the list. 130 std::optional<ArgList> ExtraArgs; 131 132 /// Add extra compilation arguments to the start of the list. 133 std::optional<ArgList> ExtraArgsBefore; 134 135 /// Only used in the FileOptionsProvider and ConfigOptionsProvider. If true 136 /// and using a FileOptionsProvider, it will take a configuration file in the 137 /// parent directory (if any exists) and apply this config file on top of the 138 /// parent one. IF true and using a ConfigOptionsProvider, it will apply this 139 /// config on top of any configuration file it finds in the directory using 140 /// the same logic as FileOptionsProvider. If false or missing, only this 141 /// configuration file will be used. 142 std::optional<bool> InheritParentConfig; 143 144 /// Use colors in diagnostics. If missing, it will be auto detected. 145 std::optional<bool> UseColor; 146 }; 147 148 /// Abstract interface for retrieving various ClangTidy options. 149 class ClangTidyOptionsProvider { 150 public: 151 static const char OptionsSourceTypeDefaultBinary[]; 152 static const char OptionsSourceTypeCheckCommandLineOption[]; 153 static const char OptionsSourceTypeConfigCommandLineOption[]; 154 ~ClangTidyOptionsProvider()155 virtual ~ClangTidyOptionsProvider() {} 156 157 /// Returns global options, which are independent of the file. 158 virtual const ClangTidyGlobalOptions &getGlobalOptions() = 0; 159 160 /// ClangTidyOptions and its source. 161 // 162 /// clang-tidy has 3 types of the sources in order of increasing priority: 163 /// * clang-tidy binary. 164 /// * '-config' commandline option or a specific configuration file. If the 165 /// commandline option is specified, clang-tidy will ignore the 166 /// configuration file. 167 /// * '-checks' commandline option. 168 using OptionsSource = std::pair<ClangTidyOptions, std::string>; 169 170 /// Returns an ordered vector of OptionsSources, in order of increasing 171 /// priority. 172 virtual std::vector<OptionsSource> 173 getRawOptions(llvm::StringRef FileName) = 0; 174 175 /// Returns options applying to a specific translation unit with the 176 /// specified \p FileName. 177 ClangTidyOptions getOptions(llvm::StringRef FileName); 178 }; 179 180 /// Implementation of the \c ClangTidyOptionsProvider interface, which 181 /// returns the same options for all files. 182 class DefaultOptionsProvider : public ClangTidyOptionsProvider { 183 public: DefaultOptionsProvider(ClangTidyGlobalOptions GlobalOptions,ClangTidyOptions Options)184 DefaultOptionsProvider(ClangTidyGlobalOptions GlobalOptions, 185 ClangTidyOptions Options) 186 : GlobalOptions(std::move(GlobalOptions)), 187 DefaultOptions(std::move(Options)) {} getGlobalOptions()188 const ClangTidyGlobalOptions &getGlobalOptions() override { 189 return GlobalOptions; 190 } 191 std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override; 192 193 private: 194 ClangTidyGlobalOptions GlobalOptions; 195 ClangTidyOptions DefaultOptions; 196 }; 197 198 class FileOptionsBaseProvider : public DefaultOptionsProvider { 199 protected: 200 // A pair of configuration file base name and a function parsing 201 // configuration from text in the corresponding format. 202 using ConfigFileHandler = std::pair<std::string, std::function<llvm::ErrorOr<ClangTidyOptions> (llvm::MemoryBufferRef)>>; 203 204 /// Configuration file handlers listed in the order of priority. 205 /// 206 /// Custom configuration file formats can be supported by constructing the 207 /// list of handlers and passing it to the appropriate \c FileOptionsProvider 208 /// constructor. E.g. initialization of a \c FileOptionsProvider with support 209 /// of a custom configuration file format for files named ".my-tidy-config" 210 /// could look similar to this: 211 /// \code 212 /// FileOptionsProvider::ConfigFileHandlers ConfigHandlers; 213 /// ConfigHandlers.emplace_back(".my-tidy-config", parseMyConfigFormat); 214 /// ConfigHandlers.emplace_back(".clang-tidy", parseConfiguration); 215 /// return std::make_unique<FileOptionsProvider>( 216 /// GlobalOptions, DefaultOptions, OverrideOptions, ConfigHandlers); 217 /// \endcode 218 /// 219 /// With the order of handlers shown above, the ".my-tidy-config" file would 220 /// take precedence over ".clang-tidy" if both reside in the same directory. 221 using ConfigFileHandlers = std::vector<ConfigFileHandler>; 222 223 FileOptionsBaseProvider(ClangTidyGlobalOptions GlobalOptions, 224 ClangTidyOptions DefaultOptions, 225 ClangTidyOptions OverrideOptions, 226 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS); 227 228 FileOptionsBaseProvider(ClangTidyGlobalOptions GlobalOptions, 229 ClangTidyOptions DefaultOptions, 230 ClangTidyOptions OverrideOptions, 231 ConfigFileHandlers ConfigHandlers); 232 233 void addRawFileOptions(llvm::StringRef AbsolutePath, 234 std::vector<OptionsSource> &CurOptions); 235 236 /// Try to read configuration files from \p Directory using registered 237 /// \c ConfigHandlers. 238 std::optional<OptionsSource> tryReadConfigFile(llvm::StringRef Directory); 239 240 llvm::StringMap<OptionsSource> CachedOptions; 241 ClangTidyOptions OverrideOptions; 242 ConfigFileHandlers ConfigHandlers; 243 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; 244 }; 245 246 /// Implementation of ClangTidyOptions interface, which is used for 247 /// '-config' command-line option. 248 class ConfigOptionsProvider : public FileOptionsBaseProvider { 249 public: 250 ConfigOptionsProvider( 251 ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, 252 ClangTidyOptions ConfigOptions, ClangTidyOptions OverrideOptions, 253 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr); 254 std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override; 255 256 private: 257 ClangTidyOptions ConfigOptions; 258 }; 259 260 /// Implementation of the \c ClangTidyOptionsProvider interface, which 261 /// tries to find a configuration file in the closest parent directory of each 262 /// source file. 263 /// 264 /// By default, files named ".clang-tidy" will be considered, and the 265 /// \c clang::tidy::parseConfiguration function will be used for parsing, but a 266 /// custom set of configuration file names and parsing functions can be 267 /// specified using the appropriate constructor. 268 class FileOptionsProvider : public FileOptionsBaseProvider { 269 public: 270 /// Initializes the \c FileOptionsProvider instance. 271 /// 272 /// \param GlobalOptions are just stored and returned to the caller of 273 /// \c getGlobalOptions. 274 /// 275 /// \param DefaultOptions are used for all settings not specified in a 276 /// configuration file. 277 /// 278 /// If any of the \param OverrideOptions fields are set, they will override 279 /// whatever options are read from the configuration file. 280 FileOptionsProvider( 281 ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, 282 ClangTidyOptions OverrideOptions, 283 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr); 284 285 /// Initializes the \c FileOptionsProvider instance with a custom set 286 /// of configuration file handlers. 287 /// 288 /// \param GlobalOptions are just stored and returned to the caller of 289 /// \c getGlobalOptions. 290 /// 291 /// \param DefaultOptions are used for all settings not specified in a 292 /// configuration file. 293 /// 294 /// If any of the \param OverrideOptions fields are set, they will override 295 /// whatever options are read from the configuration file. 296 /// 297 /// \param ConfigHandlers specifies a custom set of configuration file 298 /// handlers. Each handler is a pair of configuration file name and a function 299 /// that can parse configuration from this file type. The configuration files 300 /// in each directory are searched for in the order of appearance in 301 /// \p ConfigHandlers. 302 FileOptionsProvider(ClangTidyGlobalOptions GlobalOptions, 303 ClangTidyOptions DefaultOptions, 304 ClangTidyOptions OverrideOptions, 305 ConfigFileHandlers ConfigHandlers); 306 307 std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override; 308 }; 309 310 /// Parses LineFilter from JSON and stores it to the \p Options. 311 std::error_code parseLineFilter(llvm::StringRef LineFilter, 312 ClangTidyGlobalOptions &Options); 313 314 /// Parses configuration from JSON and returns \c ClangTidyOptions or an 315 /// error. 316 llvm::ErrorOr<ClangTidyOptions> 317 parseConfiguration(llvm::MemoryBufferRef Config); 318 319 using DiagCallback = llvm::function_ref<void(const llvm::SMDiagnostic &)>; 320 321 llvm::ErrorOr<ClangTidyOptions> 322 parseConfigurationWithDiags(llvm::MemoryBufferRef Config, DiagCallback Handler); 323 324 /// Serializes configuration to a YAML-encoded string. 325 std::string configurationAsText(const ClangTidyOptions &Options); 326 327 } // namespace clang::tidy 328 329 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H 330