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 "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/Lex/Lexer.h" 13 14 using namespace clang::ast_matchers; 15 16 namespace clang { 17 namespace tidy { 18 namespace readability { 19 20 void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) { 21 const auto DeleteExpr = 22 cxxDeleteExpr(has(castExpr(has(declRefExpr( 23 to(decl(equalsBoundNode("deletedPointer")))))))) 24 .bind("deleteExpr"); 25 26 const auto DeleteMemberExpr = 27 cxxDeleteExpr(has(castExpr(has(memberExpr(hasDeclaration( 28 fieldDecl(equalsBoundNode("deletedMemberPointer")))))))) 29 .bind("deleteMemberExpr"); 30 31 const auto PointerExpr = ignoringImpCasts(anyOf( 32 declRefExpr(to(decl().bind("deletedPointer"))), 33 memberExpr(hasDeclaration(fieldDecl().bind("deletedMemberPointer"))))); 34 35 const auto PointerCondition = castExpr(hasCastKind(CK_PointerToBoolean), 36 hasSourceExpression(PointerExpr)); 37 const auto BinaryPointerCheckCondition = 38 binaryOperator(hasEitherOperand(castExpr(hasCastKind(CK_NullToPointer))), 39 hasEitherOperand(PointerExpr)); 40 41 Finder->addMatcher( 42 ifStmt(hasCondition(anyOf(PointerCondition, BinaryPointerCheckCondition)), 43 hasThen(anyOf( 44 DeleteExpr, DeleteMemberExpr, 45 compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)), 46 statementCountIs(1)) 47 .bind("compound")))) 48 .bind("ifWithDelete"), 49 this); 50 } 51 52 void DeleteNullPointerCheck::check(const MatchFinder::MatchResult &Result) { 53 const auto *IfWithDelete = Result.Nodes.getNodeAs<IfStmt>("ifWithDelete"); 54 const auto *Compound = Result.Nodes.getNodeAs<CompoundStmt>("compound"); 55 56 auto Diag = diag( 57 IfWithDelete->getBeginLoc(), 58 "'if' statement is unnecessary; deleting null pointer has no effect"); 59 if (IfWithDelete->getElse()) 60 return; 61 // FIXME: generate fixit for this case. 62 63 Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange( 64 IfWithDelete->getBeginLoc(), 65 Lexer::getLocForEndOfToken(IfWithDelete->getCond()->getEndLoc(), 0, 66 *Result.SourceManager, 67 Result.Context->getLangOpts()))); 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