117 const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>(
"cast");
120 if (CastExpr->getExprLoc().isMacroID())
125 if (CastExpr->getCastKind() == CK_ToVoid)
128 auto IsFunction = [](QualType T) {
129 T = T.getCanonicalType().getNonReferenceType();
130 return T->isFunctionType() || T->isFunctionPointerType() ||
131 T->isMemberFunctionPointerType();
134 const QualType DestTypeAsWritten =
135 CastExpr->getTypeAsWritten().getUnqualifiedType();
136 const QualType SourceTypeAsWritten =
137 CastExpr->getSubExprAsWritten()->getType().getUnqualifiedType();
138 const QualType SourceType = SourceTypeAsWritten.getCanonicalType();
139 const QualType DestType = DestTypeAsWritten.getCanonicalType();
144 IsFunction(SourceTypeAsWritten) && IsFunction(DestTypeAsWritten);
146 const bool ConstructorCast = !CastExpr->getTypeAsWritten().hasQualifiers() &&
147 DestTypeAsWritten->isRecordType() &&
148 !DestTypeAsWritten->isElaboratedTypeSpecifier();
150 if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast) {
156 diag(CastExpr->getBeginLoc(),
"redundant cast to the same type")
157 << FixItHint::CreateRemoval(ReplaceRange);
164 if (!getLangOpts().CPlusPlus || getLangOpts().ObjC)
167 if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context)
172 if (getCurrentMainFile().ends_with(
".c"))
175 SourceManager &SM = *Result.SourceManager;
179 if (SM.getFilename(SM.getSpellingLoc(CastExpr->getBeginLoc()))
188 diag(CastExpr->getBeginLoc(),
"C-style casts are discouraged; use %0");
190 auto ReplaceWithCast = [&](std::string CastText) {
191 const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
192 if (!isa<ParenExpr>(SubExpr) && !isa<CXXFunctionalCastExpr>(CastExpr)) {
193 CastText.push_back(
'(');
194 Diag << FixItHint::CreateInsertion(
195 Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0, SM,
199 Diag << FixItHint::CreateReplacement(ReplaceRange, CastText);
201 auto ReplaceWithNamedCast = [&](StringRef CastType) {
203 ReplaceWithCast((CastType +
"<" + DestTypeString +
">").str());
205 auto ReplaceWithConstructorCall = [&]() {
206 Diag <<
"constructor call syntax";
208 ReplaceWithCast(DestTypeString.str());
211 switch (CastExpr->getCastKind()) {
212 case CK_FunctionToPointerDecay:
213 ReplaceWithNamedCast(
"static_cast");
215 case CK_ConstructorConversion:
216 if (ConstructorCast) {
217 ReplaceWithConstructorCall();
219 ReplaceWithNamedCast(
"static_cast");
224 ReplaceWithNamedCast(
"static_cast");
227 if (SourceType == DestType) {
228 Diag <<
"static_cast (if needed, the cast may be redundant)";
229 ReplaceWithCast((
"static_cast<" + DestTypeString +
">").str());
234 ReplaceWithNamedCast(
"const_cast");
237 if (ConstructorCast) {
238 ReplaceWithConstructorCall();
241 if (DestType->isReferenceType()) {
242 QualType Dest = DestType.getNonReferenceType();
243 QualType Source = SourceType.getNonReferenceType();
244 if (Source == Dest.withConst() ||
245 SourceType.getNonReferenceType() == DestType.getNonReferenceType()) {
246 ReplaceWithNamedCast(
"const_cast");
252 case clang::CK_IntegralCast:
256 if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) &&
257 (DestType->isBuiltinType() || DestType->isEnumeralType())) {
258 ReplaceWithNamedCast(
"static_cast");
265 if (SourceType->isVoidPointerType())
266 ReplaceWithNamedCast(
"static_cast");
268 ReplaceWithNamedCast(
"reinterpret_cast");
276 Diag <<
"static_cast/const_cast/reinterpret_cast";