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