11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 17 namespace ast_matchers {
22 namespace llvm_check {
24 void PreferIsaOrDynCastInConditionalsCheck::registerMatchers(
25 MatchFinder *Finder) {
26 if (!getLangOpts().CPlusPlus)
29 auto Condition = hasCondition(implicitCastExpr(has(
31 allOf(unless(
isMacroID()), unless(cxxMemberCallExpr()),
32 anyOf(callee(namedDecl(hasName(
"cast"))),
33 callee(namedDecl(hasName(
"dyn_cast")).bind(
"dyn_cast")))))
37 has(declStmt(containsDeclaration(
39 varDecl(hasInitializer(
40 callExpr(allOf(unless(
isMacroID()), unless(cxxMemberCallExpr()),
41 callee(namedDecl(hasName(
"cast")))))
47 allOf(unless(
isMacroID()), unless(cxxMemberCallExpr()),
48 allOf(callee(namedDecl(anyOf(hasName(
"isa"), hasName(
"cast"),
49 hasName(
"cast_or_null"),
51 hasName(
"dyn_cast_or_null")))
53 hasArgument(0, anyOf(declRefExpr().bind(
"arg"),
54 cxxMemberCallExpr().bind(
"arg"))))))
58 stmt(anyOf(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)),
70 void PreferIsaOrDynCastInConditionalsCheck::check(
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");
106 StringRef LHSString(Lexer::getSourceText(
108 *Result.SourceManager, getLangOpts()));
110 StringRef ArgString(Lexer::getSourceText(
112 *Result.SourceManager, getLangOpts()));
114 if (ArgString != LHSString)
117 StringRef RHSString(Lexer::getSourceText(
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()),
static bool isMacroID(SourceRange R)
AST_MATCHER(Expr, isMacroID)
constexpr llvm::StringLiteral Message
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::string Condition
Condition used after the preprocessor directive.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result