11#include "clang/AST/ASTContext.h"
12#include "clang/AST/TypeBase.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/Lex/Lexer.h"
24 const auto *TS = S->getAs<TypedefType>();
25 const auto *TD = D->getAs<TypedefType>();
29 const QualType PtrS = S->getPointeeType();
30 const QualType PtrD = D->getPointeeType();
32 if (!PtrS.isNull() && !PtrD.isNull())
33 return areTypesEqual(PtrS.IgnoreParens(), PtrD.IgnoreParens());
35 const DeducedType *DT = S->getContainedDeducedType();
36 if (DT && DT->isDeduced())
37 return D == DT->getDeducedType();
43 bool IgnoreTypeAliases) {
44 const QualType CTypeS = TypeS.getCanonicalType();
45 const QualType CTypeD = TypeD.getCanonicalType();
49 return IgnoreTypeAliases ||
areTypesEqual(TypeS.getLocalUnqualifiedType(),
50 TypeD.getLocalUnqualifiedType());
54 const Expr *E,
bool IgnoreTypeAliases,
bool IgnoreImplicitCasts) {
57 const Expr *WithoutImplicitAndParen = E->IgnoreParenImpCasts();
58 if (!WithoutImplicitAndParen)
60 if (
const auto *B = dyn_cast<BinaryOperator>(WithoutImplicitAndParen)) {
61 const QualType Type = WithoutImplicitAndParen->getType();
65 const QualType NonReferenceType = Type.getNonReferenceType();
66 const QualType LHSType = B->getLHS()->IgnoreImplicit()->getType();
67 const QualType RHSType = B->getRHS()->IgnoreImplicit()->getType();
68 const bool LHSMatches =
69 !LHSType.isNull() &&
areTypesEqual(LHSType.getNonReferenceType(),
70 NonReferenceType, IgnoreTypeAliases);
71 const bool RHSMatches =
72 !RHSType.isNull() &&
areTypesEqual(RHSType.getNonReferenceType(),
73 NonReferenceType, IgnoreTypeAliases);
78 const bool CastIsNeeded = IgnoreImplicitCasts
79 ? (!LHSMatches || !RHSMatches)
80 : (!LHSMatches && !RHSMatches);
88 const Expr *CleanSourceExpr = SourceExpr->IgnoreParenImpCasts();
89 if (
const auto *E = dyn_cast<DeclRefExpr>(CleanSourceExpr))
92 if (
const auto *E = dyn_cast<CallExpr>(CleanSourceExpr))
93 return E->getCalleeDecl();
95 if (
const auto *E = dyn_cast<MemberExpr>(CleanSourceExpr))
96 return E->getMemberDecl();
103 IgnoreMacros(Options.get(
"IgnoreMacros", true)),
104 IgnoreTypeAliases(Options.get(
"IgnoreTypeAliases", false)),
105 IgnoreImplicitCasts(Options.get(
"IgnoreImplicitCasts", false)) {}
108 Options.store(Opts,
"IgnoreMacros", IgnoreMacros);
109 Options.store(Opts,
"IgnoreTypeAliases", IgnoreTypeAliases);
110 Options.store(Opts,
"IgnoreImplicitCasts", IgnoreImplicitCasts);
114 auto SimpleType = qualType(hasCanonicalType(
115 qualType(anyOf(builtinType(), references(builtinType()),
116 references(pointsTo(qualType())), pointsTo(qualType())))));
118 auto BitfieldMemberExpr = memberExpr(member(fieldDecl(isBitField())));
120 const ast_matchers::internal::VariadicDynCastAllOfMatcher<
121 Stmt, CXXParenListInitExpr>
122 cxxParenListInitExpr;
126 unless(hasCastKind(CK_ConstructorConversion)),
127 unless(hasCastKind(CK_UserDefinedConversion)),
128 unless(cxxFunctionalCastExpr(hasDestinationType(unless(SimpleType)))),
130 hasDestinationType(qualType().bind(
"dstType")),
131 hasSourceExpression(anyOf(
132 expr(unless(initListExpr()), unless(BitfieldMemberExpr),
133 unless(cxxParenListInitExpr()),
134 hasType(qualType().bind(
"srcType")))
136 initListExpr(unless(hasInit(1, expr())),
137 hasInit(0, expr(unless(BitfieldMemberExpr),
138 hasType(qualType().bind(
"srcType")))
145 const auto *SourceExpr = Result.Nodes.getNodeAs<Expr>(
"source");
146 auto TypeD = *Result.Nodes.getNodeAs<QualType>(
"dstType");
148 if (SourceExpr->getValueKind() == VK_LValue &&
149 TypeD.getCanonicalType()->isRValueReferenceType())
153 Result.Nodes.getNodeAs<QualType>(
"srcType")->getNonReferenceType();
154 TypeD = TypeD.getNonReferenceType();
160 SourceExpr, IgnoreTypeAliases, IgnoreImplicitCasts))
163 const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>(
"cast");
165 (CastExpr->getBeginLoc().isMacroID() ||
166 CastExpr->getEndLoc().isMacroID() || CastExpr->getExprLoc().isMacroID()))
170 auto Diag = diag(CastExpr->getExprLoc(),
171 "redundant explicit casting to the same type %0 as the "
172 "sub-expression, remove this casting");
175 const SourceManager &SM = *Result.SourceManager;
176 const SourceLocation SourceExprBegin =
177 SM.getExpansionLoc(SourceExpr->getBeginLoc());
178 const SourceLocation SourceExprEnd =
179 SM.getExpansionLoc(SourceExpr->getEndLoc());
181 if (SourceExprBegin != CastExpr->getBeginLoc())
182 Diag << FixItHint::CreateRemoval(SourceRange(
183 CastExpr->getBeginLoc(), SourceExprBegin.getLocWithOffset(-1)));
185 const SourceLocation NextToken = Lexer::getLocForEndOfToken(
186 SourceExprEnd, 0U, SM, Result.Context->getLangOpts());
188 if (SourceExprEnd != CastExpr->getEndLoc()) {
189 Diag << FixItHint::CreateRemoval(
190 SourceRange(NextToken, CastExpr->getEndLoc()));
194 Diag << FixItHint::CreateInsertion(SourceExprBegin,
"(")
195 << FixItHint::CreateInsertion(NextToken,
")");
203 if (
const auto *D = dyn_cast<CXXConstructorDecl>(SourceExprDecl)) {
204 diag(
D->getLocation(),
205 "source type originates from the invocation of this constructor",
206 DiagnosticIDs::Note);
210 if (
const auto *D = dyn_cast<FunctionDecl>(SourceExprDecl)) {
211 diag(
D->getLocation(),
212 "source type originates from the invocation of this "
213 "%select{function|method}0",
215 << isa<CXXMethodDecl>(D) <<
D->getReturnTypeSourceRange();
219 if (
const auto *D = dyn_cast<FieldDecl>(SourceExprDecl)) {
220 diag(
D->getLocation(),
221 "source type originates from referencing this member",
223 << SourceRange(
D->getTypeSpecStartLoc(),
D->getTypeSpecEndLoc());
227 if (
const auto *D = dyn_cast<ParmVarDecl>(SourceExprDecl)) {
228 diag(
D->getLocation(),
229 "source type originates from referencing this parameter",
231 << SourceRange(
D->getTypeSpecStartLoc(),
D->getTypeSpecEndLoc());
235 if (
const auto *D = dyn_cast<VarDecl>(SourceExprDecl)) {
236 diag(
D->getLocation(),
237 "source type originates from referencing this variable",
239 << SourceRange(
D->getTypeSpecStartLoc(),
D->getTypeSpecEndLoc());
243 if (
const auto *D = dyn_cast<EnumConstantDecl>(SourceExprDecl)) {
244 diag(
D->getLocation(),
245 "source type originates from referencing this enum constant",
246 DiagnosticIDs::Note);
250 if (
const auto *D = dyn_cast<BindingDecl>(SourceExprDecl)) {
251 diag(
D->getLocation(),
252 "source type originates from referencing this bound variable",
253 DiagnosticIDs::Note);
257 if (
const auto *D = dyn_cast<NonTypeTemplateParmDecl>(SourceExprDecl)) {
258 diag(
D->getLocation(),
259 "source type originates from referencing this non-type template "
261 DiagnosticIDs::Note);
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
RedundantCastingCheck(StringRef Name, ClangTidyContext *Context)
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
static bool areTypesEqual(QualType S, QualType D)
static const Decl * getSourceExprDecl(const Expr *SourceExpr)
static bool binaryOperatorOperandsTypesEqualToOperatorResultType(const Expr *E, bool IgnoreTypeAliases, bool IgnoreImplicitCasts)
bool areParensNeededForStatement(const Stmt &Node)
llvm::StringMap< ClangTidyValue > OptionMap