clang-tools  11.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 llvm::Expected<std::string>
81  auto IterLocal = CheckOptions.find(NamePrefix + LocalName.str());
82  auto IterGlobal = CheckOptions.find(LocalName.str());
83  if (IterLocal != CheckOptions.end() &&
84  (IterGlobal == CheckOptions.end() ||
85  IterLocal->second.Priority >= IterGlobal->second.Priority))
86  return IterLocal->second.Value;
87  if (IterGlobal != CheckOptions.end())
88  return IterGlobal->second.Value;
89  return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str());
90 }
91 
92 static llvm::Expected<bool> getAsBool(StringRef Value,
93  const llvm::Twine &LookupName) {
94  if (Value == "true")
95  return true;
96  if (Value == "false")
97  return false;
98  bool Result;
99  if (!Value.getAsInteger(10, Result))
100  return Result;
101  return llvm::make_error<UnparseableIntegerOptionError>(LookupName.str(),
102  Value.str(), true);
103 }
104 
105 template <>
106 llvm::Expected<bool>
107 ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName) const {
108  llvm::Expected<std::string> ValueOr = get(LocalName);
109  if (ValueOr)
110  return getAsBool(*ValueOr, NamePrefix + LocalName);
111  return ValueOr.takeError();
112 }
113 
114 template <>
115 bool ClangTidyCheck::OptionsView::get<bool>(StringRef LocalName,
116  bool Default) const {
117  llvm::Expected<bool> ValueOr = get<bool>(LocalName);
118  if (ValueOr)
119  return *ValueOr;
120  logErrToStdErr(ValueOr.takeError());
121  return Default;
122 }
123 
124 template <>
125 llvm::Expected<bool>
126 ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName) const {
127  auto IterLocal = CheckOptions.find(NamePrefix + LocalName.str());
128  auto IterGlobal = CheckOptions.find(LocalName.str());
129  if (IterLocal != CheckOptions.end() &&
130  (IterGlobal == CheckOptions.end() ||
131  IterLocal->second.Priority >= IterGlobal->second.Priority))
132  return getAsBool(IterLocal->second.Value, NamePrefix + LocalName);
133  if (IterGlobal != CheckOptions.end())
134  return getAsBool(IterGlobal->second.Value, llvm::Twine(LocalName));
135  return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str());
136 }
137 
138 template <>
139 bool ClangTidyCheck::OptionsView::getLocalOrGlobal<bool>(StringRef LocalName,
140  bool Default) const {
141  llvm::Expected<bool> ValueOr = getLocalOrGlobal<bool>(LocalName);
142  if (ValueOr)
143  return *ValueOr;
144  logErrToStdErr(ValueOr.takeError());
145  return Default;
146 }
147 
149  StringRef LocalName,
150  StringRef Value) const {
151  Options[NamePrefix + LocalName.str()] = Value;
152 }
153 
155  StringRef LocalName,
156  int64_t Value) const {
157  store(Options, LocalName, llvm::itostr(Value));
158 }
159 
160 llvm::Expected<int64_t> ClangTidyCheck::OptionsView::getEnumInt(
161  StringRef LocalName, ArrayRef<std::pair<StringRef, int64_t>> Mapping,
162  bool CheckGlobal, bool IgnoreCase) {
163  auto Iter = CheckOptions.find((NamePrefix + LocalName).str());
164  if (CheckGlobal && Iter == CheckOptions.end())
165  Iter = CheckOptions.find(LocalName.str());
166  if (Iter == CheckOptions.end())
167  return llvm::make_error<MissingOptionError>((NamePrefix + LocalName).str());
168 
169  StringRef Value = Iter->second.Value;
170  StringRef Closest;
171  unsigned EditDistance = -1;
172  for (const auto &NameAndEnum : Mapping) {
173  if (IgnoreCase) {
174  if (Value.equals_lower(NameAndEnum.first))
175  return NameAndEnum.second;
176  } else if (Value.equals(NameAndEnum.first)) {
177  return NameAndEnum.second;
178  } else if (Value.equals_lower(NameAndEnum.first)) {
179  Closest = NameAndEnum.first;
180  EditDistance = 0;
181  continue;
182  }
183  unsigned Distance = Value.edit_distance(NameAndEnum.first);
184  if (Distance < EditDistance) {
185  EditDistance = Distance;
186  Closest = NameAndEnum.first;
187  }
188  }
189  if (EditDistance < 3)
190  return llvm::make_error<UnparseableEnumOptionError>(
191  Iter->first, Iter->second.Value, std::string(Closest));
192  return llvm::make_error<UnparseableEnumOptionError>(Iter->first,
193  Iter->second.Value);
194 }
195 
196 void ClangTidyCheck::OptionsView::logErrToStdErr(llvm::Error &&Err) {
197  llvm::logAllUnhandledErrors(
198  llvm::handleErrors(std::move(Err),
199  [](const MissingOptionError &) -> llvm::Error {
200  return llvm::Error::success();
201  }),
202  llvm::errs(), "warning: ");
203 }
204 } // namespace tidy
205 } // namespace clang
SourceLocation Loc
&#39;#&#39; location in the include directive
std::string message() const override
std::string message() const override
static constexpr std::pair< StringRef, IdentifierNamingCheck::CaseType > Mapping[]
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.
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.