@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());
    }
Esempio n. 2
0
 public TypeParamsChecker(PsiElement expression, PsiClass aClass) {
   myClass = aClass;
   PsiElement parent = expression != null ? expression.getParent() : null;
   while (parent instanceof PsiParenthesizedExpression) {
     parent = parent.getParent();
   }
   if (parent instanceof PsiExpressionList) {
     final PsiElement gParent = parent.getParent();
     if (gParent instanceof PsiCall) {
       final Pair<PsiMethod, PsiSubstitutor> pair = MethodCandidateInfo.getCurrentMethod(parent);
       myMethod = pair != null ? pair.first : null;
       if (myMethod == null) {
         myMethod = ((PsiCall) gParent).resolveMethod();
       }
       if (myMethod != null && PsiTreeUtil.isAncestor(myMethod, expression, false)) {
         myMethod = null;
       }
     }
   }
 }
  static PsiSubstitutor infer(
      @NotNull PsiTypeParameter[] typeParameters,
      @NotNull PsiParameter[] parameters,
      @NotNull PsiExpression[] arguments,
      @NotNull PsiSubstitutor partialSubstitutor,
      @NotNull final PsiElement parent,
      @NotNull final ParameterTypeInferencePolicy policy) {
    if (parent instanceof PsiCall) {
      final PsiExpressionList argumentList = ((PsiCall) parent).getArgumentList();
      final MethodCandidateInfo.CurrentCandidateProperties properties =
          MethodCandidateInfo.getCurrentMethod(argumentList);
      // overload resolution can't depend on outer call => should not traverse to top
      if (properties != null
          && !properties.isApplicabilityCheck()
          &&
          // in order to to avoid caching of candidates's errors on parent (!) , so check for
          // overload resolution is left here
          // But overload resolution can depend on type of lambda parameter. As it can't depend on
          // lambda body,
          // traversing down would stop at lambda level and won't take into account overloaded
          // method
          !MethodCandidateInfo.ourOverloadGuard.currentStack().contains(argumentList)) {
        final PsiCall topLevelCall =
            PsiResolveHelper.ourGraphGuard.doPreventingRecursion(
                parent,
                false,
                new Computable<PsiCall>() {
                  @Override
                  public PsiCall compute() {
                    if (parent instanceof PsiExpression
                        && !PsiPolyExpressionUtil.isPolyExpression((PsiExpression) parent)) {
                      return null;
                    }
                    return LambdaUtil.treeWalkUp(parent);
                  }
                });
        if (topLevelCall != null) {

          InferenceSession session;
          if (MethodCandidateInfo.isOverloadCheck()
              || !PsiDiamondType.ourDiamondGuard.currentStack().isEmpty()
              || LambdaUtil.isLambdaParameterCheck()) {
            session = startTopLevelInference(topLevelCall, policy);
          } else {
            session =
                CachedValuesManager.getCachedValue(
                    topLevelCall,
                    new CachedValueProvider<InferenceSession>() {
                      @Nullable
                      @Override
                      public Result<InferenceSession> compute() {
                        return new Result<InferenceSession>(
                            startTopLevelInference(topLevelCall, policy),
                            PsiModificationTracker.MODIFICATION_COUNT);
                      }
                    });

            if (session != null) {
              // reject cached top level session if it was based on wrong candidate: check nested
              // session if candidate (it's type parameters) are the same
              // such situations are avoided when overload resolution is performed
              // (MethodCandidateInfo.isOverloadCheck above)
              // but situations when client code iterates through
              // PsiResolveHelper.getReferencedMethodCandidates or similar are impossible to guess
              final Map<PsiElement, InferenceSession> sessions =
                  session.getInferenceSessionContainer().myNestedSessions;
              final InferenceSession childSession = sessions.get(parent);
              if (childSession != null) {
                for (PsiTypeParameter parameter : typeParameters) {
                  if (!childSession
                      .getInferenceSubstitution()
                      .getSubstitutionMap()
                      .containsKey(parameter)) {
                    session = startTopLevelInference(topLevelCall, policy);
                    break;
                  }
                }
              }
            }
          }

          if (session != null) {
            final PsiSubstitutor childSubstitutor =
                inferNested(
                    typeParameters,
                    parameters,
                    arguments,
                    partialSubstitutor,
                    (PsiCall) parent,
                    policy,
                    properties,
                    session);
            if (childSubstitutor != null) return childSubstitutor;
          } else if (topLevelCall instanceof PsiMethodCallExpression) {
            return new InferenceSession(
                    typeParameters, partialSubstitutor, parent.getManager(), parent, policy)
                .prepareSubstitution();
          }
        }
      }
    }

    final InferenceSession inferenceSession =
        new InferenceSession(
            typeParameters, partialSubstitutor, parent.getManager(), parent, policy);
    inferenceSession.initExpressionConstraints(parameters, arguments, parent);
    return inferenceSession.infer(parameters, arguments, parent);
  }
Esempio n. 4
0
  @Nullable
  public static PsiType getFunctionalInterfaceType(
      PsiElement expression, final boolean tryToSubstitute, int paramIdx) {
    PsiElement parent = expression.getParent();
    PsiElement element = expression;
    while (parent instanceof PsiParenthesizedExpression
        || parent instanceof PsiConditionalExpression) {
      if (parent instanceof PsiConditionalExpression
          && ((PsiConditionalExpression) parent).getThenExpression() != element
          && ((PsiConditionalExpression) parent).getElseExpression() != element) break;
      element = parent;
      parent = parent.getParent();
    }
    if (parent instanceof PsiArrayInitializerExpression) {
      final PsiType psiType = ((PsiArrayInitializerExpression) parent).getType();
      if (psiType instanceof PsiArrayType) {
        return ((PsiArrayType) psiType).getComponentType();
      }
    } else if (parent instanceof PsiTypeCastExpression) {
      final PsiType castType = ((PsiTypeCastExpression) parent).getType();
      if (castType instanceof PsiIntersectionType) {
        for (PsiType conjunctType : ((PsiIntersectionType) castType).getConjuncts()) {
          if (getFunctionalInterfaceMethod(conjunctType) != null) return conjunctType;
        }
      }
      return castType;
    } else if (parent instanceof PsiVariable) {
      return ((PsiVariable) parent).getType();
    } else if (parent instanceof PsiAssignmentExpression
        && expression instanceof PsiExpression
        && !PsiUtil.isOnAssignmentLeftHand((PsiExpression) expression)) {
      final PsiExpression lExpression = ((PsiAssignmentExpression) parent).getLExpression();
      return lExpression.getType();
    } else if (parent instanceof PsiExpressionList) {
      final PsiExpressionList expressionList = (PsiExpressionList) parent;
      final int lambdaIdx = getLambdaIdx(expressionList, expression);
      if (lambdaIdx > -1) {

        PsiType cachedType = null;
        final Pair<PsiMethod, PsiSubstitutor> method = MethodCandidateInfo.getCurrentMethod(parent);
        if (method != null) {
          final PsiParameter[] parameters = method.first.getParameterList().getParameters();
          cachedType =
              lambdaIdx < parameters.length
                  ? method.second.substitute(
                      getNormalizedType(
                          parameters[adjustLambdaIdx(lambdaIdx, method.first, parameters)]))
                  : null;
          if (!tryToSubstitute) return cachedType;
        }

        PsiElement gParent = expressionList.getParent();

        if (gParent instanceof PsiAnonymousClass) {
          gParent = gParent.getParent();
        }

        if (gParent instanceof PsiCall) {
          final PsiCall contextCall = (PsiCall) gParent;
          final JavaResolveResult resolveResult = contextCall.resolveMethodGenerics();
          final PsiElement resolve = resolveResult.getElement();
          if (resolve instanceof PsiMethod) {
            final PsiParameter[] parameters =
                ((PsiMethod) resolve).getParameterList().getParameters();
            final int finalLambdaIdx = adjustLambdaIdx(lambdaIdx, (PsiMethod) resolve, parameters);
            if (finalLambdaIdx < parameters.length) {
              if (!tryToSubstitute) return getNormalizedType(parameters[finalLambdaIdx]);
              if (cachedType != null && paramIdx > -1) {
                final PsiMethod interfaceMethod = getFunctionalInterfaceMethod(cachedType);
                if (interfaceMethod != null) {
                  final PsiClassType.ClassResolveResult cachedResult =
                      PsiUtil.resolveGenericsClassInType(cachedType);
                  final PsiType interfaceMethodParameterType =
                      interfaceMethod.getParameterList().getParameters()[paramIdx].getType();
                  if (!dependsOnTypeParams(
                      cachedResult.getSubstitutor().substitute(interfaceMethodParameterType),
                      cachedType,
                      expression)) {
                    return cachedType;
                  }
                }
              }
              return PsiResolveHelper.ourGuard.doPreventingRecursion(
                  expression,
                  true,
                  new Computable<PsiType>() {
                    @Override
                    public PsiType compute() {
                      return resolveResult
                          .getSubstitutor()
                          .substitute(getNormalizedType(parameters[finalLambdaIdx]));
                    }
                  });
            }
          }
          return null;
        }
      }
    } else if (parent instanceof PsiReturnStatement) {
      final PsiLambdaExpression gParent =
          PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class);
      if (gParent != null) {
        return getFunctionalInterfaceTypeByContainingLambda(gParent);
      } else {
        final PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class);
        if (method != null) {
          return method.getReturnType();
        }
      }
    } else if (parent instanceof PsiLambdaExpression) {
      return getFunctionalInterfaceTypeByContainingLambda((PsiLambdaExpression) parent);
    }
    return null;
  }