73 const SourceManager &SM,
74 const LangOptions &LangOpts) {
75 if (ReplacementText.empty())
78 const SourceLocation Begin = Range.getBegin();
79 if (Begin.isInvalid() || Begin.isMacroID())
82 auto BeginInfo = SM.getDecomposedLoc(Begin);
84 StringRef Buffer = SM.getBufferData(BeginInfo.first, &Invalid);
85 if (Invalid || BeginInfo.second == 0)
88 return Lexer::isAsciiIdentifierContinueChar(Buffer[BeginInfo.second - 1],
90 Lexer::isAsciiIdentifierContinueChar(ReplacementText.front(),
139 const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>(
"cast");
142 if (CastExpr->getExprLoc().isMacroID())
147 if (CastExpr->getCastKind() == CK_ToVoid)
150 auto IsFunction = [](QualType T) {
151 T = T.getCanonicalType().getNonReferenceType();
152 return T->isFunctionType() || T->isFunctionPointerType() ||
153 T->isMemberFunctionPointerType();
156 const QualType DestTypeAsWritten =
157 CastExpr->getTypeAsWritten().getUnqualifiedType();
158 const QualType SourceTypeAsWritten =
159 CastExpr->getSubExprAsWritten()->getType().getUnqualifiedType();
160 const QualType SourceType = SourceTypeAsWritten.getCanonicalType();
161 const QualType DestType = DestTypeAsWritten.getCanonicalType();
165 const bool FnToFnCast =
166 IsFunction(SourceTypeAsWritten) && IsFunction(DestTypeAsWritten);
168 const bool ConstructorCast = !CastExpr->getTypeAsWritten().hasQualifiers() &&
169 DestTypeAsWritten->isRecordType() &&
170 !DestTypeAsWritten->isElaboratedTypeSpecifier();
172 if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast) {
178 diag(CastExpr->getBeginLoc(),
"redundant cast to the same type")
179 << FixItHint::CreateRemoval(ReplaceRange);
186 if (!getLangOpts().CPlusPlus || getLangOpts().ObjC)
189 if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context)
194 if (getCurrentMainFile().ends_with(
".c"))
197 SourceManager &SM = *Result.SourceManager;
201 if (SM.getFilename(SM.getSpellingLoc(CastExpr->getBeginLoc()))
210 diag(CastExpr->getBeginLoc(),
"C-style casts are discouraged; use %0");
212 auto ReplaceWithCast = [&](std::string CastText) {
213 const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
214 if (!isa<ParenExpr>(SubExpr) && !isa<CXXFunctionalCastExpr>(CastExpr)) {
215 CastText.push_back(
'(');
216 Diag << FixItHint::CreateInsertion(
217 Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0, SM,
222 CastText.insert(CastText.begin(),
' ');
223 Diag << FixItHint::CreateReplacement(ReplaceRange, CastText);
225 auto ReplaceWithNamedCast = [&](StringRef CastType) {
227 ReplaceWithCast((CastType +
"<" + DestTypeString +
">").str());
229 auto ReplaceWithConstructorCall = [&]() {
230 Diag <<
"constructor call syntax";
232 ReplaceWithCast(DestTypeString.str());
235 switch (CastExpr->getCastKind()) {
236 case CK_FunctionToPointerDecay:
237 ReplaceWithNamedCast(
"static_cast");
239 case CK_ConstructorConversion:
241 ReplaceWithConstructorCall();
243 ReplaceWithNamedCast(
"static_cast");
247 ReplaceWithNamedCast(
"static_cast");
250 if (SourceType == DestType) {
251 Diag <<
"static_cast (if needed, the cast may be redundant)";
252 ReplaceWithCast((
"static_cast<" + DestTypeString +
">").str());
257 ReplaceWithNamedCast(
"const_cast");
260 if (ConstructorCast) {
261 ReplaceWithConstructorCall();
264 if (DestType->isReferenceType()) {
265 const QualType Dest = DestType.getNonReferenceType();
266 const QualType Source = SourceType.getNonReferenceType();
267 if (Source == Dest.withConst() ||
268 SourceType.getNonReferenceType() == DestType.getNonReferenceType()) {
269 ReplaceWithNamedCast(
"const_cast");
274 if (DestType->isVoidPointerType() && SourceType->isPointerType() &&
275 !SourceType->getPointeeType()->isPointerType()) {
276 ReplaceWithNamedCast(
"reinterpret_cast");
281 case CK_IntegralCast:
285 if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) &&
286 (DestType->isBuiltinType() || DestType->isEnumeralType())) {
287 ReplaceWithNamedCast(
"static_cast");
294 if (SourceType->isVoidPointerType())
295 ReplaceWithNamedCast(
"static_cast");
297 ReplaceWithNamedCast(
"reinterpret_cast");
301 case CK_BaseToDerived:
303 ReplaceWithNamedCast(
"static_cast");
311 Diag <<
"static_cast/const_cast/reinterpret_cast";