//===--- RedundantControlFlowCheck.cpp - clang-tidy------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "RedundantControlFlowCheck.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 { namespace { const char *const RedundantReturnDiag = "redundant return statement at the end " "of a function with a void return type"; const char *const RedundantContinueDiag = "redundant continue statement at the " "end of loop statement"; bool isLocationInMacroExpansion(const SourceManager &SM, SourceLocation Loc) { return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc); } } // namespace void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( functionDecl( isDefinition(), returns(voidType()), has(compoundStmt(hasAnySubstatement(returnStmt(unless(has(expr()))))) .bind("return"))), this); auto CompoundContinue = has(compoundStmt(hasAnySubstatement(continueStmt())).bind("continue")); Finder->addMatcher( stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt()), CompoundContinue), this); } void RedundantControlFlowCheck::check(const MatchFinder::MatchResult &Result) { if (const auto *Return = Result.Nodes.getNodeAs("return")) checkRedundantReturn(Result, Return); else if (const auto *Continue = Result.Nodes.getNodeAs("continue")) checkRedundantContinue(Result, Continue); } void RedundantControlFlowCheck::checkRedundantReturn( const MatchFinder::MatchResult &Result, const CompoundStmt *Block) { CompoundStmt::const_reverse_body_iterator last = Block->body_rbegin(); if (const auto *Return = dyn_cast(*last)) issueDiagnostic(Result, Block, Return->getSourceRange(), RedundantReturnDiag); } void RedundantControlFlowCheck::checkRedundantContinue( const MatchFinder::MatchResult &Result, const CompoundStmt *Block) { CompoundStmt::const_reverse_body_iterator last = Block->body_rbegin(); if (const auto *Continue = dyn_cast(*last)) issueDiagnostic(Result, Block, Continue->getSourceRange(), RedundantContinueDiag); } void RedundantControlFlowCheck::issueDiagnostic( const MatchFinder::MatchResult &Result, const CompoundStmt *const Block, const SourceRange &StmtRange, const char *const Diag) { SourceManager &SM = *Result.SourceManager; if (isLocationInMacroExpansion(SM, StmtRange.getBegin())) return; CompoundStmt::const_reverse_body_iterator Previous = ++Block->body_rbegin(); SourceLocation Start; if (Previous != Block->body_rend()) Start = Lexer::findLocationAfterToken( dyn_cast(*Previous)->getEndLoc(), tok::semi, SM, getLangOpts(), /*SkipTrailingWhitespaceAndNewLine=*/true); if (!Start.isValid()) Start = StmtRange.getBegin(); auto RemovedRange = CharSourceRange::getCharRange( Start, Lexer::findLocationAfterToken( StmtRange.getEnd(), tok::semi, SM, getLangOpts(), /*SkipTrailingWhitespaceAndNewLine=*/true)); diag(StmtRange.getBegin(), Diag) << FixItHint::CreateRemoval(RemovedRange); } } // namespace readability } // namespace tidy } // namespace clang