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
15using namespace clang::ast_matchers;
16
17namespace clang::tidy::readability {
18
19void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) {
20 const auto DeleteExpr =
21 cxxDeleteExpr(
22 has(declRefExpr(to(InnerMatcher: decl(equalsBoundNode(ID: "deletedPointer"))))))
23 .bind(ID: "deleteExpr");
24
25 const auto DeleteMemberExpr =
26 cxxDeleteExpr(has(memberExpr(hasDeclaration(
27 InnerMatcher: fieldDecl(equalsBoundNode(ID: "deletedMemberPointer"))))))
28 .bind(ID: "deleteMemberExpr");
29
30 const auto PointerExpr = anyOf(
31 declRefExpr(to(InnerMatcher: decl().bind(ID: "deletedPointer"))),
32 memberExpr(hasDeclaration(InnerMatcher: fieldDecl().bind(ID: "deletedMemberPointer"))));
33
34 const auto BinaryPointerCheckCondition = binaryOperator(hasOperands(
35 Matcher1: anyOf(cxxNullPtrLiteralExpr(), integerLiteral(equals(Value: 0))), Matcher2: PointerExpr));
36
37 Finder->addMatcher(
38 NodeMatch: ifStmt(hasCondition(InnerMatcher: anyOf(PointerExpr, BinaryPointerCheckCondition)),
39 hasThen(InnerMatcher: anyOf(
40 DeleteExpr, DeleteMemberExpr,
41 compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)),
42 statementCountIs(N: 1))
43 .bind(ID: "compound"))))
44 .bind(ID: "ifWithDelete"),
45 Action: this);
46}
47
48void DeleteNullPointerCheck::check(const MatchFinder::MatchResult &Result) {
49 const auto *IfWithDelete = Result.Nodes.getNodeAs<IfStmt>(ID: "ifWithDelete");
50 const auto *Compound = Result.Nodes.getNodeAs<CompoundStmt>(ID: "compound");
51
52 auto Diag = diag(
53 Loc: IfWithDelete->getBeginLoc(),
54 Description: "'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(RemoveRange: CharSourceRange::getTokenRange(
60 B: IfWithDelete->getBeginLoc(),
61 E: utils::lexer::getPreviousToken(Location: IfWithDelete->getThen()->getBeginLoc(),
62 SM: *Result.SourceManager,
63 LangOpts: Result.Context->getLangOpts())
64 .getLocation()));
65
66 if (Compound) {
67 Diag << FixItHint::CreateRemoval(
68 RemoveRange: CharSourceRange::getTokenRange(R: Compound->getLBracLoc()));
69 Diag << FixItHint::CreateRemoval(
70 RemoveRange: CharSourceRange::getTokenRange(R: Compound->getRBracLoc()));
71 }
72}
73
74} // namespace clang::tidy::readability
75

source code of clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp