private PsiType addBounds(PsiType substituted, final PsiTypeParameter typeParameter) { PsiElement captureContext = null; if (substituted instanceof PsiCapturedWildcardType) { final PsiCapturedWildcardType captured = (PsiCapturedWildcardType) substituted; substituted = captured.getWildcard(); captureContext = captured.getContext(); } if (substituted instanceof PsiWildcardType && !((PsiWildcardType) substituted).isSuper()) { PsiType originalBound = ((PsiWildcardType) substituted).getBound(); PsiManager manager = typeParameter.getManager(); final PsiType[] boundTypes = typeParameter.getExtendsListTypes(); for (PsiType boundType : boundTypes) { PsiType substitutedBoundType = boundType.accept(mySimpleSubstitutionVisitor); PsiWildcardType wildcardType = (PsiWildcardType) substituted; if (substitutedBoundType != null && !(substitutedBoundType instanceof PsiWildcardType) && !substitutedBoundType.equalsToText("java.lang.Object")) { if (originalBound == null || (!TypeConversionUtil.erasure(substitutedBoundType) .isAssignableFrom(TypeConversionUtil.erasure(originalBound)) && !TypeConversionUtil.erasure(substitutedBoundType) .isAssignableFrom( originalBound))) { // erasure is essential to avoid infinite recursion if (wildcardType.isExtends()) { final PsiType glb = GenericsUtil.getGreatestLowerBound(wildcardType.getBound(), substitutedBoundType); if (glb != null) { substituted = PsiWildcardType.createExtends(manager, glb); } } else { // unbounded substituted = PsiWildcardType.createExtends(manager, substitutedBoundType); } } } } } if (captureContext != null) { LOG.assertTrue(substituted instanceof PsiWildcardType); substituted = PsiCapturedWildcardType.create((PsiWildcardType) substituted, captureContext); } return substituted; }
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); } }