|
|
|||
File indexing completed on 2026-05-10 08:36:22
0001 //===--- ClangTidyCheck.h - clang-tidy --------------------------*- C++ -*-===// 0002 // 0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 0004 // See https://llvm.org/LICENSE.txt for license information. 0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0006 // 0007 //===----------------------------------------------------------------------===// 0008 0009 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H 0010 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H 0011 0012 #include "ClangTidyDiagnosticConsumer.h" 0013 #include "ClangTidyOptions.h" 0014 #include "clang/ASTMatchers/ASTMatchFinder.h" 0015 #include "clang/Basic/Diagnostic.h" 0016 #include <optional> 0017 #include <type_traits> 0018 #include <utility> 0019 #include <vector> 0020 0021 namespace clang { 0022 0023 class SourceManager; 0024 0025 namespace tidy { 0026 0027 /// This class should be specialized by any enum type that needs to be converted 0028 /// to and from an \ref llvm::StringRef. 0029 template <class T> struct OptionEnumMapping { 0030 // Specializations of this struct must implement this function. 0031 static ArrayRef<std::pair<T, StringRef>> getEnumMapping() = delete; 0032 }; 0033 0034 /// Base class for all clang-tidy checks. 0035 /// 0036 /// To implement a ``ClangTidyCheck``, write a subclass and override some of the 0037 /// base class's methods. E.g. to implement a check that validates namespace 0038 /// declarations, override ``registerMatchers``: 0039 /// 0040 /// ~~~{.cpp} 0041 /// void registerMatchers(ast_matchers::MatchFinder *Finder) override { 0042 /// Finder->addMatcher(namespaceDecl().bind("namespace"), this); 0043 /// } 0044 /// ~~~ 0045 /// 0046 /// and then override ``check(const MatchResult &Result)`` to do the actual 0047 /// check for each match. 0048 /// 0049 /// A new ``ClangTidyCheck`` instance is created per translation unit. 0050 /// 0051 /// FIXME: Figure out whether carrying information from one TU to another is 0052 /// useful/necessary. 0053 class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { 0054 public: 0055 /// Initializes the check with \p CheckName and \p Context. 0056 /// 0057 /// Derived classes must implement the constructor with this signature or 0058 /// delegate it. If a check needs to read options, it can do this in the 0059 /// constructor using the Options.get() methods below. 0060 ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context); 0061 0062 /// Override this to disable registering matchers and PP callbacks if an 0063 /// invalid language version is being used. 0064 /// 0065 /// For example if a check is examining overloaded functions then this should 0066 /// be overridden to return false when the CPlusPlus flag is not set in 0067 /// \p LangOpts. 0068 virtual bool isLanguageVersionSupported(const LangOptions &LangOpts) const { 0069 return true; 0070 } 0071 0072 /// Override this to register ``PPCallbacks`` in the preprocessor. 0073 /// 0074 /// This should be used for clang-tidy checks that analyze preprocessor- 0075 /// dependent properties, e.g. include directives and macro definitions. 0076 /// 0077 /// This will only be executed if the function isLanguageVersionSupported 0078 /// returns true. 0079 /// 0080 /// There are two Preprocessors to choose from that differ in how they handle 0081 /// modular #includes: 0082 /// - PP is the real Preprocessor. It doesn't walk into modular #includes and 0083 /// thus doesn't generate PPCallbacks for their contents. 0084 /// - ModuleExpanderPP preprocesses the whole translation unit in the 0085 /// non-modular mode, which allows it to generate PPCallbacks not only for 0086 /// the main file and textual headers, but also for all transitively 0087 /// included modular headers when the analysis runs with modules enabled. 0088 /// When modules are not enabled ModuleExpanderPP just points to the real 0089 /// preprocessor. 0090 virtual void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, 0091 Preprocessor *ModuleExpanderPP) {} 0092 0093 /// Override this to register AST matchers with \p Finder. 0094 /// 0095 /// This should be used by clang-tidy checks that analyze code properties that 0096 /// dependent on AST knowledge. 0097 /// 0098 /// You can register as many matchers as necessary with \p Finder. Usually, 0099 /// "this" will be used as callback, but you can also specify other callback 0100 /// classes. Thereby, different matchers can trigger different callbacks. 0101 /// 0102 /// This will only be executed if the function isLanguageVersionSupported 0103 /// returns true. 0104 /// 0105 /// If you need to merge information between the different matchers, you can 0106 /// store these as members of the derived class. However, note that all 0107 /// matches occur in the order of the AST traversal. 0108 virtual void registerMatchers(ast_matchers::MatchFinder *Finder) {} 0109 0110 /// ``ClangTidyChecks`` that register ASTMatchers should do the actual 0111 /// work in here. 0112 virtual void check(const ast_matchers::MatchFinder::MatchResult &Result) {} 0113 0114 /// Add a diagnostic with the check's name. 0115 DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, 0116 DiagnosticIDs::Level Level = DiagnosticIDs::Warning); 0117 0118 /// Add a diagnostic with the check's name. 0119 DiagnosticBuilder diag(StringRef Description, 0120 DiagnosticIDs::Level Level = DiagnosticIDs::Warning); 0121 0122 /// Adds a diagnostic to report errors in the check's configuration. 0123 DiagnosticBuilder 0124 configurationDiag(StringRef Description, 0125 DiagnosticIDs::Level Level = DiagnosticIDs::Warning) const; 0126 0127 /// Should store all options supported by this check with their 0128 /// current values or default values for options that haven't been overridden. 0129 /// 0130 /// The check should use ``Options.store()`` to store each option it supports 0131 /// whether it has the default value or it has been overridden. 0132 virtual void storeOptions(ClangTidyOptions::OptionMap &Options) {} 0133 0134 /// Provides access to the ``ClangTidyCheck`` options via check-local 0135 /// names. 0136 /// 0137 /// Methods of this class prepend ``CheckName + "."`` to translate check-local 0138 /// option names to global option names. 0139 class OptionsView { 0140 void diagnoseBadIntegerOption(const Twine &Lookup, 0141 StringRef Unparsed) const; 0142 void diagnoseBadBooleanOption(const Twine &Lookup, 0143 StringRef Unparsed) const; 0144 void diagnoseBadEnumOption(const Twine &Lookup, StringRef Unparsed, 0145 StringRef Suggestion = StringRef()) const; 0146 0147 public: 0148 /// Initializes the instance using \p CheckName + "." as a prefix. 0149 OptionsView(StringRef CheckName, 0150 const ClangTidyOptions::OptionMap &CheckOptions, 0151 ClangTidyContext *Context); 0152 0153 /// Read a named option from the ``Context``. 0154 /// 0155 /// Reads the option with the check-local name \p LocalName from the 0156 /// ``CheckOptions``. If the corresponding key is not present, return 0157 /// ``std::nullopt``. 0158 std::optional<StringRef> get(StringRef LocalName) const; 0159 0160 /// Read a named option from the ``Context``. 0161 /// 0162 /// Reads the option with the check-local name \p LocalName from the 0163 /// ``CheckOptions``. If the corresponding key is not present, returns 0164 /// \p Default. 0165 StringRef get(StringRef LocalName, StringRef Default) const; 0166 0167 /// Read a named option from the ``Context``. 0168 /// 0169 /// Reads the option with the check-local name \p LocalName from local or 0170 /// global ``CheckOptions``. Gets local option first. If local is not 0171 /// present, falls back to get global option. If global option is not 0172 /// present either, return ``std::nullopt``. 0173 std::optional<StringRef> getLocalOrGlobal(StringRef LocalName) const; 0174 0175 /// Read a named option from the ``Context``. 0176 /// 0177 /// Reads the option with the check-local name \p LocalName from local or 0178 /// global ``CheckOptions``. Gets local option first. If local is not 0179 /// present, falls back to get global option. If global option is not 0180 /// present either, returns \p Default. 0181 StringRef getLocalOrGlobal(StringRef LocalName, StringRef Default) const; 0182 0183 /// Read a named option from the ``Context`` and parse it as an 0184 /// integral type ``T``. 0185 /// 0186 /// Reads the option with the check-local name \p LocalName from the 0187 /// ``CheckOptions``. If the corresponding key is not present, 0188 /// return ``std::nullopt``. 0189 /// 0190 /// If the corresponding key can't be parsed as a ``T``, emit a 0191 /// diagnostic and return ``std::nullopt``. 0192 template <typename T> 0193 std::enable_if_t<std::is_integral_v<T>, std::optional<T>> 0194 get(StringRef LocalName) const { 0195 if (std::optional<StringRef> Value = get(LocalName)) { 0196 T Result{}; 0197 if (!StringRef(*Value).getAsInteger(10, Result)) 0198 return Result; 0199 diagnoseBadIntegerOption(NamePrefix + LocalName, *Value); 0200 } 0201 return std::nullopt; 0202 } 0203 0204 /// Read a named option from the ``Context`` and parse it as an 0205 /// integral type ``T``. 0206 /// 0207 /// Reads the option with the check-local name \p LocalName from the 0208 /// ``CheckOptions``. If the corresponding key is `none`, `null`, 0209 /// `-1` or empty, return ``std::nullopt``. If the corresponding 0210 /// key is not present, return \p Default. 0211 /// 0212 /// If the corresponding key can't be parsed as a ``T``, emit a 0213 /// diagnostic and return \p Default. 0214 template <typename T> 0215 std::enable_if_t<std::is_integral_v<T>, std::optional<T>> 0216 get(StringRef LocalName, std::optional<T> Default) const { 0217 if (std::optional<StringRef> Value = get(LocalName)) { 0218 if (Value == "" || Value == "none" || Value == "null" || 0219 (std::is_unsigned_v<T> && Value == "-1")) 0220 return std::nullopt; 0221 T Result{}; 0222 if (!StringRef(*Value).getAsInteger(10, Result)) 0223 return Result; 0224 diagnoseBadIntegerOption(NamePrefix + LocalName, *Value); 0225 } 0226 return Default; 0227 } 0228 0229 /// Read a named option from the ``Context`` and parse it as an 0230 /// integral type ``T``. 0231 /// 0232 /// Reads the option with the check-local name \p LocalName from the 0233 /// ``CheckOptions``. If the corresponding key is not present, return 0234 /// \p Default. 0235 /// 0236 /// If the corresponding key can't be parsed as a ``T``, emit a 0237 /// diagnostic and return \p Default. 0238 template <typename T> 0239 std::enable_if_t<std::is_integral_v<T>, T> get(StringRef LocalName, 0240 T Default) const { 0241 return get<T>(LocalName).value_or(Default); 0242 } 0243 0244 /// Read a named option from the ``Context`` and parse it as an 0245 /// integral type ``T``. 0246 /// 0247 /// Reads the option with the check-local name \p LocalName from local or 0248 /// global ``CheckOptions``. Gets local option first. If local is not 0249 /// present, falls back to get global option. If global option is not 0250 /// present either, return ``std::nullopt``. 0251 /// 0252 /// If the corresponding key can't be parsed as a ``T``, emit a 0253 /// diagnostic and return ``std::nullopt``. 0254 template <typename T> 0255 std::enable_if_t<std::is_integral_v<T>, std::optional<T>> 0256 getLocalOrGlobal(StringRef LocalName) const { 0257 std::optional<StringRef> ValueOr = get(LocalName); 0258 bool IsGlobal = false; 0259 if (!ValueOr) { 0260 IsGlobal = true; 0261 ValueOr = getLocalOrGlobal(LocalName); 0262 if (!ValueOr) 0263 return std::nullopt; 0264 } 0265 T Result{}; 0266 if (!StringRef(*ValueOr).getAsInteger(10, Result)) 0267 return Result; 0268 diagnoseBadIntegerOption( 0269 IsGlobal ? Twine(LocalName) : NamePrefix + LocalName, *ValueOr); 0270 return std::nullopt; 0271 } 0272 0273 /// Read a named option from the ``Context`` and parse it as an 0274 /// integral type ``T``. 0275 /// 0276 /// Reads the option with the check-local name \p LocalName from local or 0277 /// global ``CheckOptions``. Gets local option first. If local is not 0278 /// present, falls back to get global option. If global option is not 0279 /// present either, return \p Default. If the value value was found 0280 /// and equals ``none``, ``null``, ``-1`` or empty, return ``std::nullopt``. 0281 /// 0282 /// If the corresponding key can't be parsed as a ``T``, emit a 0283 /// diagnostic and return \p Default. 0284 template <typename T> 0285 std::enable_if_t<std::is_integral_v<T>, std::optional<T>> 0286 getLocalOrGlobal(StringRef LocalName, std::optional<T> Default) const { 0287 std::optional<StringRef> ValueOr = get(LocalName); 0288 bool IsGlobal = false; 0289 if (!ValueOr) { 0290 IsGlobal = true; 0291 ValueOr = getLocalOrGlobal(LocalName); 0292 if (!ValueOr) 0293 return Default; 0294 } 0295 T Result{}; 0296 if (ValueOr == "" || ValueOr == "none" || ValueOr == "null" || 0297 (std::is_unsigned_v<T> && ValueOr == "-1")) 0298 return std::nullopt; 0299 if (!StringRef(*ValueOr).getAsInteger(10, Result)) 0300 return Result; 0301 diagnoseBadIntegerOption( 0302 IsGlobal ? Twine(LocalName) : NamePrefix + LocalName, *ValueOr); 0303 return Default; 0304 } 0305 0306 /// Read a named option from the ``Context`` and parse it as an 0307 /// integral type ``T``. 0308 /// 0309 /// Reads the option with the check-local name \p LocalName from local or 0310 /// global ``CheckOptions``. Gets local option first. If local is not 0311 /// present, falls back to get global option. If global option is not 0312 /// present either, return \p Default. 0313 /// 0314 /// If the corresponding key can't be parsed as a ``T``, emit a 0315 /// diagnostic and return \p Default. 0316 template <typename T> 0317 std::enable_if_t<std::is_integral_v<T>, T> 0318 getLocalOrGlobal(StringRef LocalName, T Default) const { 0319 return getLocalOrGlobal<T>(LocalName).value_or(Default); 0320 } 0321 0322 /// Read a named option from the ``Context`` and parse it as an 0323 /// enum type ``T``. 0324 /// 0325 /// Reads the option with the check-local name \p LocalName from the 0326 /// ``CheckOptions``. If the corresponding key is not present, return 0327 /// ``std::nullopt``. 0328 /// 0329 /// If the corresponding key can't be parsed as a ``T``, emit a 0330 /// diagnostic and return ``std::nullopt``. 0331 /// 0332 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 0333 /// supply the mapping required to convert between ``T`` and a string. 0334 template <typename T> 0335 std::enable_if_t<std::is_enum_v<T>, std::optional<T>> 0336 get(StringRef LocalName) const { 0337 if (std::optional<int64_t> ValueOr = 0338 getEnumInt(LocalName, typeEraseMapping<T>(), false)) 0339 return static_cast<T>(*ValueOr); 0340 return std::nullopt; 0341 } 0342 0343 /// Read a named option from the ``Context`` and parse it as an 0344 /// enum type ``T``. 0345 /// 0346 /// Reads the option with the check-local name \p LocalName from the 0347 /// ``CheckOptions``. If the corresponding key is not present, 0348 /// return \p Default. 0349 /// 0350 /// If the corresponding key can't be parsed as a ``T``, emit a 0351 /// diagnostic and return \p Default. 0352 /// 0353 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 0354 /// supply the mapping required to convert between ``T`` and a string. 0355 template <typename T> 0356 std::enable_if_t<std::is_enum_v<T>, T> get(StringRef LocalName, 0357 T Default) const { 0358 return get<T>(LocalName).value_or(Default); 0359 } 0360 0361 /// Read a named option from the ``Context`` and parse it as an 0362 /// enum type ``T``. 0363 /// 0364 /// Reads the option with the check-local name \p LocalName from local or 0365 /// global ``CheckOptions``. Gets local option first. If local is not 0366 /// present, falls back to get global option. If global option is not 0367 /// present either, returns ``std::nullopt``. 0368 /// 0369 /// If the corresponding key can't be parsed as a ``T``, emit a 0370 /// diagnostic and return ``std::nullopt``. 0371 /// 0372 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 0373 /// supply the mapping required to convert between ``T`` and a string. 0374 template <typename T> 0375 std::enable_if_t<std::is_enum_v<T>, std::optional<T>> 0376 getLocalOrGlobal(StringRef LocalName) const { 0377 if (std::optional<int64_t> ValueOr = 0378 getEnumInt(LocalName, typeEraseMapping<T>(), true)) 0379 return static_cast<T>(*ValueOr); 0380 return std::nullopt; 0381 } 0382 0383 /// Read a named option from the ``Context`` and parse it as an 0384 /// enum type ``T``. 0385 /// 0386 /// Reads the option with the check-local name \p LocalName from local or 0387 /// global ``CheckOptions``. Gets local option first. If local is not 0388 /// present, falls back to get global option. If global option is not 0389 /// present either return \p Default. 0390 /// 0391 /// If the corresponding key can't be parsed as a ``T``, emit a 0392 /// diagnostic and return \p Default. 0393 /// 0394 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 0395 /// supply the mapping required to convert between ``T`` and a string. 0396 template <typename T> 0397 std::enable_if_t<std::is_enum_v<T>, T> getLocalOrGlobal(StringRef LocalName, 0398 T Default) const { 0399 return getLocalOrGlobal<T>(LocalName).value_or(Default); 0400 } 0401 0402 /// Stores an option with the check-local name \p LocalName with 0403 /// string value \p Value to \p Options. 0404 void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 0405 StringRef Value) const; 0406 0407 /// Stores an option with the check-local name \p LocalName with 0408 /// integer value \p Value to \p Options. 0409 template <typename T> 0410 std::enable_if_t<std::is_integral_v<T>> 0411 store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 0412 T Value) const { 0413 if constexpr (std::is_signed_v<T>) 0414 storeInt(Options, LocalName, Value); 0415 else 0416 storeUnsigned(Options, LocalName, Value); 0417 } 0418 0419 /// Stores an option with the check-local name \p LocalName with 0420 /// integer value \p Value to \p Options. If the value is empty 0421 /// stores `` 0422 template <typename T> 0423 std::enable_if_t<std::is_integral_v<T>> 0424 store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 0425 std::optional<T> Value) const { 0426 if (Value) 0427 store(Options, LocalName, *Value); 0428 else 0429 store(Options, LocalName, "none"); 0430 } 0431 0432 /// Stores an option with the check-local name \p LocalName as the string 0433 /// representation of the Enum \p Value to \p Options. 0434 /// 0435 /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to 0436 /// supply the mapping required to convert between ``T`` and a string. 0437 template <typename T> 0438 std::enable_if_t<std::is_enum_v<T>> 0439 store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 0440 T Value) const { 0441 ArrayRef<std::pair<T, StringRef>> Mapping = 0442 OptionEnumMapping<T>::getEnumMapping(); 0443 auto Iter = llvm::find_if( 0444 Mapping, [&](const std::pair<T, StringRef> &NameAndEnum) { 0445 return NameAndEnum.first == Value; 0446 }); 0447 assert(Iter != Mapping.end() && "Unknown Case Value"); 0448 store(Options, LocalName, Iter->second); 0449 } 0450 0451 private: 0452 using NameAndValue = std::pair<int64_t, StringRef>; 0453 0454 std::optional<int64_t> getEnumInt(StringRef LocalName, 0455 ArrayRef<NameAndValue> Mapping, 0456 bool CheckGlobal) const; 0457 0458 template <typename T> 0459 std::enable_if_t<std::is_enum_v<T>, std::vector<NameAndValue>> 0460 typeEraseMapping() const { 0461 ArrayRef<std::pair<T, StringRef>> Mapping = 0462 OptionEnumMapping<T>::getEnumMapping(); 0463 std::vector<NameAndValue> Result; 0464 Result.reserve(Mapping.size()); 0465 for (auto &MappedItem : Mapping) { 0466 Result.emplace_back(static_cast<int64_t>(MappedItem.first), 0467 MappedItem.second); 0468 } 0469 return Result; 0470 } 0471 0472 void storeInt(ClangTidyOptions::OptionMap &Options, StringRef LocalName, 0473 int64_t Value) const; 0474 0475 void storeUnsigned(ClangTidyOptions::OptionMap &Options, 0476 StringRef LocalName, uint64_t Value) const; 0477 0478 std::string NamePrefix; 0479 const ClangTidyOptions::OptionMap &CheckOptions; 0480 ClangTidyContext *Context; 0481 }; 0482 0483 private: 0484 void run(const ast_matchers::MatchFinder::MatchResult &Result) override; 0485 std::string CheckName; 0486 ClangTidyContext *Context; 0487 0488 protected: 0489 OptionsView Options; 0490 /// Returns the main file name of the current translation unit. 0491 StringRef getCurrentMainFile() const { return Context->getCurrentFile(); } 0492 /// Returns the language options from the context. 0493 const LangOptions &getLangOpts() const { return Context->getLangOpts(); } 0494 /// Returns true when the check is run in a use case when only 1 fix will be 0495 /// applied at a time. 0496 bool areDiagsSelfContained() const { 0497 return Context->areDiagsSelfContained(); 0498 } 0499 StringRef getID() const override { return CheckName; } 0500 }; 0501 0502 /// Read a named option from the ``Context`` and parse it as a bool. 0503 /// 0504 /// Reads the option with the check-local name \p LocalName from the 0505 /// ``CheckOptions``. If the corresponding key is not present, return 0506 /// ``std::nullopt``. 0507 /// 0508 /// If the corresponding key can't be parsed as a bool, emit a 0509 /// diagnostic and return ``std::nullopt``. 0510 template <> 0511 std::optional<bool> 0512 ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const; 0513 0514 /// Read a named option from the ``Context`` and parse it as a bool. 0515 /// 0516 /// Reads the option with the check-local name \p LocalName from the 0517 /// ``CheckOptions``. If the corresponding key is not present, return 0518 /// \p Default. 0519 /// 0520 /// If the corresponding key can't be parsed as a bool, emit a 0521 /// diagnostic and return \p Default. 0522 template <> 0523 std::optional<bool> 0524 ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const; 0525 0526 /// Stores an option with the check-local name \p LocalName with 0527 /// bool value \p Value to \p Options. 0528 template <> 0529 void ClangTidyCheck::OptionsView::store<bool>( 0530 ClangTidyOptions::OptionMap &Options, StringRef LocalName, 0531 bool Value) const; 0532 0533 0534 } // namespace tidy 0535 } // namespace clang 0536 0537 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|