private void processForeach(@NotNull PsiForeachStatementBase statement) {
    startElement(statement);
    final PsiExpression iteratedValue = PsiUtil.skipParenthesizedExprDown(statement.getIteratedValue());

    ControlFlowOffset loopEndOffset = getEndOffset(statement);
    boolean hasSizeCheck = false;

    if (iteratedValue != null) {
      iteratedValue.accept(this);

      PsiType type = iteratedValue.getType();
      SpecialField length = null;
      if (type instanceof PsiArrayType) {
        length = SpecialField.ARRAY_LENGTH;
      }
      else if (InheritanceUtil.isInheritor(type, JAVA_UTIL_COLLECTION)) {
        length = SpecialField.COLLECTION_SIZE;
      }
      if (length != null) {
        addInstruction(new UnwrapDerivedVariableInstruction(length));
        addInstruction(new ConditionalGotoInstruction(loopEndOffset, DfTypes.intValue(0)));
        hasSizeCheck = true;
      } else {
        addInstruction(new PopInstruction());
      }
    }

    ControlFlowOffset offset = myCurrentFlow.getNextOffset();
    if (statement instanceof PsiForeachStatement normalForeach) {
      PsiParameter parameter = normalForeach.getIterationParameter();
      DfaVariableValue dfaVariable = PlainDescriptor.createVariableValue(myFactory, parameter);
      DfaValue commonValue = getIteratedElement(parameter.getType(), iteratedValue);
      if (DfaTypeValue.isUnknown(commonValue)) {
        addInstruction(new FlushVariableInstruction(dfaVariable));
      } else {
        new CFGBuilder(this).pushForWrite(dfaVariable).push(commonValue).assign().pop();
      }
    }
    else if (statement instanceof PsiForeachPatternStatement patternForeach &&
             patternForeach.getIterationPattern() instanceof PsiDeconstructionPattern pattern) {
      PsiType contextType = JavaPsiPatternUtil.getContextType(pattern);
      if (contextType == null) {
        contextType = TypeUtils.getObjectType(statement);
      }
      DfaValue commonValue = getIteratedElement(contextType, iteratedValue);
      addInstruction(new PushInstruction(commonValue, null));
      DeferredOffset endPattern = new DeferredOffset();
      processPattern(pattern, pattern, contextType,null, endPattern);
      endPattern.setOffset(getInstructionCount());
      addInstruction(new EnsureInstruction(null, RelationType.EQ, DfTypes.TRUE, null));
      addInstruction(new PopInstruction());
    }

    if (!hasSizeCheck) {
      pushUnknown();
      addInstruction(new ConditionalGotoInstruction(loopEndOffset, DfType.TOP));
    }

    final PsiStatement body = statement.getBody();
    if (body != null) {
      body.accept(this);
    }

    if (hasSizeCheck) {
      pushUnknown();
      addInstruction(new ConditionalGotoInstruction(loopEndOffset, DfType.TOP));
    }

    addInstruction(new GotoInstruction(offset));

    finishElement(statement);
  }
private void processForeach(@NotNull PsiForeachStatementBase statement)