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 "llvm/ADT/Optional.h" 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 /// ``None``. 158 llvm::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 ``None``. 173 llvm::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, return 188 /// ``None``. 189 /// 190 /// If the corresponding key can't be parsed as a ``T``, emit a 191 /// diagnostic and return ``None``. 192 template <typename T> 193 std::enable_if_t<std::is_integral<T>::value, llvm::Optional<T>> get(StringRef LocalName)194 get(StringRef LocalName) const { 195 if (llvm::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 None; 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 not present, return 209 /// \p Default. 210 /// 211 /// If the corresponding key can't be parsed as a ``T``, emit a 212 /// diagnostic and return \p Default. 213 template <typename T> get(StringRef LocalName,T Default)214 std::enable_if_t<std::is_integral<T>::value, T> get(StringRef LocalName, 215 T Default) const { 216 return get<T>(LocalName).value_or(Default); 217 } 218 219 /// Read a named option from the ``Context`` and parse it as an 220 /// integral type ``T``. 221 /// 222 /// Reads the option with the check-local name \p LocalName from local or 223 /// global ``CheckOptions``. Gets local option first. If local is not 224 /// present, falls back to get global option. If global option is not 225 /// present either, return ``None``. 226 /// 227 /// If the corresponding key can't be parsed as a ``T``, emit a 228 /// diagnostic and return ``None``. 229 template <typename T> 230 std::enable_if_t<std::is_integral<T>::value, llvm::Optional<T>> getLocalOrGlobal(StringRef LocalName)231 getLocalOrGlobal(StringRef LocalName) const { 232 llvm::Optional<StringRef> ValueOr = get(LocalName); 233 bool IsGlobal = false; 234 if (!ValueOr) { 235 IsGlobal = true; 236 ValueOr = getLocalOrGlobal(LocalName); 237 if (!ValueOr) 238 return None; 239 } 240 T Result{}; 241 if (!StringRef(*ValueOr).getAsInteger(10, Result)) 242 return Result; 243 diagnoseBadIntegerOption( 244 IsGlobal ? Twine(LocalName) : NamePrefix + LocalName, *ValueOr); 245 return None; 246 } 247 248 /// Read a named option from the ``Context`` and parse it as an 249 /// integral type ``T``. 250 /// 251 /// Reads the option with the check-local name \p LocalName from local or 252 /// global ``CheckOptions``. Gets local option first. If local is not 253 /// present, falls back to get global option. If global option is not 254 /// present either, return \p Default. 255 /// 256 /// If the corresponding key can't be parsed as a ``T``, emit a 257 /// diagnostic and return \p Default. 258 template <typename T> 259 std::enable_if_t<std::is_integral<T>::value, T> getLocalOrGlobal(StringRef LocalName,T Default)260 getLocalOrGlobal(StringRef LocalName, T Default) const { 261 return getLocalOrGlobal<T>(LocalName).value_or(Default); 262 } 263 264 /// Read a named option from the ``Context`` and parse it as an 265 /// enum type ``T``. 266 /// 267 /// Reads the option with the check-local name \p LocalName from the 268 /// ``CheckOptions``. If the corresponding key is not present, return 269 /// ``None``. 270 /// 271 /// If the corresponding key can't be parsed as a ``T``, emit a 272 /// diagnostic and return ``None``. 273 /// 274 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 275 /// supply the mapping required to convert between ``T`` and a string. 276 template <typename T> 277 std::enable_if_t<std::is_enum<T>::value, llvm::Optional<T>> 278 get(StringRef LocalName, bool IgnoreCase = false) const { 279 if (llvm::Optional<int64_t> ValueOr = 280 getEnumInt(LocalName, typeEraseMapping<T>(), false, IgnoreCase)) 281 return static_cast<T>(*ValueOr); 282 return None; 283 } 284 285 /// Read a named option from the ``Context`` and parse it as an 286 /// enum type ``T``. 287 /// 288 /// Reads the option with the check-local name \p LocalName from the 289 /// ``CheckOptions``. If the corresponding key is not present, return 290 /// \p Default. 291 /// 292 /// If the corresponding key can't be parsed as a ``T``, emit a 293 /// diagnostic and return \p Default. 294 /// 295 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 296 /// supply the mapping required to convert between ``T`` and a string. 297 template <typename T> 298 std::enable_if_t<std::is_enum<T>::value, T> 299 get(StringRef LocalName, T Default, bool IgnoreCase = false) const { 300 return get<T>(LocalName, IgnoreCase).value_or(Default); 301 } 302 303 /// Read a named option from the ``Context`` and parse it as an 304 /// enum type ``T``. 305 /// 306 /// Reads the option with the check-local name \p LocalName from local or 307 /// global ``CheckOptions``. Gets local option first. If local is not 308 /// present, falls back to get global option. If global option is not 309 /// present either, returns ``None``. 310 /// 311 /// If the corresponding key can't be parsed as a ``T``, emit a 312 /// diagnostic and return ``None``. 313 /// 314 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 315 /// supply the mapping required to convert between ``T`` and a string. 316 template <typename T> 317 std::enable_if_t<std::is_enum<T>::value, llvm::Optional<T>> 318 getLocalOrGlobal(StringRef LocalName, bool IgnoreCase = false) const { 319 if (llvm::Optional<int64_t> ValueOr = 320 getEnumInt(LocalName, typeEraseMapping<T>(), true, IgnoreCase)) 321 return static_cast<T>(*ValueOr); 322 return None; 323 } 324 325 /// Read a named option from the ``Context`` and parse it as an 326 /// enum type ``T``. 327 /// 328 /// Reads the option with the check-local name \p LocalName from local or 329 /// global ``CheckOptions``. Gets local option first. If local is not 330 /// present, falls back to get global option. If global option is not 331 /// present either return \p Default. 332 /// 333 /// If the corresponding key can't be parsed as a ``T``, emit a 334 /// diagnostic and return \p Default. 335 /// 336 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 337 /// supply the mapping required to convert between ``T`` and a string. 338 template <typename T> 339 std::enable_if_t<std::is_enum<T>::value, T> 340 getLocalOrGlobal(StringRef LocalName, T Default, 341 bool IgnoreCase = false) const { 342 return getLocalOrGlobal<T>(LocalName, IgnoreCase).value_or(Default); 343 } 344 345 /// Stores an option with the check-local name \p LocalName with 346 /// string value \p Value to \p Options. 347 void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 348 StringRef Value) const; 349 350 /// Stores an option with the check-local name \p LocalName with 351 /// integer value \p Value to \p Options. 352 template <typename T> 353 std::enable_if_t<std::is_integral<T>::value> store(ClangTidyOptions::OptionMap & Options,StringRef LocalName,T Value)354 store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 355 T Value) const { 356 storeInt(Options, LocalName, Value); 357 } 358 359 /// Stores an option with the check-local name \p LocalName as the string 360 /// representation of the Enum \p Value to \p Options. 361 /// 362 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 363 /// supply the mapping required to convert between ``T`` and a string. 364 template <typename T> 365 std::enable_if_t<std::is_enum<T>::value> store(ClangTidyOptions::OptionMap & Options,StringRef LocalName,T Value)366 store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 367 T Value) const { 368 ArrayRef<std::pair<T, StringRef>> Mapping = 369 OptionEnumMapping<T>::getEnumMapping(); 370 auto Iter = llvm::find_if( 371 Mapping, [&](const std::pair<T, StringRef> &NameAndEnum) { 372 return NameAndEnum.first == Value; 373 }); 374 assert(Iter != Mapping.end() && "Unknown Case Value"); 375 store(Options, LocalName, Iter->second); 376 } 377 378 private: 379 using NameAndValue = std::pair<int64_t, StringRef>; 380 381 llvm::Optional<int64_t> getEnumInt(StringRef LocalName, 382 ArrayRef<NameAndValue> Mapping, 383 bool CheckGlobal, bool IgnoreCase) const; 384 385 template <typename T> 386 std::enable_if_t<std::is_enum<T>::value, std::vector<NameAndValue>> typeEraseMapping()387 typeEraseMapping() const { 388 ArrayRef<std::pair<T, StringRef>> Mapping = 389 OptionEnumMapping<T>::getEnumMapping(); 390 std::vector<NameAndValue> Result; 391 Result.reserve(Mapping.size()); 392 for (auto &MappedItem : Mapping) { 393 Result.emplace_back(static_cast<int64_t>(MappedItem.first), 394 MappedItem.second); 395 } 396 return Result; 397 } 398 399 void storeInt(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 400 int64_t Value) const; 401 402 403 std::string NamePrefix; 404 const ClangTidyOptions::OptionMap &CheckOptions; 405 ClangTidyContext *Context; 406 }; 407 408 private: 409 void run(const ast_matchers::MatchFinder::MatchResult &Result) override; getID()410 StringRef getID() const override { return CheckName; } 411 std::string CheckName; 412 ClangTidyContext *Context; 413 414 protected: 415 OptionsView Options; 416 /// Returns the main file name of the current translation unit. getCurrentMainFile()417 StringRef getCurrentMainFile() const { return Context->getCurrentFile(); } 418 /// Returns the language options from the context. getLangOpts()419 const LangOptions &getLangOpts() const { return Context->getLangOpts(); } 420 /// Returns true when the check is run in a use case when only 1 fix will be 421 /// applied at a time. areDiagsSelfContained()422 bool areDiagsSelfContained() const { 423 return Context->areDiagsSelfContained(); 424 } 425 }; 426 427 /// Read a named option from the ``Context`` and parse it as a bool. 428 /// 429 /// Reads the option with the check-local name \p LocalName from the 430 /// ``CheckOptions``. If the corresponding key is not present, return 431 /// ``None``. 432 /// 433 /// If the corresponding key can't be parsed as a bool, emit a 434 /// diagnostic and return ``None``. 435 template <> 436 llvm::Optional<bool> 437 ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const; 438 439 /// Read a named option from the ``Context`` and parse it as a bool. 440 /// 441 /// Reads the option with the check-local name \p LocalName from the 442 /// ``CheckOptions``. If the corresponding key is not present, return 443 /// \p Default. 444 /// 445 /// If the corresponding key can't be parsed as a bool, emit a 446 /// diagnostic and return \p Default. 447 template <> 448 llvm::Optional<bool> 449 ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const; 450 451 /// Stores an option with the check-local name \p LocalName with 452 /// bool value \p Value to \p Options. 453 template <> 454 void ClangTidyCheck::OptionsView::store<bool>( 455 ClangTidyOptions::OptionMap &Options, StringRef LocalName, 456 bool Value) const; 457 458 459 } // namespace tidy 460 } // namespace clang 461 462 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H 463