@Nullable
  private TerminalBlock extractOperation() {
    TerminalBlock withFilter = extractFilter();
    if(withFilter != null) return withFilter;
    // extract flatMap
    if(getSingleStatement() instanceof PsiLoopStatement loopStatement) {
      StreamSource source = StreamSource.tryCreate(loopStatement);
      final PsiStatement body = loopStatement.getBody();
      if(source == null || body == null) return null;
      FlatMapOp op = new FlatMapOp(source, myVariable);
      TerminalBlock withFlatMap = new TerminalBlock(this, op, source.getVariable(), body);
      if(!VariableAccessUtils.variableIsUsed(myVariable, body)) {
        return withFlatMap;
      } else {
        // Try extract nested filter like this:
        // for(List subList : list) for(T t : subList) if(condition.test(t)) { ...; break; }
        // if t is not used in "...", then this could be converted to
        // list.stream().filter(subList -> subList.stream().anyMatch(condition)).forEach(subList -> ...)
        TerminalBlock withFlatMapFilter = withFlatMap.extractFilter();
        if(withFlatMapFilter != null && !withFlatMapFilter.isEmpty()) {
          PsiStatement[] statements = withFlatMapFilter.getStatements();
          PsiStatement lastStatement = statements[statements.length-1];
          boolean flowBreaks = lastStatement instanceof PsiBreakStatement && op.breaksMe((PsiBreakStatement)lastStatement) ||
                               lastStatement instanceof PsiReturnStatement ||
                               lastStatement instanceof PsiThrowStatement;
          if (flowBreaks && ReferencesSearch.search(withFlatMapFilter.getVariable(), new LocalSearchScope(statements)).findFirst() == null) {
            FilterOp filterOp = (FilterOp)withFlatMapFilter.getLastOperation();
            return new TerminalBlock(this, new CompoundFilterOp(op.getSource(), op.getVariable(), filterOp),
                                     myVariable,
                                     lastStatement instanceof PsiReturnStatement || lastStatement instanceof PsiThrowStatement
                                     ? statements
                                     : Arrays.copyOf(statements, statements.length - 1));
          }
        }
      }
    }
    if(myStatements.length >= 1) {
      PsiStatement first = myStatements[0];
      if(PsiUtil.isLanguageLevel9OrHigher(myVariable.getContainingFile()) && first instanceof PsiIfStatement ifStatement) {
        PsiExpression condition = ifStatement.getCondition();
        if(ifStatement.getElseBranch() == null && condition != null) {
          PsiStatement thenStatement = ControlFlowUtils.stripBraces(ifStatement.getThenBranch());
          PsiStatement sourceStatement = getStreamSourceStatement();
          if( sourceStatement instanceof PsiLoopStatement && ControlFlowUtils.statementBreaksLoop(thenStatement,
                                                                                                  (PsiLoopStatement)sourceStatement)) {
            TakeWhileOp op = new TakeWhileOp(condition, myVariable, true);
            PsiStatement[] leftOver = Arrays.copyOfRange(myStatements, 1, myStatements.length);
            return new TerminalBlock(this, op, myVariable, leftOver);
          }
        }
      }
      // extract map
      if(first instanceof PsiDeclarationStatement decl) {
        PsiElement[] elements = decl.getDeclaredElements();
        if(elements.length == 1) {
          PsiLocalVariable declaredVar = tryCast(elements[0], PsiLocalVariable.class);
          if (declaredVar != null && StreamApiUtil.isSupportedStreamElement(declaredVar.getType())) {
            PsiExpression initializer = declaredVar.getInitializer();
            PsiStatement[] leftOver = Arrays.copyOfRange(myStatements, 1, myStatements.length);
            if (initializer != null && ReferencesSearch.search(myVariable, new LocalSearchScope(leftOver)).findFirst() == null) {
              MapOp op = new MapOp(initializer, myVariable, declaredVar.getType());
              return new TerminalBlock(this, op, declaredVar, leftOver);
            }
          }
        }
      }
      PsiExpression rValue = ExpressionUtils.getAssignmentTo(first, myVariable);
      if(rValue != null && operations().allMatch(op -> op.canReassignVariable(myVariable))) {
        PsiStatement[] leftOver = Arrays.copyOfRange(myStatements, 1, myStatements.length);
        MapOp op = new MapOp(rValue, myVariable, myVariable.getType());
        return new TerminalBlock(this, op, myVariable, leftOver);
      }
    }
    TerminalBlock withLimit = tryPeelLimit(true);
    return withLimit == this ? null : withLimit;
  }
@Nullable
  private TerminalBlock extractOperation()