29 expr(anyOf(binaryOperator(hasAnyOperatorName(
"+",
"-",
"*",
"<<")),
30 unaryOperator(hasOperatorName(
"~"))),
34 const auto ExplicitCast = explicitCastExpr(hasDestinationType(isInteger()),
35 has(ignoringParenImpCasts(Calc)));
36 const auto ImplicitCast =
37 implicitCastExpr(hasImplicitDestinationType(isInteger()),
38 has(ignoringParenImpCasts(Calc)));
40 traverse(TK_AsIs, expr(anyOf(ExplicitCast, ImplicitCast)).bind(
"Cast"));
42 Finder->addMatcher(varDecl(hasInitializer(Cast)),
this);
43 Finder->addMatcher(returnStmt(hasReturnValue(Cast)),
this);
44 Finder->addMatcher(callExpr(hasAnyArgument(Cast)),
this);
45 Finder->addMatcher(binaryOperator(hasOperatorName(
"="), hasRHS(Cast)),
this);
47 binaryOperator(isComparisonOperator(), hasEitherOperand(Cast)),
this);
52 E = E->IgnoreParenImpCasts();
54 if (
const auto *Bop = dyn_cast<BinaryOperator>(E)) {
57 if (Bop->getOpcode() == BO_Mul)
58 return LHSWidth + RHSWidth;
59 if (Bop->getOpcode() == BO_Add)
60 return std::max(LHSWidth, RHSWidth) + 1;
61 if (Bop->getOpcode() == BO_Rem) {
62 Expr::EvalResult Result;
63 if (Bop->getRHS()->EvaluateAsInt(Result, Context))
64 return Result.Val.getInt().getActiveBits();
65 }
else if (Bop->getOpcode() == BO_Shl) {
66 Expr::EvalResult Result;
67 if (Bop->getRHS()->EvaluateAsInt(Result, Context)) {
71 return LHSWidth + Result.Val.getInt().getExtValue();
77 }
else if (
const auto *Uop = dyn_cast<UnaryOperator>(E)) {
79 if (Uop->getOpcode() == UO_Not)
82 QualType T = Uop->getType();
83 return T->isIntegerType() ? Context.getIntWidth(T) : 1024U;
84 }
else if (
const auto *I = dyn_cast<IntegerLiteral>(E)) {
85 return I->getValue().getActiveBits();
88 return Context.getIntWidth(E->getType());
179 const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(
"Cast");
180 if (!CheckImplicitCasts && isa<ImplicitCastExpr>(Cast))
182 if (Cast->getBeginLoc().isMacroID())
185 const auto *Calc = Result.Nodes.getNodeAs<Expr>(
"Calc");
186 if (Calc->getBeginLoc().isMacroID())
189 if (Cast->isTypeDependent() || Cast->isValueDependent() ||
190 Calc->isTypeDependent() || Calc->isValueDependent())
193 ASTContext &Context = *Result.Context;
195 QualType CastType = Cast->getType();
196 QualType CalcType = Calc->getType();
199 if (Context.getIntWidth(CastType) < Context.getIntWidth(CalcType))
205 if (Context.getIntWidth(CastType) == Context.getIntWidth(CalcType)) {
206 const auto *CastBuiltinType =
207 dyn_cast<BuiltinType>(CastType->getUnqualifiedDesugaredType());
208 const auto *CalcBuiltinType =
209 dyn_cast<BuiltinType>(CalcType->getUnqualifiedDesugaredType());
210 if (!CastBuiltinType || !CalcBuiltinType)
212 if (!
isFirstWider(CastBuiltinType->getKind(), CalcBuiltinType->getKind()))
221 diag(Cast->getBeginLoc(),
"either cast from %0 to %1 is ineffective, or "
222 "there is loss of precision before the conversion")
223 << CalcType << CastType;
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.