1 //===--- ClangTidyCheck.h - clang-tidy --------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H
10 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H
12 #include "ClangTidyDiagnosticConsumer.h"
13 #include "ClangTidyOptions.h"
14 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 #include "clang/Basic/Diagnostic.h"
17 #include <type_traits>
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;
34 /// Base class for all clang-tidy checks.
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``:
41 /// void registerMatchers(ast_matchers::MatchFinder *Finder) override {
42 /// Finder->addMatcher(namespaceDecl().bind("namespace"), this);
46 /// and then override ``check(const MatchResult &Result)`` to do the actual
47 /// check for each match.
49 /// A new ``ClangTidyCheck`` instance is created per translation unit.
51 /// FIXME: Figure out whether carrying information from one TU to another is
53 class ClangTidyCheck
: public ast_matchers::MatchFinder::MatchCallback
{
55 /// Initializes the check with \p CheckName and \p Context.
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
);
62 /// Override this to disable registering matchers and PP callbacks if an
63 /// invalid language version is being used.
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
68 virtual bool isLanguageVersionSupported(const LangOptions
&LangOpts
) const {
72 /// Override this to register ``PPCallbacks`` in the preprocessor.
74 /// This should be used for clang-tidy checks that analyze preprocessor-
75 /// dependent properties, e.g. include directives and macro definitions.
77 /// This will only be executed if the function isLanguageVersionSupported
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
90 virtual void registerPPCallbacks(const SourceManager
&SM
, Preprocessor
*PP
,
91 Preprocessor
*ModuleExpanderPP
) {}
93 /// Override this to register AST matchers with \p Finder.
95 /// This should be used by clang-tidy checks that analyze code properties that
96 /// dependent on AST knowledge.
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.
102 /// This will only be executed if the function isLanguageVersionSupported
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.
108 virtual void registerMatchers(ast_matchers::MatchFinder
*Finder
) {}
110 /// ``ClangTidyChecks`` that register ASTMatchers should do the actual
112 virtual void check(const ast_matchers::MatchFinder::MatchResult
&Result
) {}
114 /// Add a diagnostic with the check's name.
115 DiagnosticBuilder
diag(SourceLocation Loc
, StringRef Description
,
116 DiagnosticIDs::Level Level
= DiagnosticIDs::Warning
);
118 /// Add a diagnostic with the check's name.
119 DiagnosticBuilder
diag(StringRef Description
,
120 DiagnosticIDs::Level Level
= DiagnosticIDs::Warning
);
122 /// Adds a diagnostic to report errors in the check's configuration.
124 configurationDiag(StringRef Description
,
125 DiagnosticIDs::Level Level
= DiagnosticIDs::Warning
) const;
127 /// Should store all options supported by this check with their
128 /// current values or default values for options that haven't been overridden.
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.
132 virtual void storeOptions(ClangTidyOptions::OptionMap
&Options
) {}
134 /// Provides access to the ``ClangTidyCheck`` options via check-local
137 /// Methods of this class prepend ``CheckName + "."`` to translate check-local
138 /// option names to global option names.
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;
148 /// Initializes the instance using \p CheckName + "." as a prefix.
149 OptionsView(StringRef CheckName
,
150 const ClangTidyOptions::OptionMap
&CheckOptions
,
151 ClangTidyContext
*Context
);
153 /// Read a named option from the ``Context``.
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;
160 /// Read a named option from the ``Context``.
162 /// Reads the option with the check-local name \p LocalName from the
163 /// ``CheckOptions``. If the corresponding key is not present, returns
165 StringRef
get(StringRef LocalName
, StringRef Default
) const;
167 /// Read a named option from the ``Context``.
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;
175 /// Read a named option from the ``Context``.
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;
183 /// Read a named option from the ``Context`` and parse it as an
184 /// integral type ``T``.
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``.
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
>>
194 get(StringRef LocalName
) const {
195 if (std::optional
<StringRef
> Value
= get(LocalName
)) {
197 if (!StringRef(*Value
).getAsInteger(10, Result
))
199 diagnoseBadIntegerOption(NamePrefix
+ LocalName
, *Value
);
204 /// Read a named option from the ``Context`` and parse it as an
205 /// integral type ``T``.
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.
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
>>
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"))
222 if (!StringRef(*Value
).getAsInteger(10, Result
))
224 diagnoseBadIntegerOption(NamePrefix
+ LocalName
, *Value
);
229 /// Read a named option from the ``Context`` and parse it as an
230 /// integral type ``T``.
232 /// Reads the option with the check-local name \p LocalName from the
233 /// ``CheckOptions``. If the corresponding key is not present, return
236 /// If the corresponding key can't be parsed as a ``T``, emit a
237 /// diagnostic and return \p Default.
238 template <typename T
>
239 std::enable_if_t
<std::is_integral_v
<T
>, T
> get(StringRef LocalName
,
241 return get
<T
>(LocalName
).value_or(Default
);
244 /// Read a named option from the ``Context`` and parse it as an
245 /// integral type ``T``.
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``.
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
>>
256 getLocalOrGlobal(StringRef LocalName
) const {
257 std::optional
<StringRef
> ValueOr
= get(LocalName
);
258 bool IsGlobal
= false;
261 ValueOr
= getLocalOrGlobal(LocalName
);
266 if (!StringRef(*ValueOr
).getAsInteger(10, Result
))
268 diagnoseBadIntegerOption(
269 IsGlobal
? Twine(LocalName
) : NamePrefix
+ LocalName
, *ValueOr
);
273 /// Read a named option from the ``Context`` and parse it as an
274 /// integral type ``T``.
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``.
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
>>
286 getLocalOrGlobal(StringRef LocalName
, std::optional
<T
> Default
) const {
287 std::optional
<StringRef
> ValueOr
= get(LocalName
);
288 bool IsGlobal
= false;
291 ValueOr
= getLocalOrGlobal(LocalName
);
296 if (ValueOr
== "" || ValueOr
== "none" || ValueOr
== "null" ||
297 (std::is_unsigned_v
<T
> && ValueOr
== "-1"))
299 if (!StringRef(*ValueOr
).getAsInteger(10, Result
))
301 diagnoseBadIntegerOption(
302 IsGlobal
? Twine(LocalName
) : NamePrefix
+ LocalName
, *ValueOr
);
306 /// Read a named option from the ``Context`` and parse it as an
307 /// integral type ``T``.
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.
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
>
318 getLocalOrGlobal(StringRef LocalName
, T Default
) const {
319 return getLocalOrGlobal
<T
>(LocalName
).value_or(Default
);
322 /// Read a named option from the ``Context`` and parse it as an
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``.
329 /// If the corresponding key can't be parsed as a ``T``, emit a
330 /// diagnostic and return ``std::nullopt``.
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
);
343 /// Read a named option from the ``Context`` and parse it as an
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.
350 /// If the corresponding key can't be parsed as a ``T``, emit a
351 /// diagnostic and return \p Default.
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
);
361 /// Read a named option from the ``Context`` and parse it as an
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``.
369 /// If the corresponding key can't be parsed as a ``T``, emit a
370 /// diagnostic and return ``std::nullopt``.
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
);
383 /// Read a named option from the ``Context`` and parse it as an
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.
391 /// If the corresponding key can't be parsed as a ``T``, emit a
392 /// diagnostic and return \p Default.
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
);
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;
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
>>
412 store(ClangTidyOptions::OptionMap
&Options
, StringRef LocalName
,
414 if constexpr (std::is_signed_v
<T
>)
415 storeInt(Options
, LocalName
, Value
);
417 storeUnsigned(Options
, LocalName
, Value
);
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
423 template <typename T
>
424 std::enable_if_t
<std::is_integral_v
<T
>>
425 store(ClangTidyOptions::OptionMap
&Options
, StringRef LocalName
,
426 std::optional
<T
> Value
) const {
428 store(Options
, LocalName
, *Value
);
430 store(Options
, LocalName
, "none");
433 /// Stores an option with the check-local name \p LocalName as the string
434 /// representation of the Enum \p Value to \p Options.
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
>>
440 store(ClangTidyOptions::OptionMap
&Options
, StringRef LocalName
,
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
;
448 assert(Iter
!= Mapping
.end() && "Unknown Case Value");
449 store(Options
, LocalName
, Iter
->second
);
453 using NameAndValue
= std::pair
<int64_t, StringRef
>;
455 std::optional
<int64_t> getEnumInt(StringRef LocalName
,
456 ArrayRef
<NameAndValue
> Mapping
,
457 bool CheckGlobal
, bool IgnoreCase
) const;
459 template <typename T
>
460 std::enable_if_t
<std::is_enum_v
<T
>, std::vector
<NameAndValue
>>
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
),
473 void storeInt(ClangTidyOptions::OptionMap
&Options
, StringRef LocalName
,
474 int64_t Value
) const;
476 void storeUnsigned(ClangTidyOptions::OptionMap
&Options
,
477 StringRef LocalName
, uint64_t Value
) const;
479 std::string NamePrefix
;
480 const ClangTidyOptions::OptionMap
&CheckOptions
;
481 ClangTidyContext
*Context
;
485 void run(const ast_matchers::MatchFinder::MatchResult
&Result
) override
;
486 std::string CheckName
;
487 ClangTidyContext
*Context
;
491 /// Returns the main file name of the current translation unit.
492 StringRef
getCurrentMainFile() const { return Context
->getCurrentFile(); }
493 /// Returns the language options from the context.
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.
497 bool areDiagsSelfContained() const {
498 return Context
->areDiagsSelfContained();
500 StringRef
getID() const override
{ return CheckName
; }
503 /// Read a named option from the ``Context`` and parse it as a bool.
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``.
509 /// If the corresponding key can't be parsed as a bool, emit a
510 /// diagnostic and return ``std::nullopt``.
513 ClangTidyCheck::OptionsView::get
<bool>(StringRef LocalName
) const;
515 /// Read a named option from the ``Context`` and parse it as a bool.
517 /// Reads the option with the check-local name \p LocalName from the
518 /// ``CheckOptions``. If the corresponding key is not present, return
521 /// If the corresponding key can't be parsed as a bool, emit a
522 /// diagnostic and return \p Default.
525 ClangTidyCheck::OptionsView::getLocalOrGlobal
<bool>(StringRef LocalName
) const;
527 /// Stores an option with the check-local name \p LocalName with
528 /// bool value \p Value to \p Options.
530 void ClangTidyCheck::OptionsView::store
<bool>(
531 ClangTidyOptions::OptionMap
&Options
, StringRef LocalName
,
538 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H