blob: 9fa0d63286409102bfa22f3c8c8986790e4ac010 [file] [log] [blame]
Olivier Deprezf4ef2d02021-04-20 13:36:24 +02001//===--- 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
22namespace clang {
23
24class CompilerInstance;
25class SourceManager;
26
27namespace 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.
31template <class T> struct OptionEnumMapping {
32 // Specializations of this struct must implement this function.
33 static ArrayRef<std::pair<T, StringRef>> getEnumMapping() = delete;
34};
35
36template <typename T> class OptionError : public llvm::ErrorInfo<T> {
37 std::error_code convertToErrorCode() const override {
38 return llvm::inconvertibleErrorCode();
39 }
40
41public:
42 void log(raw_ostream &OS) const override { OS << this->message(); }
43};
44
45class MissingOptionError : public OptionError<MissingOptionError> {
46public:
47 explicit MissingOptionError(std::string OptionName)
48 : OptionName(OptionName) {}
49
50 std::string message() const override;
51 static char ID;
52private:
53 const std::string OptionName;
54};
55
56class UnparseableEnumOptionError
57 : public OptionError<UnparseableEnumOptionError> {
58public:
59 explicit UnparseableEnumOptionError(std::string LookupName,
60 std::string LookupValue)
61 : LookupName(LookupName), LookupValue(LookupValue) {}
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
71private:
72 const std::string LookupName;
73 const std::string LookupValue;
74 const llvm::Optional<std::string> SuggestedValue;
75};
76
77class UnparseableIntegerOptionError
78 : public OptionError<UnparseableIntegerOptionError> {
79public:
80 explicit UnparseableIntegerOptionError(std::string LookupName,
81 std::string LookupValue,
82 bool IsBoolean = false)
83 : LookupName(LookupName), LookupValue(LookupValue), IsBoolean(IsBoolean) {
84 }
85
86 std::string message() const override;
87 static char ID;
88
89private:
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.
114class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback {
115public:
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.
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.
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.
169 virtual void registerMatchers(ast_matchers::MatchFinder *Finder) {}
170
171 /// ``ClangTidyChecks`` that register ASTMatchers should do the actual
172 /// work in here.
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.
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.
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.
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>>
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>
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>>
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>
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>
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>
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>
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>
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>>
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
502private:
503 void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
504 StringRef getID() const override { return CheckName; }
505 std::string CheckName;
506 ClangTidyContext *Context;
507
508protected:
509 OptionsView Options;
510 /// Returns the main file name of the current translation unit.
511 StringRef getCurrentMainFile() const { return Context->getCurrentFile(); }
512 /// Returns the language options from the context.
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``.
522template <>
523llvm::Expected<bool>
524ClangTidyCheck::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.
531template <>
532bool 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``.
543template <>
544llvm::Expected<bool>
545ClangTidyCheck::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.
553template <>
554bool 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.
559template <>
560void 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.
566template <>
567Optional<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.
572template <>
573Optional<std::string>
574ClangTidyCheck::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