10#include "llvm/ADT/SmallString.h"
11#include "llvm/ADT/StringRef.h"
12#include "llvm/Support/Error.h"
13#include "llvm/Support/YAMLParser.h"
19 : CheckName(CheckName), Context(Context),
20 Options(CheckName, Context->getOptions().CheckOptions, Context) {
21 assert(Context !=
nullptr);
22 assert(!CheckName.empty());
26 DiagnosticIDs::Level Level) {
27 return Context->
diag(CheckName,
Loc, Message, Level);
31 DiagnosticIDs::Level Level) {
32 return Context->
diag(CheckName, Message, Level);
37 DiagnosticIDs::Level Level)
const {
41void ClangTidyCheck::run(
const ast_matchers::MatchFinder::MatchResult &Result) {
51 : NamePrefix((CheckName +
".").str()), CheckOptions(CheckOptions),
54std::optional<StringRef>
58 const auto &Iter = CheckOptions.find((NamePrefix + LocalName).str());
59 if (Iter != CheckOptions.end())
60 return StringRef(Iter->getValue().Value);
64static ClangTidyOptions::OptionMap::const_iterator
66 StringRef NamePrefix, StringRef LocalName,
67 llvm::StringSet<> *Collector) {
69 Collector->insert((NamePrefix + LocalName).str());
70 Collector->insert(LocalName);
72 auto IterLocal =
Options.find((NamePrefix + LocalName).str());
73 auto IterGlobal =
Options.find(LocalName);
76 if (IterGlobal ==
Options.end())
78 if (IterLocal->getValue().Priority >= IterGlobal->getValue().Priority)
83std::optional<StringRef>
87 if (Iter != CheckOptions.end())
88 return StringRef(Iter->getValue().Value);
92static std::optional<bool>
getAsBool(StringRef Value,
93 const llvm::Twine &LookupName) {
95 if (std::optional<bool> Parsed = llvm::yaml::parseBool(Value))
100 if (!Value.getAsInteger(10,
Number))
107ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName)
const {
108 if (std::optional<StringRef> ValueOr = get(LocalName)) {
109 if (
auto Result =
getAsBool(*ValueOr, NamePrefix + LocalName))
111 diagnoseBadBooleanOption(NamePrefix + LocalName, *ValueOr);
118ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName)
const {
121 if (Iter != CheckOptions.end()) {
122 if (
auto Result =
getAsBool(Iter->getValue().Value, Iter->getKey()))
124 diagnoseBadBooleanOption(Iter->getKey(), Iter->getValue().Value);
131 StringRef Value)
const {
132 Options[(NamePrefix + LocalName).str()] = Value;
137 int64_t Value)
const {
138 store(
Options, LocalName, llvm::itostr(Value));
142void ClangTidyCheck::OptionsView::store<bool>(
145 store(
Options, LocalName, Value ? StringRef(
"true") : StringRef(
"false"));
148std::optional<int64_t> ClangTidyCheck::OptionsView::getEnumInt(
149 StringRef LocalName, ArrayRef<NameAndValue> Mapping,
bool CheckGlobal,
150 bool IgnoreCase)
const {
153 auto Iter = CheckGlobal
156 : CheckOptions.find((NamePrefix + LocalName).str());
157 if (Iter == CheckOptions.end())
160 StringRef Value = Iter->getValue().Value;
162 unsigned EditDistance = 3;
163 for (
const auto &NameAndEnum : Mapping) {
165 if (Value.equals_insensitive(NameAndEnum.second))
166 return NameAndEnum.first;
167 }
else if (Value.equals(NameAndEnum.second)) {
168 return NameAndEnum.first;
169 }
else if (Value.equals_insensitive(NameAndEnum.second)) {
170 Closest = NameAndEnum.second;
175 Value.edit_distance(NameAndEnum.second,
true, EditDistance);
176 if (Distance < EditDistance) {
177 EditDistance = Distance;
178 Closest = NameAndEnum.second;
181 if (EditDistance < 3)
182 diagnoseBadEnumOption(Iter->getKey(), Iter->getValue().Value, Closest);
184 diagnoseBadEnumOption(Iter->getKey(), Iter->getValue().Value);
189 "invalid configuration value '%0' for option '%1'%select{|; expected a "
190 "bool|; expected an integer|; did you mean '%3'?}2");
192void ClangTidyCheck::OptionsView::diagnoseBadBooleanOption(
193 const Twine &Lookup, StringRef Unparsed)
const {
194 SmallString<64> Buffer;
196 << Unparsed << Lookup.toStringRef(Buffer) << 1;
199void ClangTidyCheck::OptionsView::diagnoseBadIntegerOption(
200 const Twine &Lookup, StringRef Unparsed)
const {
201 SmallString<64> Buffer;
203 << Unparsed << Lookup.toStringRef(Buffer) << 2;
206void ClangTidyCheck::OptionsView::diagnoseBadEnumOption(
207 const Twine &Lookup, StringRef Unparsed, StringRef Suggestion)
const {
208 SmallString<64> Buffer;
210 << Unparsed << Lookup.toStringRef(Buffer);
211 if (Suggestion.empty())
214 Diag << 3 << Suggestion;
218 StringRef Default)
const {
219 return get(LocalName).value_or(Default);
224 StringRef Default)
const {
225 return getLocalOrGlobal(LocalName).value_or(Default);
std::optional< StringRef > get(StringRef LocalName) const
Read a named option from the Context.
OptionsView(StringRef CheckName, const ClangTidyOptions::OptionMap &CheckOptions, ClangTidyContext *Context)
Initializes the instance using CheckName + "." as a prefix.
std::optional< StringRef > getLocalOrGlobal(StringRef LocalName) const
Read a named option from the Context.
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
DiagnosticBuilder configurationDiag(StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning) const
Adds a diagnostic to report errors in the check's configuration.
ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context)
Initializes the check with CheckName and Context.
virtual void check(const ast_matchers::MatchFinder::MatchResult &Result)
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
llvm::StringSet * getOptionsCollector() const
DiagnosticBuilder configurationDiag(StringRef Message, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Report any errors to do with reading the configuration using this method.
DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc, StringRef Message, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Report any errors detected using this method.
static constexpr llvm::StringLiteral ConfigWarning("invalid configuration value '%0' for option '%1'%select{|; expected a " "bool|; expected an integer|; did you mean '%3'?}2")
static ClangTidyOptions::OptionMap::const_iterator findPriorityOption(const ClangTidyOptions::OptionMap &Options, StringRef NamePrefix, StringRef LocalName, llvm::StringSet<> *Collector)
static std::optional< bool > getAsBool(StringRef Value, const llvm::Twine &LookupName)
llvm::StringMap< ClangTidyValue > OptionMap