11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
18 namespace ast_matchers {
23 namespace llvm_check {
25 void PreferIsaOrDynCastInConditionalsCheck::registerMatchers(
26 MatchFinder *Finder) {
27 auto Condition = hasCondition(implicitCastExpr(has(
29 allOf(unless(
isMacroID()), unless(cxxMemberCallExpr()),
30 anyOf(callee(namedDecl(hasName(
"cast"))),
31 callee(namedDecl(hasName(
"dyn_cast")).bind(
"dyn_cast")))))
35 has(declStmt(containsDeclaration(
37 varDecl(hasInitializer(
38 callExpr(allOf(unless(
isMacroID()), unless(cxxMemberCallExpr()),
39 callee(namedDecl(hasName(
"cast")))))
46 unless(
isMacroID()), unless(cxxMemberCallExpr()),
47 allOf(callee(namedDecl(hasAnyName(
"isa",
"cast",
"cast_or_null",
48 "dyn_cast",
"dyn_cast_or_null"))
52 mapAnyOf(declRefExpr, cxxMemberCallExpr).bind(
"arg")))))
58 ifStmt(Any), whileStmt(Any), doStmt(
Condition),
60 allOf(unless(isExpansionInFileMatching(
61 "llvm/include/llvm/Support/Casting.h")),
62 hasOperatorName(
"&&"),
63 hasLHS(implicitCastExpr().bind(
"lhs")),
64 hasRHS(anyOf(implicitCastExpr(has(CallExpression)),
71 const MatchFinder::MatchResult &Result) {
72 if (
const auto *MatchedDecl = Result.Nodes.getNodeAs<CallExpr>(
"assign")) {
73 SourceLocation StartLoc = MatchedDecl->getCallee()->getExprLoc();
74 SourceLocation EndLoc =
75 StartLoc.getLocWithOffset(StringRef(
"cast").size() - 1);
77 diag(MatchedDecl->getBeginLoc(),
78 "cast<> in conditional will assert rather than return a null pointer")
79 << FixItHint::CreateReplacement(SourceRange(StartLoc, EndLoc),
81 }
else if (
const auto *MatchedDecl =
82 Result.Nodes.getNodeAs<CallExpr>(
"call")) {
83 SourceLocation StartLoc = MatchedDecl->getCallee()->getExprLoc();
84 SourceLocation EndLoc =
85 StartLoc.getLocWithOffset(StringRef(
"cast").size() - 1);
88 "cast<> in conditional will assert rather than return a null pointer";
89 if (Result.Nodes.getNodeAs<NamedDecl>(
"dyn_cast"))
90 Message =
"return value from dyn_cast<> not used";
92 diag(MatchedDecl->getBeginLoc(),
Message)
93 << FixItHint::CreateReplacement(SourceRange(StartLoc, EndLoc),
"isa");
94 }
else if (
const auto *MatchedDecl =
95 Result.Nodes.getNodeAs<BinaryOperator>(
"and")) {
96 const auto *LHS = Result.Nodes.getNodeAs<ImplicitCastExpr>(
"lhs");
97 const auto *RHS = Result.Nodes.getNodeAs<CallExpr>(
"rhs");
98 const auto *Arg = Result.Nodes.getNodeAs<Expr>(
"arg");
99 const auto *Func = Result.Nodes.getNodeAs<NamedDecl>(
"func");
101 assert(LHS &&
"LHS is null");
102 assert(RHS &&
"RHS is null");
103 assert(Arg &&
"Arg is null");
104 assert(Func &&
"Func is null");
107 CharSourceRange::getTokenRange(LHS->getSourceRange()),
108 *Result.SourceManager, getLangOpts()));
111 CharSourceRange::getTokenRange(Arg->getSourceRange()),
112 *Result.SourceManager, getLangOpts()));
114 if (ArgString != LHSString)
118 CharSourceRange::getTokenRange(RHS->getSourceRange()),
119 *Result.SourceManager, getLangOpts()));
121 std::string Replacement(
"isa_and_nonnull");
122 Replacement += RHSString.substr(Func->getName().size());
124 diag(MatchedDecl->getBeginLoc(),
125 "isa_and_nonnull<> is preferred over an explicit test for null "
126 "followed by calling isa<>")
127 << FixItHint::CreateReplacement(SourceRange(MatchedDecl->getBeginLoc(),
128 MatchedDecl->getEndLoc()),