10#include "../utils/FixItHintUtils.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Lex/Lexer.h"
23 const auto *TS = S->getAs<TypedefType>();
24 const auto *TD = D->getAs<TypedefType>();
28 QualType PtrS = S->getPointeeType();
29 QualType PtrD = D->getPointeeType();
31 if (!PtrS.isNull() && !PtrD.isNull())
34 const DeducedType *DT = S->getContainedDeducedType();
35 if (DT && DT->isDeduced())
36 return D == DT->getDeducedType();
42 bool IgnoreTypeAliases) {
43 const QualType CTypeS = TypeS.getCanonicalType();
44 const QualType CTypeD = TypeD.getCanonicalType();
48 return IgnoreTypeAliases ||
areTypesEqual(TypeS.getLocalUnqualifiedType(),
49 TypeD.getLocalUnqualifiedType());
53 const Expr *
E,
bool IgnoreTypeAliases) {
56 const Expr *WithoutImplicitAndParen =
E->IgnoreParenImpCasts();
57 if (!WithoutImplicitAndParen)
59 if (
const auto *B = dyn_cast<BinaryOperator>(WithoutImplicitAndParen)) {
60 const QualType
Type = WithoutImplicitAndParen->getType();
64 const QualType NonReferenceType =
Type.getNonReferenceType();
65 const QualType
LHSType = B->getLHS()->IgnoreImplicit()->getType();
67 NonReferenceType, IgnoreTypeAliases))
69 const QualType
RHSType = B->getRHS()->IgnoreImplicit()->getType();
71 NonReferenceType, IgnoreTypeAliases))
78 const Expr *CleanSourceExpr = SourceExpr->IgnoreParenImpCasts();
79 if (
const auto *
E = dyn_cast<DeclRefExpr>(CleanSourceExpr)) {
83 if (
const auto *
E = dyn_cast<CallExpr>(CleanSourceExpr)) {
84 return E->getCalleeDecl();
87 if (
const auto *
E = dyn_cast<MemberExpr>(CleanSourceExpr)) {
88 return E->getMemberDecl();
96 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true)),
97 IgnoreTypeAliases(Options.getLocalOrGlobal(
"IgnoreTypeAliases", false)) {}
101 Options.
store(Opts,
"IgnoreTypeAliases", IgnoreTypeAliases);
105 auto SimpleType = qualType(hasCanonicalType(
106 qualType(anyOf(builtinType(), references(builtinType()),
107 references(pointsTo(qualType())), pointsTo(qualType())))));
109 auto BitfieldMemberExpr = memberExpr(member(fieldDecl(isBitField())));
113 unless(hasCastKind(CK_ConstructorConversion)),
114 unless(hasCastKind(CK_UserDefinedConversion)),
115 unless(cxxFunctionalCastExpr(hasDestinationType(unless(SimpleType)))),
117 hasDestinationType(qualType().bind(
"dstType")),
118 hasSourceExpression(anyOf(
119 expr(unless(initListExpr()), unless(BitfieldMemberExpr),
120 hasType(qualType().bind(
"srcType")))
122 initListExpr(unless(hasInit(1, expr())),
123 hasInit(0, expr(unless(BitfieldMemberExpr),
124 hasType(qualType().bind(
"srcType")))
131 const auto *SourceExpr = Result.Nodes.getNodeAs<Expr>(
"source");
132 auto TypeD = *Result.Nodes.getNodeAs<QualType>(
"dstType");
134 if (SourceExpr->getValueKind() == VK_LValue &&
135 TypeD.getCanonicalType()->isRValueReferenceType())
139 Result.Nodes.getNodeAs<QualType>(
"srcType")->getNonReferenceType();
140 TypeD = TypeD.getNonReferenceType();
146 SourceExpr, IgnoreTypeAliases))
149 const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>(
"cast");
151 (CastExpr->getBeginLoc().isMacroID() ||
152 CastExpr->getEndLoc().isMacroID() || CastExpr->getExprLoc().isMacroID()))
156 auto Diag =
diag(CastExpr->getExprLoc(),
157 "redundant explicit casting to the same type %0 as the "
158 "sub-expression, remove this casting");
161 const SourceManager &SM = *Result.SourceManager;
162 const SourceLocation SourceExprBegin =
163 SM.getExpansionLoc(SourceExpr->getBeginLoc());
164 const SourceLocation SourceExprEnd =
165 SM.getExpansionLoc(SourceExpr->getEndLoc());
167 if (SourceExprBegin != CastExpr->getBeginLoc())
168 Diag << FixItHint::CreateRemoval(SourceRange(
169 CastExpr->getBeginLoc(), SourceExprBegin.getLocWithOffset(-1)));
171 const SourceLocation NextToken = Lexer::getLocForEndOfToken(
172 SourceExprEnd, 0U, SM, Result.Context->getLangOpts());
174 if (SourceExprEnd != CastExpr->getEndLoc()) {
175 Diag << FixItHint::CreateRemoval(
176 SourceRange(NextToken, CastExpr->getEndLoc()));
180 Diag << FixItHint::CreateInsertion(SourceExprBegin,
"(")
181 << FixItHint::CreateInsertion(NextToken,
")");
189 if (
const auto *D = dyn_cast<CXXConstructorDecl>(SourceExprDecl)) {
190 diag(D->getLocation(),
191 "source type originates from the invocation of this constructor",
192 DiagnosticIDs::Note);
196 if (
const auto *D = dyn_cast<FunctionDecl>(SourceExprDecl)) {
197 diag(D->getLocation(),
198 "source type originates from the invocation of this "
199 "%select{function|method}0",
201 << isa<CXXMethodDecl>(D) << D->getReturnTypeSourceRange();
205 if (
const auto *D = dyn_cast<FieldDecl>(SourceExprDecl)) {
206 diag(D->getLocation(),
207 "source type originates from referencing this member",
209 << SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
213 if (
const auto *D = dyn_cast<ParmVarDecl>(SourceExprDecl)) {
214 diag(D->getLocation(),
215 "source type originates from referencing this parameter",
217 << SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
221 if (
const auto *D = dyn_cast<VarDecl>(SourceExprDecl)) {
222 diag(D->getLocation(),
223 "source type originates from referencing this variable",
225 << SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
229 if (
const auto *D = dyn_cast<EnumConstantDecl>(SourceExprDecl)) {
230 diag(D->getLocation(),
231 "source type originates from referencing this enum constant",
232 DiagnosticIDs::Note);
236 if (
const auto *D = dyn_cast<BindingDecl>(SourceExprDecl)) {
237 diag(D->getLocation(),
238 "source type originates from referencing this bound variable",
239 DiagnosticIDs::Note);
243 if (
const auto *D = dyn_cast<NonTypeTemplateParmDecl>(SourceExprDecl)) {
244 diag(D->getLocation(),
245 "source type originates from referencing this non-type template "
247 DiagnosticIDs::Note);
const FunctionDecl * Decl
llvm::SmallString< 256U > Name
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.
Base class for all clang-tidy checks.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
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
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
static bool areTypesEqual(QualType S, QualType D)
static bool areBinaryOperatorOperandsTypesEqualToOperatorResultType(const Expr *E, bool IgnoreTypeAliases)
static const Decl * getSourceExprDecl(const Expr *SourceExpr)
bool areParensNeededForStatement(const Stmt &Node)
llvm::StringMap< ClangTidyValue > OptionMap