clang-tools  11.0.0
NarrowingConversionsCheck.cpp
Go to the documentation of this file.
1 //===--- NarrowingConversionsCheck.cpp - clang-tidy------------------------===//
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 
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Type.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "llvm/ADT/APSInt.h"
14 #include "llvm/ADT/SmallString.h"
15 #include "llvm/ADT/SmallVector.h"
16 
17 #include <cstdint>
18 
19 using namespace clang::ast_matchers;
20 
21 namespace clang {
22 namespace tidy {
23 namespace cppcoreguidelines {
24 
25 NarrowingConversionsCheck::NarrowingConversionsCheck(StringRef Name,
26  ClangTidyContext *Context)
27  : ClangTidyCheck(Name, Context),
28  WarnOnFloatingPointNarrowingConversion(
29  Options.get("WarnOnFloatingPointNarrowingConversion", true)),
30  PedanticMode(Options.get("PedanticMode", false)) {}
31 
34  Options.store(Opts, "WarnOnFloatingPointNarrowingConversion",
35  WarnOnFloatingPointNarrowingConversion);
36  Options.store(Opts, "PedanticMode", PedanticMode);
37 }
38 
40  // ceil() and floor() are guaranteed to return integers, even though the type
41  // is not integral.
42  const auto IsCeilFloorCallExpr = expr(callExpr(callee(functionDecl(
43  hasAnyName("::ceil", "::std::ceil", "::floor", "::std::floor")))));
44 
45  // Casts:
46  // i = 0.5;
47  // void f(int); f(0.5);
48  Finder->addMatcher(
49  traverse(
50  ast_type_traits::TK_AsIs,
51  implicitCastExpr(hasImplicitDestinationType(builtinType()),
52  hasSourceExpression(hasType(builtinType())),
53  unless(hasSourceExpression(IsCeilFloorCallExpr)),
54  unless(hasParent(castExpr())),
55  unless(isInTemplateInstantiation()))
56  .bind("cast")),
57  this);
58 
59  // Binary operators:
60  // i += 0.5;
61  Finder->addMatcher(binaryOperator(isAssignmentOperator(),
62  hasLHS(expr(hasType(builtinType()))),
63  hasRHS(expr(hasType(builtinType()))),
64  unless(hasRHS(IsCeilFloorCallExpr)),
65  unless(isInTemplateInstantiation()),
66  // The `=` case generates an implicit cast
67  // which is covered by the previous matcher.
68  unless(hasOperatorName("=")))
69  .bind("binary_op"),
70  this);
71 }
72 
73 static const BuiltinType *getBuiltinType(const Expr &E) {
74  return E.getType().getCanonicalType().getTypePtr()->getAs<BuiltinType>();
75 }
76 
77 static QualType getUnqualifiedType(const Expr &E) {
78  return E.getType().getUnqualifiedType();
79 }
80 
81 static APValue getConstantExprValue(const ASTContext &Ctx, const Expr &E) {
82  llvm::APSInt IntegerConstant;
83  if (E.isIntegerConstantExpr(IntegerConstant, Ctx))
84  return APValue(IntegerConstant);
85  APValue Constant;
86  if (Ctx.getLangOpts().CPlusPlus && E.isCXX11ConstantExpr(Ctx, &Constant))
87  return Constant;
88  return {};
89 }
90 
91 static bool getIntegerConstantExprValue(const ASTContext &Context,
92  const Expr &E, llvm::APSInt &Value) {
93  APValue Constant = getConstantExprValue(Context, E);
94  if (!Constant.isInt())
95  return false;
96  Value = Constant.getInt();
97  return true;
98 }
99 
100 static bool getFloatingConstantExprValue(const ASTContext &Context,
101  const Expr &E, llvm::APFloat &Value) {
102  APValue Constant = getConstantExprValue(Context, E);
103  if (!Constant.isFloat())
104  return false;
105  Value = Constant.getFloat();
106  return true;
107 }
108 
109 namespace {
110 
111 struct IntegerRange {
112  bool Contains(const IntegerRange &From) const {
113  return llvm::APSInt::compareValues(Lower, From.Lower) <= 0 &&
114  llvm::APSInt::compareValues(Upper, From.Upper) >= 0;
115  }
116 
117  bool Contains(const llvm::APSInt &Value) const {
118  return llvm::APSInt::compareValues(Lower, Value) <= 0 &&
119  llvm::APSInt::compareValues(Upper, Value) >= 0;
120  }
121 
122  llvm::APSInt Lower;
123  llvm::APSInt Upper;
124 };
125 
126 } // namespace
127 
128 static IntegerRange createFromType(const ASTContext &Context,
129  const BuiltinType &T) {
130  if (T.isFloatingPoint()) {
131  unsigned PrecisionBits = llvm::APFloatBase::semanticsPrecision(
132  Context.getFloatTypeSemantics(T.desugar()));
133  // Contrary to two's complement integer, floating point values are
134  // symmetric and have the same number of positive and negative values.
135  // The range of valid integers for a floating point value is:
136  // [-2^PrecisionBits, 2^PrecisionBits]
137 
138  // Values are created with PrecisionBits plus two bits:
139  // - One to express the missing negative value of 2's complement
140  // representation.
141  // - One for the sign.
142  llvm::APSInt UpperValue(PrecisionBits + 2, /*isUnsigned*/ false);
143  UpperValue.setBit(PrecisionBits);
144  llvm::APSInt LowerValue(PrecisionBits + 2, /*isUnsigned*/ false);
145  LowerValue.setBit(PrecisionBits);
146  LowerValue.setSignBit();
147  return {LowerValue, UpperValue};
148  }
149  assert(T.isInteger() && "Unexpected builtin type");
150  uint64_t TypeSize = Context.getTypeSize(&T);
151  bool IsUnsignedInteger = T.isUnsignedInteger();
152  return {llvm::APSInt::getMinValue(TypeSize, IsUnsignedInteger),
153  llvm::APSInt::getMaxValue(TypeSize, IsUnsignedInteger)};
154 }
155 
156 static bool isWideEnoughToHold(const ASTContext &Context,
157  const BuiltinType &FromType,
158  const BuiltinType &ToType) {
159  IntegerRange FromIntegerRange = createFromType(Context, FromType);
160  IntegerRange ToIntegerRange = createFromType(Context, ToType);
161  return ToIntegerRange.Contains(FromIntegerRange);
162 }
163 
164 static bool isWideEnoughToHold(const ASTContext &Context,
165  const llvm::APSInt &IntegerConstant,
166  const BuiltinType &ToType) {
167  IntegerRange ToIntegerRange = createFromType(Context, ToType);
168  return ToIntegerRange.Contains(IntegerConstant);
169 }
170 
171 static llvm::SmallString<64> getValueAsString(const llvm::APSInt &Value,
172  uint64_t HexBits) {
173  llvm::SmallString<64> Str;
174  Value.toString(Str, 10);
175  if (HexBits > 0) {
176  Str.append(" (0x");
177  llvm::SmallString<32> HexValue;
178  Value.toStringUnsigned(HexValue, 16);
179  for (size_t I = HexValue.size(); I < (HexBits / 4); ++I)
180  Str.append("0");
181  Str.append(HexValue);
182  Str.append(")");
183  }
184  return Str;
185 }
186 
187 void NarrowingConversionsCheck::diagNarrowType(SourceLocation SourceLoc,
188  const Expr &Lhs,
189  const Expr &Rhs) {
190  diag(SourceLoc, "narrowing conversion from %0 to %1")
191  << getUnqualifiedType(Rhs) << getUnqualifiedType(Lhs);
192 }
193 
194 void NarrowingConversionsCheck::diagNarrowTypeToSignedInt(
195  SourceLocation SourceLoc, const Expr &Lhs, const Expr &Rhs) {
196  diag(SourceLoc, "narrowing conversion from %0 to signed type %1 is "
197  "implementation-defined")
198  << getUnqualifiedType(Rhs) << getUnqualifiedType(Lhs);
199 }
200 
201 void NarrowingConversionsCheck::diagNarrowIntegerConstant(
202  SourceLocation SourceLoc, const Expr &Lhs, const Expr &Rhs,
203  const llvm::APSInt &Value) {
204  diag(SourceLoc,
205  "narrowing conversion from constant value %0 of type %1 to %2")
206  << getValueAsString(Value, /*NoHex*/ 0) << getUnqualifiedType(Rhs)
207  << getUnqualifiedType(Lhs);
208 }
209 
210 void NarrowingConversionsCheck::diagNarrowIntegerConstantToSignedInt(
211  SourceLocation SourceLoc, const Expr &Lhs, const Expr &Rhs,
212  const llvm::APSInt &Value, const uint64_t HexBits) {
213  diag(SourceLoc, "narrowing conversion from constant value %0 of type %1 "
214  "to signed type %2 is implementation-defined")
215  << getValueAsString(Value, HexBits) << getUnqualifiedType(Rhs)
216  << getUnqualifiedType(Lhs);
217 }
218 
219 void NarrowingConversionsCheck::diagNarrowConstant(SourceLocation SourceLoc,
220  const Expr &Lhs,
221  const Expr &Rhs) {
222  diag(SourceLoc, "narrowing conversion from constant %0 to %1")
223  << getUnqualifiedType(Rhs) << getUnqualifiedType(Lhs);
224 }
225 
226 void NarrowingConversionsCheck::diagConstantCast(SourceLocation SourceLoc,
227  const Expr &Lhs,
228  const Expr &Rhs) {
229  diag(SourceLoc, "constant value should be of type of type %0 instead of %1")
230  << getUnqualifiedType(Lhs) << getUnqualifiedType(Rhs);
231 }
232 
233 void NarrowingConversionsCheck::diagNarrowTypeOrConstant(
234  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
235  const Expr &Rhs) {
236  APValue Constant = getConstantExprValue(Context, Rhs);
237  if (Constant.isInt())
238  return diagNarrowIntegerConstant(SourceLoc, Lhs, Rhs, Constant.getInt());
239  if (Constant.isFloat())
240  return diagNarrowConstant(SourceLoc, Lhs, Rhs);
241  return diagNarrowType(SourceLoc, Lhs, Rhs);
242 }
243 
244 void NarrowingConversionsCheck::handleIntegralCast(const ASTContext &Context,
245  SourceLocation SourceLoc,
246  const Expr &Lhs,
247  const Expr &Rhs) {
248  const BuiltinType *ToType = getBuiltinType(Lhs);
249  // From [conv.integral]p7.3.8:
250  // Conversions to unsigned integer is well defined so no warning is issued.
251  // "The resulting value is the smallest unsigned value equal to the source
252  // value modulo 2^n where n is the number of bits used to represent the
253  // destination type."
254  if (ToType->isUnsignedInteger())
255  return;
256  const BuiltinType *FromType = getBuiltinType(Rhs);
257  llvm::APSInt IntegerConstant;
258  if (getIntegerConstantExprValue(Context, Rhs, IntegerConstant)) {
259  if (!isWideEnoughToHold(Context, IntegerConstant, *ToType))
260  diagNarrowIntegerConstantToSignedInt(SourceLoc, Lhs, Rhs, IntegerConstant,
261  Context.getTypeSize(FromType));
262  return;
263  }
264  if (!isWideEnoughToHold(Context, *FromType, *ToType))
265  diagNarrowTypeToSignedInt(SourceLoc, Lhs, Rhs);
266 }
267 
268 void NarrowingConversionsCheck::handleIntegralToBoolean(
269  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
270  const Expr &Rhs) {
271  // Conversion from Integral to Bool value is well defined.
272 
273  // We keep this function (even if it is empty) to make sure that
274  // handleImplicitCast and handleBinaryOperator are symmetric in their behavior
275  // and handle the same cases.
276 }
277 
278 void NarrowingConversionsCheck::handleIntegralToFloating(
279  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
280  const Expr &Rhs) {
281  const BuiltinType *ToType = getBuiltinType(Lhs);
282  llvm::APSInt IntegerConstant;
283  if (getIntegerConstantExprValue(Context, Rhs, IntegerConstant)) {
284  if (!isWideEnoughToHold(Context, IntegerConstant, *ToType))
285  diagNarrowIntegerConstant(SourceLoc, Lhs, Rhs, IntegerConstant);
286  return;
287  }
288  const BuiltinType *FromType = getBuiltinType(Rhs);
289  if (!isWideEnoughToHold(Context, *FromType, *ToType))
290  diagNarrowType(SourceLoc, Lhs, Rhs);
291 }
292 
293 void NarrowingConversionsCheck::handleFloatingToIntegral(
294  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
295  const Expr &Rhs) {
296  llvm::APFloat FloatConstant(0.0);
297 
298  // We always warn when Rhs is non-constexpr.
299  if (!getFloatingConstantExprValue(Context, Rhs, FloatConstant))
300  return diagNarrowType(SourceLoc, Lhs, Rhs);
301 
302  QualType DestType = Lhs.getType();
303  unsigned DestWidth = Context.getIntWidth(DestType);
304  bool DestSigned = DestType->isSignedIntegerOrEnumerationType();
305  llvm::APSInt Result = llvm::APSInt(DestWidth, !DestSigned);
306  bool IsExact = false;
307  bool Overflows = FloatConstant.convertToInteger(
308  Result, llvm::APFloat::rmTowardZero, &IsExact) &
309  llvm::APFloat::opInvalidOp;
310  // We warn iff the constant floating point value is not exactly representable.
311  if (Overflows || !IsExact)
312  return diagNarrowConstant(SourceLoc, Lhs, Rhs);
313 
314  if (PedanticMode)
315  return diagConstantCast(SourceLoc, Lhs, Rhs);
316 }
317 
318 void NarrowingConversionsCheck::handleFloatingToBoolean(
319  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
320  const Expr &Rhs) {
321  return diagNarrowTypeOrConstant(Context, SourceLoc, Lhs, Rhs);
322 }
323 
324 void NarrowingConversionsCheck::handleBooleanToSignedIntegral(
325  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
326  const Expr &Rhs) {
327  // Conversion from Bool to SignedIntegral value is well defined.
328 
329  // We keep this function (even if it is empty) to make sure that
330  // handleImplicitCast and handleBinaryOperator are symmetric in their behavior
331  // and handle the same cases.
332 }
333 
334 void NarrowingConversionsCheck::handleFloatingCast(const ASTContext &Context,
335  SourceLocation SourceLoc,
336  const Expr &Lhs,
337  const Expr &Rhs) {
338  if (WarnOnFloatingPointNarrowingConversion) {
339  const BuiltinType *ToType = getBuiltinType(Lhs);
340  APValue Constant = getConstantExprValue(Context, Rhs);
341  if (Constant.isFloat()) {
342  // From [dcl.init.list]p7.2:
343  // Floating point constant narrowing only takes place when the value is
344  // not within destination range. We convert the value to the destination
345  // type and check if the resulting value is infinity.
346  llvm::APFloat Tmp = Constant.getFloat();
347  bool UnusedLosesInfo;
348  Tmp.convert(Context.getFloatTypeSemantics(ToType->desugar()),
349  llvm::APFloatBase::rmNearestTiesToEven, &UnusedLosesInfo);
350  if (Tmp.isInfinity())
351  diagNarrowConstant(SourceLoc, Lhs, Rhs);
352  return;
353  }
354  const BuiltinType *FromType = getBuiltinType(Rhs);
355  if (ToType->getKind() < FromType->getKind())
356  diagNarrowType(SourceLoc, Lhs, Rhs);
357  }
358 }
359 
360 void NarrowingConversionsCheck::handleBinaryOperator(const ASTContext &Context,
361  SourceLocation SourceLoc,
362  const Expr &Lhs,
363  const Expr &Rhs) {
364  assert(!Lhs.isInstantiationDependent() && !Rhs.isInstantiationDependent() &&
365  "Dependent types must be check before calling this function");
366  const BuiltinType *LhsType = getBuiltinType(Lhs);
367  const BuiltinType *RhsType = getBuiltinType(Rhs);
368  if (RhsType == nullptr || LhsType == nullptr)
369  return;
370  if (RhsType->getKind() == BuiltinType::Bool && LhsType->isSignedInteger())
371  return handleBooleanToSignedIntegral(Context, SourceLoc, Lhs, Rhs);
372  if (RhsType->isInteger() && LhsType->getKind() == BuiltinType::Bool)
373  return handleIntegralToBoolean(Context, SourceLoc, Lhs, Rhs);
374  if (RhsType->isInteger() && LhsType->isFloatingPoint())
375  return handleIntegralToFloating(Context, SourceLoc, Lhs, Rhs);
376  if (RhsType->isInteger() && LhsType->isInteger())
377  return handleIntegralCast(Context, SourceLoc, Lhs, Rhs);
378  if (RhsType->isFloatingPoint() && LhsType->getKind() == BuiltinType::Bool)
379  return handleFloatingToBoolean(Context, SourceLoc, Lhs, Rhs);
380  if (RhsType->isFloatingPoint() && LhsType->isInteger())
381  return handleFloatingToIntegral(Context, SourceLoc, Lhs, Rhs);
382  if (RhsType->isFloatingPoint() && LhsType->isFloatingPoint())
383  return handleFloatingCast(Context, SourceLoc, Lhs, Rhs);
384 }
385 
386 bool NarrowingConversionsCheck::handleConditionalOperator(
387  const ASTContext &Context, const Expr &Lhs, const Expr &Rhs) {
388  if (const auto *CO = llvm::dyn_cast<ConditionalOperator>(&Rhs)) {
389  // We have an expression like so: `output = cond ? lhs : rhs`
390  // From the point of view of narrowing conversion we treat it as two
391  // expressions `output = lhs` and `output = rhs`.
392  handleBinaryOperator(Context, CO->getLHS()->getExprLoc(), Lhs,
393  *CO->getLHS());
394  handleBinaryOperator(Context, CO->getRHS()->getExprLoc(), Lhs,
395  *CO->getRHS());
396  return true;
397  }
398  return false;
399 }
400 
401 void NarrowingConversionsCheck::handleImplicitCast(
402  const ASTContext &Context, const ImplicitCastExpr &Cast) {
403  if (Cast.getExprLoc().isMacroID())
404  return;
405  const Expr &Lhs = Cast;
406  const Expr &Rhs = *Cast.getSubExpr();
407  if (Lhs.isInstantiationDependent() || Rhs.isInstantiationDependent())
408  return;
409  if (handleConditionalOperator(Context, Lhs, Rhs))
410  return;
411  SourceLocation SourceLoc = Lhs.getExprLoc();
412  switch (Cast.getCastKind()) {
413  case CK_BooleanToSignedIntegral:
414  return handleBooleanToSignedIntegral(Context, SourceLoc, Lhs, Rhs);
415  case CK_IntegralToBoolean:
416  return handleIntegralToBoolean(Context, SourceLoc, Lhs, Rhs);
417  case CK_IntegralToFloating:
418  return handleIntegralToFloating(Context, SourceLoc, Lhs, Rhs);
419  case CK_IntegralCast:
420  return handleIntegralCast(Context, SourceLoc, Lhs, Rhs);
421  case CK_FloatingToBoolean:
422  return handleFloatingToBoolean(Context, SourceLoc, Lhs, Rhs);
423  case CK_FloatingToIntegral:
424  return handleFloatingToIntegral(Context, SourceLoc, Lhs, Rhs);
425  case CK_FloatingCast:
426  return handleFloatingCast(Context, SourceLoc, Lhs, Rhs);
427  default:
428  break;
429  }
430 }
431 
432 void NarrowingConversionsCheck::handleBinaryOperator(const ASTContext &Context,
433  const BinaryOperator &Op) {
434  if (Op.getBeginLoc().isMacroID())
435  return;
436  const Expr &Lhs = *Op.getLHS();
437  const Expr &Rhs = *Op.getRHS();
438  if (Lhs.isInstantiationDependent() || Rhs.isInstantiationDependent())
439  return;
440  if (handleConditionalOperator(Context, Lhs, Rhs))
441  return;
442  handleBinaryOperator(Context, Rhs.getBeginLoc(), Lhs, Rhs);
443 }
444 
445 void NarrowingConversionsCheck::check(const MatchFinder::MatchResult &Result) {
446  if (const auto *Op = Result.Nodes.getNodeAs<BinaryOperator>("binary_op"))
447  return handleBinaryOperator(*Result.Context, *Op);
448  if (const auto *Cast = Result.Nodes.getNodeAs<ImplicitCastExpr>("cast"))
449  return handleImplicitCast(*Result.Context, *Cast);
450  llvm_unreachable("must be binary operator or cast expression");
451 }
452 } // namespace cppcoreguidelines
453 } // namespace tidy
454 } // namespace clang
Lower
llvm::APSInt Lower
Definition: NarrowingConversionsCheck.cpp:122
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
clang::tidy::cppcoreguidelines::isWideEnoughToHold
static bool isWideEnoughToHold(const ASTContext &Context, const BuiltinType &FromType, const BuiltinType &ToType)
Definition: NarrowingConversionsCheck.cpp:156
Upper
llvm::APSInt Upper
Definition: NarrowingConversionsCheck.cpp:123
clang::tidy::cppcoreguidelines::NarrowingConversionsCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: NarrowingConversionsCheck.cpp:445
Ctx
Context Ctx
Definition: TUScheduler.cpp:324
NarrowingConversionsCheck.h
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidyCheck.h:114
clang::tidy::cppcoreguidelines::createFromType
static IntegerRange createFromType(const ASTContext &Context, const BuiltinType &T)
Definition: NarrowingConversionsCheck.cpp:128
clang::ast_matchers
Definition: AbseilMatcher.h:14
clang::tidy::cppcoreguidelines::getBuiltinType
static const BuiltinType * getBuiltinType(const Expr &E)
Definition: NarrowingConversionsCheck.cpp:73
clang::tidy::cppcoreguidelines::NarrowingConversionsCheck::storeOptions
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Definition: NarrowingConversionsCheck.cpp:32
clang::clangd::CompletionItemKind::Constant
clang::tidy::cppcoreguidelines::getConstantExprValue
static APValue getConstantExprValue(const ASTContext &Ctx, const Expr &E)
Definition: NarrowingConversionsCheck.cpp:81
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidyCheck.h:471
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:76
clang::tidy::cppcoreguidelines::getUnqualifiedType
static QualType getUnqualifiedType(const Expr &E)
Definition: NarrowingConversionsCheck.cpp:77
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
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:55
clang::tidy::cppcoreguidelines::getFloatingConstantExprValue
static bool getFloatingConstantExprValue(const ASTContext &Context, const Expr &E, llvm::APFloat &Value)
Definition: NarrowingConversionsCheck.cpp:100
clang::tidy::cppcoreguidelines::getIntegerConstantExprValue
static bool getIntegerConstantExprValue(const ASTContext &Context, const Expr &E, llvm::APSInt &Value)
Definition: NarrowingConversionsCheck.cpp:91
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:152
clang::tidy::cppcoreguidelines::getValueAsString
static llvm::SmallString< 64 > getValueAsString(const llvm::APSInt &Value, uint64_t HexBits)
Definition: NarrowingConversionsCheck.cpp:171
clang::tidy::cppcoreguidelines::NarrowingConversionsCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: NarrowingConversionsCheck.cpp:39
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, ClangTidyValue > OptionMap
Definition: ClangTidyOptions.h:111