summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
diff options
context:
space:
mode:
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