clang-tools  14.0.0git
ClangTidyCheck.cpp
Go to the documentation of this file.
1 //===--- ClangTidyCheck.cpp - 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 #include "ClangTidyCheck.h"
10 #include "llvm/ADT/SmallString.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/Support/Error.h"
13 #include "llvm/Support/YAMLParser.h"
14 
15 namespace clang {
16 namespace tidy {
17 
18 ClangTidyCheck::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());
23 }
24 
25 DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message,
26  DiagnosticIDs::Level Level) {
27  return Context->diag(CheckName, Loc, Message, Level);
28 }
29 
30 DiagnosticBuilder ClangTidyCheck::diag(StringRef Message,
31  DiagnosticIDs::Level Level) {
32  return Context->diag(CheckName, Message, Level);
33 }
34 
35 DiagnosticBuilder
37  DiagnosticIDs::Level Level) const {
38  return Context->configurationDiag(Description, Level);
39 }
40 
41 void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) {
42  // For historical reasons, checks don't implement the MatchFinder run()
43  // callback directly. We keep the run()/check() distinction to avoid interface
44  // churn, and to allow us to add cross-cutting logic in the future.
45  check(Result);
46 }
47 
49  StringRef CheckName, const ClangTidyOptions::OptionMap &CheckOptions,
50  ClangTidyContext *Context)
51  : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions),
52  Context(Context) {}
53 
54 llvm::Optional<std::string>
55 ClangTidyCheck::OptionsView::get(StringRef LocalName) const {
56  const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str());
57  if (Iter != CheckOptions.end())
58  return Iter->getValue().Value;
59  return None;
60 }
61 
62 static ClangTidyOptions::OptionMap::const_iterator
64  StringRef LocalName) {
65  auto IterLocal = Options.find((NamePrefix + LocalName).str());
66  auto IterGlobal = Options.find(LocalName.str());
67  if (IterLocal == Options.end())
68  return IterGlobal;
69  if (IterGlobal == Options.end())
70  return IterLocal;
71  if (IterLocal->getValue().Priority >= IterGlobal->getValue().Priority)
72  return IterLocal;
73  return IterGlobal;
74 }
75 
76 llvm::Optional<std::string>
78  auto Iter = findPriorityOption(CheckOptions, NamePrefix, LocalName);
79  if (Iter != CheckOptions.end())
80  return Iter->getValue().Value;
81  return None;
82 }
83 
84 static Optional<bool> getAsBool(StringRef Value,
85  const llvm::Twine &LookupName) {
86 
87  if (llvm::Optional<bool> Parsed = llvm::yaml::parseBool(Value))
88  return *Parsed;
89  // To maintain backwards compatability, we support parsing numbers as
90  // booleans, even though its not supported in YAML.
91  long long Number;
92  if (!Value.getAsInteger(10, Number))
93  return Number != 0;
94  return None;
95 }
96 
97 template <>
98 llvm::Optional<bool>
99 ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const {
100  if (llvm::Optional<std::string> ValueOr = get(LocalName)) {
101  if (auto Result = getAsBool(*ValueOr, NamePrefix + LocalName))
102  return Result;
103  diagnoseBadBooleanOption(NamePrefix + LocalName, *ValueOr);
104  }
105  return None;
106 }
107 
108 template <>
109 llvm::Optional<bool>
110 ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const {
111  auto Iter = findPriorityOption(CheckOptions, NamePrefix, LocalName);
112  if (Iter != CheckOptions.end()) {
113  if (auto Result = getAsBool(Iter->getValue().Value, Iter->getKey()))
114  return Result;
115  diagnoseBadBooleanOption(Iter->getKey(), Iter->getValue().Value);
116  }
117  return None;
118 }
119 
121  StringRef LocalName,
122  StringRef Value) const {
123  Options[NamePrefix + LocalName.str()] = Value;
124 }
125 
126 void ClangTidyCheck::OptionsView::storeInt(ClangTidyOptions::OptionMap &Options,
127  StringRef LocalName,
128  int64_t Value) const {
129  store(Options, LocalName, llvm::itostr(Value));
130 }
131 
132 template <>
133 void ClangTidyCheck::OptionsView::store<bool>(
134  ClangTidyOptions::OptionMap &Options, StringRef LocalName,
135  bool Value) const {
136  store(Options, LocalName, Value ? StringRef("true") : StringRef("false"));
137 }
138 
139 llvm::Optional<int64_t> ClangTidyCheck::OptionsView::getEnumInt(
140  StringRef LocalName, ArrayRef<NameAndValue> Mapping, bool CheckGlobal,
141  bool IgnoreCase) const {
142  auto Iter = CheckGlobal
143  ? findPriorityOption(CheckOptions, NamePrefix, LocalName)
144  : CheckOptions.find((NamePrefix + LocalName).str());
145  if (Iter == CheckOptions.end())
146  return None;
147 
148  StringRef Value = Iter->getValue().Value;
149  StringRef Closest;
150  unsigned EditDistance = 3;
151  for (const auto &NameAndEnum : Mapping) {
152  if (IgnoreCase) {
153  if (Value.equals_insensitive(NameAndEnum.second))
154  return NameAndEnum.first;
155  } else if (Value.equals(NameAndEnum.second)) {
156  return NameAndEnum.first;
157  } else if (Value.equals_insensitive(NameAndEnum.second)) {
158  Closest = NameAndEnum.second;
159  EditDistance = 0;
160  continue;
161  }
162  unsigned Distance =
163  Value.edit_distance(NameAndEnum.second, true, EditDistance);
164  if (Distance < EditDistance) {
165  EditDistance = Distance;
166  Closest = NameAndEnum.second;
167  }
168  }
169  if (EditDistance < 3)
170  diagnoseBadEnumOption(Iter->getKey().str(), Iter->getValue().Value,
171  Closest);
172  else
173  diagnoseBadEnumOption(Iter->getKey().str(), Iter->getValue().Value);
174  return None;
175 }
176 
177 static constexpr llvm::StringLiteral ConfigWarning(
178  "invalid configuration value '%0' for option '%1'%select{|; expected a "
179  "bool|; expected an integer|; did you mean '%3'?}2");
180 
181 void ClangTidyCheck::OptionsView::diagnoseBadBooleanOption(
182  const Twine &Lookup, StringRef Unparsed) const {
183  SmallString<64> Buffer;
185  << Unparsed << Lookup.toStringRef(Buffer) << 1;
186 }
187 
188 void ClangTidyCheck::OptionsView::diagnoseBadIntegerOption(
189  const Twine &Lookup, StringRef Unparsed) const {
190  SmallString<64> Buffer;
192  << Unparsed << Lookup.toStringRef(Buffer) << 2;
193 }
194 
195 void ClangTidyCheck::OptionsView::diagnoseBadEnumOption(
196  const Twine &Lookup, StringRef Unparsed, StringRef Suggestion) const {
197  SmallString<64> Buffer;
198  auto Diag = Context->configurationDiag(ConfigWarning)
199  << Unparsed << Lookup.toStringRef(Buffer);
200  if (Suggestion.empty())
201  Diag << 0;
202  else
203  Diag << 3 << Suggestion;
204 }
205 
206 std::string ClangTidyCheck::OptionsView::get(StringRef LocalName,
207  StringRef Default) const {
208  if (llvm::Optional<std::string> Val = get(LocalName))
209  return std::move(*Val);
210  return Default.str();
211 }
212 std::string
214  StringRef Default) const {
215  if (llvm::Optional<std::string> Val = getLocalOrGlobal(LocalName))
216  return std::move(*Val);
217  return Default.str();
218 }
219 } // namespace tidy
220 } // namespace clang
Loc
SourceLocation Loc
Definition: KernelNameRestrictionCheck.cpp:45
clang::tidy::ClangTidyOptions::OptionMap
llvm::StringMap< ClangTidyValue > OptionMap
Definition: ClangTidyOptions.h:115
clang::tidy::ClangTidyCheck::ClangTidyCheck
ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context)
Initializes the check with CheckName and Context.
Definition: ClangTidyCheck.cpp:18
clang::tidy::bugprone::Message
static const char Message[]
Definition: ReservedIdentifierCheck.cpp:31
clang::tidy::getAsBool
static Optional< bool > getAsBool(StringRef Value, const llvm::Twine &LookupName)
Definition: ClangTidyCheck.cpp:84
clang::tidy::ConfigWarning
static constexpr llvm::StringLiteral ConfigWarning("invalid configuration value '%0' for option '%1'%select{|; expected a " "bool|; expected an integer|; did you mean '%3'?}2")
clang::tidy::ClangTidyCheck::OptionsView::get
llvm::Optional< std::string > get(StringRef LocalName) const
Read a named option from the Context.
Definition: ClangTidyCheck.cpp:55
Number
unsigned Number
Definition: SourceCodeTests.cpp:95
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidyCheck.h:416
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:76
Description
const char * Description
Definition: Dexp.cpp:361
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
Definition: ClangTidyCheck.cpp:25
clang::tidy::ClangTidyCheck::check
virtual void check(const ast_matchers::MatchFinder::MatchResult &Result)
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: ClangTidyCheck.h:113
clang::tidy::ClangTidyCheck::configurationDiag
DiagnosticBuilder configurationDiag(StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning) const
Adds a diagnostic to report errors in the check's configuration.
Definition: ClangTidyCheck.cpp:36
clang::tidy::ClangTidyCheck::OptionsView::getLocalOrGlobal
llvm::Optional< std::string > getLocalOrGlobal(StringRef LocalName) const
Read a named option from the Context.
Definition: ClangTidyCheck.cpp:77
clang::tidy::findPriorityOption
static ClangTidyOptions::OptionMap::const_iterator findPriorityOption(const ClangTidyOptions::OptionMap &Options, StringRef NamePrefix, StringRef LocalName)
Definition: ClangTidyCheck.cpp:63
clang::tidy::bugprone::model::MixFlags::None
@ None
Mix between the two parameters is not possible.
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::tidy::ClangTidyCheck::OptionsView::store
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.
Definition: ClangTidyCheck.cpp:120
clang::tidy::ClangTidyCheck::OptionsView::OptionsView
OptionsView(StringRef CheckName, const ClangTidyOptions::OptionMap &CheckOptions, ClangTidyContext *Context)
Initializes the instance using CheckName + "." as a prefix.
Definition: ClangTidyCheck.cpp:48
clang::tidy::ClangTidyContext::diag
DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc, StringRef Message, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Report any errors detected using this method.
Definition: ClangTidyDiagnosticConsumer.cpp:186
ClangTidyCheck.h
clang::tidy::ClangTidyContext::configurationDiag
DiagnosticBuilder configurationDiag(StringRef Message, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Report any errors to do with reading the configuration using this method.
Definition: ClangTidyDiagnosticConsumer.cpp:205