xref: /llvm-project/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp (revision 7d2ea6c422d3f5712b7253407005e1a465a76946)
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::tidy::readability {
18 
registerMatchers(MatchFinder * Finder)19 void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) {
20   const auto DeleteExpr =
21       cxxDeleteExpr(
22           has(declRefExpr(to(decl(equalsBoundNode("deletedPointer"))))))
23           .bind("deleteExpr");
24 
25   const auto DeleteMemberExpr =
26       cxxDeleteExpr(has(memberExpr(hasDeclaration(
27                         fieldDecl(equalsBoundNode("deletedMemberPointer"))))))
28           .bind("deleteMemberExpr");
29 
30   const auto PointerExpr = anyOf(
31       declRefExpr(to(decl().bind("deletedPointer"))),
32       memberExpr(hasDeclaration(fieldDecl().bind("deletedMemberPointer"))));
33 
34   const auto BinaryPointerCheckCondition = binaryOperator(hasOperands(
35       anyOf(cxxNullPtrLiteralExpr(), integerLiteral(equals(0))), PointerExpr));
36 
37   Finder->addMatcher(
38       ifStmt(hasCondition(anyOf(PointerExpr, BinaryPointerCheckCondition)),
39              hasThen(anyOf(
40                  DeleteExpr, DeleteMemberExpr,
41                  compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)),
42                               statementCountIs(1))
43                      .bind("compound"))))
44           .bind("ifWithDelete"),
45       this);
46 }
47 
check(const MatchFinder::MatchResult & Result)48 void DeleteNullPointerCheck::check(const MatchFinder::MatchResult &Result) {
49   const auto *IfWithDelete = Result.Nodes.getNodeAs<IfStmt>("ifWithDelete");
50   const auto *Compound = Result.Nodes.getNodeAs<CompoundStmt>("compound");
51 
52   auto Diag = diag(
53       IfWithDelete->getBeginLoc(),
54       "'if' statement is unnecessary; deleting null pointer has no effect");
55   if (IfWithDelete->getElse())
56     return;
57   // FIXME: generate fixit for this case.
58 
59   Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
60       IfWithDelete->getBeginLoc(),
61       utils::lexer::getPreviousToken(IfWithDelete->getThen()->getBeginLoc(),
62                                      *Result.SourceManager,
63                                      Result.Context->getLangOpts())
64           .getLocation()));
65 
66   if (Compound) {
67     Diag << FixItHint::CreateRemoval(
68         CharSourceRange::getTokenRange(Compound->getLBracLoc()));
69     Diag << FixItHint::CreateRemoval(
70         CharSourceRange::getTokenRange(Compound->getRBracLoc()));
71   }
72 }
73 
74 } // namespace clang::tidy::readability
75