@Override
    @Nullable
    public PsiType fun(final PsiMethodCallExpression call) {
      PsiReferenceExpression methodExpression = call.getMethodExpression();
      PsiType theOnly = null;
      final JavaResolveResult[] results = methodExpression.multiResolve(false);
      LanguageLevel languageLevel = PsiUtil.getLanguageLevel(call);

      final PsiElement callParent = PsiUtil.skipParenthesizedExprUp(call.getParent());
      final PsiExpressionList parentArgList;
      if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
        parentArgList =
            callParent instanceof PsiConditionalExpression
                    && !PsiPolyExpressionUtil.isPolyExpression((PsiExpression) callParent)
                ? null
                : PsiTreeUtil.getParentOfType(call, PsiExpressionList.class);
      } else {
        parentArgList = null;
      }
      final MethodCandidateInfo.CurrentCandidateProperties properties =
          MethodCandidateInfo.getCurrentMethod(parentArgList);
      final boolean genericMethodCall =
          properties != null && properties.getInfo().isToInferApplicability();

      for (int i = 0; i < results.length; i++) {
        final JavaResolveResult candidateInfo = results[i];

        if (genericMethodCall
            && PsiPolyExpressionUtil.isMethodCallPolyExpression(
                call, (PsiMethod) candidateInfo.getElement())) {
          if (callParent instanceof PsiAssignmentExpression) {
            return null;
          }
          LOG.error("poly expression evaluation during overload resolution");
        }

        final PsiType type = getResultType(call, methodExpression, candidateInfo, languageLevel);
        if (type == null) {
          return null;
        }

        if (i == 0) {
          theOnly = type;
        } else if (!theOnly.equals(type)) {
          return null;
        }
      }

      return PsiClassImplUtil.correctType(theOnly, call.getResolveScope());
    }
 protected boolean findNewParamsPlace(
     PsiExpression[] expressions,
     PsiMethod targetMethod,
     PsiSubstitutor substitutor,
     StringBuilder buf,
     HashSet<ParameterInfoImpl> newParams,
     PsiParameter[] parameters,
     List<ParameterInfoImpl> result) {
   // find which parameters to introduce and where
   Set<String> existingNames = new HashSet<String>();
   for (PsiParameter parameter : parameters) {
     existingNames.add(parameter.getName());
   }
   int ei = 0;
   int pi = 0;
   PsiParameter varargParam = targetMethod.isVarArgs() ? parameters[parameters.length - 1] : null;
   while (ei < expressions.length || pi < parameters.length) {
     if (buf.length() > 0) buf.append(", ");
     PsiExpression expression = ei < expressions.length ? expressions[ei] : null;
     PsiParameter parameter = pi < parameters.length ? parameters[pi] : null;
     PsiType paramType = parameter == null ? null : substitutor.substitute(parameter.getType());
     boolean parameterAssignable =
         paramType != null
             && (expression == null
                 || TypeConversionUtil.areTypesAssignmentCompatible(paramType, expression));
     if (parameterAssignable) {
       final PsiType type = parameter.getType();
       result.add(new ParameterInfoImpl(pi, parameter.getName(), type));
       buf.append(escapePresentableType(type));
       pi++;
       ei++;
     } else if (isArgumentInVarargPosition(expressions, ei, varargParam, substitutor)) {
       if (pi == parameters.length - 1) {
         assert varargParam != null;
         final PsiType type = varargParam.getType();
         result.add(new ParameterInfoImpl(pi, varargParam.getName(), type));
         buf.append(escapePresentableType(type));
       }
       pi++;
       ei++;
     } else if (expression != null) {
       if (varargParam != null && pi >= parameters.length) return false;
       if (PsiPolyExpressionUtil.isPolyExpression(expression)) return false;
       PsiType exprType = RefactoringUtil.getTypeByExpression(expression);
       if (exprType == null) return false;
       if (exprType instanceof PsiDisjunctionType) {
         exprType = ((PsiDisjunctionType) exprType).getLeastUpperBound();
       }
       JavaCodeStyleManager codeStyleManager =
           JavaCodeStyleManager.getInstance(expression.getProject());
       String name =
           suggestUniqueParameterName(codeStyleManager, expression, exprType, existingNames);
       final ParameterInfoImpl newParameterInfo =
           new ParameterInfoImpl(-1, name, exprType, expression.getText().replace('\n', ' '));
       result.add(newParameterInfo);
       newParams.add(newParameterInfo);
       buf.append("<b>").append(escapePresentableType(exprType)).append("</b>");
       ei++;
     }
   }
   if (result.size() != expressions.length && varargParam == null) return false;
   return true;
 }
  private ParameterInfoImpl[] getNewParametersInfo(
      PsiExpression[] expressions,
      PsiMethod targetMethod,
      PsiSubstitutor substitutor,
      final StringBuilder buf,
      final HashSet<ParameterInfoImpl> newParams,
      final HashSet<ParameterInfoImpl> removedParams,
      final HashSet<ParameterInfoImpl> changedParams) {
    PsiParameter[] parameters = targetMethod.getParameterList().getParameters();
    List<ParameterInfoImpl> result = new ArrayList<ParameterInfoImpl>();
    if (expressions.length < parameters.length) {
      // find which parameters to remove
      int ei = 0;
      int pi = 0;

      while (ei < expressions.length && pi < parameters.length) {
        PsiExpression expression = expressions[ei];
        PsiParameter parameter = parameters[pi];
        PsiType paramType = substitutor.substitute(parameter.getType());
        if (buf.length() > 0) buf.append(", ");
        final PsiType parameterType = PsiUtil.convertAnonymousToBaseType(paramType);
        final String presentableText = escapePresentableType(parameterType);
        final ParameterInfoImpl parameterInfo =
            new ParameterInfoImpl(pi, parameter.getName(), parameter.getType());
        if (TypeConversionUtil.areTypesAssignmentCompatible(paramType, expression)) {
          buf.append(presentableText);
          result.add(parameterInfo);
          pi++;
          ei++;
        } else {
          buf.append("<s>").append(presentableText).append("</s>");
          removedParams.add(parameterInfo);
          pi++;
        }
      }
      if (result.size() != expressions.length) return null;
      for (int i = pi; i < parameters.length; i++) {
        if (buf.length() > 0) buf.append(", ");
        buf.append("<s>").append(escapePresentableType(parameters[i].getType())).append("</s>");
        final ParameterInfoImpl parameterInfo =
            new ParameterInfoImpl(pi, parameters[i].getName(), parameters[i].getType());
        removedParams.add(parameterInfo);
      }
    } else if (expressions.length > parameters.length) {
      if (!findNewParamsPlace(
          expressions, targetMethod, substitutor, buf, newParams, parameters, result)) return null;
    } else {
      // parameter type changed
      for (int i = 0; i < parameters.length; i++) {
        if (buf.length() > 0) buf.append(", ");
        PsiParameter parameter = parameters[i];
        PsiExpression expression = expressions[i];
        PsiType paramType = substitutor.substitute(parameter.getType());
        final String presentableText = escapePresentableType(paramType);
        if (TypeConversionUtil.areTypesAssignmentCompatible(paramType, expression)) {
          result.add(new ParameterInfoImpl(i, parameter.getName(), paramType));
          buf.append(presentableText);
        } else {
          if (PsiPolyExpressionUtil.isPolyExpression(expression)) return null;
          PsiType exprType = RefactoringUtil.getTypeByExpression(expression);
          if (exprType == null) return null;
          if (exprType instanceof PsiDisjunctionType) {
            exprType = ((PsiDisjunctionType) exprType).getLeastUpperBound();
          }
          final ParameterInfoImpl changedParameterInfo =
              new ParameterInfoImpl(i, parameter.getName(), exprType);
          result.add(changedParameterInfo);
          changedParams.add(changedParameterInfo);
          buf.append("<s>")
              .append(presentableText)
              .append("</s> <b>")
              .append(escapePresentableType(exprType))
              .append("</b>");
        }
      }
      // do not perform silly refactorings
      boolean isSilly = true;
      for (int i = 0; i < result.size(); i++) {
        PsiParameter parameter = parameters[i];
        PsiType paramType = substitutor.substitute(parameter.getType());
        ParameterInfoImpl parameterInfo = result.get(i);
        String typeText = parameterInfo.getTypeText();
        if (!paramType.equalsToText(typeText) && !paramType.getPresentableText().equals(typeText)) {
          isSilly = false;
          break;
        }
      }
      if (isSilly) return null;
    }
    return result.toArray(new ParameterInfoImpl[result.size()]);
  }