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();
143 const bool FnToFnCast =
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:
217 ReplaceWithConstructorCall();
219 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 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";