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