1 //===--- DeleteNullPointerCheck.cpp - clang-tidy---------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "DeleteNullPointerCheck.h"
10 #include "../utils/LexerUtils.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 
registerMatchers(MatchFinder * Finder)21 void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) {
22   const auto DeleteExpr =
23       cxxDeleteExpr(
24           has(declRefExpr(to(decl(equalsBoundNode("deletedPointer"))))))
25           .bind("deleteExpr");
26 
27   const auto DeleteMemberExpr =
28       cxxDeleteExpr(has(memberExpr(hasDeclaration(
29                         fieldDecl(equalsBoundNode("deletedMemberPointer"))))))
30           .bind("deleteMemberExpr");
31 
32   const auto PointerExpr = anyOf(
33       declRefExpr(to(decl().bind("deletedPointer"))),
34       memberExpr(hasDeclaration(fieldDecl().bind("deletedMemberPointer"))));
35 
36   const auto BinaryPointerCheckCondition = binaryOperator(hasOperands(
37       anyOf(cxxNullPtrLiteralExpr(), integerLiteral(equals(0))), PointerExpr));
38 
39   Finder->addMatcher(
40       ifStmt(hasCondition(anyOf(PointerExpr, BinaryPointerCheckCondition)),
41              hasThen(anyOf(
42                  DeleteExpr, DeleteMemberExpr,
43                  compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)),
44                               statementCountIs(1))
45                      .bind("compound"))))
46           .bind("ifWithDelete"),
47       this);
48 }
49 
check(const MatchFinder::MatchResult & Result)50 void DeleteNullPointerCheck::check(const MatchFinder::MatchResult &Result) {
51   const auto *IfWithDelete = Result.Nodes.getNodeAs<IfStmt>("ifWithDelete");
52   const auto *Compound = Result.Nodes.getNodeAs<CompoundStmt>("compound");
53 
54   auto Diag = diag(
55       IfWithDelete->getBeginLoc(),
56       "'if' statement is unnecessary; deleting null pointer has no effect");
57   if (IfWithDelete->getElse())
58     return;
59   // FIXME: generate fixit for this case.
60 
61   Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
62       IfWithDelete->getBeginLoc(),
63       utils::lexer::getPreviousToken(IfWithDelete->getThen()->getBeginLoc(),
64                                      *Result.SourceManager,
65                                      Result.Context->getLangOpts())
66           .getLocation()));
67 
68   if (Compound) {
69     Diag << FixItHint::CreateRemoval(
70         CharSourceRange::getTokenRange(Compound->getLBracLoc()));
71     Diag << FixItHint::CreateRemoval(
72         CharSourceRange::getTokenRange(Compound->getRBracLoc()));
73   }
74 }
75 
76 } // namespace readability
77 } // namespace tidy
78 } // namespace clang
79