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 const 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 const 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();
176 if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast &&
178 diag(CastExpr->getBeginLoc(),
"redundant cast to the same type")
179 << FixItHint::CreateRemoval(ReplaceRange);
185 if (!getLangOpts().CPlusPlus || getLangOpts().ObjC)
188 if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context)
193 if (getCurrentMainFile().ends_with(
".c"))
196 SourceManager &SM = *Result.SourceManager;
200 if (SM.getFilename(SM.getSpellingLoc(CastExpr->getBeginLoc()))
209 diag(CastExpr->getBeginLoc(),
"C-style casts are discouraged; use %0");
211 auto ReplaceWithCast = [&](std::string CastText) {
212 const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts();
213 if (!isa<ParenExpr>(SubExpr) && !isa<CXXFunctionalCastExpr>(CastExpr)) {
214 CastText.push_back(
'(');
215 Diag << FixItHint::CreateInsertion(
216 Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0, SM,
221 CastText.insert(CastText.begin(),
' ');
222 Diag << FixItHint::CreateReplacement(ReplaceRange, CastText);
224 const auto ReplaceWithNamedCast = [&](StringRef CastType) {
226 ReplaceWithCast((CastType +
"<" + DestTypeString +
">").str());
228 const auto ReplaceWithConstructorCall = [&]() {
229 Diag <<
"constructor call syntax";
231 ReplaceWithCast(DestTypeString.str());
234 switch (CastExpr->getCastKind()) {
235 case CK_FunctionToPointerDecay:
236 ReplaceWithNamedCast(
"static_cast");
238 case CK_ConstructorConversion:
240 ReplaceWithConstructorCall();
242 ReplaceWithNamedCast(
"static_cast");
246 ReplaceWithNamedCast(
"static_cast");
249 if (SourceType == DestType) {
250 Diag <<
"static_cast (if needed, the cast may be redundant)";
251 ReplaceWithCast((
"static_cast<" + DestTypeString +
">").str());
256 ReplaceWithNamedCast(
"const_cast");
259 if (ConstructorCast) {
260 ReplaceWithConstructorCall();
263 if (DestType->isReferenceType()) {
264 const QualType Dest = DestType.getNonReferenceType();
265 const QualType Source = SourceType.getNonReferenceType();
266 if (Source == Dest.withConst() ||
267 SourceType.getNonReferenceType() == DestType.getNonReferenceType()) {
268 ReplaceWithNamedCast(
"const_cast");
273 if (DestType->isVoidPointerType() && SourceType->isPointerType() &&
274 !SourceType->getPointeeType()->isPointerType()) {
275 ReplaceWithNamedCast(
"reinterpret_cast");
280 case CK_IntegralCast:
284 if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) &&
285 (DestType->isBuiltinType() || DestType->isEnumeralType())) {
286 ReplaceWithNamedCast(
"static_cast");
293 if (SourceType->isVoidPointerType())
294 ReplaceWithNamedCast(
"static_cast");
296 ReplaceWithNamedCast(
"reinterpret_cast");
300 case CK_BaseToDerived:
302 ReplaceWithNamedCast(
"static_cast");
310 Diag <<
"static_cast/const_cast/reinterpret_cast";