summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2016-02-01 15:31:15 +0000
committerAaron Ballman <aaron@aaronballman.com>2016-02-01 15:31:15 +0000
commitc3975b7d6af5970598db272f9b13423d2e09d5ab (patch)
tree62f4218c507699e26ed1270536422870938496fa /clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
parenta052037034df09335b964ef9dae91bb9b54c94fa (diff)
downloadbcm5719-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.cpp99
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
OpenPOWER on IntegriCloud