11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/ASTMatchers/ASTMatchers.h"
14 #include "clang/Lex/Lexer.h"
16 using namespace clang::ast_matchers;
21 namespace readability {
23 void AvoidCStyleCastsCheck::registerMatchers(
24 ast_matchers::MatchFinder *
Finder) {
30 unless(hasParent(substNonTypeTemplateParmExpr())),
32 unless(isInTemplateInstantiation()))
38 SourceType = SourceType.getNonReferenceType();
39 DestType = DestType.getNonReferenceType();
40 while (SourceType->isPointerType() && DestType->isPointerType()) {
41 SourceType = SourceType->getPointeeType();
42 DestType = DestType->getPointeeType();
43 if (SourceType.isConstQualified() && !DestType.isConstQualified())
50 SourceType = SourceType.getNonReferenceType();
51 DestType = DestType.getNonReferenceType();
52 while (SourceType->isPointerType() && DestType->isPointerType()) {
53 SourceType = SourceType->getPointeeType();
54 DestType = DestType->getPointeeType();
56 return SourceType.getUnqualifiedType() == DestType.getUnqualifiedType();
59 void AvoidCStyleCastsCheck::check(
const MatchFinder::MatchResult &
Result) {
60 const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>(
"cast");
62 auto ParenRange = CharSourceRange::getTokenRange(CastExpr->getLParenLoc(),
63 CastExpr->getRParenLoc());
65 if (ParenRange.getBegin().isMacroID() || ParenRange.getEnd().isMacroID())
70 if (CastExpr->getTypeAsWritten()->isVoidType())
73 QualType SourceType = CastExpr->getSubExprAsWritten()->getType();
74 QualType DestType = CastExpr->getTypeAsWritten();
76 if (SourceType == DestType) {
77 diag(CastExpr->getLocStart(),
"redundant cast to the same type")
78 << FixItHint::CreateRemoval(ParenRange);
81 SourceType = SourceType.getCanonicalType();
82 DestType = DestType.getCanonicalType();
83 if (SourceType == DestType) {
84 diag(CastExpr->getLocStart(),
85 "possibly redundant cast between typedefs of the same type");
90 if (!getLangOpts().CPlusPlus)
93 if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context)
98 if (getCurrentMainFile().endswith(
".c"))
102 SourceManager &
SM = *Result.SourceManager;
103 if (SM.getFilename(SM.getSpellingLoc(CastExpr->getLocStart())).endswith(
".c"))
108 StringRef DestTypeString =
109 Lexer::getSourceText(CharSourceRange::getTokenRange(
110 CastExpr->getLParenLoc().getLocWithOffset(1),
111 CastExpr->getRParenLoc().getLocWithOffset(-1)),
115 diag(CastExpr->getLocStart(),
"C-style casts are discouraged; use %0");
117 auto ReplaceWithCast = [&](StringRef CastType) {
118 diag_builder << CastType;
120 const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
121 std::string CastText = (CastType +
"<" + DestTypeString +
">").str();
122 if (!isa<ParenExpr>(SubExpr)) {
123 CastText.push_back(
'(');
124 diag_builder << FixItHint::CreateInsertion(
125 Lexer::getLocForEndOfToken(SubExpr->getLocEnd(), 0,
SM,
129 diag_builder << FixItHint::CreateReplacement(ParenRange, CastText);
133 switch (CastExpr->getCastKind()) {
137 ReplaceWithCast(
"const_cast");
140 if (DestType->isReferenceType() &&
141 (SourceType.getNonReferenceType() ==
142 DestType.getNonReferenceType().withConst() ||
143 SourceType.getNonReferenceType() == DestType.getNonReferenceType())) {
144 ReplaceWithCast(
"const_cast");
148 case clang::CK_IntegralCast:
152 if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) &&
153 (DestType->isBuiltinType() || DestType->isEnumeralType())) {
154 ReplaceWithCast(
"static_cast");
161 ReplaceWithCast(
"reinterpret_cast");
169 diag_builder <<
"static_cast/const_cast/reinterpret_cast";
std::unique_ptr< ast_matchers::MatchFinder > Finder
static bool needsConstCast(QualType SourceType, QualType DestType)
static bool pointedTypesAreEqual(QualType SourceType, QualType DestType)