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