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 "llvm/Support/Error.h"
18 #include <type_traits>
19 #include <utility>
20 #include <vector>
21 
22 namespace clang {
23 
24 class CompilerInstance;
25 class SourceManager;
26 
27 namespace tidy {
28 
29 /// This class should be specialized by any enum type that needs to be converted
30 /// to and from an \ref llvm::StringRef.
31 template <class T> struct OptionEnumMapping {
32   // Specializations of this struct must implement this function.
33   static ArrayRef<std::pair<T, StringRef>> getEnumMapping() = delete;
34 };
35 
36 template <typename T> class OptionError : public llvm::ErrorInfo<T> {
convertToErrorCode()37   std::error_code convertToErrorCode() const override {
38     return llvm::inconvertibleErrorCode();
39   }
40 
41 public:
log(raw_ostream & OS)42   void log(raw_ostream &OS) const override { OS << this->message(); }
43 };
44 
45 class MissingOptionError : public OptionError<MissingOptionError> {
46 public:
MissingOptionError(std::string OptionName)47   explicit MissingOptionError(std::string OptionName)
48       : OptionName(OptionName) {}
49 
50   std::string message() const override;
51   static char ID;
52 private:
53   const std::string OptionName;
54 };
55 
56 class UnparseableEnumOptionError
57     : public OptionError<UnparseableEnumOptionError> {
58 public:
UnparseableEnumOptionError(std::string LookupName,std::string LookupValue)59   explicit UnparseableEnumOptionError(std::string LookupName,
60                                       std::string LookupValue)
61       : LookupName(LookupName), LookupValue(LookupValue) {}
UnparseableEnumOptionError(std::string LookupName,std::string LookupValue,std::string SuggestedValue)62   explicit UnparseableEnumOptionError(std::string LookupName,
63                                       std::string LookupValue,
64                                       std::string SuggestedValue)
65       : LookupName(LookupName), LookupValue(LookupValue),
66         SuggestedValue(SuggestedValue) {}
67 
68   std::string message() const override;
69   static char ID;
70 
71 private:
72   const std::string LookupName;
73   const std::string LookupValue;
74   const llvm::Optional<std::string> SuggestedValue;
75 };
76 
77 class UnparseableIntegerOptionError
78     : public OptionError<UnparseableIntegerOptionError> {
79 public:
80   explicit UnparseableIntegerOptionError(std::string LookupName,
81                                          std::string LookupValue,
82                                          bool IsBoolean = false)
LookupName(LookupName)83       : LookupName(LookupName), LookupValue(LookupValue), IsBoolean(IsBoolean) {
84   }
85 
86   std::string message() const override;
87   static char ID;
88 
89 private:
90   const std::string LookupName;
91   const std::string LookupValue;
92   const bool IsBoolean;
93 };
94 
95 /// Base class for all clang-tidy checks.
96 ///
97 /// To implement a ``ClangTidyCheck``, write a subclass and override some of the
98 /// base class's methods. E.g. to implement a check that validates namespace
99 /// declarations, override ``registerMatchers``:
100 ///
101 /// ~~~{.cpp}
102 /// void registerMatchers(ast_matchers::MatchFinder *Finder) override {
103 ///   Finder->addMatcher(namespaceDecl().bind("namespace"), this);
104 /// }
105 /// ~~~
106 ///
107 /// and then override ``check(const MatchResult &Result)`` to do the actual
108 /// check for each match.
109 ///
110 /// A new ``ClangTidyCheck`` instance is created per translation unit.
111 ///
112 /// FIXME: Figure out whether carrying information from one TU to another is
113 /// useful/necessary.
114 class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback {
115 public:
116   /// Initializes the check with \p CheckName and \p Context.
117   ///
118   /// Derived classes must implement the constructor with this signature or
119   /// delegate it. If a check needs to read options, it can do this in the
120   /// constructor using the Options.get() methods below.
121   ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context);
122 
123   /// Override this to disable registering matchers and PP callbacks if an
124   /// invalid language version is being used.
125   ///
126   /// For example if a check is examining overloaded functions then this should
127   /// be overridden to return false when the CPlusPlus flag is not set in
128   /// \p LangOpts.
isLanguageVersionSupported(const LangOptions & LangOpts)129   virtual bool isLanguageVersionSupported(const LangOptions &LangOpts) const {
130     return true;
131   }
132 
133   /// Override this to register ``PPCallbacks`` in the preprocessor.
134   ///
135   /// This should be used for clang-tidy checks that analyze preprocessor-
136   /// dependent properties, e.g. include directives and macro definitions.
137   ///
138   /// This will only be executed if the function isLanguageVersionSupported
139   /// returns true.
140   ///
141   /// There are two Preprocessors to choose from that differ in how they handle
142   /// modular #includes:
143   ///  - PP is the real Preprocessor. It doesn't walk into modular #includes and
144   ///    thus doesn't generate PPCallbacks for their contents.
145   ///  - ModuleExpanderPP preprocesses the whole translation unit in the
146   ///    non-modular mode, which allows it to generate PPCallbacks not only for
147   ///    the main file and textual headers, but also for all transitively
148   ///    included modular headers when the analysis runs with modules enabled.
149   ///    When modules are not enabled ModuleExpanderPP just points to the real
150   ///    preprocessor.
registerPPCallbacks(const SourceManager & SM,Preprocessor * PP,Preprocessor * ModuleExpanderPP)151   virtual void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
152                                    Preprocessor *ModuleExpanderPP) {}
153 
154   /// Override this to register AST matchers with \p Finder.
155   ///
156   /// This should be used by clang-tidy checks that analyze code properties that
157   /// dependent on AST knowledge.
158   ///
159   /// You can register as many matchers as necessary with \p Finder. Usually,
160   /// "this" will be used as callback, but you can also specify other callback
161   /// classes. Thereby, different matchers can trigger different callbacks.
162   ///
163   /// This will only be executed if the function isLanguageVersionSupported
164   /// returns true.
165   ///
166   /// If you need to merge information between the different matchers, you can
167   /// store these as members of the derived class. However, note that all
168   /// matches occur in the order of the AST traversal.
registerMatchers(ast_matchers::MatchFinder * Finder)169   virtual void registerMatchers(ast_matchers::MatchFinder *Finder) {}
170 
171   /// ``ClangTidyChecks`` that register ASTMatchers should do the actual
172   /// work in here.
check(const ast_matchers::MatchFinder::MatchResult & Result)173   virtual void check(const ast_matchers::MatchFinder::MatchResult &Result) {}
174 
175   /// Add a diagnostic with the check's name.
176   DiagnosticBuilder diag(SourceLocation Loc, StringRef Description,
177                          DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
178 
179   /// Add a diagnostic with the check's name.
180   DiagnosticBuilder diag(StringRef Description,
181                          DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
182 
183   /// Adds a diagnostic to report errors in the check's configuration.
184   DiagnosticBuilder
185   configurationDiag(StringRef Description,
186                     DiagnosticIDs::Level Level = DiagnosticIDs::Warning);
187 
188   /// Should store all options supported by this check with their
189   /// current values or default values for options that haven't been overridden.
190   ///
191   /// The check should use ``Options.store()`` to store each option it supports
192   /// whether it has the default value or it has been overridden.
storeOptions(ClangTidyOptions::OptionMap & Options)193   virtual void storeOptions(ClangTidyOptions::OptionMap &Options) {}
194 
195   /// Provides access to the ``ClangTidyCheck`` options via check-local
196   /// names.
197   ///
198   /// Methods of this class prepend ``CheckName + "."`` to translate check-local
199   /// option names to global option names.
200   class OptionsView {
201   public:
202     /// Initializes the instance using \p CheckName + "." as a prefix.
203     OptionsView(StringRef CheckName,
204                 const ClangTidyOptions::OptionMap &CheckOptions,
205                 ClangTidyContext *Context);
206 
207     /// Read a named option from the ``Context``.
208     ///
209     /// Reads the option with the check-local name \p LocalName from the
210     /// ``CheckOptions``. If the corresponding key is not present, returns
211     /// a ``MissingOptionError``.
212     llvm::Expected<std::string> get(StringRef LocalName) const;
213 
214     /// Read a named option from the ``Context``.
215     ///
216     /// Reads the option with the check-local name \p LocalName from the
217     /// ``CheckOptions``. If the corresponding key is not present, returns
218     /// \p Default.
get(StringRef LocalName,StringRef Default)219     std::string get(StringRef LocalName, StringRef Default) const {
220       if (llvm::Expected<std::string> Val = get(LocalName))
221         return *Val;
222       else
223         llvm::consumeError(Val.takeError());
224       return Default.str();
225     }
226 
227     /// Read a named option from the ``Context``.
228     ///
229     /// Reads the option with the check-local name \p LocalName from local or
230     /// global ``CheckOptions``. Gets local option first. If local is not
231     /// present, falls back to get global option. If global option is not
232     /// present either, returns a ``MissingOptionError``.
233     llvm::Expected<std::string> getLocalOrGlobal(StringRef LocalName) const;
234 
235     /// Read a named option from the ``Context``.
236     ///
237     /// Reads the option with the check-local name \p LocalName from local or
238     /// global ``CheckOptions``. Gets local option first. If local is not
239     /// present, falls back to get global option. If global option is not
240     /// present either, returns \p Default.
getLocalOrGlobal(StringRef LocalName,StringRef Default)241     std::string getLocalOrGlobal(StringRef LocalName, StringRef Default) const {
242       if (llvm::Expected<std::string> Val = getLocalOrGlobal(LocalName))
243         return *Val;
244       else
245         llvm::consumeError(Val.takeError());
246       return Default.str();
247     }
248 
249     /// Read a named option from the ``Context`` and parse it as an
250     /// integral type ``T``.
251     ///
252     /// Reads the option with the check-local name \p LocalName from the
253     /// ``CheckOptions``. If the corresponding key is not present, returns
254     /// a ``MissingOptionError``. If the corresponding key can't be parsed as
255     /// a ``T``, return an ``UnparseableIntegerOptionError``.
256     template <typename T>
257     std::enable_if_t<std::is_integral<T>::value, llvm::Expected<T>>
get(StringRef LocalName)258     get(StringRef LocalName) const {
259       if (llvm::Expected<std::string> Value = get(LocalName)) {
260         T Result{};
261         if (!StringRef(*Value).getAsInteger(10, Result))
262           return Result;
263         return llvm::make_error<UnparseableIntegerOptionError>(
264             (NamePrefix + LocalName).str(), *Value);
265       } else
266         return std::move(Value.takeError());
267     }
268 
269     /// Read a named option from the ``Context`` and parse it as an
270     /// integral type ``T``.
271     ///
272     /// Reads the option with the check-local name \p LocalName from the
273     /// ``CheckOptions``. If the corresponding key is not present or it can't be
274     /// parsed as a ``T``, returns \p Default.
275     template <typename T>
get(StringRef LocalName,T Default)276     std::enable_if_t<std::is_integral<T>::value, T> get(StringRef LocalName,
277                                                         T Default) const {
278       if (llvm::Expected<T> ValueOr = get<T>(LocalName))
279         return *ValueOr;
280       else
281         reportOptionParsingError(ValueOr.takeError());
282       return Default;
283     }
284 
285     /// Read a named option from the ``Context`` and parse it as an
286     /// integral type ``T``.
287     ///
288     /// Reads the option with the check-local name \p LocalName from local or
289     /// global ``CheckOptions``. Gets local option first. If local is not
290     /// present, falls back to get global option. If global option is not
291     /// present either, returns a ``MissingOptionError``. If the corresponding
292     /// key can't be parsed as a ``T``, return an
293     /// ``UnparseableIntegerOptionError``.
294     template <typename T>
295     std::enable_if_t<std::is_integral<T>::value, llvm::Expected<T>>
getLocalOrGlobal(StringRef LocalName)296     getLocalOrGlobal(StringRef LocalName) const {
297       llvm::Expected<std::string> ValueOr = get(LocalName);
298       bool IsGlobal = false;
299       if (!ValueOr) {
300         IsGlobal = true;
301         llvm::consumeError(ValueOr.takeError());
302         ValueOr = getLocalOrGlobal(LocalName);
303         if (!ValueOr)
304           return std::move(ValueOr.takeError());
305       }
306       T Result{};
307       if (!StringRef(*ValueOr).getAsInteger(10, Result))
308         return Result;
309       return llvm::make_error<UnparseableIntegerOptionError>(
310           (IsGlobal ? LocalName.str() : (NamePrefix + LocalName).str()),
311           *ValueOr);
312     }
313 
314     /// Read a named option from the ``Context`` and parse it as an
315     /// integral type ``T``.
316     ///
317     /// Reads the option with the check-local name \p LocalName from local or
318     /// global ``CheckOptions``. Gets local option first. If local is not
319     /// present, falls back to get global option. If global option is not
320     /// present either or it can't be parsed as a ``T``, returns \p Default.
321     template <typename T>
322     std::enable_if_t<std::is_integral<T>::value, T>
getLocalOrGlobal(StringRef LocalName,T Default)323     getLocalOrGlobal(StringRef LocalName, T Default) const {
324       if (llvm::Expected<T> ValueOr = getLocalOrGlobal<T>(LocalName))
325         return *ValueOr;
326       else
327         reportOptionParsingError(ValueOr.takeError());
328       return Default;
329     }
330 
331     /// Read a named option from the ``Context`` and parse it as an
332     /// enum type ``T``.
333     ///
334     /// Reads the option with the check-local name \p LocalName from the
335     /// ``CheckOptions``. If the corresponding key is not present, returns a
336     /// ``MissingOptionError``. If the key can't be parsed as a ``T`` returns a
337     /// ``UnparseableEnumOptionError``.
338     ///
339     /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to
340     /// supply the mapping required to convert between ``T`` and a string.
341     template <typename T>
342     std::enable_if_t<std::is_enum<T>::value, llvm::Expected<T>>
343     get(StringRef LocalName, bool IgnoreCase = false) const {
344       if (llvm::Expected<int64_t> ValueOr =
345               getEnumInt(LocalName, typeEraseMapping<T>(), false, IgnoreCase))
346         return static_cast<T>(*ValueOr);
347       else
348         return std::move(ValueOr.takeError());
349     }
350 
351     /// Read a named option from the ``Context`` and parse it as an
352     /// enum type ``T``.
353     ///
354     /// Reads the option with the check-local name \p LocalName from the
355     /// ``CheckOptions``. If the corresponding key is not present or it can't be
356     /// parsed as a ``T``, returns \p Default.
357     ///
358     /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to
359     /// supply the mapping required to convert between ``T`` and a string.
360     template <typename T>
361     std::enable_if_t<std::is_enum<T>::value, T>
362     get(StringRef LocalName, T Default, bool IgnoreCase = false) const {
363       if (auto ValueOr = get<T>(LocalName, IgnoreCase))
364         return *ValueOr;
365       else
366         reportOptionParsingError(ValueOr.takeError());
367       return Default;
368     }
369 
370     /// Read a named option from the ``Context`` and parse it as an
371     /// enum type ``T``.
372     ///
373     /// Reads the option with the check-local name \p LocalName from local or
374     /// global ``CheckOptions``. Gets local option first. If local is not
375     /// present, falls back to get global option. If global option is not
376     /// present either, returns a ``MissingOptionError``. If the key can't be
377     /// parsed as a ``T`` returns a ``UnparseableEnumOptionError``.
378     ///
379     /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to
380     /// supply the mapping required to convert between ``T`` and a string.
381     template <typename T>
382     std::enable_if_t<std::is_enum<T>::value, llvm::Expected<T>>
383     getLocalOrGlobal(StringRef LocalName, bool IgnoreCase = false) const {
384       if (llvm::Expected<int64_t> ValueOr =
385               getEnumInt(LocalName, typeEraseMapping<T>(), true, IgnoreCase))
386         return static_cast<T>(*ValueOr);
387       else
388         return std::move(ValueOr.takeError());
389     }
390 
391     /// Read a named option from the ``Context`` and parse it as an
392     /// enum type ``T``.
393     ///
394     /// Reads the option with the check-local name \p LocalName from local or
395     /// global ``CheckOptions``. Gets local option first. If local is not
396     /// present, falls back to get global option. If global option is not
397     /// present either or it can't be parsed as a ``T``, returns \p Default.
398     ///
399     /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to
400     /// supply the mapping required to convert between ``T`` and a string.
401     template <typename T>
402     std::enable_if_t<std::is_enum<T>::value, T>
403     getLocalOrGlobal(StringRef LocalName, T Default,
404                      bool IgnoreCase = false) const {
405       if (auto ValueOr = getLocalOrGlobal<T>(LocalName, IgnoreCase))
406         return *ValueOr;
407       else
408         reportOptionParsingError(ValueOr.takeError());
409       return Default;
410     }
411 
412     /// Returns the value for the option \p LocalName represented as a ``T``.
413     /// If the option is missing returns None, if the option can't be parsed
414     /// as a ``T``, log that to stderr and return None.
415     template <typename T = std::string>
getOptional(StringRef LocalName)416     llvm::Optional<T> getOptional(StringRef LocalName) const {
417       if (auto ValueOr = get<T>(LocalName))
418         return *ValueOr;
419       else
420         reportOptionParsingError(ValueOr.takeError());
421       return llvm::None;
422     }
423 
424     /// Returns the value for the local or global option \p LocalName
425     /// represented as a ``T``.
426     /// If the option is missing returns None, if the
427     /// option can't be parsed as a ``T``, log that to stderr and return None.
428     template <typename T = std::string>
getOptionalLocalOrGlobal(StringRef LocalName)429     llvm::Optional<T> getOptionalLocalOrGlobal(StringRef LocalName) const {
430       if (auto ValueOr = getLocalOrGlobal<T>(LocalName))
431         return *ValueOr;
432       else
433         reportOptionParsingError(ValueOr.takeError());
434       return llvm::None;
435     }
436 
437     /// Stores an option with the check-local name \p LocalName with
438     /// string value \p Value to \p Options.
439     void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName,
440                StringRef Value) const;
441 
442     /// Stores an option with the check-local name \p LocalName with
443     /// integer value \p Value to \p Options.
444     template <typename T>
445     std::enable_if_t<std::is_integral<T>::value>
store(ClangTidyOptions::OptionMap & Options,StringRef LocalName,T Value)446     store(ClangTidyOptions::OptionMap &Options, StringRef LocalName,
447           T Value) const {
448       storeInt(Options, LocalName, Value);
449     }
450 
451     /// Stores an option with the check-local name \p LocalName as the string
452     /// representation of the Enum \p Value to \p Options.
453     ///
454     /// \ref clang::tidy::OptionEnumMapping must be specialized for ``T`` to
455     /// supply the mapping required to convert between ``T`` and a string.
456     template <typename T>
457     std::enable_if_t<std::is_enum<T>::value>
store(ClangTidyOptions::OptionMap & Options,StringRef LocalName,T Value)458     store(ClangTidyOptions::OptionMap &Options, StringRef LocalName,
459           T Value) const {
460       ArrayRef<std::pair<T, StringRef>> Mapping =
461           OptionEnumMapping<T>::getEnumMapping();
462       auto Iter = llvm::find_if(
463           Mapping, [&](const std::pair<T, StringRef> &NameAndEnum) {
464             return NameAndEnum.first == Value;
465           });
466       assert(Iter != Mapping.end() && "Unknown Case Value");
467       store(Options, LocalName, Iter->second);
468     }
469 
470   private:
471     using NameAndValue = std::pair<int64_t, StringRef>;
472 
473     llvm::Expected<int64_t> getEnumInt(StringRef LocalName,
474                                        ArrayRef<NameAndValue> Mapping,
475                                        bool CheckGlobal, bool IgnoreCase) const;
476 
477     template <typename T>
478     std::enable_if_t<std::is_enum<T>::value, std::vector<NameAndValue>>
typeEraseMapping()479     typeEraseMapping() const {
480       ArrayRef<std::pair<T, StringRef>> Mapping =
481           OptionEnumMapping<T>::getEnumMapping();
482       std::vector<NameAndValue> Result;
483       Result.reserve(Mapping.size());
484       for (auto &MappedItem : Mapping) {
485         Result.emplace_back(static_cast<int64_t>(MappedItem.first),
486                             MappedItem.second);
487       }
488       return Result;
489     }
490 
491     void storeInt(ClangTidyOptions::OptionMap &Options, StringRef LocalName,
492                   int64_t Value) const;
493 
494     /// Emits a diagnostic if \p Err is not a MissingOptionError.
495     void reportOptionParsingError(llvm::Error &&Err) const;
496 
497     std::string NamePrefix;
498     const ClangTidyOptions::OptionMap &CheckOptions;
499     ClangTidyContext *Context;
500   };
501 
502 private:
503   void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
getID()504   StringRef getID() const override { return CheckName; }
505   std::string CheckName;
506   ClangTidyContext *Context;
507 
508 protected:
509   OptionsView Options;
510   /// Returns the main file name of the current translation unit.
getCurrentMainFile()511   StringRef getCurrentMainFile() const { return Context->getCurrentFile(); }
512   /// Returns the language options from the context.
getLangOpts()513   const LangOptions &getLangOpts() const { return Context->getLangOpts(); }
514 };
515 
516 /// Read a named option from the ``Context`` and parse it as a bool.
517 ///
518 /// Reads the option with the check-local name \p LocalName from the
519 /// ``CheckOptions``. If the corresponding key is not present, returns
520 /// a ``MissingOptionError``. If the corresponding key can't be parsed as
521 /// a bool, return an ``UnparseableIntegerOptionError``.
522 template <>
523 llvm::Expected<bool>
524 ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const;
525 
526 /// Read a named option from the ``Context`` and parse it as a bool.
527 ///
528 /// Reads the option with the check-local name \p LocalName from the
529 /// ``CheckOptions``. If the corresponding key is not present or it can't be
530 /// parsed as a bool, returns \p Default.
531 template <>
532 bool ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName,
533                                             bool Default) const;
534 
535 /// Read a named option from the ``Context`` and parse it as a bool.
536 ///
537 /// Reads the option with the check-local name \p LocalName from local or
538 /// global ``CheckOptions``. Gets local option first. If local is not
539 /// present, falls back to get global option. If global option is not
540 /// present either, returns a ``MissingOptionError``. If the corresponding
541 /// key can't be parsed as a bool, return an
542 /// ``UnparseableIntegerOptionError``.
543 template <>
544 llvm::Expected<bool>
545 ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const;
546 
547 /// Read a named option from the ``Context`` and parse it as a bool.
548 ///
549 /// Reads the option with the check-local name \p LocalName from local or
550 /// global ``CheckOptions``. Gets local option first. If local is not
551 /// present, falls back to get global option. If global option is not
552 /// present either or it can't be parsed as a bool, returns \p Default.
553 template <>
554 bool ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName,
555                                                          bool Default) const;
556 
557 /// Stores an option with the check-local name \p LocalName with
558 /// bool value \p Value to \p Options.
559 template <>
560 void ClangTidyCheck::OptionsView::store<bool>(
561     ClangTidyOptions::OptionMap &Options, StringRef LocalName,
562     bool Value) const;
563 
564 /// Returns the value for the option \p LocalName.
565 /// If the option is missing returns None.
566 template <>
567 Optional<std::string> ClangTidyCheck::OptionsView::getOptional<std::string>(
568     StringRef LocalName) const;
569 
570 /// Returns the value for the local or global option \p LocalName.
571 /// If the option is missing returns None.
572 template <>
573 Optional<std::string>
574 ClangTidyCheck::OptionsView::getOptionalLocalOrGlobal<std::string>(
575     StringRef LocalName) const;
576 
577 } // namespace tidy
578 } // namespace clang
579 
580 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H
581