10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Lex/Lexer.h"
19 SourceType = SourceType.getNonReferenceType();
20 DestType = DestType.getNonReferenceType();
21 while (SourceType->isPointerType() && DestType->isPointerType()) {
22 SourceType = SourceType->getPointeeType();
23 DestType = DestType->getPointeeType();
24 if (SourceType.isConstQualified() && !DestType.isConstQualified())
32 cStyleCastExpr(unless(isInTemplateInstantiation())).bind(
"cast"),
this);
36 const auto *MatchedCast = Result.Nodes.getNodeAs<CStyleCastExpr>(
"cast");
38 if (MatchedCast->getCastKind() == CK_BitCast ||
39 MatchedCast->getCastKind() == CK_LValueBitCast ||
40 MatchedCast->getCastKind() == CK_IntegralToPointer ||
41 MatchedCast->getCastKind() == CK_PointerToIntegral ||
42 MatchedCast->getCastKind() == CK_ReinterpretMemberPointer) {
43 diag(MatchedCast->getBeginLoc(),
44 "do not use C-style cast to convert between unrelated types");
48 QualType SourceType = MatchedCast->getSubExpr()->getType();
50 if (MatchedCast->getCastKind() == CK_BaseToDerived) {
51 const auto *SourceDecl = SourceType->getPointeeCXXRecordDecl();
53 SourceDecl = SourceType->getAsCXXRecordDecl();
57 if (SourceDecl->isPolymorphic()) {
61 StringRef DestTypeString = Lexer::getSourceText(
62 CharSourceRange::getTokenRange(
63 MatchedCast->getLParenLoc().getLocWithOffset(1),
64 MatchedCast->getRParenLoc().getLocWithOffset(-1)),
67 auto DiagBuilder =
diag(
68 MatchedCast->getBeginLoc(),
69 "do not use C-style cast to downcast from a base to a derived class; "
70 "use dynamic_cast instead");
73 MatchedCast->getSubExprAsWritten()->IgnoreImpCasts();
74 std::string CastText = (
"dynamic_cast<" + DestTypeString +
">").str();
75 if (!isa<ParenExpr>(SubExpr)) {
76 CastText.push_back(
'(');
77 DiagBuilder << FixItHint::CreateInsertion(
78 Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0,
82 auto ParenRange = CharSourceRange::getTokenRange(
83 MatchedCast->getLParenLoc(), MatchedCast->getRParenLoc());
84 DiagBuilder << FixItHint::CreateReplacement(ParenRange, CastText);
87 MatchedCast->getBeginLoc(),
88 "do not use C-style cast to downcast from a base to a derived class");
93 if (MatchedCast->getCastKind() == CK_NoOp &&
95 diag(MatchedCast->getBeginLoc(),
96 "do not use C-style cast to cast away constness");
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
const LangOptions & getLangOpts() const
Returns the language options from the context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
static bool needsConstCast(QualType SourceType, QualType DestType)