private static boolean tryConsumeIteration(@NotNull List<PsiStatement> statements,
                                               int count,
                                               int offset,
                                               @NotNull List<PsiExpression> expressionsToReplace,
                                               @NotNull List<PsiExpression> expressionsToIterate) {
      EquivalenceChecker equivalence = EquivalenceChecker.getCanonicalPsiEquivalence();
      PsiExpression firstIterationExpression = null;
      PsiExpression curIterationExpression = null;
      boolean secondIteration = count == offset;
      int mismatchedStatements = 0;
      for (int index = 0; index < count; index++) {
        PsiStatement first = statements.get(index);
        PsiStatement cur = statements.get(index + offset);
        EquivalenceChecker.Match match = new TrackingEquivalenceChecker().statementsMatch(first, cur);
        if (match.isExactMismatch()) return false;
        if (match.isExactMatch()) continue;
        mismatchedStatements++;
        PsiElement leftDiff = match.getLeftDiff();
        PsiElement rightDiff = match.getRightDiff();
        if (!(leftDiff instanceof PsiExpression) || !(rightDiff instanceof PsiExpression)) return false;
        curIterationExpression = (PsiExpression)rightDiff;
        firstIterationExpression = (PsiExpression)leftDiff;
        if (PsiUtil.isAccessedForWriting(curIterationExpression)) return false;
        PsiType curType = curIterationExpression.getType();
        PsiType firstType = firstIterationExpression.getType();
        if (curType == null || !curType.equals(firstType)) return false;
        Set<PsiVariable> usedVariables;
        if (secondIteration) {
          if (!expressionsToReplace.isEmpty()) {
            PsiExpression firstExpressionToReplace = expressionsToReplace.get(0);
            if (!equivalence.expressionsAreEquivalent(firstExpressionToReplace, firstIterationExpression)) return false;
            if (!firstType.equals(firstExpressionToReplace.getType())) return false;
          }
          expressionsToReplace.add(firstIterationExpression);
          usedVariables = StreamEx.of(firstIterationExpression, curIterationExpression)
            .map(VariableAccessUtils::collectUsedVariables).toFlatCollection(Function.identity(), HashSet::new);
        }
        else {
          if (!expressionsToReplace.contains(firstIterationExpression)) return false;
          usedVariables = VariableAccessUtils.collectUsedVariables(curIterationExpression);
        }
        if (!usedVariables.isEmpty() &&
            ContainerUtil.exists(statements.subList(0, count), st -> VariableAccessUtils.isAnyVariableAssigned(usedVariables, st))) {
          return false;
        }
      }
      if (secondIteration) {
        ContainerUtil.addIfNotNull(expressionsToIterate, firstIterationExpression);
      } else {
        if (mismatchedStatements != expressionsToReplace.size()) {
          return false;
        }
      }
      ContainerUtil.addIfNotNull(expressionsToIterate, curIterationExpression);
      return true;
    }
private static boolean tryConsumeIteration(@NotNull List<PsiStatement> statements,
                                               int count,
                                               int offset,
                                               @NotNull List<PsiExpression> expressionsToReplace,
                                               @NotNull List<PsiExpression> expressionsToIterate)