diff options
author | Aaron Ballman <aaron@aaronballman.com> | 2016-02-01 15:31:15 +0000 |
---|---|---|
committer | Aaron Ballman <aaron@aaronballman.com> | 2016-02-01 15:31:15 +0000 |
commit | c3975b7d6af5970598db272f9b13423d2e09d5ab (patch) | |
tree | 62f4218c507699e26ed1270536422870938496fa /clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp | |
parent | a052037034df09335b964ef9dae91bb9b54c94fa (diff) | |
download | bcm5719-llvm-c3975b7d6af5970598db272f9b13423d2e09d5ab.tar.gz bcm5719-llvm-c3975b7d6af5970598db272f9b13423d2e09d5ab.zip |
Add a new check, readability-redundant-control-flow, that check for some forms of redundant control flow statements. Currently checks for return statements at the end of a function with a void return type and continue statements at the end of looping statements.
Patch by Richard Thomson.
llvm-svn: 259362
Diffstat (limited to 'clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp new file mode 100644 index 00000000000..54a26e24abb --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp @@ -0,0 +1,99 @@ +//===--- 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<CompoundStmt>("return")) + checkRedundantReturn(Result, Return); + else if (const auto *Continue = + Result.Nodes.getNodeAs<CompoundStmt>("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<ReturnStmt>(*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<ContinueStmt>(*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<Stmt>(*Previous)->getLocEnd(), tok::semi, SM, + Result.Context->getLangOpts(), + /*SkipTrailingWhitespaceAndNewLine=*/true); + else + Start = StmtRange.getBegin(); + auto RemovedRange = CharSourceRange::getCharRange( + Start, + Lexer::findLocationAfterToken(StmtRange.getEnd(), tok::semi, SM, + Result.Context->getLangOpts(), + /*SkipTrailingWhitespaceAndNewLine=*/true)); + + diag(StmtRange.getBegin(), Diag) << FixItHint::CreateRemoval(RemovedRange); +} + +} // namespace readability +} // namespace tidy +} // namespace clang |