//===--- DeleteNullPointerCheck.cpp - clang-tidy---------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "DeleteNullPointerCheck.h" #include "../utils/LexerUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; namespace clang { namespace tidy { namespace readability { void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) { const auto DeleteExpr = cxxDeleteExpr(has(castExpr(has(declRefExpr( to(decl(equalsBoundNode("deletedPointer")))))))) .bind("deleteExpr"); const auto DeleteMemberExpr = cxxDeleteExpr(has(castExpr(has(memberExpr(hasDeclaration( fieldDecl(equalsBoundNode("deletedMemberPointer")))))))) .bind("deleteMemberExpr"); const auto PointerExpr = ignoringImpCasts(anyOf( declRefExpr(to(decl().bind("deletedPointer"))), memberExpr(hasDeclaration(fieldDecl().bind("deletedMemberPointer"))))); const auto PointerCondition = castExpr(hasCastKind(CK_PointerToBoolean), hasSourceExpression(PointerExpr)); const auto BinaryPointerCheckCondition = binaryOperator(hasEitherOperand(castExpr(hasCastKind(CK_NullToPointer))), hasEitherOperand(PointerExpr)); Finder->addMatcher( ifStmt(hasCondition(anyOf(PointerCondition, BinaryPointerCheckCondition)), hasThen(anyOf( DeleteExpr, DeleteMemberExpr, compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)), statementCountIs(1)) .bind("compound")))) .bind("ifWithDelete"), this); } void DeleteNullPointerCheck::check(const MatchFinder::MatchResult &Result) { const auto *IfWithDelete = Result.Nodes.getNodeAs("ifWithDelete"); const auto *Compound = Result.Nodes.getNodeAs("compound"); auto Diag = diag( IfWithDelete->getBeginLoc(), "'if' statement is unnecessary; deleting null pointer has no effect"); if (IfWithDelete->getElse()) return; // FIXME: generate fixit for this case. Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange( IfWithDelete->getBeginLoc(), utils::lexer::getPreviousToken(IfWithDelete->getThen()->getBeginLoc(), *Result.SourceManager, Result.Context->getLangOpts()) .getLocation())); if (Compound) { Diag << FixItHint::CreateRemoval( CharSourceRange::getTokenRange(Compound->getLBracLoc())); Diag << FixItHint::CreateRemoval( CharSourceRange::getTokenRange(Compound->getRBracLoc())); } } } // namespace readability } // namespace tidy } // namespace clang