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 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 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