10#include "llvm/ADT/StringRef.h"
11#include "llvm/ADT/StringSet.h"
12#include "llvm/Support/YAMLParser.h"
18ClangTidyCheck::ClangTidyCheck(StringRef CheckName,
ClangTidyContext *Context)
19 : CheckName(CheckName), Context(Context),
20 Options(CheckName, Context->getOptions().CheckOptions, Context) {
21 assert(Context !=
nullptr);
22 assert(!CheckName.empty());
25DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc,
26 StringRef Description,
27 DiagnosticIDs::Level Level) {
28 return Context->diag(CheckName, Loc, Description, Level);
31DiagnosticBuilder ClangTidyCheck::diag(StringRef Description,
32 DiagnosticIDs::Level Level) {
33 return Context->diag(CheckName, Description, Level);
37ClangTidyCheck::configurationDiag(StringRef Description,
38 DiagnosticIDs::Level Level)
const {
39 return Context->configurationDiag(Description, Level);
42void ClangTidyCheck::run(
const ast_matchers::MatchFinder::MatchResult &Result) {
49ClangTidyCheck::OptionsView::OptionsView(
51 ClangTidyContext *Context)
52 : NamePrefix((CheckName +
".").str()), CheckOptions(CheckOptions),
55std::optional<StringRef>
56ClangTidyCheck::OptionsView::get(StringRef LocalName)
const {
57 if (Context->getOptionsCollector())
58 Context->getOptionsCollector()->insert((NamePrefix + LocalName).str());
59 const auto &Iter = CheckOptions.find((NamePrefix + LocalName).str());
60 if (Iter != CheckOptions.end())
61 return StringRef(Iter->getValue().Value);
65static ClangTidyOptions::OptionMap::const_iterator
67 StringRef NamePrefix, StringRef LocalName,
71 Collector->insert((NamePrefix + LocalName).str());
72 Collector->insert(LocalName);
74 auto IterLocal = Options.find((NamePrefix + LocalName).str());
75 auto IterGlobal = Options.find(LocalName);
76 if (IterLocal == Options.end())
78 if (IterGlobal == Options.end())
80 if (IterLocal->getValue().Priority >= IterGlobal->getValue().Priority)
85std::optional<StringRef>
86ClangTidyCheck::OptionsView::getLocalOrGlobal(StringRef LocalName)
const {
87 auto Iter = findPriorityOption(CheckOptions, NamePrefix, LocalName, Context);
88 if (Iter != CheckOptions.end())
89 return StringRef(Iter->getValue().Value);
93static std::optional<bool>
getAsBool(StringRef Value,
94 const llvm::Twine &LookupName) {
96 if (std::optional<bool> Parsed = llvm::yaml::parseBool(Value))
100 long long Number = 0;
101 if (!Value.getAsInteger(10, Number))
108ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName)
const {
109 if (std::optional<StringRef> ValueOr = get(LocalName)) {
110 if (
auto Result = getAsBool(*ValueOr, NamePrefix + LocalName))
112 diagnoseBadBooleanOption(NamePrefix + LocalName, *ValueOr);
119ClangTidyCheck::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));
141void ClangTidyCheck::OptionsView::storeUnsigned(
143 uint64_t Value)
const {
144 store(Options, LocalName, llvm::utostr(Value));
148void ClangTidyCheck::OptionsView::store<bool>(
151 store(Options, LocalName, Value ? StringRef(
"true") : StringRef(
"false"));
154std::optional<int64_t>
155ClangTidyCheck::OptionsView::getEnumInt(StringRef LocalName,
156 ArrayRef<NameAndValue> Mapping,
157 bool CheckGlobal)
const {
158 if (!CheckGlobal && Context->getOptionsCollector())
159 Context->getOptionsCollector()->insert((NamePrefix + LocalName).str());
162 : CheckOptions.find((NamePrefix + LocalName).str());
163 if (Iter == CheckOptions.end())
166 StringRef Value = Iter->getValue().Value;
168 unsigned EditDistance = 3;
169 for (
const auto &NameAndEnum : Mapping) {
170 if (Value == NameAndEnum.second) {
171 return NameAndEnum.first;
173 if (Value.equals_insensitive(NameAndEnum.second)) {
174 Closest = NameAndEnum.second;
179 Value.edit_distance(NameAndEnum.second,
true, EditDistance);
180 if (Distance < EditDistance) {
181 EditDistance = Distance;
182 Closest = NameAndEnum.second;
185 if (EditDistance < 3)
186 diagnoseBadEnumOption(Iter->getKey(), Iter->getValue().Value, Closest);
188 diagnoseBadEnumOption(Iter->getKey(), Iter->getValue().Value);
193 "invalid configuration value '%0' for option '%1'%select{|; expected a "
194 "bool|; expected an integer|; did you mean '%3'?}2");
196void ClangTidyCheck::OptionsView::diagnoseBadBooleanOption(
197 const Twine &Lookup, StringRef Unparsed)
const {
198 SmallString<64> Buffer;
200 << Unparsed << Lookup.toStringRef(Buffer) << 1;
203void ClangTidyCheck::OptionsView::diagnoseBadIntegerOption(
204 const Twine &Lookup, StringRef Unparsed)
const {
205 SmallString<64> Buffer;
206 Context->configurationDiag(ConfigWarning)
207 << Unparsed << Lookup.toStringRef(Buffer) << 2;
210void ClangTidyCheck::OptionsView::diagnoseBadEnumOption(
211 const Twine &Lookup, StringRef Unparsed, StringRef Suggestion)
const {
212 SmallString<64> Buffer;
213 auto Diag = Context->configurationDiag(ConfigWarning)
214 << Unparsed << Lookup.toStringRef(Buffer);
215 if (Suggestion.empty())
218 Diag << 3 << Suggestion;
221StringRef ClangTidyCheck::OptionsView::get(StringRef LocalName,
222 StringRef Default)
const {
223 return get(LocalName).value_or(Default);
227ClangTidyCheck::OptionsView::getLocalOrGlobal(StringRef LocalName,
228 StringRef Default)
const {
229 return getLocalOrGlobal(LocalName).value_or(Default);
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
llvm::StringSet * getOptionsCollector() const
bool check(llvm::StringRef File, const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts)
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, ClangTidyContext *Context)
static std::optional< bool > getAsBool(StringRef Value, const llvm::Twine &LookupName)
llvm::StringMap< ClangTidyValue > OptionMap
llvm::StringMap< ClangTidyValue > OptionMap