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 namespace readability {
22 void AvoidCStyleCastsCheck::registerMatchers(
23 ast_matchers::MatchFinder *Finder) {
29 unless(hasParent(substNonTypeTemplateParmExpr())),
31 unless(isInTemplateInstantiation()))
37 while ((SourceType->isPointerType() && DestType->isPointerType()) ||
38 (SourceType->isReferenceType() && DestType->isReferenceType())) {
39 SourceType = SourceType->getPointeeType();
40 DestType = DestType->getPointeeType();
41 if (SourceType.isConstQualified() && !DestType.isConstQualified()) {
42 return (SourceType->isPointerType() == DestType->isPointerType()) &&
43 (SourceType->isReferenceType() == DestType->isReferenceType());
50 while ((T1->isPointerType() && T2->isPointerType()) ||
51 (T1->isReferenceType() && T2->isReferenceType())) {
52 T1 = T1->getPointeeType();
53 T2 = T2->getPointeeType();
55 return T1.getUnqualifiedType() == T2.getUnqualifiedType();
58 void AvoidCStyleCastsCheck::check(
const MatchFinder::MatchResult &Result) {
59 const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>(
"cast");
62 if (CastExpr->getExprLoc().isMacroID())
67 if (CastExpr->getCastKind() == CK_ToVoid)
70 auto isFunction = [](QualType T) {
71 T = T.getCanonicalType().getNonReferenceType();
72 return T->isFunctionType() || T->isFunctionPointerType() ||
73 T->isMemberFunctionPointerType();
76 const QualType DestTypeAsWritten =
77 CastExpr->getTypeAsWritten().getUnqualifiedType();
78 const QualType SourceTypeAsWritten =
79 CastExpr->getSubExprAsWritten()->getType().getUnqualifiedType();
80 const QualType SourceType = SourceTypeAsWritten.getCanonicalType();
81 const QualType DestType = DestTypeAsWritten.getCanonicalType();
83 auto ReplaceRange = CharSourceRange::getCharRange(
84 CastExpr->getLParenLoc(), CastExpr->getSubExprAsWritten()->getBeginLoc());
87 isFunction(SourceTypeAsWritten) && isFunction(DestTypeAsWritten);
89 const bool ConstructorCast = !CastExpr->getTypeAsWritten().hasQualifiers() &&
90 DestTypeAsWritten->isRecordType() &&
91 !DestTypeAsWritten->isElaboratedTypeSpecifier();
93 if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast) {
98 if (SourceTypeAsWritten == DestTypeAsWritten) {
99 diag(CastExpr->getBeginLoc(),
"redundant cast to the same type")
100 << FixItHint::CreateRemoval(ReplaceRange);
107 if (!getLangOpts().CPlusPlus || getLangOpts().ObjC)
110 if (!
match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context)
115 if (getCurrentMainFile().endswith(
".c"))
118 SourceManager &SM = *Result.SourceManager;
122 if (SM.getFilename(SM.getSpellingLoc(CastExpr->getBeginLoc())).endswith(
".c"))
127 StringRef DestTypeString =
129 CastExpr->getLParenLoc().getLocWithOffset(1),
130 CastExpr->getRParenLoc().getLocWithOffset(-1)),
134 diag(CastExpr->getBeginLoc(),
"C-style casts are discouraged; use %0");
136 auto ReplaceWithCast = [&](std::string CastText) {
137 const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
138 if (!isa<ParenExpr>(SubExpr)) {
139 CastText.push_back(
'(');
140 Diag << FixItHint::CreateInsertion(
141 Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0, SM,
145 Diag << FixItHint::CreateReplacement(ReplaceRange, CastText);
147 auto ReplaceWithNamedCast = [&](StringRef CastType) {
149 ReplaceWithCast((CastType +
"<" + DestTypeString +
">").str());
151 auto ReplaceWithConstructorCall = [&]() {
152 Diag <<
"constructor call syntax";
154 ReplaceWithCast(DestTypeString.str());
157 switch (CastExpr->getCastKind()) {
158 case CK_FunctionToPointerDecay:
159 ReplaceWithNamedCast(
"static_cast");
161 case CK_ConstructorConversion:
162 if (ConstructorCast) {
163 ReplaceWithConstructorCall();
165 ReplaceWithNamedCast(
"static_cast");
170 ReplaceWithNamedCast(
"static_cast");
173 if (SourceType == DestType) {
174 Diag <<
"static_cast (if needed, the cast may be redundant)";
175 ReplaceWithCast((
"static_cast<" + DestTypeString +
">").str());
180 ReplaceWithNamedCast(
"const_cast");
183 if (ConstructorCast) {
184 ReplaceWithConstructorCall();
187 if (DestType->isReferenceType()) {
188 QualType Dest = DestType.getNonReferenceType();
189 QualType Source = SourceType.getNonReferenceType();
190 if (Source == Dest.withConst() ||
191 SourceType.getNonReferenceType() == DestType.getNonReferenceType()) {
192 ReplaceWithNamedCast(
"const_cast");
198 case clang::CK_IntegralCast:
202 if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) &&
203 (DestType->isBuiltinType() || DestType->isEnumeralType())) {
204 ReplaceWithNamedCast(
"static_cast");
211 if (SourceType->isVoidPointerType())
212 ReplaceWithNamedCast(
"static_cast");
214 ReplaceWithNamedCast(
"reinterpret_cast");
222 Diag <<
"static_cast/const_cast/reinterpret_cast";
std::vector< std::string > match(const SymbolIndex &I, const FuzzyFindRequest &Req, bool *Incomplete)
static bool needsConstCast(QualType SourceType, QualType DestType)
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
static bool pointedUnqualifiedTypesAreEqual(QualType T1, QualType T2)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//