public static boolean provablyDistinct(PsiWildcardType type1, PsiWildcardType type2) { if (type1.isSuper() && type2.isSuper()) return false; if (type1.isExtends() && type2.isExtends()) { final PsiType extendsBound1 = type1.getExtendsBound(); final PsiType extendsBound2 = type2.getExtendsBound(); if (extendsBound1 instanceof PsiArrayType && proveArrayTypeDistinct( type1.getManager().getProject(), (PsiArrayType) extendsBound1, extendsBound2) || extendsBound2 instanceof PsiArrayType && proveArrayTypeDistinct( type1.getManager().getProject(), (PsiArrayType) extendsBound2, extendsBound1)) return true; final PsiClass boundClass1 = PsiUtil.resolveClassInType(extendsBound1); final PsiClass boundClass2 = PsiUtil.resolveClassInType(extendsBound2); if (boundClass1 != null && boundClass2 != null) { return proveExtendsBoundsDistinct(type1, type2, boundClass1, boundClass2); } return provablyDistinct(extendsBound1, extendsBound2, 1); } if (type2.isExtends()) return provablyDistinct(type2, type1); if (type1.isExtends() && type2.isSuper()) { final PsiType extendsBound = type1.getExtendsBound(); final PsiType superBound = type2.getSuperBound(); if (extendsBound instanceof PsiArrayType && proveArrayTypeDistinct( type1.getManager().getProject(), (PsiArrayType) extendsBound, superBound) || superBound instanceof PsiArrayType && proveArrayTypeDistinct( type1.getManager().getProject(), (PsiArrayType) superBound, extendsBound)) return true; final PsiClass extendsBoundClass = PsiUtil.resolveClassInType(extendsBound); final PsiClass superBoundClass = PsiUtil.resolveClassInType(superBound); if (extendsBoundClass != null && superBoundClass != null) { if (extendsBoundClass instanceof PsiTypeParameter) { return try2ProveTypeParameterDistinct(type2, extendsBoundClass); } if (superBoundClass instanceof PsiTypeParameter) return false; return !InheritanceUtil.isInheritorOrSelf(superBoundClass, extendsBoundClass, true); } return true; } if (!type1.isBounded() || !type2.isBounded()) { return false; } return !type1.equals(type2); }
@Nullable private static PsiType doNormalizeWildcardByPosition( final PsiType type, final GrExpression expression, final GrExpression toplevel) { if (type instanceof PsiCapturedWildcardType) { return doNormalizeWildcardByPosition( ((PsiCapturedWildcardType) type).getWildcard(), expression, toplevel); } if (type instanceof PsiWildcardType) { final PsiWildcardType wildcardType = (PsiWildcardType) type; if (PsiUtil.isAccessedForWriting(toplevel)) { return wildcardType.isSuper() ? wildcardType.getBound() : PsiCapturedWildcardType.create(wildcardType, expression); } else { if (wildcardType.isExtends()) { return wildcardType.getBound(); } else { return PsiType.getJavaLangObject(expression.getManager(), expression.getResolveScope()); } } } else if (type instanceof PsiArrayType) { final PsiType componentType = ((PsiArrayType) type).getComponentType(); final PsiType normalizedComponentType = doNormalizeWildcardByPosition(componentType, expression, toplevel); if (normalizedComponentType != componentType) { assert normalizedComponentType != null; return normalizedComponentType.createArrayType(); } } return type; }
private static PsiType getLeastContainingTypeArgument( PsiType type1, PsiType type2, Set<Pair<PsiType, PsiType>> compared, PsiManager manager, PsiClass nestedLayer, PsiTypeParameter parameter) { Pair<PsiType, PsiType> types = new Pair<PsiType, PsiType>(type1, type2); if (compared.contains(types)) { if (nestedLayer != null) { PsiSubstitutor subst = PsiSubstitutor.EMPTY; for (PsiTypeParameter param : PsiUtil.typeParametersIterable(nestedLayer)) { subst = subst.put(param, PsiWildcardType.createUnbounded(manager)); } subst = subst.put( parameter, getLeastContainingTypeArgument(type1, type2, compared, manager, null, null)); final PsiClassType boundType = JavaPsiFacade.getInstance(manager.getProject()) .getElementFactory() .createType(nestedLayer, subst); return PsiWildcardType.createExtends(manager, boundType); } return PsiWildcardType.createUnbounded(manager); } compared.add(types); try { if (type1 instanceof PsiWildcardType) { PsiWildcardType wild1 = (PsiWildcardType) type1; final PsiType bound1 = wild1.getBound(); if (bound1 == null) return type1; if (type2 instanceof PsiWildcardType) { PsiWildcardType wild2 = (PsiWildcardType) type2; final PsiType bound2 = wild2.getBound(); if (bound2 == null) return type2; if (wild1.isExtends() == wild2.isExtends()) { return wild1.isExtends() ? PsiWildcardType.createExtends( manager, getLeastUpperBound(bound1, bound2, compared, manager)) : PsiWildcardType.createSuper(manager, getGreatestLowerBound(bound1, bound2)); } else { return bound1.equals(bound2) ? bound1 : PsiWildcardType.createUnbounded(manager); } } else { return wild1.isExtends() ? PsiWildcardType.createExtends( manager, getLeastUpperBound(bound1, type2, compared, manager)) : wild1.isSuper() ? PsiWildcardType.createSuper(manager, getGreatestLowerBound(bound1, type2)) : wild1; } } else if (type2 instanceof PsiWildcardType) { return getLeastContainingTypeArgument(type2, type1, compared, manager, null, null); } // Done with wildcards if (type1.equals(type2)) return type1; return PsiWildcardType.createExtends( manager, getLeastUpperBound(type1, type2, compared, manager)); } finally { compared.remove(types); } }