clang-tools  14.0.0git
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 "../utils/OptionsUtils.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/AST/Expr.h"
13 #include "clang/AST/Type.h"
14 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 #include "clang/ASTMatchers/ASTMatchers.h"
16 #include "llvm/ADT/APSInt.h"
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/ADT/SmallVector.h"
19 
20 #include <cstdint>
21 
22 using namespace clang::ast_matchers;
23 
24 namespace clang {
25 namespace tidy {
26 namespace cppcoreguidelines {
27 namespace {
28 auto hasAnyListedName(const std::string &Names) {
29  const std::vector<std::string> NameList =
31  return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end()));
32 }
33 } // namespace
34 
35 NarrowingConversionsCheck::NarrowingConversionsCheck(StringRef Name,
36  ClangTidyContext *Context)
37  : ClangTidyCheck(Name, Context),
38  WarnOnIntegerNarrowingConversion(
39  Options.get("WarnOnIntegerNarrowingConversion", true)),
40  WarnOnFloatingPointNarrowingConversion(
41  Options.get("WarnOnFloatingPointNarrowingConversion", true)),
42  WarnWithinTemplateInstantiation(
43  Options.get("WarnWithinTemplateInstantiation", false)),
44  WarnOnEquivalentBitWidth(Options.get("WarnOnEquivalentBitWidth", true)),
45  IgnoreConversionFromTypes(Options.get("IgnoreConversionFromTypes", "")),
46  PedanticMode(Options.get("PedanticMode", false)) {}
47 
50  Options.store(Opts, "WarnOnIntegerNarrowingConversion",
51  WarnOnIntegerNarrowingConversion);
52  Options.store(Opts, "WarnOnFloatingPointNarrowingConversion",
53  WarnOnFloatingPointNarrowingConversion);
54  Options.store(Opts, "WarnWithinTemplateInstantiation",
55  WarnWithinTemplateInstantiation);
56  Options.store(Opts, "WarnOnEquivalentBitWidth", WarnOnEquivalentBitWidth);
57  Options.store(Opts, "IgnoreConversionFromTypes", IgnoreConversionFromTypes);
58  Options.store(Opts, "PedanticMode", PedanticMode);
59 }
60 
62  // ceil() and floor() are guaranteed to return integers, even though the type
63  // is not integral.
64  const auto IsCeilFloorCallExpr = expr(callExpr(callee(functionDecl(
65  hasAnyName("::ceil", "::std::ceil", "::floor", "::std::floor")))));
66 
67  // We may want to exclude other types from the checks, such as `size_type`
68  // and `difference_type`. These are often used to count elements, represented
69  // in 64 bits and assigned to `int`. Rarely are people counting >2B elements.
70  const auto IsConversionFromIgnoredType =
71  hasType(namedDecl(hasAnyListedName(IgnoreConversionFromTypes)));
72 
73  // `IsConversionFromIgnoredType` will ignore narrowing calls from those types,
74  // but not expressions that are promoted to an ignored type as a result of a
75  // binary expression with one of those types.
76  // For example, it will continue to reject:
77  // `int narrowed = int_value + container.size()`.
78  // We attempt to address common incidents of compound expressions with
79  // `IsIgnoredTypeTwoLevelsDeep`, allowing binary expressions that have one
80  // operand of the ignored types and the other operand of another integer type.
81  const auto IsIgnoredTypeTwoLevelsDeep =
82  anyOf(IsConversionFromIgnoredType,
83  binaryOperator(hasOperands(IsConversionFromIgnoredType,
84  hasType(isInteger()))));
85 
86  // Casts:
87  // i = 0.5;
88  // void f(int); f(0.5);
89  Finder->addMatcher(
90  traverse(TK_AsIs, implicitCastExpr(
91  hasImplicitDestinationType(
92  hasUnqualifiedDesugaredType(builtinType())),
93  hasSourceExpression(hasType(
94  hasUnqualifiedDesugaredType(builtinType()))),
95  unless(hasSourceExpression(IsCeilFloorCallExpr)),
96  unless(hasParent(castExpr())),
97  WarnWithinTemplateInstantiation
98  ? stmt()
99  : stmt(unless(isInTemplateInstantiation())),
100  IgnoreConversionFromTypes.empty()
101  ? castExpr()
102  : castExpr(unless(hasSourceExpression(
103  IsIgnoredTypeTwoLevelsDeep))))
104  .bind("cast")),
105  this);
106 
107  // Binary operators:
108  // i += 0.5;
109  Finder->addMatcher(
110  binaryOperator(
111  isAssignmentOperator(),
112  hasLHS(expr(hasType(hasUnqualifiedDesugaredType(builtinType())))),
113  hasRHS(expr(hasType(hasUnqualifiedDesugaredType(builtinType())))),
114  unless(hasRHS(IsCeilFloorCallExpr)),
115  WarnWithinTemplateInstantiation
116  ? binaryOperator()
117  : binaryOperator(unless(isInTemplateInstantiation())),
118  IgnoreConversionFromTypes.empty()
119  ? binaryOperator()
120  : binaryOperator(unless(hasRHS(IsIgnoredTypeTwoLevelsDeep))),
121  // The `=` case generates an implicit cast
122  // which is covered by the previous matcher.
123  unless(hasOperatorName("=")))
124  .bind("binary_op"),
125  this);
126 }
127 
128 static const BuiltinType *getBuiltinType(const Expr &E) {
129  return E.getType().getCanonicalType().getTypePtr()->getAs<BuiltinType>();
130 }
131 
132 static QualType getUnqualifiedType(const Expr &E) {
133  return E.getType().getUnqualifiedType();
134 }
135 
136 static APValue getConstantExprValue(const ASTContext &Ctx, const Expr &E) {
137  if (auto IntegerConstant = E.getIntegerConstantExpr(Ctx))
138  return APValue(*IntegerConstant);
139  APValue Constant;
140  if (Ctx.getLangOpts().CPlusPlus && E.isCXX11ConstantExpr(Ctx, &Constant))
141  return Constant;
142  return {};
143 }
144 
145 static bool getIntegerConstantExprValue(const ASTContext &Context,
146  const Expr &E, llvm::APSInt &Value) {
147  APValue Constant = getConstantExprValue(Context, E);
148  if (!Constant.isInt())
149  return false;
150  Value = Constant.getInt();
151  return true;
152 }
153 
154 static bool getFloatingConstantExprValue(const ASTContext &Context,
155  const Expr &E, llvm::APFloat &Value) {
156  APValue Constant = getConstantExprValue(Context, E);
157  if (!Constant.isFloat())
158  return false;
159  Value = Constant.getFloat();
160  return true;
161 }
162 
163 namespace {
164 
165 struct IntegerRange {
166  bool contains(const IntegerRange &From) const {
167  return llvm::APSInt::compareValues(Lower, From.Lower) <= 0 &&
168  llvm::APSInt::compareValues(Upper, From.Upper) >= 0;
169  }
170 
171  bool contains(const llvm::APSInt &Value) const {
172  return llvm::APSInt::compareValues(Lower, Value) <= 0 &&
173  llvm::APSInt::compareValues(Upper, Value) >= 0;
174  }
175 
176  llvm::APSInt Lower;
177  llvm::APSInt Upper;
178 };
179 
180 } // namespace
181 
182 static IntegerRange createFromType(const ASTContext &Context,
183  const BuiltinType &T) {
184  if (T.isFloatingPoint()) {
185  unsigned PrecisionBits = llvm::APFloatBase::semanticsPrecision(
186  Context.getFloatTypeSemantics(T.desugar()));
187  // Contrary to two's complement integer, floating point values are
188  // symmetric and have the same number of positive and negative values.
189  // The range of valid integers for a floating point value is:
190  // [-2^PrecisionBits, 2^PrecisionBits]
191 
192  // Values are created with PrecisionBits plus two bits:
193  // - One to express the missing negative value of 2's complement
194  // representation.
195  // - One for the sign.
196  llvm::APSInt UpperValue(PrecisionBits + 2, /*isUnsigned*/ false);
197  UpperValue.setBit(PrecisionBits);
198  llvm::APSInt LowerValue(PrecisionBits + 2, /*isUnsigned*/ false);
199  LowerValue.setBit(PrecisionBits);
200  LowerValue.setSignBit();
201  return {LowerValue, UpperValue};
202  }
203  assert(T.isInteger() && "Unexpected builtin type");
204  uint64_t TypeSize = Context.getTypeSize(&T);
205  bool IsUnsignedInteger = T.isUnsignedInteger();
206  return {llvm::APSInt::getMinValue(TypeSize, IsUnsignedInteger),
207  llvm::APSInt::getMaxValue(TypeSize, IsUnsignedInteger)};
208 }
209 
210 static bool isWideEnoughToHold(const ASTContext &Context,
211  const BuiltinType &FromType,
212  const BuiltinType &ToType) {
213  IntegerRange FromIntegerRange = createFromType(Context, FromType);
214  IntegerRange ToIntegerRange = createFromType(Context, ToType);
215  return ToIntegerRange.contains(FromIntegerRange);
216 }
217 
218 static bool isWideEnoughToHold(const ASTContext &Context,
219  const llvm::APSInt &IntegerConstant,
220  const BuiltinType &ToType) {
221  IntegerRange ToIntegerRange = createFromType(Context, ToType);
222  return ToIntegerRange.contains(IntegerConstant);
223 }
224 
225 // Returns true iff the floating point constant can be losslessly represented
226 // by an integer in the given destination type. eg. 2.0 can be accurately
227 // represented by an int32_t, but neither 2^33 nor 2.001 can.
228 static bool isFloatExactlyRepresentable(const ASTContext &Context,
229  const llvm::APFloat &FloatConstant,
230  const QualType &DestType) {
231  unsigned DestWidth = Context.getIntWidth(DestType);
232  bool DestSigned = DestType->isSignedIntegerOrEnumerationType();
233  llvm::APSInt Result = llvm::APSInt(DestWidth, !DestSigned);
234  bool IsExact = false;
235  bool Overflows = FloatConstant.convertToInteger(
236  Result, llvm::APFloat::rmTowardZero, &IsExact) &
237  llvm::APFloat::opInvalidOp;
238  return !Overflows && IsExact;
239 }
240 
241 static llvm::SmallString<64> getValueAsString(const llvm::APSInt &Value,
242  uint64_t HexBits) {
243  llvm::SmallString<64> Str;
244  Value.toString(Str, 10);
245  if (HexBits > 0) {
246  Str.append(" (0x");
247  llvm::SmallString<32> HexValue;
248  Value.toStringUnsigned(HexValue, 16);
249  for (size_t I = HexValue.size(); I < (HexBits / 4); ++I)
250  Str.append("0");
251  Str.append(HexValue);
252  Str.append(")");
253  }
254  return Str;
255 }
256 
257 bool NarrowingConversionsCheck::isWarningInhibitedByEquivalentSize(
258  const ASTContext &Context, const BuiltinType &FromType,
259  const BuiltinType &ToType) const {
260  // With this option, we don't warn on conversions that have equivalent width
261  // in bits. eg. uint32 <-> int32.
262  if (!WarnOnEquivalentBitWidth) {
263  uint64_t FromTypeSize = Context.getTypeSize(&FromType);
264  uint64_t ToTypeSize = Context.getTypeSize(&ToType);
265  if (FromTypeSize == ToTypeSize) {
266  return true;
267  }
268  }
269  return false;
270 }
271 
272 void NarrowingConversionsCheck::diagNarrowType(SourceLocation SourceLoc,
273  const Expr &Lhs,
274  const Expr &Rhs) {
275  diag(SourceLoc, "narrowing conversion from %0 to %1")
276  << getUnqualifiedType(Rhs) << getUnqualifiedType(Lhs);
277 }
278 
279 void NarrowingConversionsCheck::diagNarrowTypeToSignedInt(
280  SourceLocation SourceLoc, const Expr &Lhs, const Expr &Rhs) {
281  diag(SourceLoc, "narrowing conversion from %0 to signed type %1 is "
282  "implementation-defined")
283  << getUnqualifiedType(Rhs) << getUnqualifiedType(Lhs);
284 }
285 
286 void NarrowingConversionsCheck::diagNarrowIntegerConstant(
287  SourceLocation SourceLoc, const Expr &Lhs, const Expr &Rhs,
288  const llvm::APSInt &Value) {
289  diag(SourceLoc,
290  "narrowing conversion from constant value %0 of type %1 to %2")
291  << getValueAsString(Value, /*NoHex*/ 0) << getUnqualifiedType(Rhs)
292  << getUnqualifiedType(Lhs);
293 }
294 
295 void NarrowingConversionsCheck::diagNarrowIntegerConstantToSignedInt(
296  SourceLocation SourceLoc, const Expr &Lhs, const Expr &Rhs,
297  const llvm::APSInt &Value, const uint64_t HexBits) {
298  diag(SourceLoc, "narrowing conversion from constant value %0 of type %1 "
299  "to signed type %2 is implementation-defined")
300  << getValueAsString(Value, HexBits) << getUnqualifiedType(Rhs)
301  << getUnqualifiedType(Lhs);
302 }
303 
304 void NarrowingConversionsCheck::diagNarrowConstant(SourceLocation SourceLoc,
305  const Expr &Lhs,
306  const Expr &Rhs) {
307  diag(SourceLoc, "narrowing conversion from constant %0 to %1")
308  << getUnqualifiedType(Rhs) << getUnqualifiedType(Lhs);
309 }
310 
311 void NarrowingConversionsCheck::diagConstantCast(SourceLocation SourceLoc,
312  const Expr &Lhs,
313  const Expr &Rhs) {
314  diag(SourceLoc, "constant value should be of type of type %0 instead of %1")
315  << getUnqualifiedType(Lhs) << getUnqualifiedType(Rhs);
316 }
317 
318 void NarrowingConversionsCheck::diagNarrowTypeOrConstant(
319  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
320  const Expr &Rhs) {
321  APValue Constant = getConstantExprValue(Context, Rhs);
322  if (Constant.isInt())
323  return diagNarrowIntegerConstant(SourceLoc, Lhs, Rhs, Constant.getInt());
324  if (Constant.isFloat())
325  return diagNarrowConstant(SourceLoc, Lhs, Rhs);
326  return diagNarrowType(SourceLoc, Lhs, Rhs);
327 }
328 
329 void NarrowingConversionsCheck::handleIntegralCast(const ASTContext &Context,
330  SourceLocation SourceLoc,
331  const Expr &Lhs,
332  const Expr &Rhs) {
333  if (WarnOnIntegerNarrowingConversion) {
334  const BuiltinType *ToType = getBuiltinType(Lhs);
335  // From [conv.integral]p7.3.8:
336  // Conversions to unsigned integer is well defined so no warning is issued.
337  // "The resulting value is the smallest unsigned value equal to the source
338  // value modulo 2^n where n is the number of bits used to represent the
339  // destination type."
340  if (ToType->isUnsignedInteger())
341  return;
342  const BuiltinType *FromType = getBuiltinType(Rhs);
343 
344  // With this option, we don't warn on conversions that have equivalent width
345  // in bits. eg. uint32 <-> int32.
346  if (!WarnOnEquivalentBitWidth) {
347  uint64_t FromTypeSize = Context.getTypeSize(FromType);
348  uint64_t ToTypeSize = Context.getTypeSize(ToType);
349  if (FromTypeSize == ToTypeSize)
350  return;
351  }
352 
353  llvm::APSInt IntegerConstant;
354  if (getIntegerConstantExprValue(Context, Rhs, IntegerConstant)) {
355  if (!isWideEnoughToHold(Context, IntegerConstant, *ToType))
356  diagNarrowIntegerConstantToSignedInt(SourceLoc, Lhs, Rhs,
357  IntegerConstant,
358  Context.getTypeSize(FromType));
359  return;
360  }
361  if (!isWideEnoughToHold(Context, *FromType, *ToType))
362  diagNarrowTypeToSignedInt(SourceLoc, Lhs, Rhs);
363  }
364 }
365 
366 void NarrowingConversionsCheck::handleIntegralToBoolean(
367  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
368  const Expr &Rhs) {
369  // Conversion from Integral to Bool value is well defined.
370 
371  // We keep this function (even if it is empty) to make sure that
372  // handleImplicitCast and handleBinaryOperator are symmetric in their behavior
373  // and handle the same cases.
374 }
375 
376 void NarrowingConversionsCheck::handleIntegralToFloating(
377  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
378  const Expr &Rhs) {
379  const BuiltinType *ToType = getBuiltinType(Lhs);
380  llvm::APSInt IntegerConstant;
381  if (getIntegerConstantExprValue(Context, Rhs, IntegerConstant)) {
382  if (!isWideEnoughToHold(Context, IntegerConstant, *ToType))
383  diagNarrowIntegerConstant(SourceLoc, Lhs, Rhs, IntegerConstant);
384  return;
385  }
386 
387  const BuiltinType *FromType = getBuiltinType(Rhs);
388  if (isWarningInhibitedByEquivalentSize(Context, *FromType, *ToType))
389  return;
390  if (!isWideEnoughToHold(Context, *FromType, *ToType))
391  diagNarrowType(SourceLoc, Lhs, Rhs);
392 }
393 
394 void NarrowingConversionsCheck::handleFloatingToIntegral(
395  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
396  const Expr &Rhs) {
397  llvm::APFloat FloatConstant(0.0);
398  if (getFloatingConstantExprValue(Context, Rhs, FloatConstant)) {
399  if (!isFloatExactlyRepresentable(Context, FloatConstant, Lhs.getType()))
400  return diagNarrowConstant(SourceLoc, Lhs, Rhs);
401 
402  if (PedanticMode)
403  return diagConstantCast(SourceLoc, Lhs, Rhs);
404 
405  return;
406  }
407 
408  const BuiltinType *FromType = getBuiltinType(Rhs);
409  const BuiltinType *ToType = getBuiltinType(Lhs);
410  if (isWarningInhibitedByEquivalentSize(Context, *FromType, *ToType))
411  return;
412  diagNarrowType(SourceLoc, Lhs, Rhs); // Assumed always lossy.
413 }
414 
415 void NarrowingConversionsCheck::handleFloatingToBoolean(
416  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
417  const Expr &Rhs) {
418  return diagNarrowTypeOrConstant(Context, SourceLoc, Lhs, Rhs);
419 }
420 
421 void NarrowingConversionsCheck::handleBooleanToSignedIntegral(
422  const ASTContext &Context, SourceLocation SourceLoc, const Expr &Lhs,
423  const Expr &Rhs) {
424  // Conversion from Bool to SignedIntegral value is well defined.
425 
426  // We keep this function (even if it is empty) to make sure that
427  // handleImplicitCast and handleBinaryOperator are symmetric in their behavior
428  // and handle the same cases.
429 }
430 
431 void NarrowingConversionsCheck::handleFloatingCast(const ASTContext &Context,
432  SourceLocation SourceLoc,
433  const Expr &Lhs,
434  const Expr &Rhs) {
435  if (WarnOnFloatingPointNarrowingConversion) {
436  const BuiltinType *ToType = getBuiltinType(Lhs);
437  APValue Constant = getConstantExprValue(Context, Rhs);
438  if (Constant.isFloat()) {
439  // From [dcl.init.list]p7.2:
440  // Floating point constant narrowing only takes place when the value is
441  // not within destination range. We convert the value to the destination
442  // type and check if the resulting value is infinity.
443  llvm::APFloat Tmp = Constant.getFloat();
444  bool UnusedLosesInfo;
445  Tmp.convert(Context.getFloatTypeSemantics(ToType->desugar()),
446  llvm::APFloatBase::rmNearestTiesToEven, &UnusedLosesInfo);
447  if (Tmp.isInfinity())
448  diagNarrowConstant(SourceLoc, Lhs, Rhs);
449  return;
450  }
451  const BuiltinType *FromType = getBuiltinType(Rhs);
452  if (ToType->getKind() < FromType->getKind())
453  diagNarrowType(SourceLoc, Lhs, Rhs);
454  }
455 }
456 
457 void NarrowingConversionsCheck::handleBinaryOperator(const ASTContext &Context,
458  SourceLocation SourceLoc,
459  const Expr &Lhs,
460  const Expr &Rhs) {
461  assert(!Lhs.isInstantiationDependent() && !Rhs.isInstantiationDependent() &&
462  "Dependent types must be check before calling this function");
463  const BuiltinType *LhsType = getBuiltinType(Lhs);
464  const BuiltinType *RhsType = getBuiltinType(Rhs);
465  if (RhsType == nullptr || LhsType == nullptr)
466  return;
467  if (RhsType->getKind() == BuiltinType::Bool && LhsType->isSignedInteger())
468  return handleBooleanToSignedIntegral(Context, SourceLoc, Lhs, Rhs);
469  if (RhsType->isInteger() && LhsType->getKind() == BuiltinType::Bool)
470  return handleIntegralToBoolean(Context, SourceLoc, Lhs, Rhs);
471  if (RhsType->isInteger() && LhsType->isFloatingPoint())
472  return handleIntegralToFloating(Context, SourceLoc, Lhs, Rhs);
473  if (RhsType->isInteger() && LhsType->isInteger())
474  return handleIntegralCast(Context, SourceLoc, Lhs, Rhs);
475  if (RhsType->isFloatingPoint() && LhsType->getKind() == BuiltinType::Bool)
476  return handleFloatingToBoolean(Context, SourceLoc, Lhs, Rhs);
477  if (RhsType->isFloatingPoint() && LhsType->isInteger())
478  return handleFloatingToIntegral(Context, SourceLoc, Lhs, Rhs);
479  if (RhsType->isFloatingPoint() && LhsType->isFloatingPoint())
480  return handleFloatingCast(Context, SourceLoc, Lhs, Rhs);
481 }
482 
483 bool NarrowingConversionsCheck::handleConditionalOperator(
484  const ASTContext &Context, const Expr &Lhs, const Expr &Rhs) {
485  if (const auto *CO = llvm::dyn_cast<ConditionalOperator>(&Rhs)) {
486  // We have an expression like so: `output = cond ? lhs : rhs`
487  // From the point of view of narrowing conversion we treat it as two
488  // expressions `output = lhs` and `output = rhs`.
489  handleBinaryOperator(Context, CO->getLHS()->getExprLoc(), Lhs,
490  *CO->getLHS());
491  handleBinaryOperator(Context, CO->getRHS()->getExprLoc(), Lhs,
492  *CO->getRHS());
493  return true;
494  }
495  return false;
496 }
497 
498 void NarrowingConversionsCheck::handleImplicitCast(
499  const ASTContext &Context, const ImplicitCastExpr &Cast) {
500  if (Cast.getExprLoc().isMacroID())
501  return;
502  const Expr &Lhs = Cast;
503  const Expr &Rhs = *Cast.getSubExpr();
504  if (Lhs.isInstantiationDependent() || Rhs.isInstantiationDependent())
505  return;
506  if (handleConditionalOperator(Context, Lhs, Rhs))
507  return;
508  SourceLocation SourceLoc = Lhs.getExprLoc();
509  switch (Cast.getCastKind()) {
510  case CK_BooleanToSignedIntegral:
511  return handleBooleanToSignedIntegral(Context, SourceLoc, Lhs, Rhs);
512  case CK_IntegralToBoolean:
513  return handleIntegralToBoolean(Context, SourceLoc, Lhs, Rhs);
514  case CK_IntegralToFloating:
515  return handleIntegralToFloating(Context, SourceLoc, Lhs, Rhs);
516  case CK_IntegralCast:
517  return handleIntegralCast(Context, SourceLoc, Lhs, Rhs);
518  case CK_FloatingToBoolean:
519  return handleFloatingToBoolean(Context, SourceLoc, Lhs, Rhs);
520  case CK_FloatingToIntegral:
521  return handleFloatingToIntegral(Context, SourceLoc, Lhs, Rhs);
522  case CK_FloatingCast:
523  return handleFloatingCast(Context, SourceLoc, Lhs, Rhs);
524  default:
525  break;
526  }
527 }
528 
529 void NarrowingConversionsCheck::handleBinaryOperator(const ASTContext &Context,
530  const BinaryOperator &Op) {
531  if (Op.getBeginLoc().isMacroID())
532  return;
533  const Expr &Lhs = *Op.getLHS();
534  const Expr &Rhs = *Op.getRHS();
535  if (Lhs.isInstantiationDependent() || Rhs.isInstantiationDependent())
536  return;
537  if (handleConditionalOperator(Context, Lhs, Rhs))
538  return;
539  handleBinaryOperator(Context, Rhs.getBeginLoc(), Lhs, Rhs);
540 }
541 
542 void NarrowingConversionsCheck::check(const MatchFinder::MatchResult &Result) {
543  if (const auto *Op = Result.Nodes.getNodeAs<BinaryOperator>("binary_op"))
544  return handleBinaryOperator(*Result.Context, *Op);
545  if (const auto *Cast = Result.Nodes.getNodeAs<ImplicitCastExpr>("cast"))
546  return handleImplicitCast(*Result.Context, *Cast);
547  llvm_unreachable("must be binary operator or cast expression");
548 }
549 } // namespace cppcoreguidelines
550 } // namespace tidy
551 } // namespace clang
Lower
llvm::APSInt Lower
Definition: NarrowingConversionsCheck.cpp:176
clang::tidy::ClangTidyOptions::OptionMap
llvm::StringMap< ClangTidyValue > OptionMap
Definition: ClangTidyOptions.h:115
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:210
Upper
llvm::APSInt Upper
Definition: NarrowingConversionsCheck.cpp:177
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:542
Ctx
Context Ctx
Definition: TUScheduler.cpp:460
NarrowingConversionsCheck.h
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidyCheck.h:54
clang::tidy::cppcoreguidelines::createFromType
static IntegerRange createFromType(const ASTContext &Context, const BuiltinType &T)
Definition: NarrowingConversionsCheck.cpp:182
clang::tidy::bugprone::hasAnyListedName
static Matcher< TypedefDecl > hasAnyListedName(const std::string &Names)
Definition: SignedCharMisuseCheck.cpp:23
clang::ast_matchers
Definition: AbseilMatcher.h:14
clang::tidy::cppcoreguidelines::getBuiltinType
static const BuiltinType * getBuiltinType(const Expr &E)
Definition: NarrowingConversionsCheck.cpp:128
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:48
clang::clangd::CompletionItemKind::Constant
@ Constant
clang::tidy::cppcoreguidelines::getConstantExprValue
static APValue getConstantExprValue(const ASTContext &Ctx, const Expr &E)
Definition: NarrowingConversionsCheck.cpp:136
clang::tidy::utils::options::parseStringList
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
Definition: OptionsUtils.cpp:18
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
clang::tidy::cppcoreguidelines::getUnqualifiedType
static QualType getUnqualifiedType(const Expr &E)
Definition: NarrowingConversionsCheck.cpp:132
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:28
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::cppcoreguidelines::getFloatingConstantExprValue
static bool getFloatingConstantExprValue(const ASTContext &Context, const Expr &E, llvm::APFloat &Value)
Definition: NarrowingConversionsCheck.cpp:154
clang::tidy::cppcoreguidelines::getIntegerConstantExprValue
static bool getIntegerConstantExprValue(const ASTContext &Context, const Expr &E, llvm::APSInt &Value)
Definition: NarrowingConversionsCheck.cpp:145
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::tidy::cppcoreguidelines::isFloatExactlyRepresentable
static bool isFloatExactlyRepresentable(const ASTContext &Context, const llvm::APFloat &FloatConstant, const QualType &DestType)
Definition: NarrowingConversionsCheck.cpp:228
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::cppcoreguidelines::getValueAsString
static llvm::SmallString< 64 > getValueAsString(const llvm::APSInt &Value, uint64_t HexBits)
Definition: NarrowingConversionsCheck.cpp:241
clang::tidy::cppcoreguidelines::NarrowingConversionsCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: NarrowingConversionsCheck.cpp:61
contains
This directory contains
Definition: README.txt:6