11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
15 using namespace clang::ast_matchers;
19 namespace readability {
21 void DeleteNullPointerCheck::registerMatchers(MatchFinder *
Finder) {
22 const auto DeleteExpr =
23 cxxDeleteExpr(has(castExpr(has(declRefExpr(
24 to(decl(equalsBoundNode(
"deletedPointer"))))))))
27 const auto PointerExpr =
28 ignoringImpCasts(declRefExpr(to(decl().bind(
"deletedPointer"))));
29 const auto PointerCondition = castExpr(hasCastKind(CK_PointerToBoolean),
30 hasSourceExpression(PointerExpr));
31 const auto BinaryPointerCheckCondition =
32 binaryOperator(hasEitherOperand(castExpr(hasCastKind(CK_NullToPointer))),
33 hasEitherOperand(PointerExpr));
36 ifStmt(hasCondition(anyOf(PointerCondition, BinaryPointerCheckCondition)),
37 hasThen(anyOf(DeleteExpr,
38 compoundStmt(has(DeleteExpr), statementCountIs(1))
40 .bind(
"ifWithDelete"),
44 void DeleteNullPointerCheck::check(
const MatchFinder::MatchResult &
Result) {
45 const auto *IfWithDelete = Result.Nodes.getNodeAs<IfStmt>(
"ifWithDelete");
46 const auto *Compound = Result.Nodes.getNodeAs<CompoundStmt>(
"compound");
49 IfWithDelete->getLocStart(),
50 "'if' statement is unnecessary; deleting null pointer has no effect");
51 if (IfWithDelete->getElse())
55 Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
56 IfWithDelete->getLocStart(),
57 Lexer::getLocForEndOfToken(IfWithDelete->getCond()->getLocEnd(), 0,
58 *Result.SourceManager,
59 Result.Context->getLangOpts())));
61 Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
62 Compound->getLBracLoc(),
63 Lexer::getLocForEndOfToken(Compound->getLBracLoc(), 0,
64 *Result.SourceManager,
65 Result.Context->getLangOpts())));
66 Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
67 Compound->getRBracLoc(),
68 Lexer::getLocForEndOfToken(Compound->getRBracLoc(), 0,
69 *Result.SourceManager,
70 Result.Context->getLangOpts())));
std::unique_ptr< ast_matchers::MatchFinder > Finder