public static PsiType[] getErasedParameterTypes(MethodSignature signature) { PsiType[] parameterTypes = signature.getParameterTypes(); if (parameterTypes.length == 0) return PsiType.EMPTY_ARRAY; PsiSubstitutor substitutor = signature.getSubstitutor(); PsiType[] erasedTypes = new PsiType[parameterTypes.length]; for (int i = 0; i < parameterTypes.length; i++) { erasedTypes[i] = TypeConversionUtil.erasure(substitutor.substitute(parameterTypes[i]), substitutor); } return erasedTypes; }
@Override public int computeHashCode(final MethodSignature signature) { int result = signature.isConstructor() ? 0 : signature.getName().hashCode(); PsiType[] parameterTypes = signature.getParameterTypes(); result += 37 * parameterTypes.length; PsiType firstParamType = parameterTypes.length == 0 ? null : parameterTypes[0]; if (firstParamType != null) { firstParamType = TypeConversionUtil.erasure(firstParamType, signature.getSubstitutor()); assert firstParamType != null : parameterTypes[0]; result = 31 * result + firstParamType.hashCode(); } return result; }
public static boolean isSubsignature( @NotNull MethodSignature superSignature, @NotNull MethodSignature subSignature) { if (subSignature == superSignature) return true; if (!areSignaturesEqualLightweight(superSignature, subSignature)) return false; PsiSubstitutor unifyingSubstitutor = getSuperMethodSignatureSubstitutor(subSignature, superSignature); if (checkSignaturesEqualInner(superSignature, subSignature, unifyingSubstitutor)) return true; if (subSignature.getTypeParameters().length > 0) return false; final PsiType[] subParameterTypes = subSignature.getParameterTypes(); final PsiType[] superParameterTypes = superSignature.getParameterTypes(); for (int i = 0; i < subParameterTypes.length; i++) { PsiType type1 = subParameterTypes[i]; PsiType type2 = TypeConversionUtil.erasure(superParameterTypes[i], superSignature.getSubstitutor()); if (!Comparing.equal(type1, type2)) return false; } return true; }
@Nullable private static PsiSubstitutor getSuperMethodSignatureSubstitutorImpl( @NotNull MethodSignature methodSignature, @NotNull MethodSignature superSignature) { // normalize generic method declarations: correlate type parameters // todo: correlate type params by name? PsiTypeParameter[] methodTypeParameters = methodSignature.getTypeParameters(); PsiTypeParameter[] superTypeParameters = superSignature.getTypeParameters(); // both methods are parameterized and number of parameters mismatch if (methodTypeParameters.length != superTypeParameters.length) return null; PsiSubstitutor result = superSignature.getSubstitutor(); for (int i = 0; i < methodTypeParameters.length; i++) { PsiTypeParameter methodTypeParameter = methodTypeParameters[i]; PsiElementFactory factory = JavaPsiFacade.getInstance(methodTypeParameter.getProject()).getElementFactory(); result = result.put(superTypeParameters[i], factory.createType(methodTypeParameter)); } return result; }
/** * @param methodSignature method signature * @param superMethodSignature super method signature * @return null if signatures do not match */ @Nullable public static PsiSubstitutor getSuperMethodSignatureSubstitutor( @NotNull MethodSignature methodSignature, @NotNull MethodSignature superMethodSignature) { PsiSubstitutor result = getSuperMethodSignatureSubstitutorImpl(methodSignature, superMethodSignature); if (result == null) return null; PsiTypeParameter[] methodTypeParameters = methodSignature.getTypeParameters(); PsiTypeParameter[] superTypeParameters = superMethodSignature.getTypeParameters(); PsiSubstitutor methodSubstitutor = methodSignature.getSubstitutor(); // check bounds for (int i = 0; i < methodTypeParameters.length; i++) { PsiTypeParameter methodTypeParameter = methodTypeParameters[i]; PsiTypeParameter superTypeParameter = superTypeParameters[i]; final Set<PsiType> methodSupers = new HashSet<PsiType>(); for (PsiClassType methodSuper : methodTypeParameter.getSuperTypes()) { methodSupers.add(methodSubstitutor.substitute(methodSuper)); } final Set<PsiType> superSupers = new HashSet<PsiType>(); for (PsiClassType superSuper : superTypeParameter.getSuperTypes()) { superSupers.add( methodSubstitutor.substitute( PsiUtil.captureToplevelWildcards( result.substitute(superSuper), methodTypeParameter))); } methodSupers.remove( PsiType.getJavaLangObject( methodTypeParameter.getManager(), methodTypeParameter.getResolveScope())); superSupers.remove( PsiType.getJavaLangObject( superTypeParameter.getManager(), superTypeParameter.getResolveScope())); if (!methodSupers.equals(superSupers)) return null; } return result; }
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; }