public static boolean isReceiverType( PsiType functionalInterfaceType, PsiClass containingClass, @Nullable PsiMethod referencedMethod) { final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); final MethodSignature function = LambdaUtil.getFunction(resolveResult.getElement()); if (function != null) { final int interfaceMethodParamsLength = function.getParameterTypes().length; if (interfaceMethodParamsLength > 0) { final PsiType firstParamType = resolveResult.getSubstitutor().substitute(function.getParameterTypes()[0]); boolean isReceiver = isReceiverType( firstParamType, containingClass, PsiUtil.resolveGenericsClassInType(firstParamType).getSubstitutor()); if (isReceiver) { if (referencedMethod == null) { if (interfaceMethodParamsLength == 1) return true; return false; } if (referencedMethod.getParameterList().getParametersCount() != interfaceMethodParamsLength - 1) { return false; } return true; } } } return false; }
@Nullable public static PsiType getFunctionalInterfaceReturnType( @Nullable PsiType functionalInterfaceType) { final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); final PsiClass psiClass = resolveResult.getElement(); if (psiClass != null) { final MethodSignature methodSignature = getFunction(psiClass); if (methodSignature != null) { final PsiType returnType = getReturnType(psiClass, methodSignature); return resolveResult.getSubstitutor().substitute(returnType); } } return null; }
@NotNull public static QualifierResolveResult getQualifierResolveResult( @NotNull PsiMethodReferenceExpression methodReferenceExpression) { PsiClass containingClass = null; PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; final PsiExpression expression = methodReferenceExpression.getQualifierExpression(); if (expression != null) { final PsiType expressionType = getExpandedType(expression.getType(), expression); PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(expressionType); containingClass = result.getElement(); if (containingClass != null) { substitutor = result.getSubstitutor(); } if (containingClass == null && expression instanceof PsiReferenceExpression) { final JavaResolveResult resolveResult = ((PsiReferenceExpression) expression).advancedResolve(false); final PsiElement resolve = resolveResult.getElement(); if (resolve instanceof PsiClass) { containingClass = (PsiClass) resolve; substitutor = resolveResult.getSubstitutor(); return new QualifierResolveResult(containingClass, substitutor, true); } } } else { final PsiTypeElement typeElement = methodReferenceExpression.getQualifierType(); if (typeElement != null) { PsiType type = getExpandedType(typeElement.getType(), typeElement); PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(type); containingClass = result.getElement(); if (containingClass != null) { return new QualifierResolveResult(containingClass, result.getSubstitutor(), true); } } } return new QualifierResolveResult(containingClass, substitutor, false); }
private static PsiType getLambdaParameterFromType( int parameterIndex, PsiLambdaExpression lambdaExpression, PsiType conjunct) { final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(conjunct); if (resolveResult != null) { final PsiMethod method = getFunctionalInterfaceMethod(conjunct); if (method != null) { final PsiParameter[] parameters = method.getParameterList().getParameters(); if (parameterIndex < parameters.length) { final PsiType psiType = getSubstitutor(method, resolveResult) .substitute(parameters[parameterIndex].getType()); if (!dependsOnTypeParams(psiType, conjunct, lambdaExpression)) { return GenericsUtil.eliminateWildcards(psiType); } } } } return null; }
public static boolean isReceiverType( PsiType receiverType, @Nullable PsiClass containingClass, PsiSubstitutor psiSubstitutor) { if (containingClass != null) { receiverType = getExpandedType(receiverType, containingClass); } final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(receiverType); final PsiClass receiverClass = resolveResult.getElement(); if (receiverClass != null && isReceiverType(receiverClass, containingClass)) { if (emptyOrRaw(containingClass, psiSubstitutor)) { return true; } final PsiSubstitutor derivedSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, receiverClass, psiSubstitutor); return derivedSubstitutor != null && TypeConversionUtil.isAssignable( JavaPsiFacade.getElementFactory(containingClass.getProject()) .createType(containingClass, derivedSubstitutor), receiverType); } return false; }
private static boolean hasReceiver( @NotNull PsiMethodReferenceExpression methodRef, @NotNull PsiMethod method, PsiType functionalInterfaceType) { final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType); final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult); final MethodSignature signature = interfaceMethod != null ? interfaceMethod.getSignature( LambdaUtil.getSubstitutor(interfaceMethod, resolveResult)) : null; if (signature == null) { return false; } final PsiType[] parameterTypes = signature.getParameterTypes(); final QualifierResolveResult qualifierResolveResult = getQualifierResolveResult(methodRef); return (method.getParameterList().getParametersCount() + 1 == parameterTypes.length || method.isVarArgs() && parameterTypes.length > 0 && !method.hasModifierProperty(PsiModifier.STATIC)) && hasReceiver(parameterTypes, qualifierResolveResult, methodRef); }
private static boolean provablyDistinct(PsiType type1, PsiType type2, int level) { if (type1 instanceof PsiClassType && ((PsiClassType) type1).resolve() instanceof PsiTypeParameter) return false; if (type2 instanceof PsiClassType && ((PsiClassType) type2).resolve() instanceof PsiTypeParameter) return false; if (type1 instanceof PsiWildcardType) { if (type2 instanceof PsiWildcardType) { return provablyDistinct((PsiWildcardType) type1, (PsiWildcardType) type2); } if (type2 instanceof PsiCapturedWildcardType) { return ((PsiWildcardType) type1).isExtends() && level > 0 || provablyDistinct( (PsiWildcardType) type1, ((PsiCapturedWildcardType) type2).getWildcard()); } if (type2 instanceof PsiClassType) { final PsiClass psiClass2 = PsiUtil.resolveClassInType(type2); if (psiClass2 == null) return false; if (((PsiWildcardType) type1).isExtends()) { final PsiType extendsBound = ((PsiWildcardType) type1).getExtendsBound(); if (extendsBound instanceof PsiArrayType && proveArrayTypeDistinct( ((PsiWildcardType) type1).getManager().getProject(), (PsiArrayType) extendsBound, type2)) return true; final PsiClass boundClass1 = PsiUtil.resolveClassInType(extendsBound); if (boundClass1 == null) return false; return proveExtendsBoundsDistinct(type1, type2, boundClass1, psiClass2); } if (((PsiWildcardType) type1).isSuper()) { final PsiType superBound = ((PsiWildcardType) type1).getSuperBound(); if (superBound instanceof PsiArrayType && proveArrayTypeDistinct( ((PsiWildcardType) type1).getManager().getProject(), (PsiArrayType) superBound, type2)) return true; final PsiClass boundClass1 = PsiUtil.resolveClassInType(superBound); if (boundClass1 == null || boundClass1 instanceof PsiTypeParameter) return false; return !InheritanceUtil.isInheritorOrSelf(boundClass1, psiClass2, true); } final PsiType bound = ((PsiWildcardType) type1).getBound(); return bound != null && !bound.equals(psiClass2); } if (type2 instanceof PsiArrayType) { return proveArrayTypeDistinct( ((PsiWildcardType) type1).getManager().getProject(), (PsiArrayType) type2, type1); } } if (type1 instanceof PsiCapturedWildcardType) return provablyDistinct(((PsiCapturedWildcardType) type1).getWildcard(), type2, level); if (type2 instanceof PsiWildcardType || type2 instanceof PsiCapturedWildcardType) return provablyDistinct(type2, type1, level); final PsiClassType.ClassResolveResult classResolveResult1 = PsiUtil.resolveGenericsClassInType(type1); final PsiClassType.ClassResolveResult classResolveResult2 = PsiUtil.resolveGenericsClassInType(type2); if (Comparing.equal(TypeConversionUtil.erasure(type1), TypeConversionUtil.erasure(type2))) { final PsiSubstitutor substitutor1 = classResolveResult1.getSubstitutor(); final PsiSubstitutor substitutor2 = classResolveResult2.getSubstitutor(); for (PsiTypeParameter parameter : substitutor1.getSubstitutionMap().keySet()) { final PsiType substitutedType1 = substitutor1.substitute(parameter); final PsiType substitutedType2 = substitutor2.substitute(parameter); if (substitutedType1 == null && substitutedType2 == null) return false; if (substitutedType1 == null || substitutedType2 == null) { return true; } else { if (provablyDistinct(substitutedType1, substitutedType2, level + 1)) return true; if (substitutedType1 instanceof PsiWildcardType && !((PsiWildcardType) substitutedType1).isBounded()) return true; } } return false; } final PsiClass boundClass1 = classResolveResult1.getElement(); final PsiClass boundClass2 = classResolveResult2.getElement(); return type2 != null && type1 != null && !type1.equals(type2) && (!InheritanceUtil.isInheritorOrSelf(boundClass1, boundClass2, true) || !InheritanceUtil.isInheritorOrSelf(boundClass2, boundClass1, true)); }
public TypeParamsChecker(PsiElement expression) { this( expression, PsiUtil.resolveGenericsClassInType(getFunctionalInterfaceType(expression, false)) .getElement()); }
@Nullable public static PsiMethod getFunctionalInterfaceMethod(@Nullable PsiType functionalInterfaceType) { return getFunctionalInterfaceMethod( PsiUtil.resolveGenericsClassInType(functionalInterfaceType)); }
@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; }
public static boolean isAcceptable( PsiLambdaExpression lambdaExpression, final PsiType leftType, boolean checkReturnType) { if (leftType instanceof PsiIntersectionType) { for (PsiType conjunctType : ((PsiIntersectionType) leftType).getConjuncts()) { if (isAcceptable(lambdaExpression, conjunctType, checkReturnType)) return true; } return false; } final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(GenericsUtil.eliminateWildcards(leftType)); final PsiClass psiClass = resolveResult.getElement(); if (psiClass instanceof PsiAnonymousClass) { return isAcceptable( lambdaExpression, ((PsiAnonymousClass) psiClass).getBaseClassType(), checkReturnType); } final MethodSignature methodSignature = getFunction(psiClass); if (methodSignature == null) return false; final PsiParameter[] lambdaParameters = lambdaExpression.getParameterList().getParameters(); final PsiType[] parameterTypes = methodSignature.getParameterTypes(); if (lambdaParameters.length != parameterTypes.length) return false; for (int lambdaParamIdx = 0, length = lambdaParameters.length; lambdaParamIdx < length; lambdaParamIdx++) { PsiParameter parameter = lambdaParameters[lambdaParamIdx]; final PsiTypeElement typeElement = parameter.getTypeElement(); if (typeElement != null) { final PsiType lambdaFormalType = typeElement.getType(); final PsiType methodParameterType = parameterTypes[lambdaParamIdx]; if (lambdaFormalType instanceof PsiPrimitiveType) { if (methodParameterType instanceof PsiPrimitiveType) return methodParameterType.equals(lambdaFormalType); return false; } if (!TypeConversionUtil.erasure(lambdaFormalType) .isAssignableFrom( TypeConversionUtil.erasure( GenericsUtil.eliminateWildcards( resolveResult .getSubstitutor() .substitute( methodSignature .getSubstitutor() .substitute(methodParameterType)))))) { return false; } } } if (checkReturnType) { final String uniqueVarName = JavaCodeStyleManager.getInstance(lambdaExpression.getProject()) .suggestUniqueVariableName("l", lambdaExpression, true); String canonicalText = leftType.getCanonicalText(); if (leftType instanceof PsiEllipsisType) { canonicalText = ((PsiEllipsisType) leftType).toArrayType().getCanonicalText(); } final PsiStatement assignmentFromText = JavaPsiFacade.getElementFactory(lambdaExpression.getProject()) .createStatementFromText( canonicalText + " " + uniqueVarName + " = " + lambdaExpression.getText(), lambdaExpression); final PsiLocalVariable localVariable = (PsiLocalVariable) ((PsiDeclarationStatement) assignmentFromText).getDeclaredElements()[0]; LOG.assertTrue(psiClass != null); PsiType methodReturnType = getReturnType(psiClass, methodSignature); if (methodReturnType != null) { methodReturnType = resolveResult .getSubstitutor() .substitute(methodSignature.getSubstitutor().substitute(methodReturnType)); return LambdaHighlightingUtil.checkReturnTypeCompatible( (PsiLambdaExpression) localVariable.getInitializer(), methodReturnType) == null; } } return true; }