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 /// \brief Exclude warnings from headers matching this filter, even if they 87 /// match \c HeaderFilterRegex. 88 std::optional<std::string> ExcludeHeaderFilterRegex; 89 90 /// Output warnings from system headers matching \c HeaderFilterRegex. 91 std::optional<bool> SystemHeaders; 92 93 /// Format code around applied fixes with clang-format using this 94 /// style. 95 /// 96 /// Can be one of: 97 /// * 'none' - don't format code around applied fixes; 98 /// * 'llvm', 'google', 'mozilla' or other predefined clang-format style 99 /// names; 100 /// * 'file' - use the .clang-format file in the closest parent directory of 101 /// each source file; 102 /// * '{inline-formatting-style-in-yaml-format}'. 103 /// 104 /// See clang-format documentation for more about configuring format style. 105 std::optional<std::string> FormatStyle; 106 107 /// Specifies the name or e-mail of the user running clang-tidy. 108 /// 109 /// This option is used, for example, to place the correct user name in TODO() 110 /// comments in the relevant check. 111 std::optional<std::string> User; 112 113 /// Helper structure for storing option value with priority of the value. 114 struct ClangTidyValue { 115 ClangTidyValue() = default; ClangTidyValueClangTidyOptions::ClangTidyValue116 ClangTidyValue(const char *Value) : Value(Value) {} 117 ClangTidyValue(llvm::StringRef Value, unsigned Priority = 0) ValueClangTidyOptions::ClangTidyValue118 : Value(Value), Priority(Priority) {} 119 120 std::string Value; 121 /// Priority stores relative precedence of the value loaded from config 122 /// files to disambiguate local vs global value from different levels. 123 unsigned Priority = 0; 124 }; 125 using StringPair = std::pair<std::string, std::string>; 126 using OptionMap = llvm::StringMap<ClangTidyValue>; 127 128 /// Key-value mapping used to store check-specific options. 129 OptionMap CheckOptions; 130 131 using ArgList = std::vector<std::string>; 132 133 /// Add extra compilation arguments to the end of the list. 134 std::optional<ArgList> ExtraArgs; 135 136 /// Add extra compilation arguments to the start of the list. 137 std::optional<ArgList> ExtraArgsBefore; 138 139 /// Only used in the FileOptionsProvider and ConfigOptionsProvider. If true 140 /// and using a FileOptionsProvider, it will take a configuration file in the 141 /// parent directory (if any exists) and apply this config file on top of the 142 /// parent one. IF true and using a ConfigOptionsProvider, it will apply this 143 /// config on top of any configuration file it finds in the directory using 144 /// the same logic as FileOptionsProvider. If false or missing, only this 145 /// configuration file will be used. 146 std::optional<bool> InheritParentConfig; 147 148 /// Use colors in diagnostics. If missing, it will be auto detected. 149 std::optional<bool> UseColor; 150 }; 151 152 /// Abstract interface for retrieving various ClangTidy options. 153 class ClangTidyOptionsProvider { 154 public: 155 static const char OptionsSourceTypeDefaultBinary[]; 156 static const char OptionsSourceTypeCheckCommandLineOption[]; 157 static const char OptionsSourceTypeConfigCommandLineOption[]; 158 ~ClangTidyOptionsProvider()159 virtual ~ClangTidyOptionsProvider() {} 160 161 /// Returns global options, which are independent of the file. 162 virtual const ClangTidyGlobalOptions &getGlobalOptions() = 0; 163 164 /// ClangTidyOptions and its source. 165 // 166 /// clang-tidy has 3 types of the sources in order of increasing priority: 167 /// * clang-tidy binary. 168 /// * '-config' commandline option or a specific configuration file. If the 169 /// commandline option is specified, clang-tidy will ignore the 170 /// configuration file. 171 /// * '-checks' commandline option. 172 using OptionsSource = std::pair<ClangTidyOptions, std::string>; 173 174 /// Returns an ordered vector of OptionsSources, in order of increasing 175 /// priority. 176 virtual std::vector<OptionsSource> 177 getRawOptions(llvm::StringRef FileName) = 0; 178 179 /// Returns options applying to a specific translation unit with the 180 /// specified \p FileName. 181 ClangTidyOptions getOptions(llvm::StringRef FileName); 182 }; 183 184 /// Implementation of the \c ClangTidyOptionsProvider interface, which 185 /// returns the same options for all files. 186 class DefaultOptionsProvider : public ClangTidyOptionsProvider { 187 public: DefaultOptionsProvider(ClangTidyGlobalOptions GlobalOptions,ClangTidyOptions Options)188 DefaultOptionsProvider(ClangTidyGlobalOptions GlobalOptions, 189 ClangTidyOptions Options) 190 : GlobalOptions(std::move(GlobalOptions)), 191 DefaultOptions(std::move(Options)) {} getGlobalOptions()192 const ClangTidyGlobalOptions &getGlobalOptions() override { 193 return GlobalOptions; 194 } 195 std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override; 196 197 private: 198 ClangTidyGlobalOptions GlobalOptions; 199 ClangTidyOptions DefaultOptions; 200 }; 201 202 class FileOptionsBaseProvider : public DefaultOptionsProvider { 203 protected: 204 // A pair of configuration file base name and a function parsing 205 // configuration from text in the corresponding format. 206 using ConfigFileHandler = std::pair<std::string, std::function<llvm::ErrorOr<ClangTidyOptions> (llvm::MemoryBufferRef)>>; 207 208 /// Configuration file handlers listed in the order of priority. 209 /// 210 /// Custom configuration file formats can be supported by constructing the 211 /// list of handlers and passing it to the appropriate \c FileOptionsProvider 212 /// constructor. E.g. initialization of a \c FileOptionsProvider with support 213 /// of a custom configuration file format for files named ".my-tidy-config" 214 /// could look similar to this: 215 /// \code 216 /// FileOptionsProvider::ConfigFileHandlers ConfigHandlers; 217 /// ConfigHandlers.emplace_back(".my-tidy-config", parseMyConfigFormat); 218 /// ConfigHandlers.emplace_back(".clang-tidy", parseConfiguration); 219 /// return std::make_unique<FileOptionsProvider>( 220 /// GlobalOptions, DefaultOptions, OverrideOptions, ConfigHandlers); 221 /// \endcode 222 /// 223 /// With the order of handlers shown above, the ".my-tidy-config" file would 224 /// take precedence over ".clang-tidy" if both reside in the same directory. 225 using ConfigFileHandlers = std::vector<ConfigFileHandler>; 226 227 FileOptionsBaseProvider(ClangTidyGlobalOptions GlobalOptions, 228 ClangTidyOptions DefaultOptions, 229 ClangTidyOptions OverrideOptions, 230 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS); 231 232 FileOptionsBaseProvider(ClangTidyGlobalOptions GlobalOptions, 233 ClangTidyOptions DefaultOptions, 234 ClangTidyOptions OverrideOptions, 235 ConfigFileHandlers ConfigHandlers); 236 237 void addRawFileOptions(llvm::StringRef AbsolutePath, 238 std::vector<OptionsSource> &CurOptions); 239 240 /// Try to read configuration files from \p Directory using registered 241 /// \c ConfigHandlers. 242 std::optional<OptionsSource> tryReadConfigFile(llvm::StringRef Directory); 243 244 llvm::StringMap<OptionsSource> CachedOptions; 245 ClangTidyOptions OverrideOptions; 246 ConfigFileHandlers ConfigHandlers; 247 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; 248 }; 249 250 /// Implementation of ClangTidyOptions interface, which is used for 251 /// '-config' command-line option. 252 class ConfigOptionsProvider : public FileOptionsBaseProvider { 253 public: 254 ConfigOptionsProvider( 255 ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, 256 ClangTidyOptions ConfigOptions, ClangTidyOptions OverrideOptions, 257 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr); 258 std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override; 259 260 private: 261 ClangTidyOptions ConfigOptions; 262 }; 263 264 /// Implementation of the \c ClangTidyOptionsProvider interface, which 265 /// tries to find a configuration file in the closest parent directory of each 266 /// source file. 267 /// 268 /// By default, files named ".clang-tidy" will be considered, and the 269 /// \c clang::tidy::parseConfiguration function will be used for parsing, but a 270 /// custom set of configuration file names and parsing functions can be 271 /// specified using the appropriate constructor. 272 class FileOptionsProvider : public FileOptionsBaseProvider { 273 public: 274 /// Initializes the \c FileOptionsProvider instance. 275 /// 276 /// \param GlobalOptions are just stored and returned to the caller of 277 /// \c getGlobalOptions. 278 /// 279 /// \param DefaultOptions are used for all settings not specified in a 280 /// configuration file. 281 /// 282 /// If any of the \param OverrideOptions fields are set, they will override 283 /// whatever options are read from the configuration file. 284 FileOptionsProvider( 285 ClangTidyGlobalOptions GlobalOptions, ClangTidyOptions DefaultOptions, 286 ClangTidyOptions OverrideOptions, 287 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr); 288 289 /// Initializes the \c FileOptionsProvider instance with a custom set 290 /// of configuration file handlers. 291 /// 292 /// \param GlobalOptions are just stored and returned to the caller of 293 /// \c getGlobalOptions. 294 /// 295 /// \param DefaultOptions are used for all settings not specified in a 296 /// configuration file. 297 /// 298 /// If any of the \param OverrideOptions fields are set, they will override 299 /// whatever options are read from the configuration file. 300 /// 301 /// \param ConfigHandlers specifies a custom set of configuration file 302 /// handlers. Each handler is a pair of configuration file name and a function 303 /// that can parse configuration from this file type. The configuration files 304 /// in each directory are searched for in the order of appearance in 305 /// \p ConfigHandlers. 306 FileOptionsProvider(ClangTidyGlobalOptions GlobalOptions, 307 ClangTidyOptions DefaultOptions, 308 ClangTidyOptions OverrideOptions, 309 ConfigFileHandlers ConfigHandlers); 310 311 std::vector<OptionsSource> getRawOptions(llvm::StringRef FileName) override; 312 }; 313 314 /// Parses LineFilter from JSON and stores it to the \p Options. 315 std::error_code parseLineFilter(llvm::StringRef LineFilter, 316 ClangTidyGlobalOptions &Options); 317 318 /// Parses configuration from JSON and returns \c ClangTidyOptions or an 319 /// error. 320 llvm::ErrorOr<ClangTidyOptions> 321 parseConfiguration(llvm::MemoryBufferRef Config); 322 323 using DiagCallback = llvm::function_ref<void(const llvm::SMDiagnostic &)>; 324 325 llvm::ErrorOr<ClangTidyOptions> 326 parseConfigurationWithDiags(llvm::MemoryBufferRef Config, DiagCallback Handler); 327 328 /// Serializes configuration to a YAML-encoded string. 329 std::string configurationAsText(const ClangTidyOptions &Options); 330 331 } // namespace clang::tidy 332 333 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYOPTIONS_H 334