Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp =================================================================== --- lib/StaticAnalyzer/Core/LoopUnrolling.cpp +++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -84,9 +84,8 @@ hasOperatorName("<="), hasOperatorName(">="), hasOperatorName("!=")), hasEitherOperand(ignoringParenImpCasts(declRefExpr( - to(varDecl(hasType(isInteger())).bind(BindName))))), - hasEitherOperand(ignoringParenImpCasts( - integerLiteral().bind("boundNum")))) + to(varDecl(hasType(isInteger())).bind(BindName))) + .bind("boundVarOperand")))) .bind("conditionOperator"); } @@ -200,18 +199,40 @@ if (!isLoopStmt(LoopStmt)) return false; - // TODO: Match the cases where the bound is not a concrete literal but an - // integer with known value auto Matches = match(forLoopMatcher(), *LoopStmt, ASTCtx); if (Matches.empty()) return false; + const auto State = Pred->getState(); + auto &SVB = State->getStateManager().getSValBuilder(); + auto CounterVar = Matches[0].getNodeAs("initVarName"); - llvm::APInt BoundNum = - Matches[0].getNodeAs("boundNum")->getValue(); llvm::APInt InitNum = Matches[0].getNodeAs("initNum")->getValue(); auto CondOp = Matches[0].getNodeAs("conditionOperator"); + + const Expr *BoundExpr = CondOp->getLHS()->IgnoreParenImpCasts(); + if (BoundExpr == Matches[0].getNodeAs("boundVarOperand")) + BoundExpr = CondOp->getRHS()->IgnoreParenImpCasts(); + SVal BoundNumVal = Pred->getSVal(BoundExpr); + + // If the value of the expression is unknown and it is a declaration + // reference then try to get the value of the declaration instead + if (BoundNumVal.isUnknown()) { + if (const auto *BoundDeclRefExpr = dyn_cast(BoundExpr)) { + // FIXME: Add other declarations such as Objective-C fields + if (const auto *BoundVarDecl = + dyn_cast(BoundDeclRefExpr->getDecl())) { + BoundNumVal = State->getSVal( + State->getLValue(BoundVarDecl, Pred->getLocationContext())); + } + } + } + const llvm::APSInt *BoundNumPtr = SVB.getKnownValue(State, BoundNumVal); + if (!BoundNumPtr) + return false; + llvm::APInt BoundNum = *BoundNumPtr; + if (InitNum.getBitWidth() != BoundNum.getBitWidth()) { InitNum = InitNum.zextOrSelf(BoundNum.getBitWidth()); BoundNum = BoundNum.zextOrSelf(InitNum.getBitWidth()); Index: test/Analysis/loop-unrolling.cpp =================================================================== --- test/Analysis/loop-unrolling.cpp +++ test/Analysis/loop-unrolling.cpp @@ -499,3 +499,15 @@ clang_analyzer_numTimesReached(); // expected-warning {{6}} } } + +int unroll_known_value_of_variable() { + int a[9]; + int k = 42; + int n = 9; + for (int i = 0; i < n; i++) { + clang_analyzer_numTimesReached(); // expected-warning {{9}} + a[i] = 42; + } + int b = 22 / (k - 42); // expected-warning {{Division by zero}} + return 0; +}