@@ -23,6 +23,8 @@ using namespace clang;
2323using namespace ento ;
2424using namespace clang ::ast_matchers;
2525
26+ using ast_matchers::internal::Matcher;
27+
2628static const int MAXIMUM_STEP_UNROLLED = 128 ;
2729
2830namespace {
@@ -69,6 +71,11 @@ struct LoopState {
6971REGISTER_LIST_WITH_PROGRAMSTATE (LoopStack, LoopState)
7072
7173namespace clang {
74+ namespace {
75+ AST_MATCHER (QualType, isIntegralOrEnumerationType) {
76+ return Node->isIntegralOrEnumerationType ();
77+ }
78+ } // namespace
7279namespace ento {
7380
7481static bool isLoopStmt (const Stmt *S) {
@@ -82,22 +89,23 @@ ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State) {
8289 return State;
8390}
8491
85- static internal::Matcher<Stmt> simpleCondition (StringRef BindName,
86- StringRef RefName) {
92+ static Matcher<Stmt> simpleCondition (StringRef BindName, StringRef RefName) {
93+ auto LoopVariable = ignoringParenImpCasts (
94+ declRefExpr (to (varDecl (hasType (isInteger ())).bind (BindName)))
95+ .bind (RefName));
96+ auto UpperBound = ignoringParenImpCasts (
97+ expr (hasType (isIntegralOrEnumerationType ())).bind (" boundNum" ));
98+
8799 return binaryOperator (
88100 anyOf (hasOperatorName (" <" ), hasOperatorName (" >" ),
89101 hasOperatorName (" <=" ), hasOperatorName (" >=" ),
90102 hasOperatorName (" !=" )),
91- hasEitherOperand (ignoringParenImpCasts (
92- declRefExpr (to (varDecl (hasType (isInteger ())).bind (BindName)))
93- .bind (RefName))),
94- hasEitherOperand (
95- ignoringParenImpCasts (integerLiteral ().bind (" boundNum" ))))
103+ anyOf (binaryOperator (hasLHS (LoopVariable), hasRHS (UpperBound)),
104+ binaryOperator (hasRHS (LoopVariable), hasLHS (UpperBound))))
96105 .bind (" conditionOperator" );
97106}
98107
99- static internal::Matcher<Stmt>
100- changeIntBoundNode (internal::Matcher<Decl> VarNodeMatcher) {
108+ static Matcher<Stmt> changeIntBoundNode (Matcher<Decl> VarNodeMatcher) {
101109 return anyOf (
102110 unaryOperator (anyOf (hasOperatorName (" --" ), hasOperatorName (" ++" )),
103111 hasUnaryOperand (ignoringParenImpCasts (
@@ -107,30 +115,27 @@ changeIntBoundNode(internal::Matcher<Decl> VarNodeMatcher) {
107115 declRefExpr (to (varDecl (VarNodeMatcher)))))));
108116}
109117
110- static internal::Matcher<Stmt>
111- callByRef (internal::Matcher<Decl> VarNodeMatcher) {
118+ static Matcher<Stmt> callByRef (Matcher<Decl> VarNodeMatcher) {
112119 return callExpr (forEachArgumentWithParam (
113120 declRefExpr (to (varDecl (VarNodeMatcher))),
114121 parmVarDecl (hasType (references (qualType (unless (isConstQualified ())))))));
115122}
116123
117- static internal::Matcher<Stmt>
118- assignedToRef (internal::Matcher<Decl> VarNodeMatcher) {
124+ static Matcher<Stmt> assignedToRef (Matcher<Decl> VarNodeMatcher) {
119125 return declStmt (hasDescendant (varDecl (
120126 allOf (hasType (referenceType ()),
121127 hasInitializer (anyOf (
122128 initListExpr (has (declRefExpr (to (varDecl (VarNodeMatcher))))),
123129 declRefExpr (to (varDecl (VarNodeMatcher)))))))));
124130}
125131
126- static internal::Matcher<Stmt>
127- getAddrTo (internal::Matcher<Decl> VarNodeMatcher) {
132+ static Matcher<Stmt> getAddrTo (Matcher<Decl> VarNodeMatcher) {
128133 return unaryOperator (
129134 hasOperatorName (" &" ),
130135 hasUnaryOperand (declRefExpr (hasDeclaration (VarNodeMatcher))));
131136}
132137
133- static internal:: Matcher<Stmt> hasSuspiciousStmt (StringRef NodeName) {
138+ static Matcher<Stmt> hasSuspiciousStmt (StringRef NodeName) {
134139 return hasDescendant (stmt (
135140 anyOf (gotoStmt (), switchStmt (), returnStmt (),
136141 // Escaping and not known mutation of the loop counter is handled
@@ -142,7 +147,7 @@ static internal::Matcher<Stmt> hasSuspiciousStmt(StringRef NodeName) {
142147 assignedToRef (equalsBoundNode (std::string (NodeName))))));
143148}
144149
145- static internal:: Matcher<Stmt> forLoopMatcher () {
150+ static Matcher<Stmt> forLoopMatcher () {
146151 return forStmt (
147152 hasCondition (simpleCondition (" initVarName" , " initVarRef" )),
148153 // Initialization should match the form: 'int i = 6' or 'i = 42'.
@@ -271,23 +276,26 @@ static bool shouldCompletelyUnroll(const Stmt *LoopStmt, ASTContext &ASTCtx,
271276 if (!isLoopStmt (LoopStmt))
272277 return false ;
273278
274- // TODO: Match the cases where the bound is not a concrete literal but an
275- // integer with known value
276279 auto Matches = match (forLoopMatcher (), *LoopStmt, ASTCtx);
277280 if (Matches.empty ())
278281 return false ;
279282
280283 const auto *CounterVarRef = Matches[0 ].getNodeAs <DeclRefExpr>(" initVarRef" );
281- llvm::APInt BoundNum =
282- Matches[0 ].getNodeAs <IntegerLiteral>(" boundNum" )->getValue ();
284+ const Expr *BoundNumExpr = Matches[0 ].getNodeAs <Expr>(" boundNum" );
285+
286+ Expr::EvalResult BoundNumResult;
287+ if (!BoundNumExpr || !BoundNumExpr->EvaluateAsInt (BoundNumResult, ASTCtx,
288+ Expr::SE_NoSideEffects)) {
289+ return false ;
290+ }
283291 llvm::APInt InitNum =
284292 Matches[0 ].getNodeAs <IntegerLiteral>(" initNum" )->getValue ();
285293 auto CondOp = Matches[0 ].getNodeAs <BinaryOperator>(" conditionOperator" );
286- unsigned MaxWidth = std::max (InitNum.getBitWidth (), BoundNum.getBitWidth ());
294+ unsigned MaxWidth = std::max (InitNum.getBitWidth (),
295+ BoundNumResult.Val .getInt ().getBitWidth ());
287296
288297 InitNum = InitNum.zext (MaxWidth);
289- BoundNum = BoundNum.zext (MaxWidth);
290-
298+ llvm::APInt BoundNum = BoundNumResult.Val .getInt ().zext (MaxWidth);
291299 if (CondOp->getOpcode () == BO_GE || CondOp->getOpcode () == BO_LE)
292300 maxStep = (BoundNum - InitNum + 1 ).abs ().getZExtValue ();
293301 else
0 commit comments