10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/ASTMatchers/ASTMatchers.h"
13#include "clang/Lex/Lexer.h"
20 ast_matchers::MatchFinder *Finder) {
26 unless(hasParent(substNonTypeTemplateParmExpr())))
31 cxxFunctionalCastExpr(
32 hasDestinationType(hasCanonicalType(anyOf(
33 builtinType(), references(qualType()), pointsTo(qualType())))),
35 hasSourceExpression(anyOf(cxxConstructExpr(), initListExpr()))))
41 while ((SourceType->isPointerType() && DestType->isPointerType()) ||
42 (SourceType->isReferenceType() && DestType->isReferenceType())) {
43 SourceType = SourceType->getPointeeType();
44 DestType = DestType->getPointeeType();
45 if (SourceType.isConstQualified() && !DestType.isConstQualified()) {
46 return (SourceType->isPointerType() == DestType->isPointerType()) &&
47 (SourceType->isReferenceType() == DestType->isReferenceType());
54 while ((T1->isPointerType() && T2->isPointerType()) ||
55 (T1->isReferenceType() && T2->isReferenceType())) {
56 T1 = T1->getPointeeType();
57 T2 = T2->getPointeeType();
59 return T1.getUnqualifiedType() == T2.getUnqualifiedType();
63 if (
const auto *CastExpr = dyn_cast<CStyleCastExpr>(Expr))
64 return CharSourceRange::getCharRange(
65 CastExpr->getLParenLoc(),
66 CastExpr->getSubExprAsWritten()->getBeginLoc());
67 if (
const auto *CastExpr = dyn_cast<CXXFunctionalCastExpr>(Expr))
68 return CharSourceRange::getCharRange(CastExpr->getBeginLoc(),
69 CastExpr->getLParenLoc());
70 llvm_unreachable(
"Unsupported CastExpr");
74 const LangOptions &LangOpts,
75 const ExplicitCastExpr *Expr) {
76 SourceLocation BeginLoc;
77 SourceLocation EndLoc;
79 if (
const auto *CastExpr = dyn_cast<CStyleCastExpr>(Expr)) {
80 BeginLoc = CastExpr->getLParenLoc().getLocWithOffset(1);
81 EndLoc = CastExpr->getRParenLoc().getLocWithOffset(-1);
82 }
else if (
const auto *CastExpr = dyn_cast<CXXFunctionalCastExpr>(Expr)) {
83 BeginLoc = CastExpr->getBeginLoc();
84 EndLoc = CastExpr->getLParenLoc().getLocWithOffset(-1);
86 llvm_unreachable(
"Unsupported CastExpr");
88 return Lexer::getSourceText(CharSourceRange::getTokenRange(BeginLoc, EndLoc),
93 const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>(
"cast");
96 if (CastExpr->getExprLoc().isMacroID())
101 if (CastExpr->getCastKind() == CK_ToVoid)
104 auto IsFunction = [](QualType T) {
105 T = T.getCanonicalType().getNonReferenceType();
106 return T->isFunctionType() || T->isFunctionPointerType() ||
107 T->isMemberFunctionPointerType();
110 const QualType DestTypeAsWritten =
111 CastExpr->getTypeAsWritten().getUnqualifiedType();
112 const QualType SourceTypeAsWritten =
113 CastExpr->getSubExprAsWritten()->getType().getUnqualifiedType();
114 const QualType SourceType = SourceTypeAsWritten.getCanonicalType();
115 const QualType DestType = DestTypeAsWritten.getCanonicalType();
120 IsFunction(SourceTypeAsWritten) && IsFunction(DestTypeAsWritten);
122 const bool ConstructorCast = !CastExpr->getTypeAsWritten().hasQualifiers() &&
123 DestTypeAsWritten->isRecordType() &&
124 !DestTypeAsWritten->isElaboratedTypeSpecifier();
126 if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast) {
131 QualType
Src = SourceTypeAsWritten, Dst = DestTypeAsWritten;
132 if (
const auto *ElTy = dyn_cast<ElaboratedType>(
Src))
133 Src = ElTy->getNamedType();
134 if (
const auto *ElTy = dyn_cast<ElaboratedType>(Dst))
135 Dst = ElTy->getNamedType();
137 diag(CastExpr->getBeginLoc(),
"redundant cast to the same type")
138 << FixItHint::CreateRemoval(ReplaceRange);
148 if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context)
156 SourceManager &SM = *Result.SourceManager;
160 if (SM.getFilename(SM.getSpellingLoc(CastExpr->getBeginLoc()))
169 diag(CastExpr->getBeginLoc(),
"C-style casts are discouraged; use %0");
171 auto ReplaceWithCast = [&](std::string CastText) {
172 const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
173 if (!isa<ParenExpr>(SubExpr) && !isa<CXXFunctionalCastExpr>(CastExpr)) {
174 CastText.push_back(
'(');
175 Diag << FixItHint::CreateInsertion(
176 Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0, SM,
180 Diag << FixItHint::CreateReplacement(ReplaceRange, CastText);
182 auto ReplaceWithNamedCast = [&](StringRef CastType) {
184 ReplaceWithCast((CastType +
"<" + DestTypeString +
">").str());
186 auto ReplaceWithConstructorCall = [&]() {
187 Diag <<
"constructor call syntax";
189 ReplaceWithCast(DestTypeString.str());
192 switch (CastExpr->getCastKind()) {
193 case CK_FunctionToPointerDecay:
194 ReplaceWithNamedCast(
"static_cast");
196 case CK_ConstructorConversion:
197 if (ConstructorCast) {
198 ReplaceWithConstructorCall();
200 ReplaceWithNamedCast(
"static_cast");
205 ReplaceWithNamedCast(
"static_cast");
208 if (SourceType == DestType) {
209 Diag <<
"static_cast (if needed, the cast may be redundant)";
210 ReplaceWithCast((
"static_cast<" + DestTypeString +
">").str());
215 ReplaceWithNamedCast(
"const_cast");
218 if (ConstructorCast) {
219 ReplaceWithConstructorCall();
222 if (DestType->isReferenceType()) {
223 QualType Dest = DestType.getNonReferenceType();
224 QualType Source = SourceType.getNonReferenceType();
225 if (Source == Dest.withConst() ||
226 SourceType.getNonReferenceType() == DestType.getNonReferenceType()) {
227 ReplaceWithNamedCast(
"const_cast");
233 case clang::CK_IntegralCast:
237 if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) &&
238 (DestType->isBuiltinType() || DestType->isEnumeralType())) {
239 ReplaceWithNamedCast(
"static_cast");
246 if (SourceType->isVoidPointerType())
247 ReplaceWithNamedCast(
"static_cast");
249 ReplaceWithNamedCast(
"reinterpret_cast");
257 Diag <<
"static_cast/const_cast/reinterpret_cast";
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
StringRef getCurrentMainFile() const
Returns the main file name of the current translation unit.
const LangOptions & getLangOpts() const
Returns the language options from the context.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
static bool needsConstCast(QualType SourceType, QualType DestType)
static StringRef getDestTypeString(const SourceManager &SM, const LangOptions &LangOpts, const ExplicitCastExpr *Expr)
static bool pointedUnqualifiedTypesAreEqual(QualType T1, QualType T2)
static clang::CharSourceRange getReplaceRange(const ExplicitCastExpr *Expr)