boolean (PsiForStatement statement, ControlFlowOffset startOffset) { CountingLoop loop = CountingLoop.from(statement); if (loop == null || loop.isDescending()) return false; PsiLocalVariable counter = loop.getCounter(); PsiType counterType = counter.getType(); Long end = asLong(loop.getBound()); if (loop.isIncluding() && !(PsiTypes.longType().equals(counterType) && PsiTypes.intType().equals(loop.getBound().getType()))) { // could be for(int i=0; i<=Integer.MAX_VALUE; i++) which will overflow: conservatively skip this if (end == null || end == Long.MAX_VALUE || end == Integer.MAX_VALUE) return false; } PsiExpression initializer = loop.getInitializer(); if (!PsiTypes.intType().equals(counterType) && !PsiTypes.longType().equals(counterType)) return false; DfaValue origin = null; Object initialValue = ExpressionUtils.computeConstantExpression(initializer); if (initialValue instanceof Number) { origin = myFactory.fromDfType(DfTypes.constant(initialValue, counterType)); } else if (initializer instanceof PsiReferenceExpression ref) { PsiVariable initialVariable = ObjectUtils.tryCast(ref.resolve(), PsiVariable.class); if (PsiUtil.isJvmLocalVariable(initialVariable) && !VariableAccessUtils.variableIsAssigned(initialVariable, statement.getBody())) { origin = PlainDescriptor.createVariableValue(myFactory, initialVariable); } } if (origin == null) return false; Long start = asLong(initializer); long diff = start == null || end == null ? -1 : end - start; DfaVariableValue loopVar = PlainDescriptor.createVariableValue(myFactory, counter); if(diff >= 0 && diff <= MAX_UNROLL_SIZE) { // Unroll small loops Objects.requireNonNull(statement.getUpdate()).accept(this); // It's possible that a nested loop may cause widening, dismissing our efforts to track the loop variable // In this case, we should at least ensure that it's not lower than the start. addInstruction(new PushInstruction(loopVar, null)); DfType startBound = PsiTypes.intType().equals(counterType) ? DfTypes.intValue(Math.toIntExact(start)) : DfTypes.longValue(start); addInstruction(new EnsureInstruction(null, RelationType.GE, startBound, null)); addInstruction(new PopInstruction()); addInstruction(new GotoInstruction(startOffset, false)); return true; } else if (start != null) { long maxValue = end == null ? Long.MAX_VALUE : loop.isIncluding() ? end + 1 : end; if (start >= maxValue && !loop.mayOverflow()) { addInstruction(new GotoInstruction(getEndOffset(statement))); } else { LongRangeSet rangeSet = start >= maxValue ? LongRangeSet.all().subtract(LongRangeSet.range(maxValue + 1, start)) : LongRangeSet.range(start + 1L, maxValue); DfType range = DfTypes.rangeClamped(rangeSet, JvmPsiRangeSetUtil.getLongRangeType(counterType)); new CFGBuilder(this).assignAndPop(loopVar, range); } } else { // loop like for(int i = start; i != end; i++) if (loop.mayOverflow()) return false; new CFGBuilder(this).assign(loopVar, DfType.TOP) .push(origin) .compare(RelationType.LE); addInstruction(new ConditionalGotoInstruction(getEndOffset(statement), DfTypes.TRUE, null)); } addInstruction(new GotoInstruction(startOffset)); return true; }