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 if constexpr (std::is_signed_v<T>) 415 storeInt(Options, LocalName, Value); 416 else 417 storeUnsigned(Options, LocalName, Value); 418 } 419 420 /// Stores an option with the check-local name \p LocalName with 421 /// integer value \p Value to \p Options. If the value is empty 422 /// stores `` 423 template <typename T> 424 std::enable_if_t<std::is_integral_v<T>> store(ClangTidyOptions::OptionMap & Options,StringRef LocalName,std::optional<T> Value)425 store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 426 std::optional<T> Value) const { 427 if (Value) 428 store(Options, LocalName, *Value); 429 else 430 store(Options, LocalName, "none"); 431 } 432 433 /// Stores an option with the check-local name \p LocalName as the string 434 /// representation of the Enum \p Value to \p Options. 435 /// 436 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 437 /// supply the mapping required to convert between ``T`` and a string. 438 template <typename T> 439 std::enable_if_t<std::is_enum_v<T>> store(ClangTidyOptions::OptionMap & Options,StringRef LocalName,T Value)440 store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 441 T Value) const { 442 ArrayRef<std::pair<T, StringRef>> Mapping = 443 OptionEnumMapping<T>::getEnumMapping(); 444 auto Iter = llvm::find_if( 445 Mapping, [&](const std::pair<T, StringRef> &NameAndEnum) { 446 return NameAndEnum.first == Value; 447 }); 448 assert(Iter != Mapping.end() && "Unknown Case Value"); 449 store(Options, LocalName, Iter->second); 450 } 451 452 private: 453 using NameAndValue = std::pair<int64_t, StringRef>; 454 455 std::optional<int64_t> getEnumInt(StringRef LocalName, 456 ArrayRef<NameAndValue> Mapping, 457 bool CheckGlobal, bool IgnoreCase) const; 458 459 template <typename T> 460 std::enable_if_t<std::is_enum_v<T>, std::vector<NameAndValue>> typeEraseMapping()461 typeEraseMapping() const { 462 ArrayRef<std::pair<T, StringRef>> Mapping = 463 OptionEnumMapping<T>::getEnumMapping(); 464 std::vector<NameAndValue> Result; 465 Result.reserve(Mapping.size()); 466 for (auto &MappedItem : Mapping) { 467 Result.emplace_back(static_cast<int64_t>(MappedItem.first), 468 MappedItem.second); 469 } 470 return Result; 471 } 472 473 void storeInt(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 474 int64_t Value) const; 475 476 void storeUnsigned(ClangTidyOptions::OptionMap &Options, 477 StringRef LocalName, uint64_t Value) const; 478 479 std::string NamePrefix; 480 const ClangTidyOptions::OptionMap &CheckOptions; 481 ClangTidyContext *Context; 482 }; 483 484 private: 485 void run(const ast_matchers::MatchFinder::MatchResult &Result) override; 486 std::string CheckName; 487 ClangTidyContext *Context; 488 489 protected: 490 OptionsView Options; 491 /// Returns the main file name of the current translation unit. getCurrentMainFile()492 StringRef getCurrentMainFile() const { return Context->getCurrentFile(); } 493 /// Returns the language options from the context. getLangOpts()494 const LangOptions &getLangOpts() const { return Context->getLangOpts(); } 495 /// Returns true when the check is run in a use case when only 1 fix will be 496 /// applied at a time. areDiagsSelfContained()497 bool areDiagsSelfContained() const { 498 return Context->areDiagsSelfContained(); 499 } getID()500 StringRef getID() const override { return CheckName; } 501 }; 502 503 /// Read a named option from the ``Context`` and parse it as a bool. 504 /// 505 /// Reads the option with the check-local name \p LocalName from the 506 /// ``CheckOptions``. If the corresponding key is not present, return 507 /// ``std::nullopt``. 508 /// 509 /// If the corresponding key can't be parsed as a bool, emit a 510 /// diagnostic and return ``std::nullopt``. 511 template <> 512 std::optional<bool> 513 ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const; 514 515 /// Read a named option from the ``Context`` and parse it as a bool. 516 /// 517 /// Reads the option with the check-local name \p LocalName from the 518 /// ``CheckOptions``. If the corresponding key is not present, return 519 /// \p Default. 520 /// 521 /// If the corresponding key can't be parsed as a bool, emit a 522 /// diagnostic and return \p Default. 523 template <> 524 std::optional<bool> 525 ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const; 526 527 /// Stores an option with the check-local name \p LocalName with 528 /// bool value \p Value to \p Options. 529 template <> 530 void ClangTidyCheck::OptionsView::store<bool>( 531 ClangTidyOptions::OptionMap &Options, StringRef LocalName, 532 bool Value) const; 533 534 535 } // namespace tidy 536 } // namespace clang 537 538 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H 539