10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h" 20 static internal::Matcher<Stmt>
22 return stmt(anyOf(breakStmt(Internal), returnStmt(Internal),
23 gotoStmt(Internal), cxxThrowExpr(Internal),
24 callExpr(Internal, callee(functionDecl(isNoReturn())))));
29 if (
const auto *DRE = dyn_cast<DeclRefExpr>(S))
30 return DRE->getDecl() == Var;
37 if (
const auto *DS = dyn_cast<DeclStmt>(S)) {
38 for (
const Decl *D : DS->getDeclGroup()) {
39 if (
const auto *LeftVar = dyn_cast<VarDecl>(D)) {
40 if (LeftVar->hasInit() && LeftVar->getType()->isReferenceType()) {
45 }
else if (
const auto *UnOp = dyn_cast<UnaryOperator>(S)) {
46 if (UnOp->getOpcode() == UO_AddrOf)
58 for (
const Stmt *Child : S->children()) {
76 static bool isChanged(
const Stmt *LoopStmt,
const VarDecl *Var,
77 ASTContext *Context) {
78 if (
const auto *ForLoop = dyn_cast<ForStmt>(LoopStmt))
79 return (ForLoop->getInc() &&
80 ExprMutationAnalyzer(*ForLoop->getInc(), *Context)
82 (ForLoop->getBody() &&
83 ExprMutationAnalyzer(*ForLoop->getBody(), *Context)
85 (ForLoop->getCond() &&
86 ExprMutationAnalyzer(*ForLoop->getCond(), *Context).isMutated(Var));
88 return ExprMutationAnalyzer(*LoopStmt, *Context).isMutated(Var);
93 const Stmt *LoopStmt,
const Stmt *Cond,
94 ASTContext *Context) {
95 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
96 if (
const auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
97 if (!Var->isLocalVarDeclOrParm())
100 if (Var->getType().isVolatileQualified())
103 if (!Var->getType().getTypePtr()->isIntegerType())
110 }
else if (isa<MemberExpr>(Cond) || isa<CallExpr>(Cond)) {
120 const Stmt *LoopStmt,
const Stmt *Cond,
121 ASTContext *Context) {
125 for (
const Stmt *Child : Cond->children()) {
137 if (
const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
138 if (
const auto *Var = dyn_cast<VarDecl>(DRE->getDecl()))
139 return Var->getName();
143 for (
const Stmt *Child : Cond->children()) {
148 if (!Result.empty() && !NewNames.empty())
156 if (Cond.isValueDependent())
159 if (Cond.EvaluateAsBooleanCondition(Result, Ctx))
164 void InfiniteLoopCheck::registerMatchers(MatchFinder *Finder) {
165 const auto LoopCondition = allOf(
167 expr(forFunction(functionDecl().bind(
"func"))).bind(
"condition")),
168 unless(hasBody(hasDescendant(
171 Finder->addMatcher(stmt(anyOf(whileStmt(LoopCondition), doStmt(LoopCondition),
172 forStmt(LoopCondition)))
177 void InfiniteLoopCheck::check(
const MatchFinder::MatchResult &Result) {
178 const auto *Cond = Result.Nodes.getNodeAs<Expr>(
"condition");
179 const auto *LoopStmt = Result.Nodes.getNodeAs<Stmt>(
"loop-stmt");
180 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>(
"func");
185 bool ShouldHaveConditionVariables =
true;
186 if (
const auto *While = dyn_cast<WhileStmt>(LoopStmt)) {
187 if (
const VarDecl *LoopVarDecl = While->getConditionVariable()) {
188 if (
const Expr *Init = LoopVarDecl->getInit()) {
189 ShouldHaveConditionVariables =
false;
199 if (ShouldHaveConditionVariables && CondVarNames.empty())
202 if (CondVarNames.empty()) {
203 diag(LoopStmt->getBeginLoc(),
204 "this loop is infinite; it does not check any variables in the" 207 diag(LoopStmt->getBeginLoc(),
208 "this loop is infinite; none of its condition variables (%0)" 209 " are updated in the loop body")
static std::string getCondVarNames(const Stmt *Cond)
Return the variable names in Cond.
const FunctionDecl * Decl
static bool isChanged(const Stmt *LoopStmt, const VarDecl *Var, ASTContext *Context)
Return whether Var was changed in LoopStmt.
static bool isKnownFalse(const Expr &Cond, const ASTContext &Ctx)
static bool hasPtrOrReferenceInStmt(const Stmt *S, const VarDecl *Var)
Return whether Var has a pointer or reference in S.
static bool isAccessForVar(const Stmt *S, const VarDecl *Var)
Return whether S is a reference to the declaration of Var.
static bool isPtrOrReferenceForVar(const Stmt *S, const VarDecl *Var)
Return whether Var has a pointer or reference in S.
static bool hasPtrOrReferenceInFunc(const FunctionDecl *Func, const VarDecl *Var)
Return whether Var has a pointer or reference in Func.
static bool isVarThatIsPossiblyChanged(const FunctionDecl *Func, const Stmt *LoopStmt, const Stmt *Cond, ASTContext *Context)
Return whether Cond is a variable that is possibly changed in LoopStmt.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static internal::Matcher< Stmt > loopEndingStmt(internal::Matcher< Stmt > Internal)
static bool isAtLeastOneCondVarChanged(const FunctionDecl *Func, const Stmt *LoopStmt, const Stmt *Cond, ASTContext *Context)
Return whether at least one variable of Cond changed in LoopStmt.