11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
14 #include "clang/Frontend/CompilerInstance.h"
22 AST_MATCHER_P(Stmt, nextStmt, ast_matchers::internal::Matcher<Stmt>,
24 DynTypedNodeList
Parents = Finder->getASTContext().getParents(Node);
28 auto *C =
Parents[0].get<CompoundStmt>();
32 const auto *I = llvm::find(C->body(), &Node);
33 assert(I != C->body_end() &&
"C is parent of Node");
34 if (++I == C->body_end())
37 return InnerMatcher.matches(**I, Finder,
Builder);
42 namespace readability {
44 void UseAnyOfAllOfCheck::registerMatchers(MatchFinder *Finder) {
45 auto returns = [](
bool V) {
46 return returnStmt(hasReturnValue(cxxBoolLiteral(equals(V))));
49 auto returnsButNotTrue =
50 returnStmt(hasReturnValue(unless(cxxBoolLiteral(equals(
true)))));
51 auto returnsButNotFalse =
52 returnStmt(hasReturnValue(unless(cxxBoolLiteral(equals(
false)))));
56 nextStmt(returns(
false).bind(
"final_return")),
57 hasBody(allOf(hasDescendant(returns(
true)),
58 unless(anyOf(hasDescendant(breakStmt()),
59 hasDescendant(gotoStmt()),
60 hasDescendant(returnsButNotTrue))))))
66 nextStmt(returns(
true).bind(
"final_return")),
67 hasBody(allOf(hasDescendant(returns(
false)),
68 unless(anyOf(hasDescendant(breakStmt()),
69 hasDescendant(gotoStmt()),
70 hasDescendant(returnsButNotFalse))))))
75 static bool isViableLoop(
const CXXForRangeStmt &S, ASTContext &Context) {
77 ExprMutationAnalyzer Mutations(*S.getBody(), Context);
78 if (Mutations.isMutated(S.getLoopVariable()))
81 match(findAll(declRefExpr().bind(
"decl_ref")), *S.getBody(), Context);
83 return llvm::none_of(Matches, [&Mutations](
auto &
DeclRef) {
85 return Mutations.isMutated(
86 DeclRef.template getNodeAs<DeclRefExpr>(
"decl_ref")->getDecl());
90 void UseAnyOfAllOfCheck::check(
const MatchFinder::MatchResult &Result) {
91 StringRef Ranges = getLangOpts().CPlusPlus20 ?
"::ranges" :
"";
93 if (
const auto *S = Result.Nodes.getNodeAs<CXXForRangeStmt>(
"any_of_loop")) {
97 diag(S->getForLoc(),
"replace loop by 'std%0::any_of()'") << Ranges;
98 }
else if (
const auto *S =
99 Result.Nodes.getNodeAs<CXXForRangeStmt>(
"all_of_loop")) {
103 diag(S->getForLoc(),
"replace loop by 'std%0::all_of()'") << Ranges;