@MethodCandidateInfo.ApplicabilityLevelConstant
  public static int getApplicabilityLevel(@NotNull PsiMethod method,
                                          @NotNull PsiSubstitutor substitutorForMethod,
                                          PsiType @NotNull [] args,
                                          @NotNull LanguageLevel languageLevel,
                                          boolean allowUncheckedConversion,
                                          boolean checkVarargs,
                                          @NotNull ApplicabilityChecker function) {
    PsiParameter[] parameters = method.getParameterList().getParameters();
    if (args.length < parameters.length - 1) return ApplicabilityLevel.NOT_APPLICABLE;

    PsiClass containingClass = method.getContainingClass();
    boolean isRaw = containingClass != null && isRawSubstitutor(method, substitutorForMethod) && isRawSubstitutor(containingClass, substitutorForMethod);
    if (!areFirstArgumentsApplicable(args, parameters, languageLevel, substitutorForMethod, isRaw, allowUncheckedConversion, function)) {
      return ApplicabilityLevel.NOT_APPLICABLE;
    }
    if (args.length == parameters.length) {
      if (parameters.length == 0) return ApplicabilityLevel.FIXED_ARITY;
      PsiType parmType = getParameterType(parameters[parameters.length - 1], languageLevel, substitutorForMethod);
      PsiType argType = args[args.length - 1];
      if (argType == null) return ApplicabilityLevel.NOT_APPLICABLE;
      if (function.isApplicable(parmType, argType, allowUncheckedConversion, parameters.length - 1)) return ApplicabilityLevel.FIXED_ARITY;

      if (isRaw) {
        PsiType erasedParamType = TypeConversionUtil.erasure(parmType);
        if (erasedParamType != null && function.isApplicable(erasedParamType, argType, allowUncheckedConversion, parameters.length - 1)) {
          return ApplicabilityLevel.FIXED_ARITY;
        }
      }
    }

    if (checkVarargs && method.isVarArgs() && languageLevel.compareTo(LanguageLevel.JDK_1_5) >= 0) {
      if (args.length < parameters.length) return ApplicabilityLevel.VARARGS;
      PsiParameter lastParameter = parameters.length == 0 ? null : parameters[parameters.length - 1];
      if (lastParameter == null || !lastParameter.isVarArgs()) return ApplicabilityLevel.NOT_APPLICABLE;
      PsiType lastParmType = getParameterType(lastParameter, languageLevel, substitutorForMethod);
      if (!(lastParmType instanceof PsiArrayType)) return ApplicabilityLevel.NOT_APPLICABLE;
      lastParmType = ((PsiArrayType)lastParmType).getComponentType();
      if (lastParmType instanceof PsiCapturedWildcardType &&
          !JavaVersionService.getInstance().isAtLeast(((PsiCapturedWildcardType)lastParmType).getContext(), JavaSdkVersion.JDK_1_8)) {
        lastParmType = ((PsiCapturedWildcardType)lastParmType).getWildcard();
      }
      if (lastParmType instanceof PsiClassType) {
        lastParmType = ((PsiClassType)lastParmType).setLanguageLevel(languageLevel);
      }
      for (int i = parameters.length - 1; i < args.length; i++) {
        PsiType argType = args[i];
        if (argType == null || !function.isApplicable(lastParmType, argType, allowUncheckedConversion, i)) {
          return ApplicabilityLevel.NOT_APPLICABLE;
        }
      }
      return ApplicabilityLevel.VARARGS;
    }

    return ApplicabilityLevel.NOT_APPLICABLE;
  }
@MethodCandidateInfo.ApplicabilityLevelConstant
  public static int getApplicabilityLevel(@NotNull PsiMethod method,
                                          @NotNull PsiSubstitutor substitutorForMethod,
                                          PsiType @NotNull [] args,
                                          @NotNull LanguageLevel languageLevel,
                                          boolean allowUncheckedConversion,
                                          boolean checkVarargs,
                                          @NotNull ApplicabilityChecker function)