116 const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>(
"cast");
119 if (CastExpr->getExprLoc().isMacroID())
124 if (CastExpr->getCastKind() == CK_ToVoid)
127 auto IsFunction = [](QualType T) {
128 T = T.getCanonicalType().getNonReferenceType();
129 return T->isFunctionType() || T->isFunctionPointerType() ||
130 T->isMemberFunctionPointerType();
133 const QualType DestTypeAsWritten =
134 CastExpr->getTypeAsWritten().getUnqualifiedType();
135 const QualType SourceTypeAsWritten =
136 CastExpr->getSubExprAsWritten()->getType().getUnqualifiedType();
137 const QualType SourceType = SourceTypeAsWritten.getCanonicalType();
138 const QualType DestType = DestTypeAsWritten.getCanonicalType();
142 const bool FnToFnCast =
143 IsFunction(SourceTypeAsWritten) && IsFunction(DestTypeAsWritten);
145 const bool ConstructorCast = !CastExpr->getTypeAsWritten().hasQualifiers() &&
146 DestTypeAsWritten->isRecordType() &&
147 !DestTypeAsWritten->isElaboratedTypeSpecifier();
149 if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast) {
155 diag(CastExpr->getBeginLoc(),
"redundant cast to the same type")
156 << FixItHint::CreateRemoval(ReplaceRange);
163 if (!getLangOpts().CPlusPlus || getLangOpts().ObjC)
166 if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context)
171 if (getCurrentMainFile().ends_with(
".c"))
174 SourceManager &SM = *Result.SourceManager;
178 if (SM.getFilename(SM.getSpellingLoc(CastExpr->getBeginLoc()))
187 diag(CastExpr->getBeginLoc(),
"C-style casts are discouraged; use %0");
189 auto ReplaceWithCast = [&](std::string CastText) {
190 const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
191 if (!isa<ParenExpr>(SubExpr) && !isa<CXXFunctionalCastExpr>(CastExpr)) {
192 CastText.push_back(
'(');
193 Diag << FixItHint::CreateInsertion(
194 Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0, SM,
198 Diag << FixItHint::CreateReplacement(ReplaceRange, CastText);
200 auto ReplaceWithNamedCast = [&](StringRef CastType) {
202 ReplaceWithCast((CastType +
"<" + DestTypeString +
">").str());
204 auto ReplaceWithConstructorCall = [&]() {
205 Diag <<
"constructor call syntax";
207 ReplaceWithCast(DestTypeString.str());
210 switch (CastExpr->getCastKind()) {
211 case CK_FunctionToPointerDecay:
212 ReplaceWithNamedCast(
"static_cast");
214 case CK_ConstructorConversion:
215 if (ConstructorCast) {
216 ReplaceWithConstructorCall();
218 ReplaceWithNamedCast(
"static_cast");
223 ReplaceWithNamedCast(
"static_cast");
226 if (SourceType == DestType) {
227 Diag <<
"static_cast (if needed, the cast may be redundant)";
228 ReplaceWithCast((
"static_cast<" + DestTypeString +
">").str());
233 ReplaceWithNamedCast(
"const_cast");
236 if (ConstructorCast) {
237 ReplaceWithConstructorCall();
240 if (DestType->isReferenceType()) {
241 const QualType Dest = DestType.getNonReferenceType();
242 const QualType Source = SourceType.getNonReferenceType();
243 if (Source == Dest.withConst() ||
244 SourceType.getNonReferenceType() == DestType.getNonReferenceType()) {
245 ReplaceWithNamedCast(
"const_cast");
250 if (DestType->isVoidPointerType() && SourceType->isPointerType() &&
251 !SourceType->getPointeeType()->isPointerType()) {
252 ReplaceWithNamedCast(
"reinterpret_cast");
257 case clang::CK_IntegralCast:
261 if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) &&
262 (DestType->isBuiltinType() || DestType->isEnumeralType())) {
263 ReplaceWithNamedCast(
"static_cast");
270 if (SourceType->isVoidPointerType())
271 ReplaceWithNamedCast(
"static_cast");
273 ReplaceWithNamedCast(
"reinterpret_cast");
277 case CK_BaseToDerived:
279 ReplaceWithNamedCast(
"static_cast");
287 Diag <<
"static_cast/const_cast/reinterpret_cast";