UNSUPPORT test on 64-bit AIX too
[llvm-project.git] / clang-tools-extra / clang-tidy / ClangTidyCheck.h
blobabf528d655972b465291e22ac43c38bd3bd51be9
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 //===----------------------------------------------------------------------===//
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"
16 #include "llvm/ADT/Optional.h"
17 #include <type_traits>
18 #include <utility>
19 #include <vector>
21 namespace clang {
23 class SourceManager;
25 namespace tidy {
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.
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);
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.
68 virtual bool isLanguageVersionSupported(const LangOptions &LangOpts) const {
69 return true;
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.
90 virtual void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
91 Preprocessor *ModuleExpanderPP) {}
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.
102 /// This will only be executed if the function isLanguageVersionSupported
103 /// returns true.
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
111 /// work in here.
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.
123 DiagnosticBuilder
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
135 /// names.
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;
147 public:
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 /// ``None``.
158 llvm::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
164 /// \p Default.
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 ``None``.
173 llvm::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, return
188 /// ``None``.
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>>
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);
201 return None;
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 not present, return
209 /// \p Default.
211 /// If the corresponding key can't be parsed as a ``T``, emit a
212 /// diagnostic and return \p Default.
213 template <typename T>
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);
219 /// Read a named option from the ``Context`` and parse it as an
220 /// integral type ``T``.
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``.
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>>
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;
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;
248 /// Read a named option from the ``Context`` and parse it as an
249 /// integral type ``T``.
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.
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>
260 getLocalOrGlobal(StringRef LocalName, T Default) const {
261 return getLocalOrGlobal<T>(LocalName).value_or(Default);
264 /// Read a named option from the ``Context`` and parse it as an
265 /// enum type ``T``.
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``.
271 /// If the corresponding key can't be parsed as a ``T``, emit a
272 /// diagnostic and return ``None``.
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;
285 /// Read a named option from the ``Context`` and parse it as an
286 /// enum type ``T``.
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.
292 /// If the corresponding key can't be parsed as a ``T``, emit a
293 /// diagnostic and return \p Default.
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);
303 /// Read a named option from the ``Context`` and parse it as an
304 /// enum type ``T``.
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``.
311 /// If the corresponding key can't be parsed as a ``T``, emit a
312 /// diagnostic and return ``None``.
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;
325 /// Read a named option from the ``Context`` and parse it as an
326 /// enum type ``T``.
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.
333 /// If the corresponding key can't be parsed as a ``T``, emit a
334 /// diagnostic and return \p Default.
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);
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;
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>
354 store(ClangTidyOptions::OptionMap &Options, StringRef LocalName,
355 T Value) const {
356 storeInt(Options, LocalName, Value);
359 /// Stores an option with the check-local name \p LocalName as the string
360 /// representation of the Enum \p Value to \p Options.
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>
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;
374 assert(Iter != Mapping.end() && "Unknown Case Value");
375 store(Options, LocalName, Iter->second);
378 private:
379 using NameAndValue = std::pair<int64_t, StringRef>;
381 llvm::Optional<int64_t> getEnumInt(StringRef LocalName,
382 ArrayRef<NameAndValue> Mapping,
383 bool CheckGlobal, bool IgnoreCase) const;
385 template <typename T>
386 std::enable_if_t<std::is_enum<T>::value, std::vector<NameAndValue>>
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);
396 return Result;
399 void storeInt(ClangTidyOptions::OptionMap &Options, StringRef LocalName,
400 int64_t Value) const;
403 std::string NamePrefix;
404 const ClangTidyOptions::OptionMap &CheckOptions;
405 ClangTidyContext *Context;
408 private:
409 void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
410 StringRef getID() const override { return CheckName; }
411 std::string CheckName;
412 ClangTidyContext *Context;
414 protected:
415 OptionsView Options;
416 /// Returns the main file name of the current translation unit.
417 StringRef getCurrentMainFile() const { return Context->getCurrentFile(); }
418 /// Returns the language options from the context.
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.
422 bool areDiagsSelfContained() const {
423 return Context->areDiagsSelfContained();
427 /// Read a named option from the ``Context`` and parse it as a bool.
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``.
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;
439 /// Read a named option from the ``Context`` and parse it as a bool.
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.
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;
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;
459 } // namespace tidy
460 } // namespace clang
462 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H