10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h"
13 #include "../utils/Aliasing.h"
22 static internal::Matcher<Stmt>
24 return stmt(anyOf(breakStmt(Internal), returnStmt(Internal),
25 gotoStmt(Internal), cxxThrowExpr(Internal),
26 callExpr(Internal, callee(functionDecl(isNoReturn())))));
30 static bool isChanged(
const Stmt *LoopStmt,
const VarDecl *Var,
31 ASTContext *Context) {
32 if (
const auto *ForLoop = dyn_cast<ForStmt>(LoopStmt))
33 return (ForLoop->getInc() &&
34 ExprMutationAnalyzer(*ForLoop->getInc(), *Context)
36 (ForLoop->getBody() &&
37 ExprMutationAnalyzer(*ForLoop->getBody(), *Context)
39 (ForLoop->getCond() &&
40 ExprMutationAnalyzer(*ForLoop->getCond(), *Context).isMutated(Var));
42 return ExprMutationAnalyzer(*LoopStmt, *Context).isMutated(Var);
47 const Stmt *LoopStmt,
const Stmt *Cond,
48 ASTContext *Context) {
49 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
50 if (
const auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
51 if (!Var->isLocalVarDeclOrParm())
54 if (Var->getType().isVolatileQualified())
57 if (!Var->getType().getTypePtr()->isIntegerType())
64 }
else if (isa<MemberExpr>(Cond) || isa<CallExpr>(Cond)) {
74 const Stmt *LoopStmt,
const Stmt *Cond,
75 ASTContext *Context) {
79 for (
const Stmt *Child : Cond->children()) {
91 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
92 if (
const auto *Var = dyn_cast<VarDecl>(DRE->getDecl()))
93 return std::string(Var->getName());
97 for (
const Stmt *Child : Cond->children()) {
102 if (!Result.empty() && !NewNames.empty())
110 if (Cond.isValueDependent())
113 if (Cond.EvaluateAsBooleanCondition(Result,
Ctx))
118 void InfiniteLoopCheck::registerMatchers(MatchFinder *Finder) {
119 const auto LoopCondition = allOf(
121 expr(forFunction(functionDecl().bind(
"func"))).bind(
"condition")),
122 unless(hasBody(hasDescendant(
125 Finder->addMatcher(stmt(anyOf(whileStmt(LoopCondition), doStmt(LoopCondition),
126 forStmt(LoopCondition)))
131 void InfiniteLoopCheck::check(
const MatchFinder::MatchResult &Result) {
132 const auto *Cond = Result.Nodes.getNodeAs<Expr>(
"condition");
133 const auto *LoopStmt = Result.Nodes.getNodeAs<Stmt>(
"loop-stmt");
134 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>(
"func");
139 bool ShouldHaveConditionVariables =
true;
140 if (
const auto *While = dyn_cast<WhileStmt>(LoopStmt)) {
141 if (
const VarDecl *LoopVarDecl = While->getConditionVariable()) {
142 if (
const Expr *Init = LoopVarDecl->getInit()) {
143 ShouldHaveConditionVariables =
false;
153 if (ShouldHaveConditionVariables && CondVarNames.empty())
156 if (CondVarNames.empty()) {
157 diag(LoopStmt->getBeginLoc(),
158 "this loop is infinite; it does not check any variables in the"
161 diag(LoopStmt->getBeginLoc(),
162 "this loop is infinite; none of its condition variables (%0)"
163 " are updated in the loop body")