11 #include "../utils/Matchers.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 21 MisplacedWideningCastCheck::MisplacedWideningCastCheck(
24 CheckImplicitCasts(Options.get(
"CheckImplicitCasts", false)) {}
28 Options.
store(Opts,
"CheckImplicitCasts", CheckImplicitCasts);
33 expr(anyOf(binaryOperator(
34 anyOf(hasOperatorName(
"+"), hasOperatorName(
"-"),
35 hasOperatorName(
"*"), hasOperatorName(
"<<"))),
36 unaryOperator(hasOperatorName(
"~"))),
40 const auto ExplicitCast = explicitCastExpr(hasDestinationType(isInteger()),
41 has(ignoringParenImpCasts(Calc)));
42 const auto ImplicitCast =
43 implicitCastExpr(hasImplicitDestinationType(isInteger()),
44 has(ignoringParenImpCasts(Calc)));
45 const auto Cast = expr(anyOf(ExplicitCast, ImplicitCast)).bind(
"Cast");
47 Finder->addMatcher(varDecl(hasInitializer(Cast)),
this);
48 Finder->addMatcher(returnStmt(hasReturnValue(Cast)),
this);
49 Finder->addMatcher(callExpr(hasAnyArgument(Cast)),
this);
50 Finder->addMatcher(binaryOperator(hasOperatorName(
"="), hasRHS(Cast)),
this);
52 binaryOperator(matchers::isComparisonOperator(), hasEitherOperand(Cast)),
58 E = E->IgnoreParenImpCasts();
60 if (
const auto *Bop = dyn_cast<BinaryOperator>(E)) {
63 if (Bop->getOpcode() == BO_Mul)
64 return LHSWidth + RHSWidth;
65 if (Bop->getOpcode() == BO_Add)
66 return std::max(LHSWidth, RHSWidth) + 1;
67 if (Bop->getOpcode() == BO_Rem) {
69 if (Bop->getRHS()->EvaluateAsInt(Val, Context))
70 return Val.getActiveBits();
71 }
else if (Bop->getOpcode() == BO_Shl) {
73 if (Bop->getRHS()->EvaluateAsInt(Bits, Context)) {
77 return LHSWidth + Bits.getExtValue();
83 }
else if (
const auto *Uop = dyn_cast<UnaryOperator>(E)) {
85 if (Uop->getOpcode() == UO_Not)
88 QualType T = Uop->getType();
89 return T->isIntegerType() ? Context.getIntWidth(T) : 1024U;
90 }
else if (
const auto *I = dyn_cast<IntegerLiteral>(E)) {
91 return I->getValue().getActiveBits();
94 return Context.getIntWidth(E->getType());
99 case BuiltinType::UChar:
101 case BuiltinType::SChar:
103 case BuiltinType::Char_U:
105 case BuiltinType::Char_S:
107 case BuiltinType::UShort:
109 case BuiltinType::Short:
111 case BuiltinType::UInt:
113 case BuiltinType::Int:
115 case BuiltinType::ULong:
117 case BuiltinType::Long:
119 case BuiltinType::ULongLong:
121 case BuiltinType::LongLong:
123 case BuiltinType::UInt128:
125 case BuiltinType::Int128:
134 case BuiltinType::UChar:
136 case BuiltinType::SChar:
138 case BuiltinType::Char_U:
140 case BuiltinType::Char_S:
142 case BuiltinType::Char16:
144 case BuiltinType::Char32:
153 case BuiltinType::UChar:
155 case BuiltinType::SChar:
157 case BuiltinType::Char_U:
159 case BuiltinType::Char_S:
161 case BuiltinType::WChar_U:
163 case BuiltinType::WChar_S:
171 int FirstSize, SecondSize;
174 return FirstSize > SecondSize;
177 return FirstSize > SecondSize;
180 return FirstSize > SecondSize;
185 const auto *Cast = Result.Nodes.getNodeAs<CastExpr>(
"Cast");
186 if (!CheckImplicitCasts && isa<ImplicitCastExpr>(Cast))
188 if (Cast->getLocStart().isMacroID())
191 const auto *Calc = Result.Nodes.getNodeAs<Expr>(
"Calc");
192 if (Calc->getLocStart().isMacroID())
195 if (Cast->isTypeDependent() || Cast->isValueDependent() ||
196 Calc->isTypeDependent() || Calc->isValueDependent())
199 ASTContext &Context = *Result.Context;
201 QualType CastType = Cast->getType();
202 QualType CalcType = Calc->getType();
205 if (Context.getIntWidth(CastType) < Context.getIntWidth(CalcType))
211 if (Context.getIntWidth(CastType) == Context.getIntWidth(CalcType)) {
212 const auto *CastBuiltinType =
213 dyn_cast<BuiltinType>(CastType->getUnqualifiedDesugaredType());
214 const auto *CalcBuiltinType =
215 dyn_cast<BuiltinType>(CalcType->getUnqualifiedDesugaredType());
216 if (CastBuiltinType && CalcBuiltinType &&
217 !
isFirstWider(CastBuiltinType->getKind(), CalcBuiltinType->getKind()))
226 diag(Cast->getLocStart(),
"either cast from %0 to %1 is ineffective, or " 227 "there is loss of precision before the conversion")
228 << CalcType << CastType;
static int relativeIntSizes(BuiltinType::Kind Kind)
static int relativeCharSizesW(BuiltinType::Kind Kind)
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.
static unsigned getMaxCalculationWidth(const ASTContext &Context, const Expr *E)
Base class for all clang-tidy checks.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
static int relativeCharSizes(BuiltinType::Kind Kind)
static bool isFirstWider(BuiltinType::Kind First, BuiltinType::Kind Second)
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
std::map< std::string, std::string > OptionMap
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.