@Nullable
    private static Context from(@NotNull PsiConditionalLoopStatement loopStatement,
                                boolean noConversionToDoWhile,
                                boolean suggestConversionWhenIfIsASingleStmtInLoop) {
      boolean isEndlessLoop = ControlFlowUtils.isEndlessLoop(loopStatement);
      if (!isEndlessLoop) {
        if (loopStatement instanceof PsiForStatement forStatement) {
          if ((forStatement.getInitialization() != null && !(forStatement.getInitialization() instanceof PsiEmptyStatement))
              || (forStatement.getUpdate() != null && !(forStatement.getUpdate() instanceof PsiEmptyStatement))) {
            return null;
          }
        }
      }
      PsiStatement body = loopStatement.getBody();
      if (body == null) return null;
      PsiStatement[] statements = ControlFlowUtils.unwrapBlock(body);
      if (statements.length < 1) return null;
      if (statements.length == 1 && !suggestConversionWhenIfIsASingleStmtInLoop) return null;
      if (StreamEx.ofTree((PsiElement)body, el -> StreamEx.of(el.getChildren()))
            .select(PsiBreakStatement.class)
            .filter(stmt -> ControlFlowUtils.statementBreaksLoop(stmt, loopStatement))
            .count() != 1) {
        return null;
      }
      PsiIfStatement first = tryCast(statements[0], PsiIfStatement.class);
      Ref<Boolean> isBreakInThen = new Ref<>(false);
      PsiExpression firstBreakCondition = extractBreakCondition(first, loopStatement, isBreakInThen);
      PsiExpression loopCondition = loopStatement.getCondition();
      boolean isLoopConditionAtStart = !(loopStatement instanceof PsiDoWhileStatement);
      if (first != null
          && firstBreakCondition != null
          && (isEndlessLoop ||
           (isLoopConditionAtStart &&
            (BoolUtils.getLogicalOperandCount(loopCondition) + BoolUtils.getLogicalOperandCount(firstBreakCondition)) < 4))) {
        return new Context(loopStatement, body, firstBreakCondition, first, true, isBreakInThen.get(), isEndlessLoop);
      }
      if (noConversionToDoWhile) return null;
      PsiIfStatement last = tryCast(statements[statements.length - 1], PsiIfStatement.class);
      if (last != null && last.getElseBranch() != null) return null;
      PsiExpression lastBreakCondition = extractBreakCondition(last, loopStatement, isBreakInThen);
      if (lastBreakCondition == null || !isBreakInThen.get()) return null;
      if (!isEndlessLoop &&
          (isLoopConditionAtStart ||
           (3 < BoolUtils.getLogicalOperandCount(loopCondition) + BoolUtils.getLogicalOperandCount(lastBreakCondition)))) {
        return null;
      }
      if (StreamEx.of(statements)
        .flatMap(statement -> StreamEx.ofTree((PsiElement)statement, el -> StreamEx.of(el.getChildren())))
        .anyMatch(e -> e instanceof PsiContinueStatement &&
                       ((PsiContinueStatement)e).findContinuedStatement() == loopStatement)) {
        return null;
      }
      boolean variablesInLoop =
        ContainerUtil.exists(VariableAccessUtils.collectUsedVariables(lastBreakCondition),
                             variable -> PsiTreeUtil.isAncestor(loopStatement, variable, false));
      if (variablesInLoop) return null;
      return new Context(loopStatement, body, lastBreakCondition, last, false, isBreakInThen.get(), isEndlessLoop);
    }
@Nullable
    private static Context from(@NotNull PsiConditionalLoopStatement loopStatement,
                                boolean noConversionToDoWhile,
                                boolean suggestConversionWhenIfIsASingleStmtInLoop)