private static boolean isSafeLambdaReplacement(@NotNull PsiLambdaExpression lambda,
                                                 @NotNull Function<? super PsiLambdaExpression, ? extends PsiExpression> replacer) {
    PsiElement body = lambda.getBody();
    if (body == null) return false;
    final PsiCall call = treeWalkUp(body);
    if (call != null) {
      Object marker = new Object();
      PsiTreeUtil.mark(lambda, marker);
      PsiType origType = call instanceof PsiExpression ? ((PsiExpression)call).getType() : null;
      PsiCall copyCall = copyTopLevelCall(call);
      if (copyCall == null) return false;
      PsiLambdaExpression lambdaCopy = ObjectUtils.tryCast(PsiTreeUtil.releaseMark(copyCall, marker), PsiLambdaExpression.class);
      if (lambdaCopy == null) return false;
      PsiExpression function = replacer.apply(lambdaCopy);
      if (function == null) return false;
      PsiElement copyCur = function, cur = lambda;
      while(cur != call) {
        cur = cur.getParent();
        copyCur = copyCur.getParent();
        if (cur instanceof PsiCall && copyCur instanceof PsiCall) {
          JavaResolveResult result = ((PsiCall)cur).resolveMethodGenerics();
          JavaResolveResult resultCopy = ((PsiCall)copyCur).resolveMethodGenerics();
          if (!equalResolveResult(result, resultCopy)) return false;
        }
      }
      if (function instanceof PsiFunctionalExpression) {
        PsiType functionalType = ((PsiFunctionalExpression)function).getFunctionalInterfaceType();
        PsiType lambdaFunctionalType = lambda.getFunctionalInterfaceType();
        boolean sameType = functionalType == null ? lambdaFunctionalType == null :
                           lambdaFunctionalType != null &&
                           functionalType.getCanonicalText().equals(lambdaFunctionalType.getCanonicalText());                   
        if (!sameType) return false;
      }
      if (origType instanceof PsiClassType && !((PsiClassType)origType).isRaw() &&
          //when lambda has no formal parameter types, it's ignored during applicability check
          //so unchecked warnings inside lambda's body won't lead to erasure of the type of the containing call
          //but after replacement of lambda with the equivalent method call, unchecked warning won't be ignored anymore
          //and the type of the call would be erased => red code may appear
          !lambda.hasFormalParameterTypes()) {
        PsiExpression expressionFromBody = extractSingleExpressionFromBody(body);
        if (expressionFromBody instanceof PsiMethodCallExpression &&
            PsiTypesUtil.isUncheckedCall(((PsiMethodCallExpression)expressionFromBody).resolveMethodGenerics())) {
          return false;
        }
      }
    }
    else if (PsiPolyExpressionUtil.isInAssignmentOrInvocationContext(lambda)) {
      PsiType origType = lambda.getFunctionalInterfaceType();
      if (origType != null) {
        PsiLambdaExpression lambdaCopy = (PsiLambdaExpression)copyWithExpectedType(lambda, origType);
        PsiExpression replacement = replacer.apply(lambdaCopy);
        PsiType type = replacement.getType();
        return type != null && origType.isAssignableFrom(type);
      }
    }
    return true;
  }
private static boolean isSafeLambdaReplacement(@NotNull PsiLambdaExpression lambda,
                                                 @NotNull Function<? super PsiLambdaExpression, ? extends PsiExpression> replacer)