1 //===--- DeleteNullPointerCheck.cpp - clang-tidy---------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "DeleteNullPointerCheck.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14 
15 using namespace clang::ast_matchers;
16 
17 namespace clang {
18 namespace tidy {
19 namespace readability {
20 
21 void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) {
22   const auto DeleteExpr =
23       cxxDeleteExpr(has(castExpr(has(declRefExpr(
24                         to(decl(equalsBoundNode("deletedPointer"))))))))
25           .bind("deleteExpr");
26 
27   const auto DeleteMemberExpr =
28       cxxDeleteExpr(has(castExpr(has(memberExpr(hasDeclaration(
29                         fieldDecl(equalsBoundNode("deletedMemberPointer"))))))))
30           .bind("deleteMemberExpr");
31 
32   const auto PointerExpr = ignoringImpCasts(anyOf(
33       declRefExpr(to(decl().bind("deletedPointer"))),
34       memberExpr(hasDeclaration(fieldDecl().bind("deletedMemberPointer")))));
35 
36   const auto PointerCondition = castExpr(hasCastKind(CK_PointerToBoolean),
37                                          hasSourceExpression(PointerExpr));
38   const auto BinaryPointerCheckCondition =
39       binaryOperator(hasEitherOperand(castExpr(hasCastKind(CK_NullToPointer))),
40                      hasEitherOperand(PointerExpr));
41 
42   Finder->addMatcher(
43       ifStmt(hasCondition(anyOf(PointerCondition, BinaryPointerCheckCondition)),
44              hasThen(anyOf(
45                  DeleteExpr, DeleteMemberExpr,
46                  compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)),
47                               statementCountIs(1))
48                      .bind("compound"))))
49           .bind("ifWithDelete"),
50       this);
51 }
52 
53 void DeleteNullPointerCheck::check(const MatchFinder::MatchResult &Result) {
54   const auto *IfWithDelete = Result.Nodes.getNodeAs<IfStmt>("ifWithDelete");
55   const auto *Compound = Result.Nodes.getNodeAs<CompoundStmt>("compound");
56 
57   auto Diag = diag(
58       IfWithDelete->getLocStart(),
59       "'if' statement is unnecessary; deleting null pointer has no effect");
60   if (IfWithDelete->getElse())
61     return;
62   // FIXME: generate fixit for this case.
63 
64   Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
65       IfWithDelete->getLocStart(),
66       Lexer::getLocForEndOfToken(IfWithDelete->getCond()->getLocEnd(), 0,
67                                  *Result.SourceManager,
68                                  Result.Context->getLangOpts())));
69   if (Compound) {
70     Diag << FixItHint::CreateRemoval(
71         CharSourceRange::getTokenRange(Compound->getLBracLoc()));
72     Diag << FixItHint::CreateRemoval(
73         CharSourceRange::getTokenRange(Compound->getRBracLoc()));
74   }
75 }
76 
77 } // namespace readability
78 } // namespace tidy
79 } // namespace clang
80