private ExpectedTypeInfo @NotNull [] getExpectedArgumentTypesForMethodCall(CandidateInfo @NotNull [] allCandidates,
                                                                               @NotNull PsiExpressionList argumentList,
                                                                               @NotNull PsiExpression argument,
                                                                               boolean forCompletion) {
      if (allCandidates.length == 0) {
        return ExpectedTypeInfo.EMPTY_ARRAY;
      }

      if (CodeInsightSettings.getInstance().SHOW_PARAMETER_NAME_HINTS_ON_COMPLETION) {
        allCandidates = selectCandidateChosenOnCompletion(argumentList.getParent(), allCandidates);
      }

      PsiMethod toExclude = JavaPsiConstructorUtil.isConstructorCall(argumentList.getParent())
                            ? PsiTreeUtil.getParentOfType(argument, PsiMethod.class) : null;

      PsiResolveHelper helper = JavaPsiFacade.getInstance(myExpr.getProject()).getResolveHelper();
      List<CandidateInfo> methodCandidates = new ArrayList<>();
      for (CandidateInfo candidate : allCandidates) {
        PsiElement element = candidate.getElement();
        if (element instanceof PsiMethod && helper.isAccessible((PsiMember)element, argumentList, null) && element != toExclude) {
          methodCandidates.add(candidate);
        }
      }
      if (methodCandidates.isEmpty()) {
        Collections.addAll(methodCandidates, allCandidates);
      }

      final PsiExpression[] args = argumentList.getExpressions().clone();
      final int index = ArrayUtil.indexOf(args, argument);
      LOG.assertTrue(index >= 0);

      final PsiExpression[] leftArgs;
      if (index <= args.length - 1) {
        leftArgs = Arrays.copyOf(args, index);
        if (forCompletion) {
          args[index] = null;
        }
      }
      else {
        leftArgs = null;
      }

      ParameterTypeInferencePolicy policy = forCompletion ? CompletionParameterTypeInferencePolicy.INSTANCE : DefaultParameterTypeInferencePolicy.INSTANCE;

      Set<ExpectedTypeInfo> set = new LinkedHashSet<>();
      for (CandidateInfo candidateInfo : methodCandidates) {
        PsiMethod method = (PsiMethod)candidateInfo.getElement();
        PsiTypeParameter returnTypeParameter = getReturnTypeParameterNotMentionedPreviously(index, method);
        PsiSubstitutor substitutor;
        if (candidateInfo instanceof MethodCandidateInfo info) {
          substitutor = info.inferSubstitutorFromArgs(policy, args);
          if (!info.isStaticsScopeCorrect() && !method.hasModifierProperty(PsiModifier.STATIC) || info.getInferenceErrorMessage() != null) continue;
          if (forCompletion && returnTypeParameter != null) {
            PsiType substituted = substitutor.substitute(returnTypeParameter);
            if (substituted instanceof PsiClassType) {
              // Relax return type substitution
              substitutor = substitutor.put(returnTypeParameter, PsiWildcardType.createExtends(method.getManager(), substituted));
            }
          }
        }
        else {
          substitutor = candidateInfo.getSubstitutor();
        }
        if (substitutor == null) {
          return ExpectedTypeInfo.EMPTY_ARRAY;
        }
        inferMethodCallArgumentTypes(argument, forCompletion, args, index, method, substitutor, set);
        if (set.size() >= myMaxCandidates) break;

        if (leftArgs != null && candidateInfo instanceof MethodCandidateInfo) {
          substitutor = ((MethodCandidateInfo)candidateInfo).inferSubstitutorFromArgs(policy, leftArgs);
          if (substitutor != null) {
            inferMethodCallArgumentTypes(argument, forCompletion, leftArgs, index, method, substitutor, set);
            if (set.size() >= myMaxCandidates) break;
          }
        }
      }

      // try to find some variants without considering previous argument PRIMITIVE_TYPES
      if (forCompletion && set.isEmpty()) {
        for (CandidateInfo candidate : methodCandidates) {
          PsiMethod method = (PsiMethod)candidate.getElement();
          PsiSubstitutor substitutor = candidate.getSubstitutor();
          PsiParameter[] params = method.getParameterList().getParameters();
          if (params.length <= index) continue;
          PsiParameter param = params[index];
          PsiType paramType = getParameterType(param, substitutor);
          if (method.hasTypeParameters() && PsiTypesUtil.mentionsTypeParameters(paramType, ContainerUtil.newHashSet(method.getTypeParameters()))) {
            continue;
          }
          TailType tailType = getMethodArgumentTailType(argument, index, method, substitutor, params);
          ExpectedTypeInfoImpl info = createInfoImpl(paramType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, paramType,
                                                     tailType, method, getPropertyName(param));
          set.add(info);
          if (set.size() >= myMaxCandidates) break;
        }
      }

      return set.toArray(ExpectedTypeInfo.EMPTY_ARRAY);
    }
private ExpectedTypeInfo @NotNull [] getExpectedArgumentTypesForMethodCall(CandidateInfo @NotNull [] allCandidates,
                                                                               @NotNull PsiExpressionList argumentList,
                                                                               @NotNull PsiExpression argument,
                                                                               boolean forCompletion)