10 #include "../utils/Matchers.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
20 MisplacedWideningCastCheck::MisplacedWideningCastCheck(
23 CheckImplicitCasts(Options.get(
"CheckImplicitCasts", false)) {}
27 Options.
store(Opts,
"CheckImplicitCasts", CheckImplicitCasts);
32 expr(anyOf(binaryOperator(hasAnyOperatorName(
"+",
"-",
"*",
"<<")),
33 unaryOperator(hasOperatorName(
"~"))),
37 const auto ExplicitCast = explicitCastExpr(hasDestinationType(isInteger()),
38 has(ignoringParenImpCasts(Calc)));
39 const auto ImplicitCast =
40 implicitCastExpr(hasImplicitDestinationType(isInteger()),
41 has(ignoringParenImpCasts(Calc)));
43 traverse(ast_type_traits::TK_AsIs,
44 expr(anyOf(ExplicitCast, ImplicitCast)).bind(
"Cast"));
46 Finder->addMatcher(varDecl(hasInitializer(Cast)),
this);
47 Finder->addMatcher(returnStmt(hasReturnValue(Cast)),
this);
48 Finder->addMatcher(callExpr(hasAnyArgument(Cast)),
this);
49 Finder->addMatcher(binaryOperator(hasOperatorName(
"="), hasRHS(Cast)),
this);
51 binaryOperator(isComparisonOperator(), hasEitherOperand(Cast)),
this);
56 E =
E->IgnoreParenImpCasts();
58 if (
const auto *Bop = dyn_cast<BinaryOperator>(
E)) {
61 if (Bop->getOpcode() == BO_Mul)
62 return LHSWidth + RHSWidth;
63 if (Bop->getOpcode() == BO_Add)
64 return std::max(LHSWidth, RHSWidth) + 1;
65 if (Bop->getOpcode() == BO_Rem) {
66 Expr::EvalResult Result;
67 if (Bop->getRHS()->EvaluateAsInt(Result, Context))
68 return Result.Val.getInt().getActiveBits();
69 }
else if (Bop->getOpcode() == BO_Shl) {
70 Expr::EvalResult Result;
71 if (Bop->getRHS()->EvaluateAsInt(Result, Context)) {
75 return LHSWidth + Result.Val.getInt().getExtValue();
81 }
else if (
const auto *Uop = dyn_cast<UnaryOperator>(
E)) {
83 if (Uop->getOpcode() == UO_Not)
86 QualType T = Uop->getType();
87 return T->isIntegerType() ? Context.getIntWidth(T) : 1024U;
88 }
else if (
const auto *I = dyn_cast<IntegerLiteral>(
E)) {
89 return I->getValue().getActiveBits();
92 return Context.getIntWidth(
E->getType());
97 case BuiltinType::UChar:
99 case BuiltinType::SChar:
101 case BuiltinType::Char_U:
103 case BuiltinType::Char_S:
105 case BuiltinType::UShort:
107 case BuiltinType::Short:
109 case BuiltinType::UInt:
111 case BuiltinType::Int:
113 case BuiltinType::ULong:
115 case BuiltinType::Long:
117 case BuiltinType::ULongLong:
119 case BuiltinType::LongLong:
121 case BuiltinType::UInt128:
123 case BuiltinType::Int128:
132 case BuiltinType::UChar:
134 case BuiltinType::SChar:
136 case BuiltinType::Char_U:
138 case BuiltinType::Char_S:
140 case BuiltinType::Char16:
142 case BuiltinType::Char32:
151 case BuiltinType::UChar:
153 case BuiltinType::SChar:
155 case BuiltinType::Char_U:
157 case BuiltinType::Char_S:
159 case BuiltinType::WChar_U:
161 case BuiltinType::WChar_S:
169 int FirstSize, SecondSize;
172 return FirstSize > SecondSize;
175 return FirstSize > SecondSize;
178 return FirstSize > SecondSize;
183 const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(
"Cast");
184 if (!CheckImplicitCasts && isa<ImplicitCastExpr>(Cast))
186 if (Cast->getBeginLoc().isMacroID())
189 const auto *Calc = Result.Nodes.getNodeAs<Expr>(
"Calc");
190 if (Calc->getBeginLoc().isMacroID())
193 if (Cast->isTypeDependent() || Cast->isValueDependent() ||
194 Calc->isTypeDependent() || Calc->isValueDependent())
197 ASTContext &Context = *Result.Context;
199 QualType CastType = Cast->getType();
200 QualType CalcType = Calc->getType();
203 if (Context.getIntWidth(CastType) < Context.getIntWidth(CalcType))
209 if (Context.getIntWidth(CastType) == Context.getIntWidth(CalcType)) {
210 const auto *CastBuiltinType =
211 dyn_cast<BuiltinType>(CastType->getUnqualifiedDesugaredType());
212 const auto *CalcBuiltinType =
213 dyn_cast<BuiltinType>(CalcType->getUnqualifiedDesugaredType());
214 if (!CastBuiltinType || !CalcBuiltinType)
216 if (!
isFirstWider(CastBuiltinType->getKind(), CalcBuiltinType->getKind()))
225 diag(Cast->getBeginLoc(),
"either cast from %0 to %1 is ineffective, or "
226 "there is loss of precision before the conversion")
227 << CalcType << CastType;