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);
48 binaryOperator(hasOperatorName(
"="),
49 hasLHS(expr(optionally(memberExpr(hasDeclaration(
50 fieldDecl(isBitField()).bind(
"BitField")))))),
54 binaryOperator(isComparisonOperator(), hasEitherOperand(Cast)),
this);
59 E = E->IgnoreParenImpCasts();
61 if (
const auto *Bop = dyn_cast<BinaryOperator>(E)) {
64 if (Bop->getOpcode() == BO_Mul)
65 return LHSWidth + RHSWidth;
66 if (Bop->getOpcode() == BO_Add)
67 return std::max(LHSWidth, RHSWidth) + 1;
68 if (Bop->getOpcode() == BO_Rem) {
69 Expr::EvalResult Result;
70 if (Bop->getRHS()->EvaluateAsInt(Result, Context))
71 return Result.Val.getInt().getActiveBits();
72 }
else if (Bop->getOpcode() == BO_Shl) {
73 Expr::EvalResult Result;
74 if (Bop->getRHS()->EvaluateAsInt(Result, Context)) {
78 return LHSWidth + Result.Val.getInt().getExtValue();
84 }
else if (
const auto *Uop = dyn_cast<UnaryOperator>(E)) {
86 if (Uop->getOpcode() == UO_Not)
89 const QualType T = Uop->getType();
90 return T->isIntegerType() ? Context.getIntWidth(T) : 1024U;
91 }
else if (
const auto *I = dyn_cast<IntegerLiteral>(E)) {
92 return I->getValue().getActiveBits();
95 return Context.getIntWidth(E->getType());
186 const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(
"Cast");
187 if (!CheckImplicitCasts && isa<ImplicitCastExpr>(Cast))
189 if (Cast->getBeginLoc().isMacroID())
192 const auto *Calc = Result.Nodes.getNodeAs<Expr>(
"Calc");
193 if (Calc->getBeginLoc().isMacroID())
196 if (Cast->isTypeDependent() || Cast->isValueDependent() ||
197 Calc->isTypeDependent() || Calc->isValueDependent())
200 const ASTContext &Context = *Result.Context;
202 const QualType CastType = Cast->getType();
203 const QualType CalcType = Calc->getType();
208 unsigned TargetWidth = Context.getIntWidth(CastType);
209 bool IsBitfieldAssign =
false;
210 if (
const auto *FD = Result.Nodes.getNodeAs<FieldDecl>(
"BitField")) {
211 TargetWidth = FD->getBitWidthValue();
212 IsBitfieldAssign =
true;
216 if (TargetWidth < Context.getIntWidth(CalcType))
222 if (TargetWidth == Context.getIntWidth(CalcType)) {
224 if (IsBitfieldAssign)
226 const auto *CastBuiltinType =
227 dyn_cast<BuiltinType>(CastType->getUnqualifiedDesugaredType());
228 const auto *CalcBuiltinType =
229 dyn_cast<BuiltinType>(CalcType->getUnqualifiedDesugaredType());
230 if (!CastBuiltinType || !CalcBuiltinType)
232 if (!
isFirstWider(CastBuiltinType->getKind(), CalcBuiltinType->getKind()))
241 diag(Cast->getBeginLoc(),
"either cast from %0 to %1 is ineffective, or "
242 "there is loss of precision before the conversion")
243 << CalcType << CastType;
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.