clang-tools  12.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/raw_ostream.h"
14 
15 namespace clang {
16 namespace tidy {
17 
21 
22 std::string MissingOptionError::message() const {
23  llvm::SmallString<128> Buffer;
24  llvm::raw_svector_ostream Output(Buffer);
25  Output << "option not found '" << OptionName << '\'';
26  return std::string(Buffer);
27 }
28 
30  llvm::SmallString<128> Buffer;
31  llvm::raw_svector_ostream Output(Buffer);
32  Output << "invalid configuration value '" << LookupValue << "' for option '"
33  << LookupName << '\'';
34  if (SuggestedValue)
35  Output << "; did you mean '" << *SuggestedValue << "'?";
36  return std::string(Buffer);
37 }
38 
40  llvm::SmallString<128> Buffer;
41  llvm::raw_svector_ostream Output(Buffer);
42  Output << "invalid configuration value '" << LookupValue << "' for option '"
43  << LookupName << "'; expected "
44  << (IsBoolean ? "a bool" : "an integer value");
45  return std::string(Buffer);
46 }
47 
48 ClangTidyCheck::ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context)
49  : CheckName(CheckName), Context(Context),
50  Options(CheckName, Context->getOptions().CheckOptions) {
51  assert(Context != nullptr);
52  assert(!CheckName.empty());
53 }
54 
55 DiagnosticBuilder ClangTidyCheck::diag(SourceLocation Loc, StringRef Message,
56  DiagnosticIDs::Level Level) {
57  return Context->diag(CheckName, Loc, Message, Level);
58 }
59 
60 void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) {
61  // For historical reasons, checks don't implement the MatchFinder run()
62  // callback directly. We keep the run()/check() distinction to avoid interface
63  // churn, and to allow us to add cross-cutting logic in the future.
64  check(Result);
65 }
66 
68  const ClangTidyOptions::OptionMap &CheckOptions)
69  : NamePrefix(CheckName.str() + "."), CheckOptions(CheckOptions) {}
70 
71 llvm::Expected<std::string>
72 ClangTidyCheck::OptionsView::get(StringRef LocalName) const {
73  const auto &Iter = CheckOptions.find(NamePrefix + LocalName.str());
74  if (Iter != CheckOptions.end())
75  return Iter->second.Value;
76  return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str());
77 }
78 
79 static ClangTidyOptions::OptionMap::const_iterator
81  StringRef LocalName) {
82  auto IterLocal = Options.find((NamePrefix + LocalName).str());
83  auto IterGlobal = Options.find(LocalName.str());
84  if (IterLocal == Options.end())
85  return IterGlobal;
86  if (IterGlobal == Options.end())
87  return IterLocal;
88  if (IterLocal->second.Priority >= IterGlobal->second.Priority)
89  return IterLocal;
90  return IterGlobal;
91 }
92 
93 llvm::Expected<std::string>
95  auto Iter = findPriorityOption(CheckOptions, NamePrefix, LocalName);
96  if (Iter != CheckOptions.end())
97  return Iter->second.Value;
98  return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str());
99 }
100 
101 static llvm::Expected<bool> getAsBool(StringRef Value,
102  const llvm::Twine &LookupName) {
103  if (Value == "true")
104  return true;
105  if (Value == "false")
106  return false;
107  bool Result;
108  if (!Value.getAsInteger(10, Result))
109  return Result;
110  return llvm::make_error<UnparseableIntegerOptionError>(LookupName.str(),
111  Value.str(), true);
112 }
113 
114 template <>
115 llvm::Expected<bool>
116 ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const {
117  llvm::Expected<std::string> ValueOr = get(LocalName);
118  if (ValueOr)
119  return getAsBool(*ValueOr, NamePrefix + LocalName);
120  return ValueOr.takeError();
121 }
122 
123 template <>
124 bool ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName,
125  bool Default) const {
126  llvm::Expected<bool> ValueOr = get<bool>(LocalName);
127  if (ValueOr)
128  return *ValueOr;
129  logErrToStdErr(ValueOr.takeError());
130  return Default;
131 }
132 
133 template <>
134 llvm::Expected<bool>
135 ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const {
136  auto Iter = findPriorityOption(CheckOptions, NamePrefix, LocalName);
137  if (Iter != CheckOptions.end())
138  return getAsBool(Iter->second.Value, Iter->first);
139  return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str());
140 }
141 
142 template <>
143 bool ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName,
144  bool Default) const {
145  llvm::Expected<bool> ValueOr = getLocalOrGlobal<bool>(LocalName);
146  if (ValueOr)
147  return *ValueOr;
148  logErrToStdErr(ValueOr.takeError());
149  return Default;
150 }
151 
153  StringRef LocalName,
154  StringRef Value) const {
155  Options[NamePrefix + LocalName.str()] = Value;
156 }
157 
158 void ClangTidyCheck::OptionsView::storeInt(ClangTidyOptions::OptionMap &Options,
159  StringRef LocalName,
160  int64_t Value) const {
161  store(Options, LocalName, llvm::itostr(Value));
162 }
163 
164 template <>
165 void ClangTidyCheck::OptionsView::store<bool>(
166  ClangTidyOptions::OptionMap &Options, StringRef LocalName,
167  bool Value) const {
168  store(Options, LocalName, Value ? StringRef("true") : StringRef("false"));
169 }
170 
171 llvm::Expected<int64_t>
172 ClangTidyCheck::OptionsView::getEnumInt(StringRef LocalName,
173  ArrayRef<NameAndValue> Mapping,
174  bool CheckGlobal, bool IgnoreCase) {
175  auto Iter = CheckGlobal
176  ? findPriorityOption(CheckOptions, NamePrefix, LocalName)
177  : CheckOptions.find((NamePrefix + LocalName).str());
178  if (Iter == CheckOptions.end())
179  return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str());
180 
181  StringRef Value = Iter->second.Value;
182  StringRef Closest;
183  unsigned EditDistance = -1;
184  for (const auto &NameAndEnum : Mapping) {
185  if (IgnoreCase) {
186  if (Value.equals_lower(NameAndEnum.second))
187  return NameAndEnum.first;
188  } else if (Value.equals(NameAndEnum.second)) {
189  return NameAndEnum.first;
190  } else if (Value.equals_lower(NameAndEnum.second)) {
191  Closest = NameAndEnum.second;
192  EditDistance = 0;
193  continue;
194  }
195  unsigned Distance = Value.edit_distance(NameAndEnum.second);
196  if (Distance < EditDistance) {
197  EditDistance = Distance;
198  Closest = NameAndEnum.second;
199  }
200  }
201  if (EditDistance < 3)
202  return llvm::make_error<UnparseableEnumOptionError>(
203  Iter->first, Iter->second.Value, std::string(Closest));
204  return llvm::make_error<UnparseableEnumOptionError>(Iter->first,
205  Iter->second.Value);
206 }
207 
208 void ClangTidyCheck::OptionsView::logErrToStdErr(llvm::Error &&Err) {
209  llvm::logAllUnhandledErrors(
210  llvm::handleErrors(std::move(Err),
211  [](const MissingOptionError &) -> llvm::Error {
212  return llvm::Error::success();
213  }),
214  llvm::errs(), "warning: ");
215 }
216 } // namespace tidy
217 } // namespace clang
SourceLocation Loc
&#39;#&#39; location in the include directive
std::string message() const override
std::string message() const override
llvm::Expected< std::string > get(StringRef LocalName) const
Read a named option from the Context.
std::string Output
Definition: TraceTests.cpp:161
void handleErrors(llvm::ArrayRef< ClangTidyError > Errors, ClangTidyContext &Context, bool Fix, unsigned &WarningsAsErrorsCount, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > BaseFS)
Displays the found Errors to the users.
Definition: ClangTidy.cpp:576
DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc, StringRef Message, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Report any errors detected using this method.
llvm::Expected< std::string > 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.
static llvm::Expected< bool > getAsBool(StringRef Value, const llvm::Twine &LookupName)
ClangTidyCheck(StringRef CheckName, ClangTidyContext *Context)
Initializes the check with CheckName and Context.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
OptionsView(StringRef CheckName, const ClangTidyOptions::OptionMap &CheckOptions)
Initializes the instance using CheckName + "." as a prefix.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
static ClangTidyOptions::OptionMap::const_iterator findPriorityOption(const ClangTidyOptions::OptionMap &Options, StringRef NamePrefix, StringRef LocalName)
std::string message() const override
std::map< std::string, ClangTidyValue > OptionMap
virtual void check(const ast_matchers::MatchFinder::MatchResult &Result)
ClangTidyChecks that register ASTMatchers should do the actual work in here.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check&#39;s name.