Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp =================================================================== --- lib/StaticAnalyzer/Core/LoopUnrolling.cpp +++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -84,10 +84,9 @@ hasOperatorName("<="), hasOperatorName(">="), hasOperatorName("!=")), hasEitherOperand(ignoringParenImpCasts(declRefExpr( - to(varDecl(hasType(isInteger())).bind(BindName))))), - hasEitherOperand(ignoringParenImpCasts( - integerLiteral().bind("boundNum")))) - .bind("conditionOperator"); + to(varDecl(allOf(hasType(isInteger()), equalsBoundNode(BindName))))) + .bind("boundVarOperand")))) +.bind("conditionOperator"); } static internal::Matcher @@ -138,17 +137,16 @@ static internal::Matcher forLoopMatcher() { return forStmt( - hasCondition(simpleCondition("initVarName")), // Initialization should match the form: 'int i = 6' or 'i = 42'. hasLoopInit( anyOf(declStmt(hasSingleDecl( - varDecl(allOf(hasInitializer(ignoringParenImpCasts( - integerLiteral().bind("initNum"))), - equalsBoundNode("initVarName"))))), - binaryOperator(hasLHS(declRefExpr(to(varDecl( - equalsBoundNode("initVarName"))))), + varDecl(hasInitializer(ignoringParenImpCasts( + integerLiteral().bind("initNum")))).bind("initVarName"))), + binaryOperator(hasLHS(declRefExpr(to(varDecl() + .bind("initVarName")))), hasRHS(ignoringParenImpCasts( - integerLiteral().bind("initNum")))))), + integerLiteral().bind("initNum")))))), + hasCondition(simpleCondition("initVarName")), // Incrementation should be a simple increment or decrement // operator call. hasIncrement(unaryOperator( @@ -196,22 +194,43 @@ bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx, ExplodedNode *Pred, unsigned &maxStep) { - 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 @@ -7,7 +7,7 @@ int getNum(); void foo(int &); -int simple_unroll1() { +/*int simple_unroll1() { int a[9]; int k = 42; for (int i = 0; i < 9; i++) { @@ -498,4 +498,28 @@ for (int i = 0; i < 6L; ++i) { clang_analyzer_numTimesReached(); // expected-warning {{6}} } +}*/ + +int unroll_known_value_of_variable1() { + 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; +} + +int unroll_known_value_of_variable2() { + int a[9]; + int k = 42; + int n = 9; + for (int i = 0; n > i; i++) { + clang_analyzer_numTimesReached(); // expected-warning {{9}} + a[i] = 42; + } + int b = 22 / (k - 42); // expected-warning {{Division by zero}} + return 0; }