1 //===--- ClangTidyCheck.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_CLANGTIDYCHECK_H 10 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H 11 12 #include "ClangTidyDiagnosticConsumer.h" 13 #include "ClangTidyOptions.h" 14 #include "clang/ASTMatchers/ASTMatchFinder.h" 15 #include "clang/Basic/Diagnostic.h" 16 #include <optional> 17 #include <type_traits> 18 #include <utility> 19 #include <vector> 20 21 namespace clang { 22 23 class SourceManager; 24 25 namespace tidy { 26 27 /// This class should be specialized by any enum type that needs to be converted 28 /// to and from an \ref llvm::StringRef. 29 template <class T> struct OptionEnumMapping { 30 // Specializations of this struct must implement this function. 31 static ArrayRef<std::pair<T, StringRef>> getEnumMapping() = delete; 32 }; 33 34 /// Base class for all clang-tidy checks. 35 /// 36 /// To implement a ``ClangTidyCheck``, write a subclass and override some of the 37 /// base class's methods. E.g. to implement a check that validates namespace 38 /// declarations, override ``registerMatchers``: 39 /// 40 /// ~~~{.cpp} 41 /// void registerMatchers(ast_matchers::MatchFinder *Finder) override { 42 /// Finder->addMatcher(namespaceDecl().bind("namespace"), this); 43 /// } 44 /// ~~~ 45 /// 46 /// and then override ``check(const MatchResult &Result)`` to do the actual 47 /// check for each match. 48 /// 49 /// A new ``ClangTidyCheck`` instance is created per translation unit. 50 /// 51 /// FIXME: Figure out whether carrying information from one TU to another is 52 /// useful/necessary. 53 class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { 54 public: 55 /// Initializes the check with \p CheckName and \p Context. 56 /// 57 /// Derived classes must implement the constructor with this signature or 58 /// delegate it. If a check needs to read options, it can do this in the 59 /// constructor using the Options.get() methods below. 60 ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context); 61 62 /// Override this to disable registering matchers and PP callbacks if an 63 /// invalid language version is being used. 64 /// 65 /// For example if a check is examining overloaded functions then this should 66 /// be overridden to return false when the CPlusPlus flag is not set in 67 /// \p LangOpts. isLanguageVersionSupported(const LangOptions & LangOpts)68 virtual bool isLanguageVersionSupported(const LangOptions &LangOpts) const { 69 return true; 70 } 71 72 /// Override this to register ``PPCallbacks`` in the preprocessor. 73 /// 74 /// This should be used for clang-tidy checks that analyze preprocessor- 75 /// dependent properties, e.g. include directives and macro definitions. 76 /// 77 /// This will only be executed if the function isLanguageVersionSupported 78 /// returns true. 79 /// 80 /// There are two Preprocessors to choose from that differ in how they handle 81 /// modular #includes: 82 /// - PP is the real Preprocessor. It doesn't walk into modular #includes and 83 /// thus doesn't generate PPCallbacks for their contents. 84 /// - ModuleExpanderPP preprocesses the whole translation unit in the 85 /// non-modular mode, which allows it to generate PPCallbacks not only for 86 /// the main file and textual headers, but also for all transitively 87 /// included modular headers when the analysis runs with modules enabled. 88 /// When modules are not enabled ModuleExpanderPP just points to the real 89 /// preprocessor. registerPPCallbacks(const SourceManager & SM,Preprocessor * PP,Preprocessor * ModuleExpanderPP)90 virtual void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, 91 Preprocessor *ModuleExpanderPP) {} 92 93 /// Override this to register AST matchers with \p Finder. 94 /// 95 /// This should be used by clang-tidy checks that analyze code properties that 96 /// dependent on AST knowledge. 97 /// 98 /// You can register as many matchers as necessary with \p Finder. Usually, 99 /// "this" will be used as callback, but you can also specify other callback 100 /// classes. Thereby, different matchers can trigger different callbacks. 101 /// 102 /// This will only be executed if the function isLanguageVersionSupported 103 /// returns true. 104 /// 105 /// If you need to merge information between the different matchers, you can 106 /// store these as members of the derived class. However, note that all 107 /// matches occur in the order of the AST traversal. registerMatchers(ast_matchers::MatchFinder * Finder)108 virtual void registerMatchers(ast_matchers::MatchFinder *Finder) {} 109 110 /// ``ClangTidyChecks`` that register ASTMatchers should do the actual 111 /// work in here. check(const ast_matchers::MatchFinder::MatchResult & Result)112 virtual void check(const ast_matchers::MatchFinder::MatchResult &Result) {} 113 114 /// Add a diagnostic with the check's name. 115 DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, 116 DiagnosticIDs::Level Level = DiagnosticIDs::Warning); 117 118 /// Add a diagnostic with the check's name. 119 DiagnosticBuilder diag(StringRef Description, 120 DiagnosticIDs::Level Level = DiagnosticIDs::Warning); 121 122 /// Adds a diagnostic to report errors in the check's configuration. 123 DiagnosticBuilder 124 configurationDiag(StringRef Description, 125 DiagnosticIDs::Level Level = DiagnosticIDs::Warning) const; 126 127 /// Should store all options supported by this check with their 128 /// current values or default values for options that haven't been overridden. 129 /// 130 /// The check should use ``Options.store()`` to store each option it supports 131 /// whether it has the default value or it has been overridden. storeOptions(ClangTidyOptions::OptionMap & Options)132 virtual void storeOptions(ClangTidyOptions::OptionMap &Options) {} 133 134 /// Provides access to the ``ClangTidyCheck`` options via check-local 135 /// names. 136 /// 137 /// Methods of this class prepend ``CheckName + "."`` to translate check-local 138 /// option names to global option names. 139 class OptionsView { 140 void diagnoseBadIntegerOption(const Twine &Lookup, 141 StringRef Unparsed) const; 142 void diagnoseBadBooleanOption(const Twine &Lookup, 143 StringRef Unparsed) const; 144 void diagnoseBadEnumOption(const Twine &Lookup, StringRef Unparsed, 145 StringRef Suggestion = StringRef()) const; 146 147 public: 148 /// Initializes the instance using \p CheckName + "." as a prefix. 149 OptionsView(StringRef CheckName, 150 const ClangTidyOptions::OptionMap &CheckOptions, 151 ClangTidyContext *Context); 152 153 /// Read a named option from the ``Context``. 154 /// 155 /// Reads the option with the check-local name \p LocalName from the 156 /// ``CheckOptions``. If the corresponding key is not present, return 157 /// ``std::nullopt``. 158 std::optional<StringRef> get(StringRef LocalName) const; 159 160 /// Read a named option from the ``Context``. 161 /// 162 /// Reads the option with the check-local name \p LocalName from the 163 /// ``CheckOptions``. If the corresponding key is not present, returns 164 /// \p Default. 165 StringRef get(StringRef LocalName, StringRef Default) const; 166 167 /// Read a named option from the ``Context``. 168 /// 169 /// Reads the option with the check-local name \p LocalName from local or 170 /// global ``CheckOptions``. Gets local option first. If local is not 171 /// present, falls back to get global option. If global option is not 172 /// present either, return ``std::nullopt``. 173 std::optional<StringRef> getLocalOrGlobal(StringRef LocalName) const; 174 175 /// Read a named option from the ``Context``. 176 /// 177 /// Reads the option with the check-local name \p LocalName from local or 178 /// global ``CheckOptions``. Gets local option first. If local is not 179 /// present, falls back to get global option. If global option is not 180 /// present either, returns \p Default. 181 StringRef getLocalOrGlobal(StringRef LocalName, StringRef Default) const; 182 183 /// Read a named option from the ``Context`` and parse it as an 184 /// integral type ``T``. 185 /// 186 /// Reads the option with the check-local name \p LocalName from the 187 /// ``CheckOptions``. If the corresponding key is not present, 188 /// return ``std::nullopt``. 189 /// 190 /// If the corresponding key can't be parsed as a ``T``, emit a 191 /// diagnostic and return ``std::nullopt``. 192 template <typename T> 193 std::enable_if_t<std::is_integral_v<T>, std::optional<T>> get(StringRef LocalName)194 get(StringRef LocalName) const { 195 if (std::optional<StringRef> Value = get(LocalName)) { 196 T Result{}; 197 if (!StringRef(*Value).getAsInteger(10, Result)) 198 return Result; 199 diagnoseBadIntegerOption(NamePrefix + LocalName, *Value); 200 } 201 return std::nullopt; 202 } 203 204 /// Read a named option from the ``Context`` and parse it as an 205 /// integral type ``T``. 206 /// 207 /// Reads the option with the check-local name \p LocalName from the 208 /// ``CheckOptions``. If the corresponding key is `none`, `null`, 209 /// `-1` or empty, return ``std::nullopt``. If the corresponding 210 /// key is not present, return \p Default. 211 /// 212 /// If the corresponding key can't be parsed as a ``T``, emit a 213 /// diagnostic and return \p Default. 214 template <typename T> 215 std::enable_if_t<std::is_integral_v<T>, std::optional<T>> get(StringRef LocalName,std::optional<T> Default)216 get(StringRef LocalName, std::optional<T> Default) const { 217 if (std::optional<StringRef> Value = get(LocalName)) { 218 if (Value == "" || Value == "none" || Value == "null" || 219 (std::is_unsigned_v<T> && Value == "-1")) 220 return std::nullopt; 221 T Result{}; 222 if (!StringRef(*Value).getAsInteger(10, Result)) 223 return Result; 224 diagnoseBadIntegerOption(NamePrefix + LocalName, *Value); 225 } 226 return Default; 227 } 228 229 /// Read a named option from the ``Context`` and parse it as an 230 /// integral type ``T``. 231 /// 232 /// Reads the option with the check-local name \p LocalName from the 233 /// ``CheckOptions``. If the corresponding key is not present, return 234 /// \p Default. 235 /// 236 /// If the corresponding key can't be parsed as a ``T``, emit a 237 /// diagnostic and return \p Default. 238 template <typename T> get(StringRef LocalName,T Default)239 std::enable_if_t<std::is_integral_v<T>, T> get(StringRef LocalName, 240 T Default) const { 241 return get<T>(LocalName).value_or(Default); 242 } 243 244 /// Read a named option from the ``Context`` and parse it as an 245 /// integral type ``T``. 246 /// 247 /// Reads the option with the check-local name \p LocalName from local or 248 /// global ``CheckOptions``. Gets local option first. If local is not 249 /// present, falls back to get global option. If global option is not 250 /// present either, return ``std::nullopt``. 251 /// 252 /// If the corresponding key can't be parsed as a ``T``, emit a 253 /// diagnostic and return ``std::nullopt``. 254 template <typename T> 255 std::enable_if_t<std::is_integral_v<T>, std::optional<T>> getLocalOrGlobal(StringRef LocalName)256 getLocalOrGlobal(StringRef LocalName) const { 257 std::optional<StringRef> ValueOr = get(LocalName); 258 bool IsGlobal = false; 259 if (!ValueOr) { 260 IsGlobal = true; 261 ValueOr = getLocalOrGlobal(LocalName); 262 if (!ValueOr) 263 return std::nullopt; 264 } 265 T Result{}; 266 if (!StringRef(*ValueOr).getAsInteger(10, Result)) 267 return Result; 268 diagnoseBadIntegerOption( 269 IsGlobal ? Twine(LocalName) : NamePrefix + LocalName, *ValueOr); 270 return std::nullopt; 271 } 272 273 /// Read a named option from the ``Context`` and parse it as an 274 /// integral type ``T``. 275 /// 276 /// Reads the option with the check-local name \p LocalName from local or 277 /// global ``CheckOptions``. Gets local option first. If local is not 278 /// present, falls back to get global option. If global option is not 279 /// present either, return \p Default. If the value value was found 280 /// and equals ``none``, ``null``, ``-1`` or empty, return ``std::nullopt``. 281 /// 282 /// If the corresponding key can't be parsed as a ``T``, emit a 283 /// diagnostic and return \p Default. 284 template <typename T> 285 std::enable_if_t<std::is_integral_v<T>, std::optional<T>> getLocalOrGlobal(StringRef LocalName,std::optional<T> Default)286 getLocalOrGlobal(StringRef LocalName, std::optional<T> Default) const { 287 std::optional<StringRef> ValueOr = get(LocalName); 288 bool IsGlobal = false; 289 if (!ValueOr) { 290 IsGlobal = true; 291 ValueOr = getLocalOrGlobal(LocalName); 292 if (!ValueOr) 293 return Default; 294 } 295 T Result{}; 296 if (ValueOr == "" || ValueOr == "none" || ValueOr == "null" || 297 (std::is_unsigned_v<T> && ValueOr == "-1")) 298 return std::nullopt; 299 if (!StringRef(*ValueOr).getAsInteger(10, Result)) 300 return Result; 301 diagnoseBadIntegerOption( 302 IsGlobal ? Twine(LocalName) : NamePrefix + LocalName, *ValueOr); 303 return Default; 304 } 305 306 /// Read a named option from the ``Context`` and parse it as an 307 /// integral type ``T``. 308 /// 309 /// Reads the option with the check-local name \p LocalName from local or 310 /// global ``CheckOptions``. Gets local option first. If local is not 311 /// present, falls back to get global option. If global option is not 312 /// present either, return \p Default. 313 /// 314 /// If the corresponding key can't be parsed as a ``T``, emit a 315 /// diagnostic and return \p Default. 316 template <typename T> 317 std::enable_if_t<std::is_integral_v<T>, T> getLocalOrGlobal(StringRef LocalName,T Default)318 getLocalOrGlobal(StringRef LocalName, T Default) const { 319 return getLocalOrGlobal<T>(LocalName).value_or(Default); 320 } 321 322 /// Read a named option from the ``Context`` and parse it as an 323 /// enum type ``T``. 324 /// 325 /// Reads the option with the check-local name \p LocalName from the 326 /// ``CheckOptions``. If the corresponding key is not present, return 327 /// ``std::nullopt``. 328 /// 329 /// If the corresponding key can't be parsed as a ``T``, emit a 330 /// diagnostic and return ``std::nullopt``. 331 /// 332 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 333 /// supply the mapping required to convert between ``T`` and a string. 334 template <typename T> 335 std::enable_if_t<std::is_enum_v<T>, std::optional<T>> 336 get(StringRef LocalName, bool IgnoreCase = false) const { 337 if (std::optional<int64_t> ValueOr = 338 getEnumInt(LocalName, typeEraseMapping<T>(), false, IgnoreCase)) 339 return static_cast<T>(*ValueOr); 340 return std::nullopt; 341 } 342 343 /// Read a named option from the ``Context`` and parse it as an 344 /// enum type ``T``. 345 /// 346 /// Reads the option with the check-local name \p LocalName from the 347 /// ``CheckOptions``. If the corresponding key is not present, 348 /// return \p Default. 349 /// 350 /// If the corresponding key can't be parsed as a ``T``, emit a 351 /// diagnostic and return \p Default. 352 /// 353 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 354 /// supply the mapping required to convert between ``T`` and a string. 355 template <typename T> 356 std::enable_if_t<std::is_enum_v<T>, T> get(StringRef LocalName, T Default, 357 bool IgnoreCase = false) const { 358 return get<T>(LocalName, IgnoreCase).value_or(Default); 359 } 360 361 /// Read a named option from the ``Context`` and parse it as an 362 /// enum type ``T``. 363 /// 364 /// Reads the option with the check-local name \p LocalName from local or 365 /// global ``CheckOptions``. Gets local option first. If local is not 366 /// present, falls back to get global option. If global option is not 367 /// present either, returns ``std::nullopt``. 368 /// 369 /// If the corresponding key can't be parsed as a ``T``, emit a 370 /// diagnostic and return ``std::nullopt``. 371 /// 372 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 373 /// supply the mapping required to convert between ``T`` and a string. 374 template <typename T> 375 std::enable_if_t<std::is_enum_v<T>, std::optional<T>> 376 getLocalOrGlobal(StringRef LocalName, bool IgnoreCase = false) const { 377 if (std::optional<int64_t> ValueOr = 378 getEnumInt(LocalName, typeEraseMapping<T>(), true, IgnoreCase)) 379 return static_cast<T>(*ValueOr); 380 return std::nullopt; 381 } 382 383 /// Read a named option from the ``Context`` and parse it as an 384 /// enum type ``T``. 385 /// 386 /// Reads the option with the check-local name \p LocalName from local or 387 /// global ``CheckOptions``. Gets local option first. If local is not 388 /// present, falls back to get global option. If global option is not 389 /// present either return \p Default. 390 /// 391 /// If the corresponding key can't be parsed as a ``T``, emit a 392 /// diagnostic and return \p Default. 393 /// 394 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 395 /// supply the mapping required to convert between ``T`` and a string. 396 template <typename T> 397 std::enable_if_t<std::is_enum_v<T>, T> 398 getLocalOrGlobal(StringRef LocalName, T Default, 399 bool IgnoreCase = false) const { 400 return getLocalOrGlobal<T>(LocalName, IgnoreCase).value_or(Default); 401 } 402 403 /// Stores an option with the check-local name \p LocalName with 404 /// string value \p Value to \p Options. 405 void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 406 StringRef Value) const; 407 408 /// Stores an option with the check-local name \p LocalName with 409 /// integer value \p Value to \p Options. 410 template <typename T> 411 std::enable_if_t<std::is_integral_v<T>> store(ClangTidyOptions::OptionMap & Options,StringRef LocalName,T Value)412 store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 413 T Value) const { 414 storeInt(Options, LocalName, Value); 415 } 416 417 /// Stores an option with the check-local name \p LocalName with 418 /// integer value \p Value to \p Options. If the value is empty 419 /// stores `` 420 template <typename T> 421 std::enable_if_t<std::is_integral_v<T>> store(ClangTidyOptions::OptionMap & Options,StringRef LocalName,std::optional<T> Value)422 store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 423 std::optional<T> Value) const { 424 if (Value) 425 storeInt(Options, LocalName, *Value); 426 else 427 store(Options, LocalName, "none"); 428 } 429 430 /// Stores an option with the check-local name \p LocalName as the string 431 /// representation of the Enum \p Value to \p Options. 432 /// 433 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 434 /// supply the mapping required to convert between ``T`` and a string. 435 template <typename T> 436 std::enable_if_t<std::is_enum_v<T>> store(ClangTidyOptions::OptionMap & Options,StringRef LocalName,T Value)437 store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 438 T Value) const { 439 ArrayRef<std::pair<T, StringRef>> Mapping = 440 OptionEnumMapping<T>::getEnumMapping(); 441 auto Iter = llvm::find_if( 442 Mapping, [&](const std::pair<T, StringRef> &NameAndEnum) { 443 return NameAndEnum.first == Value; 444 }); 445 assert(Iter != Mapping.end() && "Unknown Case Value"); 446 store(Options, LocalName, Iter->second); 447 } 448 449 private: 450 using NameAndValue = std::pair<int64_t, StringRef>; 451 452 std::optional<int64_t> getEnumInt(StringRef LocalName, 453 ArrayRef<NameAndValue> Mapping, 454 bool CheckGlobal, bool IgnoreCase) const; 455 456 template <typename T> 457 std::enable_if_t<std::is_enum_v<T>, std::vector<NameAndValue>> typeEraseMapping()458 typeEraseMapping() const { 459 ArrayRef<std::pair<T, StringRef>> Mapping = 460 OptionEnumMapping<T>::getEnumMapping(); 461 std::vector<NameAndValue> Result; 462 Result.reserve(Mapping.size()); 463 for (auto &MappedItem : Mapping) { 464 Result.emplace_back(static_cast<int64_t>(MappedItem.first), 465 MappedItem.second); 466 } 467 return Result; 468 } 469 470 void storeInt(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 471 int64_t Value) const; 472 473 474 std::string NamePrefix; 475 const ClangTidyOptions::OptionMap &CheckOptions; 476 ClangTidyContext *Context; 477 }; 478 479 private: 480 void run(const ast_matchers::MatchFinder::MatchResult &Result) override; 481 std::string CheckName; 482 ClangTidyContext *Context; 483 484 protected: 485 OptionsView Options; 486 /// Returns the main file name of the current translation unit. getCurrentMainFile()487 StringRef getCurrentMainFile() const { return Context->getCurrentFile(); } 488 /// Returns the language options from the context. getLangOpts()489 const LangOptions &getLangOpts() const { return Context->getLangOpts(); } 490 /// Returns true when the check is run in a use case when only 1 fix will be 491 /// applied at a time. areDiagsSelfContained()492 bool areDiagsSelfContained() const { 493 return Context->areDiagsSelfContained(); 494 } getID()495 StringRef getID() const override { return CheckName; } 496 }; 497 498 /// Read a named option from the ``Context`` and parse it as a bool. 499 /// 500 /// Reads the option with the check-local name \p LocalName from the 501 /// ``CheckOptions``. If the corresponding key is not present, return 502 /// ``std::nullopt``. 503 /// 504 /// If the corresponding key can't be parsed as a bool, emit a 505 /// diagnostic and return ``std::nullopt``. 506 template <> 507 std::optional<bool> 508 ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const; 509 510 /// Read a named option from the ``Context`` and parse it as a bool. 511 /// 512 /// Reads the option with the check-local name \p LocalName from the 513 /// ``CheckOptions``. If the corresponding key is not present, return 514 /// \p Default. 515 /// 516 /// If the corresponding key can't be parsed as a bool, emit a 517 /// diagnostic and return \p Default. 518 template <> 519 std::optional<bool> 520 ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const; 521 522 /// Stores an option with the check-local name \p LocalName with 523 /// bool value \p Value to \p Options. 524 template <> 525 void ClangTidyCheck::OptionsView::store<bool>( 526 ClangTidyOptions::OptionMap &Options, StringRef LocalName, 527 bool Value) const; 528 529 530 } // namespace tidy 531 } // namespace clang 532 533 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H 534