private static void buildStreamCFG(CFGBuilder builder, Step firstStep, PsiExpression originalQualifier,
                                     boolean originalQualifierAlreadyChecked) {
    PsiType inType = StreamApiUtil.getStreamElementType(originalQualifier.getType(), false);
    PsiMethodCallExpression sourceCall = tryCast(PsiUtil.skipParenthesizedExprDown(originalQualifier), PsiMethodCallExpression.class);
    if(STREAM_GENERATE.test(sourceCall)) {
      PsiExpression fn = sourceCall.getArgumentList().getExpressions()[0];
      builder
        .evaluateFunction(fn)
        .chain(firstStep::before)
        .doWhileUnknown()
        .pushForWrite(builder.createTempVariable(inType))
        .invokeFunction(0, fn)
        .assign()
        .chain(firstStep::iteration).end();
      return;
    }
    boolean empty = STREAM_EMPTY.test(sourceCall);
    boolean array = ARRAYS_STREAM.test(sourceCall);
    boolean single = STREAM_OF.test(sourceCall);
    if (STREAM_OF_ARRAY.test(sourceCall)) {
      PsiExpression[] args = sourceCall.getArgumentList().getExpressions();
      if(args.length == 0) {
        empty = true;
      } else if(args.length == 1) {
        if(MethodCallUtils.isVarArgCall(sourceCall)) {
          single = true;
        } else {
          array = true;
        }
      } else {
        builder
          .chain(firstStep::before)
          .loopOver(args, builder.createTempVariable(inType), inType)
          .chain(firstStep::iteration).end();
        return;
      }
    }
    if (empty) {
      builder.chain(firstStep::before); // skip loop at all
      return;
    }
    if (single) {
      // exactly single element
      PsiExpression arg = sourceCall.getArgumentList().getExpressions()[0];
      builder
        .pushForWrite(builder.createTempVariable(inType))
        .pushExpression(arg)
        .boxUnbox(arg, inType)
        .assign()
        .chain(firstStep::before)
        .chain(firstStep::iteration);
      return;
    }
    if (array) {
      PsiExpression arrayExpression = sourceCall.getArgumentList().getExpressions()[0];
      startStreamFromContainer(builder, firstStep, arrayExpression, SpecialField.ARRAY_LENGTH, inType);
      return;
    }
    else if (COLLECTION_STREAM.test(sourceCall)) {
      PsiExpression collectionExpression = sourceCall.getMethodExpression().getQualifierExpression();
      if (collectionExpression != null) {
        startStreamFromCollection(builder, firstStep, collectionExpression);
        return;
      }
    }
    if (OPTIONAL_STREAM.test(sourceCall)) {
      PsiExpression qualifierExpression = sourceCall.getMethodExpression().getQualifierExpression();
      if (qualifierExpression != null) {
        PsiType optValueType = PsiUtil.substituteTypeParameter(qualifierExpression.getType(), JAVA_UTIL_OPTIONAL, 0, false);
        if (optValueType != null) {
          builder
            .pushForWrite(builder.createTempVariable(optValueType))// optValueVar
            .pushExpression(qualifierExpression) //optValueVar optVar
            .unwrap(SpecialField.OPTIONAL_VALUE) //optValueVar optVar.value
            .assign() //optValueVar
            .dup() //optValueVar optValueVar
            .chain(firstStep::before)
            .ifNull() //optValueVar
            // skip loop at all
              .pop() //..
            .elseBranch() //optValueVar
              .chain(firstStep::iteration)
            .end();
          return;
        }
      }
    }
    startStreamUnknown(builder, firstStep, originalQualifier, originalQualifierAlreadyChecked, inType);
  }
private static void buildStreamCFG(CFGBuilder builder, Step firstStep, PsiExpression originalQualifier,
                                     boolean originalQualifierAlreadyChecked)