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 |
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. |
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. |
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. |
108 | virtual void registerMatchers(ast_matchers::MatchFinder *Finder) {} |
109 | |
110 | /// ``ClangTidyChecks`` that register ASTMatchers should do the actual |
111 | /// work in here. |
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. |
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>> |
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(Lookup: NamePrefix + LocalName, Unparsed: *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>> |
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(Lookup: NamePrefix + LocalName, Unparsed: *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> |
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>> |
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 | Lookup: IsGlobal ? Twine(LocalName) : NamePrefix + LocalName, Unparsed: *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>> |
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 | Lookup: IsGlobal ? Twine(LocalName) : NamePrefix + LocalName, Unparsed: *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> |
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, Mapping: typeEraseMapping<T>(), CheckGlobal: 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, Mapping: typeEraseMapping<T>(), CheckGlobal: 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>> |
412 | store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, |
413 | T Value) const { |
414 | if constexpr (std::is_signed_v<T>) |
415 | storeInt(Options, LocalName, Value); |
416 | else |
417 | storeUnsigned(Options, LocalName, Value); |
418 | } |
419 | |
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 |
422 | /// stores `` |
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 { |
427 | if (Value) |
428 | store(Options, LocalName, *Value); |
429 | else |
430 | store(Options, LocalName, Value: "none" ); |
431 | } |
432 | |
433 | /// Stores an option with the check-local name \p LocalName as the string |
434 | /// representation of the Enum \p Value to \p Options. |
435 | /// |
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, |
441 | T Value) const { |
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; |
447 | }); |
448 | assert(Iter != Mapping.end() && "Unknown Case Value" ); |
449 | store(Options, LocalName, Iter->second); |
450 | } |
451 | |
452 | private: |
453 | using NameAndValue = std::pair<int64_t, StringRef>; |
454 | |
455 | std::optional<int64_t> getEnumInt(StringRef LocalName, |
456 | ArrayRef<NameAndValue> Mapping, |
457 | bool CheckGlobal, bool IgnoreCase) const; |
458 | |
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(n: Mapping.size()); |
466 | for (auto &MappedItem : Mapping) { |
467 | Result.emplace_back(static_cast<int64_t>(MappedItem.first), |
468 | MappedItem.second); |
469 | } |
470 | return Result; |
471 | } |
472 | |
473 | void storeInt(ClangTidyOptions::OptionMap &Options, StringRef LocalName, |
474 | int64_t Value) const; |
475 | |
476 | void storeUnsigned(ClangTidyOptions::OptionMap &Options, |
477 | StringRef LocalName, uint64_t Value) const; |
478 | |
479 | std::string NamePrefix; |
480 | const ClangTidyOptions::OptionMap &CheckOptions; |
481 | ClangTidyContext *Context; |
482 | }; |
483 | |
484 | private: |
485 | void run(const ast_matchers::MatchFinder::MatchResult &Result) override; |
486 | std::string CheckName; |
487 | ClangTidyContext *Context; |
488 | |
489 | protected: |
490 | OptionsView Options; |
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(); |
499 | } |
500 | StringRef getID() const override { return CheckName; } |
501 | }; |
502 | |
503 | /// Read a named option from the ``Context`` and parse it as a bool. |
504 | /// |
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``. |
508 | /// |
509 | /// If the corresponding key can't be parsed as a bool, emit a |
510 | /// diagnostic and return ``std::nullopt``. |
511 | template <> |
512 | std::optional<bool> |
513 | ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const; |
514 | |
515 | /// Read a named option from the ``Context`` and parse it as a bool. |
516 | /// |
517 | /// Reads the option with the check-local name \p LocalName from the |
518 | /// ``CheckOptions``. If the corresponding key is not present, return |
519 | /// \p Default. |
520 | /// |
521 | /// If the corresponding key can't be parsed as a bool, emit a |
522 | /// diagnostic and return \p Default. |
523 | template <> |
524 | std::optional<bool> |
525 | ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const; |
526 | |
527 | /// Stores an option with the check-local name \p LocalName with |
528 | /// bool value \p Value to \p Options. |
529 | template <> |
530 | void ClangTidyCheck::OptionsView::store<bool>( |
531 | ClangTidyOptions::OptionMap &Options, StringRef LocalName, |
532 | bool Value) const; |
533 | |
534 | |
535 | } // namespace tidy |
536 | } // namespace clang |
537 | |
538 | #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYCHECK_H |
539 | |