Skip to content

Commit dde1990

Browse files
authored
[clang-tidy][NFC] Refactor readability-redundant-control-flow (llvm#171639)
Besides simplifying the code, this refactor should also make it more efficient: instead of using the `hasAnySubstatement` matcher to find blocks we're interested in, which requires looking through every substatement, this PR introduces a custom `hasFinalStmt` matcher which only checks the last substatement.
1 parent 6470d1b commit dde1990

File tree

2 files changed

+28
-59
lines changed

2 files changed

+28
-59
lines changed

clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp

Lines changed: 28 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,76 +8,58 @@
88

99
#include "RedundantControlFlowCheck.h"
1010
#include "clang/ASTMatchers/ASTMatchFinder.h"
11+
#include "clang/ASTMatchers/ASTMatchersMacros.h"
1112
#include "clang/Lex/Lexer.h"
1213

1314
using namespace clang::ast_matchers;
1415

1516
namespace clang::tidy::readability {
1617

17-
static const char *const RedundantReturnDiag =
18+
namespace {
19+
20+
AST_MATCHER_P(CompoundStmt, hasFinalStmt, StatementMatcher, InnerMatcher) {
21+
return !Node.body_empty() &&
22+
InnerMatcher.matches(*Node.body_back(), Finder, Builder);
23+
}
24+
25+
} // namespace
26+
27+
static constexpr StringRef RedundantReturnDiag =
1828
"redundant return statement at the end "
1929
"of a function with a void return type";
20-
static const char *const RedundantContinueDiag =
30+
static constexpr StringRef RedundantContinueDiag =
2131
"redundant continue statement at the "
2232
"end of loop statement";
2333

24-
static bool isLocationInMacroExpansion(const SourceManager &SM,
25-
SourceLocation Loc) {
26-
return SM.isMacroBodyExpansion(Loc) || SM.isMacroArgExpansion(Loc);
27-
}
28-
2934
void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {
3035
Finder->addMatcher(
31-
functionDecl(isDefinition(), returns(voidType()),
32-
hasBody(compoundStmt(hasAnySubstatement(
33-
returnStmt(unless(has(expr())))))
34-
.bind("return"))),
35-
this);
36-
Finder->addMatcher(
37-
mapAnyOf(forStmt, cxxForRangeStmt, whileStmt, doStmt)
38-
.with(hasBody(compoundStmt(hasAnySubstatement(continueStmt()))
39-
.bind("continue"))),
36+
functionDecl(returns(voidType()),
37+
hasBody(compoundStmt(hasFinalStmt(
38+
returnStmt(unless(has(expr()))).bind("stmt"))))),
4039
this);
40+
Finder->addMatcher(mapAnyOf(forStmt, cxxForRangeStmt, whileStmt, doStmt)
41+
.with(hasBody(compoundStmt(
42+
hasFinalStmt(continueStmt().bind("stmt"))))),
43+
this);
4144
}
4245

4346
void RedundantControlFlowCheck::check(const MatchFinder::MatchResult &Result) {
44-
if (const auto *Return = Result.Nodes.getNodeAs<CompoundStmt>("return"))
45-
checkRedundantReturn(Result, Return);
46-
else if (const auto *Continue =
47-
Result.Nodes.getNodeAs<CompoundStmt>("continue"))
48-
checkRedundantContinue(Result, Continue);
49-
}
50-
51-
void RedundantControlFlowCheck::checkRedundantReturn(
52-
const MatchFinder::MatchResult &Result, const CompoundStmt *Block) {
53-
const CompoundStmt::const_reverse_body_iterator Last = Block->body_rbegin();
54-
if (const auto *Return = dyn_cast<ReturnStmt>(*Last))
55-
issueDiagnostic(Result, Block, Return->getSourceRange(),
56-
RedundantReturnDiag);
57-
}
58-
59-
void RedundantControlFlowCheck::checkRedundantContinue(
60-
const MatchFinder::MatchResult &Result, const CompoundStmt *Block) {
61-
const CompoundStmt::const_reverse_body_iterator Last = Block->body_rbegin();
62-
if (const auto *Continue = dyn_cast<ContinueStmt>(*Last))
63-
issueDiagnostic(Result, Block, Continue->getSourceRange(),
64-
RedundantContinueDiag);
65-
}
47+
const auto &RedundantStmt = *Result.Nodes.getNodeAs<Stmt>("stmt");
48+
const SourceRange StmtRange = RedundantStmt.getSourceRange();
6649

67-
void RedundantControlFlowCheck::issueDiagnostic(
68-
const MatchFinder::MatchResult &Result, const CompoundStmt *const Block,
69-
const SourceRange &StmtRange, const char *const Diag) {
70-
const SourceManager &SM = *Result.SourceManager;
71-
if (isLocationInMacroExpansion(SM, StmtRange.getBegin()))
50+
if (StmtRange.getBegin().isMacroID())
7251
return;
7352

7453
const auto RemovedRange = CharSourceRange::getCharRange(
7554
StmtRange.getBegin(),
76-
Lexer::findLocationAfterToken(StmtRange.getEnd(), tok::semi, SM,
77-
getLangOpts(),
55+
Lexer::findLocationAfterToken(StmtRange.getEnd(), tok::semi,
56+
*Result.SourceManager, getLangOpts(),
7857
/*SkipTrailingWhitespaceAndNewLine=*/true));
7958

80-
diag(StmtRange.getBegin(), Diag) << FixItHint::CreateRemoval(RemovedRange);
59+
diag(StmtRange.getBegin(), isa<ReturnStmt>(RedundantStmt)
60+
? RedundantReturnDiag
61+
: RedundantContinueDiag)
62+
<< FixItHint::CreateRemoval(RemovedRange);
8163
}
8264

8365
} // namespace clang::tidy::readability

clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,6 @@ class RedundantControlFlowCheck : public ClangTidyCheck {
3030
std::optional<TraversalKind> getCheckTraversalKind() const override {
3131
return TK_IgnoreUnlessSpelledInSource;
3232
}
33-
34-
private:
35-
void
36-
checkRedundantReturn(const ast_matchers::MatchFinder::MatchResult &Result,
37-
const CompoundStmt *Block);
38-
39-
void
40-
checkRedundantContinue(const ast_matchers::MatchFinder::MatchResult &Result,
41-
const CompoundStmt *Block);
42-
43-
void issueDiagnostic(const ast_matchers::MatchFinder::MatchResult &Result,
44-
const CompoundStmt *Block, const SourceRange &StmtRange,
45-
const char *Diag);
4633
};
4734

4835
} // namespace clang::tidy::readability

0 commit comments

Comments
 (0)