11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/ASTMatchers/ASTMatchers.h" 14 #include "clang/Lex/Lexer.h" 21 namespace readability {
23 void AvoidCStyleCastsCheck::registerMatchers(
24 ast_matchers::MatchFinder *Finder) {
30 unless(hasParent(substNonTypeTemplateParmExpr())),
32 unless(isInTemplateInstantiation()))
38 while ((SourceType->isPointerType() && DestType->isPointerType()) ||
39 (SourceType->isReferenceType() && DestType->isReferenceType())) {
40 SourceType = SourceType->getPointeeType();
41 DestType = DestType->getPointeeType();
42 if (SourceType.isConstQualified() && !DestType.isConstQualified()) {
43 return (SourceType->isPointerType() == DestType->isPointerType()) &&
44 (SourceType->isReferenceType() == DestType->isReferenceType());
51 while ((T1->isPointerType() && T2->isPointerType()) ||
52 (T1->isReferenceType() && T2->isReferenceType())) {
53 T1 = T1->getPointeeType();
54 T2 = T2->getPointeeType();
56 return T1.getUnqualifiedType() == T2.getUnqualifiedType();
59 void AvoidCStyleCastsCheck::check(
const MatchFinder::MatchResult &
Result) {
60 const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>(
"cast");
63 if (CastExpr->getExprLoc().isMacroID())
68 if (CastExpr->getCastKind() == CK_ToVoid)
71 auto isFunction = [](QualType T) {
72 T = T.getCanonicalType().getNonReferenceType();
73 return T->isFunctionType() || T->isFunctionPointerType() ||
74 T->isMemberFunctionPointerType();
77 const QualType DestTypeAsWritten =
78 CastExpr->getTypeAsWritten().getUnqualifiedType();
79 const QualType SourceTypeAsWritten =
80 CastExpr->getSubExprAsWritten()->getType().getUnqualifiedType();
81 const QualType SourceType = SourceTypeAsWritten.getCanonicalType();
82 const QualType DestType = DestTypeAsWritten.getCanonicalType();
84 auto ReplaceRange = CharSourceRange::getCharRange(
85 CastExpr->getLParenLoc(), CastExpr->getSubExprAsWritten()->getBeginLoc());
88 isFunction(SourceTypeAsWritten) && isFunction(DestTypeAsWritten);
90 if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast) {
95 if (SourceTypeAsWritten == DestTypeAsWritten) {
96 diag(CastExpr->getBeginLoc(),
"redundant cast to the same type")
97 << FixItHint::CreateRemoval(ReplaceRange);
104 if (!getLangOpts().CPlusPlus || getLangOpts().ObjC)
107 if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context)
112 if (getCurrentMainFile().endswith(
".c"))
115 SourceManager &SM = *Result.SourceManager;
119 if (SM.getFilename(SM.getSpellingLoc(CastExpr->getBeginLoc())).endswith(
".c"))
124 StringRef DestTypeString =
125 Lexer::getSourceText(CharSourceRange::getTokenRange(
126 CastExpr->getLParenLoc().getLocWithOffset(1),
127 CastExpr->getRParenLoc().getLocWithOffset(-1)),
131 diag(CastExpr->getBeginLoc(),
"C-style casts are discouraged; use %0");
133 auto ReplaceWithCast = [&](std::string CastText) {
134 const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
135 if (!isa<ParenExpr>(SubExpr)) {
136 CastText.push_back(
'(');
137 Diag << FixItHint::CreateInsertion(
138 Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0, SM,
142 Diag << FixItHint::CreateReplacement(ReplaceRange, CastText);
144 auto ReplaceWithNamedCast = [&](StringRef CastType) {
146 ReplaceWithCast((CastType +
"<" + DestTypeString +
">").str());
150 switch (CastExpr->getCastKind()) {
151 case CK_FunctionToPointerDecay:
152 ReplaceWithNamedCast(
"static_cast");
154 case CK_ConstructorConversion:
155 if (!CastExpr->getTypeAsWritten().hasQualifiers() &&
156 DestTypeAsWritten->isRecordType() &&
157 !DestTypeAsWritten->isElaboratedTypeSpecifier()) {
158 Diag <<
"constructor call syntax";
160 ReplaceWithCast(DestTypeString.str());
162 ReplaceWithNamedCast(
"static_cast");
167 ReplaceWithNamedCast(
"static_cast");
170 if (SourceType == DestType) {
171 Diag <<
"static_cast (if needed, the cast may be redundant)";
172 ReplaceWithCast((
"static_cast<" + DestTypeString +
">").str());
177 ReplaceWithNamedCast(
"const_cast");
180 if (DestType->isReferenceType()) {
181 QualType Dest = DestType.getNonReferenceType();
182 QualType Source = SourceType.getNonReferenceType();
183 if (Source == Dest.withConst() ||
184 SourceType.getNonReferenceType() == DestType.getNonReferenceType()) {
185 ReplaceWithNamedCast(
"const_cast");
191 case clang::CK_IntegralCast:
195 if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) &&
196 (DestType->isBuiltinType() || DestType->isEnumeralType())) {
197 ReplaceWithNamedCast(
"static_cast");
204 if (SourceType->isVoidPointerType())
205 ReplaceWithNamedCast(
"static_cast");
207 ReplaceWithNamedCast(
"reinterpret_cast");
215 Diag <<
"static_cast/const_cast/reinterpret_cast";
static bool needsConstCast(QualType SourceType, QualType DestType)
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
static bool pointedUnqualifiedTypesAreEqual(QualType T1, QualType T2)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//