@Nullable
  static TerminalOperation createTerminal(@NotNull String name, PsiExpression @NotNull [] args,
                                          @NotNull PsiType elementType, @NotNull PsiType resultType, boolean isVoid) {
    if(isVoid) {
      if ((name.equals("forEach") || name.equals("forEachOrdered")) && args.length == 1) {
        FunctionHelper fn = FunctionHelper.create(args[0], 1, true);
        return fn == null ? null : new ForEachTerminalOperation(fn);
      }
      return null;
    }
    if(name.equals("count") && args.length == 0) {
      return TemplateBasedOperation.counting();
    }
    if(name.equals("sum") && args.length == 0) {
      return TemplateBasedOperation.summing(resultType);
    }
    if(name.equals("average") && args.length == 0) {
      if(elementType.equals(PsiTypes.doubleType())) {
        return new AverageTerminalOperation(true, true);
      }
      else if(elementType.equals(PsiTypes.intType()) || elementType.equals(PsiTypes.longType())) {
        return new AverageTerminalOperation(false, true);
      }
    }
    if(name.equals("summaryStatistics") && args.length == 0) {
      return TemplateBasedOperation.summarizing(resultType);
    }
    if((name.equals("findFirst") || name.equals("findAny")) && args.length == 0) {
      PsiType optionalElementType = OptionalUtil.getOptionalElementType(resultType);
      return optionalElementType == null ? null : new FindTerminalOperation(optionalElementType);
    }
    if(name.equals("toList") && args.length == 0) {
      return ToCollectionTerminalOperation.toList(resultType);
    }
    if(name.equals("toSet") && args.length == 0) {
      return ToCollectionTerminalOperation.toSet(resultType);
    }
    if(name.equals("toImmutableList") && args.length == 0) {
      return new WrappedCollectionTerminalOperation(ToCollectionTerminalOperation.toList(resultType), "unmodifiableList", resultType);
    }
    if(name.equals("toImmutableSet") && args.length == 0) {
      return new WrappedCollectionTerminalOperation(ToCollectionTerminalOperation.toSet(resultType), "unmodifiableSet", resultType);
    }
    if((name.equals("anyMatch") || name.equals("allMatch") || name.equals("noneMatch")) && args.length == 1) {
      FunctionHelper fn = FunctionHelper.create(args[0], 1);
      return fn == null ? null : new MatchTerminalOperation(fn, name);
    }
    if(name.equals("reduce")) {
      if(args.length == 2 || args.length == 3) {
        FunctionHelper fn = FunctionHelper.create(args[1], 2);
        if(fn != null) {
          return new ReduceTerminalOperation(args[0], fn, resultType);
        }
      }
      if(args.length == 1) {
        return ReduceToOptionalTerminalOperation.create(args[0], resultType);
      }
    }
    if(name.equals("toArray") && args.length < 2) {
      if(!(resultType instanceof PsiArrayType)) return null;
      PsiType componentType = ((PsiArrayType)resultType).getComponentType();
      if (componentType instanceof PsiPrimitiveType) {
        if (args.length == 0) return new ToPrimitiveArrayTerminalOperation(componentType);
      }
      else {
        FunctionHelper fn = null;
        if(args.length == 1) {
          fn = FunctionHelper.create(args[0], 1);
          if(fn == null) return null;
        }
        return new ToArrayTerminalOperation(elementType, fn);
      }
    }
    if ((name.equals("max") || name.equals("min")) && args.length < 2) {
      return MinMaxTerminalOperation.create(args.length == 1 ? args[0] : null, elementType, name.equals("max"));
    }
    if (name.equals("collect")) {
      if (args.length == 3) {
        FunctionHelper supplier = FunctionHelper.create(args[0], 0);
        if (supplier == null) return null;
        FunctionHelper accumulator = FunctionHelper.create(args[1], 2);
        if (accumulator == null) return null;
        return new ExplicitCollectTerminalOperation(supplier, accumulator);
      }
      if (args.length == 1) {
        return fromCollector(elementType, resultType, PsiUtil.skipParenthesizedExprDown(args[0]));
      }
    }
    return null;
  }
@Nullable
  static TerminalOperation createTerminal(@NotNull String name, PsiExpression @NotNull [] args,
                                          @NotNull PsiType elementType, @NotNull PsiType resultType, boolean isVoid)