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();
54 const Expr *E,
bool IgnoreTypeAliases) {
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 if (LHSType.isNull() || !
areTypesEqual(LHSType.getNonReferenceType(),
68 NonReferenceType, IgnoreTypeAliases))
70 const QualType RHSType = B->getRHS()->IgnoreImplicit()->getType();
71 if (RHSType.isNull() || !
areTypesEqual(RHSType.getNonReferenceType(),
72 NonReferenceType, IgnoreTypeAliases))
103 auto SimpleType = qualType(hasCanonicalType(
104 qualType(anyOf(builtinType(), references(builtinType()),
105 references(pointsTo(qualType())), pointsTo(qualType())))));
107 auto BitfieldMemberExpr = memberExpr(member(fieldDecl(isBitField())));
109 const ast_matchers::internal::VariadicDynCastAllOfMatcher<
110 Stmt, CXXParenListInitExpr>
111 cxxParenListInitExpr;
115 unless(hasCastKind(CK_ConstructorConversion)),
116 unless(hasCastKind(CK_UserDefinedConversion)),
117 unless(cxxFunctionalCastExpr(hasDestinationType(unless(SimpleType)))),
119 hasDestinationType(qualType().bind(
"dstType")),
120 hasSourceExpression(anyOf(
121 expr(unless(initListExpr()), unless(BitfieldMemberExpr),
122 unless(cxxParenListInitExpr()),
123 hasType(qualType().bind(
"srcType")))
125 initListExpr(unless(hasInit(1, expr())),
126 hasInit(0, expr(unless(BitfieldMemberExpr),
127 hasType(qualType().bind(
"srcType")))
134 const auto *SourceExpr = Result.Nodes.getNodeAs<Expr>(
"source");
135 auto TypeD = *Result.Nodes.getNodeAs<QualType>(
"dstType");
137 if (SourceExpr->getValueKind() == VK_LValue &&
138 TypeD.getCanonicalType()->isRValueReferenceType())
142 Result.Nodes.getNodeAs<QualType>(
"srcType")->getNonReferenceType();
143 TypeD = TypeD.getNonReferenceType();
149 SourceExpr, IgnoreTypeAliases))
152 const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>(
"cast");
154 (CastExpr->getBeginLoc().isMacroID() ||
155 CastExpr->getEndLoc().isMacroID() || CastExpr->getExprLoc().isMacroID()))
159 auto Diag = diag(CastExpr->getExprLoc(),
160 "redundant explicit casting to the same type %0 as the "
161 "sub-expression, remove this casting");
164 const SourceManager &SM = *Result.SourceManager;
165 const SourceLocation SourceExprBegin =
166 SM.getExpansionLoc(SourceExpr->getBeginLoc());
167 const SourceLocation SourceExprEnd =
168 SM.getExpansionLoc(SourceExpr->getEndLoc());
170 if (SourceExprBegin != CastExpr->getBeginLoc())
171 Diag << FixItHint::CreateRemoval(SourceRange(
172 CastExpr->getBeginLoc(), SourceExprBegin.getLocWithOffset(-1)));
174 const SourceLocation NextToken = Lexer::getLocForEndOfToken(
175 SourceExprEnd, 0U, SM, Result.Context->getLangOpts());
177 if (SourceExprEnd != CastExpr->getEndLoc()) {
178 Diag << FixItHint::CreateRemoval(
179 SourceRange(NextToken, CastExpr->getEndLoc()));
183 Diag << FixItHint::CreateInsertion(SourceExprBegin,
"(")
184 << FixItHint::CreateInsertion(NextToken,
")");
192 if (
const auto *D = dyn_cast<CXXConstructorDecl>(SourceExprDecl)) {
193 diag(D->getLocation(),
194 "source type originates from the invocation of this constructor",
195 DiagnosticIDs::Note);
199 if (
const auto *D = dyn_cast<FunctionDecl>(SourceExprDecl)) {
200 diag(D->getLocation(),
201 "source type originates from the invocation of this "
202 "%select{function|method}0",
204 << isa<CXXMethodDecl>(D) << D->getReturnTypeSourceRange();
208 if (
const auto *D = dyn_cast<FieldDecl>(SourceExprDecl)) {
209 diag(D->getLocation(),
210 "source type originates from referencing this member",
212 << SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
216 if (
const auto *D = dyn_cast<ParmVarDecl>(SourceExprDecl)) {
217 diag(D->getLocation(),
218 "source type originates from referencing this parameter",
220 << SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
224 if (
const auto *D = dyn_cast<VarDecl>(SourceExprDecl)) {
225 diag(D->getLocation(),
226 "source type originates from referencing this variable",
228 << SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
232 if (
const auto *D = dyn_cast<EnumConstantDecl>(SourceExprDecl)) {
233 diag(D->getLocation(),
234 "source type originates from referencing this enum constant",
235 DiagnosticIDs::Note);
239 if (
const auto *D = dyn_cast<BindingDecl>(SourceExprDecl)) {
240 diag(D->getLocation(),
241 "source type originates from referencing this bound variable",
242 DiagnosticIDs::Note);
246 if (
const auto *D = dyn_cast<NonTypeTemplateParmDecl>(SourceExprDecl)) {
247 diag(D->getLocation(),
248 "source type originates from referencing this non-type template "
250 DiagnosticIDs::Note);
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.