1 //===--- DeleteNullPointerCheck.cpp - clang-tidy---------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "DeleteNullPointerCheck.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(has(castExpr(has(declRefExpr( 24 to(decl(equalsBoundNode("deletedPointer")))))))) 25 .bind("deleteExpr"); 26 27 const auto DeleteMemberExpr = 28 cxxDeleteExpr(has(castExpr(has(memberExpr(hasDeclaration( 29 fieldDecl(equalsBoundNode("deletedMemberPointer")))))))) 30 .bind("deleteMemberExpr"); 31 32 const auto PointerExpr = ignoringImpCasts(anyOf( 33 declRefExpr(to(decl().bind("deletedPointer"))), 34 memberExpr(hasDeclaration(fieldDecl().bind("deletedMemberPointer"))))); 35 36 const auto PointerCondition = castExpr(hasCastKind(CK_PointerToBoolean), 37 hasSourceExpression(PointerExpr)); 38 const auto BinaryPointerCheckCondition = 39 binaryOperator(hasEitherOperand(castExpr(hasCastKind(CK_NullToPointer))), 40 hasEitherOperand(PointerExpr)); 41 42 Finder->addMatcher( 43 ifStmt(hasCondition(anyOf(PointerCondition, BinaryPointerCheckCondition)), 44 hasThen(anyOf( 45 DeleteExpr, DeleteMemberExpr, 46 compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)), 47 statementCountIs(1)) 48 .bind("compound")))) 49 .bind("ifWithDelete"), 50 this); 51 } 52 53 void DeleteNullPointerCheck::check(const MatchFinder::MatchResult &Result) { 54 const auto *IfWithDelete = Result.Nodes.getNodeAs<IfStmt>("ifWithDelete"); 55 const auto *Compound = Result.Nodes.getNodeAs<CompoundStmt>("compound"); 56 57 auto Diag = diag( 58 IfWithDelete->getLocStart(), 59 "'if' statement is unnecessary; deleting null pointer has no effect"); 60 if (IfWithDelete->getElse()) 61 return; 62 // FIXME: generate fixit for this case. 63 64 Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange( 65 IfWithDelete->getLocStart(), 66 Lexer::getLocForEndOfToken(IfWithDelete->getCond()->getLocEnd(), 0, 67 *Result.SourceManager, 68 Result.Context->getLangOpts()))); 69 if (Compound) { 70 Diag << FixItHint::CreateRemoval( 71 CharSourceRange::getTokenRange(Compound->getLBracLoc())); 72 Diag << FixItHint::CreateRemoval( 73 CharSourceRange::getTokenRange(Compound->getRBracLoc())); 74 } 75 } 76 77 } // namespace readability 78 } // namespace tidy 79 } // namespace clang 80