blob: 4646aea635b3390028f23b8bbed6fd8b3a13e160 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.psi;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.util.TypesDistinctProver;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author ven
*/
public class GenericsUtil {
private static final Logger LOG = Logger.getInstance("#" + GenericsUtil.class.getName());
private GenericsUtil() {}
public static PsiType getGreatestLowerBound(@Nullable PsiType type1, @Nullable PsiType type2) {
if (type1 == null || type2 == null) return null;
return PsiIntersectionType.createIntersection(type1, type2);
}
@Nullable
public static PsiType getLeastUpperBound(PsiType type1, PsiType type2, PsiManager manager) {
if (TypeConversionUtil.isPrimitiveAndNotNull(type1) || TypeConversionUtil.isPrimitiveAndNotNull(type2)) return null;
if (TypeConversionUtil.isNullType(type1)) return type2;
if (TypeConversionUtil.isNullType(type2)) return type1;
if (Comparing.equal(type1, type2)) return type1;
return getLeastUpperBound(type1, type2, new LinkedHashSet<Couple<PsiType>>(), manager);
}
@NotNull
private static PsiType getLeastUpperBound(PsiType type1, PsiType type2, Set<Couple<PsiType>> compared, PsiManager manager) {
if (type1 instanceof PsiCapturedWildcardType) {
return getLeastUpperBound(((PsiCapturedWildcardType)type1).getUpperBound(), type2, compared, manager);
}
if (type2 instanceof PsiCapturedWildcardType) {
return getLeastUpperBound(type1, ((PsiCapturedWildcardType)type2).getUpperBound(), compared, manager);
}
if (type1 instanceof PsiWildcardType) {
return getLeastUpperBound(((PsiWildcardType)type1).getExtendsBound(), type2, compared, manager);
}
if (type2 instanceof PsiWildcardType) {
return getLeastUpperBound(type1, ((PsiWildcardType)type2).getExtendsBound(), compared, manager);
}
if (type1 instanceof PsiArrayType && type2 instanceof PsiArrayType) {
final PsiType componentType1 = ((PsiArrayType)type1).getComponentType();
final PsiType componentType2 = ((PsiArrayType)type2).getComponentType();
final PsiType componentType = getLeastUpperBound(componentType1, componentType2, compared, manager);
if (componentType1 instanceof PsiPrimitiveType &&
componentType2 instanceof PsiPrimitiveType &&
componentType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
final PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
final GlobalSearchScope resolveScope = GlobalSearchScope.allScope(manager.getProject());
final PsiClassType cloneable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_CLONEABLE, resolveScope);
final PsiClassType serializable = factory.createTypeByFQClassName(CommonClassNames.JAVA_IO_SERIALIZABLE, resolveScope);
return PsiIntersectionType.createIntersection(componentType, cloneable, serializable);
}
return componentType.createArrayType();
}
if (type1 instanceof PsiIntersectionType) {
Set<PsiType> newConjuncts = new LinkedHashSet<PsiType>();
final PsiType[] conjuncts = ((PsiIntersectionType)type1).getConjuncts();
for (PsiType type : conjuncts) {
newConjuncts.add(getLeastUpperBound(type, type2, compared, manager));
}
return PsiIntersectionType.createIntersection(newConjuncts.toArray(PsiType.createArray(newConjuncts.size())));
}
if (type2 instanceof PsiIntersectionType) {
return getLeastUpperBound(type2, type1, compared, manager);
}
if (type1 instanceof PsiClassType && type2 instanceof PsiClassType) {
PsiClassType.ClassResolveResult classResolveResult1 = ((PsiClassType)type1).resolveGenerics();
PsiClassType.ClassResolveResult classResolveResult2 = ((PsiClassType)type2).resolveGenerics();
PsiClass aClass = classResolveResult1.getElement();
PsiClass bClass = classResolveResult2.getElement();
if (aClass == null || bClass == null) {
return PsiType.getJavaLangObject(manager, GlobalSearchScope.allScope(manager.getProject()));
}
PsiClass[] supers = getLeastUpperClasses(aClass, bClass);
if (supers.length == 0) {
return PsiType.getJavaLangObject(manager, aClass.getResolveScope());
}
PsiClassType[] conjuncts = new PsiClassType[supers.length];
for (int i = 0; i < supers.length; i++) {
PsiClass aSuper = supers[i];
PsiSubstitutor subst1 = TypeConversionUtil.getSuperClassSubstitutor(aSuper, aClass, classResolveResult1.getSubstitutor());
PsiSubstitutor subst2 = TypeConversionUtil.getSuperClassSubstitutor(aSuper, bClass, classResolveResult2.getSubstitutor());
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(aSuper)) {
PsiType mapping1 = subst1.substitute(parameter);
PsiType mapping2 = subst2.substitute(parameter);
if (mapping1 != null && mapping2 != null) {
substitutor = substitutor.put(parameter, getLeastContainingTypeArgument(mapping1, mapping2, compared, manager, type1.equals(mapping1) && type2.equals(mapping2) ? aSuper : null, parameter));
}
else {
substitutor = substitutor.put(parameter, null);
}
}
conjuncts[i] = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createType(aSuper, substitutor);
}
return PsiIntersectionType.createIntersection(conjuncts);
}
if (type2 instanceof PsiArrayType && !(type1 instanceof PsiArrayType)) {
return getLeastUpperBound(type2, type1, compared, manager);
}
if (type1 instanceof PsiArrayType) {
PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
GlobalSearchScope all = GlobalSearchScope.allScope(manager.getProject());
PsiClassType serializable = factory.createTypeByFQClassName(CommonClassNames.JAVA_IO_SERIALIZABLE, all);
PsiClassType cloneable = factory.createTypeByFQClassName(CommonClassNames.JAVA_LANG_CLONEABLE, all);
PsiType arraySupers = PsiIntersectionType.createIntersection(serializable, cloneable);
return getLeastUpperBound(arraySupers, type2, compared, manager);
}
return PsiType.getJavaLangObject(manager, GlobalSearchScope.allScope(manager.getProject()));
}
private static PsiType getLeastContainingTypeArgument(PsiType type1,
PsiType type2,
Set<Couple<PsiType>> compared,
PsiManager manager,
PsiClass nestedLayer,
PsiTypeParameter parameter) {
Couple<PsiType> types = Couple.of(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);
}
}
@NotNull
public static PsiClass[] getLeastUpperClasses(PsiClass aClass, PsiClass bClass) {
if (InheritanceUtil.isInheritorOrSelf(aClass, bClass, true)) return new PsiClass[]{bClass};
Set<PsiClass> supers = new LinkedHashSet<PsiClass>();
Set<PsiClass> visited = new HashSet<PsiClass>();
getLeastUpperClassesInner(aClass, bClass, supers, visited);
return supers.toArray(new PsiClass[supers.size()]);
}
private static void getLeastUpperClassesInner(PsiClass aClass, PsiClass bClass, Set<PsiClass> supers, Set<PsiClass> visited) {
if (bClass.isInheritor(aClass, true)) {
addSuper(supers, aClass);
}
else {
final PsiClass[] aSupers = aClass.getSupers();
for (PsiClass aSuper : aSupers) {
if (visited.add(aSuper)) {
getLeastUpperClassesInner(aSuper, bClass, supers, visited);
}
}
}
}
private static void addSuper(final Set<PsiClass> supers, final PsiClass classToAdd) {
for (Iterator<PsiClass> iterator = supers.iterator(); iterator.hasNext();) {
PsiClass superClass = iterator.next();
if (InheritanceUtil.isInheritorOrSelf(superClass, classToAdd, true)) return;
if (classToAdd.isInheritor(superClass, true)) iterator.remove();
}
supers.add(classToAdd);
}
public static boolean isTypeArgumentsApplicable(final PsiTypeParameter[] typeParams,
final PsiSubstitutor substitutor,
final PsiElement context) {
return isTypeArgumentsApplicable(typeParams, substitutor, context, true);
}
public static boolean isTypeArgumentsApplicable(final PsiTypeParameter[] typeParams,
final PsiSubstitutor substitutor,
final PsiElement context,
final boolean allowUncheckedConversion) {
return findTypeParameterWithBoundError(typeParams, substitutor, context, allowUncheckedConversion) == null;
}
public static Pair<PsiTypeParameter, PsiType> findTypeParameterWithBoundError(final PsiTypeParameter[] typeParams,
final PsiSubstitutor substitutor,
final PsiElement context,
final boolean allowUncheckedConversion) {
nextTypeParam:
for (PsiTypeParameter typeParameter : typeParams) {
PsiType substituted = substitutor.substitute(typeParameter);
if (substituted == null) return null;
if (context != null) {
substituted = PsiUtil.captureToplevelWildcards(substituted, context);
}
PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes();
for (PsiClassType type : extendsTypes) {
PsiType extendsType = substitutor.substitute(type);
if (substituted instanceof PsiWildcardType) {
if (((PsiWildcardType)substituted).isSuper()) {
continue;
}
final PsiType extendsBound = ((PsiWildcardType)substituted).getExtendsBound();
if (acceptExtendsBound(extendsType, extendsBound)) {
continue nextTypeParam;
}
}
else if (substituted instanceof PsiIntersectionType) {
for (PsiType extendsBound : ((PsiIntersectionType)substituted).getConjuncts()) {
if (acceptExtendsBound(extendsType, extendsBound)) continue nextTypeParam;
}
}
else if (substituted instanceof PsiCapturedWildcardType) {
final PsiType extendsBound = ((PsiCapturedWildcardType)substituted).getUpperBound();
if (acceptExtendsBound(extendsType, extendsBound)) {
continue nextTypeParam;
}
}
if (extendsType != null && !TypeConversionUtil.isAssignable(extendsType, substituted, allowUncheckedConversion)) {
return Pair.create(typeParameter, extendsType);
}
}
}
return null;
}
public static boolean acceptExtendsBound(PsiType extendsType, PsiType extendsBound) {
if (Comparing.equal(TypeConversionUtil.erasure(extendsType), TypeConversionUtil.erasure(extendsBound))) {
if (extendsBound instanceof PsiClassType) {
if (acceptExtendsBound((PsiClassType)extendsBound, 0)) return true;
}
else if (extendsBound instanceof PsiIntersectionType) {
for (PsiType psiType : ((PsiIntersectionType)extendsBound).getConjuncts()) {
if (psiType instanceof PsiClassType) {
if (acceptExtendsBound((PsiClassType)psiType, 0)) return true;
}
}
}
}
return false;
}
private static boolean acceptExtendsBound(PsiClassType extendsBound, int depth) {
PsiType[] parameters = extendsBound.getParameters();
if (parameters.length == 1) {
PsiType argType = parameters[0];
if (argType instanceof PsiCapturedWildcardType && depth == 0) {
argType = ((PsiCapturedWildcardType)argType).getWildcard();
}
if (argType instanceof PsiWildcardType) {
if (!((PsiWildcardType)argType).isBounded()) return true;
final PsiType bound = ((PsiWildcardType)argType).getExtendsBound();
if (bound instanceof PsiClassType && TypeConversionUtil.erasure(bound).equals(TypeConversionUtil.erasure(extendsBound))) {
return acceptExtendsBound((PsiClassType)bound, depth + 1);
}
if (bound instanceof PsiIntersectionType) {
for (PsiType extendsType : ((PsiIntersectionType)bound).getConjuncts()) {
if (acceptExtendsBound(extendsBound, extendsType)) {
return true;
}
}
}
}
}
return false;
}
public static boolean isFromExternalTypeLanguage(@NotNull PsiType type) {
String internalCanonicalText = type.getInternalCanonicalText();
return internalCanonicalText != null && internalCanonicalText.equals(type.getCanonicalText());
}
@Nullable
public static PsiType getVariableTypeByExpressionType(@Nullable PsiType type) {
return getVariableTypeByExpressionType(type, true);
}
@Nullable
public static PsiType getVariableTypeByExpressionType(@Nullable PsiType type, final boolean openCaptured) {
if (type == null) return null;
if (type instanceof PsiCapturedWildcardType) {
type = ((PsiCapturedWildcardType)type).getWildcard();
}
PsiType transformed = type.accept(new PsiTypeVisitor<PsiType>() {
@Override
public PsiType visitArrayType(PsiArrayType arrayType) {
PsiType componentType = arrayType.getComponentType();
PsiType type = componentType.accept(this);
if (type == componentType) return arrayType;
return type.createArrayType();
}
@Override
public PsiType visitType(PsiType type) {
return type;
}
@Override
public PsiType visitWildcardType(final PsiWildcardType wildcardType) {
final PsiType bound = wildcardType.getBound();
PsiManager manager = wildcardType.getManager();
if (bound != null) {
final PsiType acceptedBound = bound.accept(this);
if (acceptedBound instanceof PsiWildcardType) {
if (((PsiWildcardType)acceptedBound).isExtends() != wildcardType.isExtends()) return PsiWildcardType.createUnbounded(manager);
return acceptedBound;
}
if (wildcardType.isExtends() && acceptedBound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return PsiWildcardType.createUnbounded(manager);
if (acceptedBound.equals(bound)) return wildcardType;
return wildcardType.isExtends()
? PsiWildcardType.createExtends(manager, acceptedBound)
: PsiWildcardType.createSuper(manager, acceptedBound);
}
return wildcardType;
}
@Override
public PsiType visitCapturedWildcardType(PsiCapturedWildcardType capturedWildcardType) {
return openCaptured ? capturedWildcardType.getWildcard().accept(this) : capturedWildcardType;
}
@Override
public PsiType visitClassType(PsiClassType classType) {
PsiClassType.ClassResolveResult resolveResult = classType.resolveGenerics();
PsiClass aClass = resolveResult.getElement();
if (aClass == null) return classType;
boolean toExtend = false;
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(aClass)) {
PsiType typeArgument = resolveResult.getSubstitutor().substitute(typeParameter);
if (typeArgument instanceof PsiCapturedWildcardType) toExtend = true;
if (typeArgument instanceof PsiWildcardType && ((PsiWildcardType)typeArgument).getBound() instanceof PsiIntersectionType) {
toExtend = true;
}
PsiType toPut;
if (typeArgument == null) {
toPut = null;
}
else {
final PsiType accepted = typeArgument.accept(this);
if (typeArgument instanceof PsiIntersectionType) {
toPut = PsiWildcardType.createExtends(typeParameter.getManager(), accepted);
}
else {
toPut = accepted;
}
}
LOG.assertTrue(toPut == null || toPut.isValid(), toPut);
substitutor = substitutor.put(typeParameter, toPut);
}
final PsiAnnotation[] applicableAnnotations = classType.getApplicableAnnotations();
if (substitutor == PsiSubstitutor.EMPTY && !toExtend && applicableAnnotations.length == 0 && !(aClass instanceof PsiTypeParameter)) return classType;
PsiManager manager = aClass.getManager();
PsiType result = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory()
.createType(aClass, substitutor, PsiUtil.getLanguageLevel(aClass), applicableAnnotations);
if (toExtend) result = PsiWildcardType.createExtends(manager, result);
return result;
}
});
PsiType componentType = transformed != null ? transformed.getDeepComponentType() : null;
if (componentType instanceof PsiWildcardType) {
componentType = ((PsiWildcardType)componentType).getExtendsBound();
int dims = transformed.getArrayDimensions();
for (int i = 0; i < dims; i++) componentType = componentType.createArrayType();
return componentType;
}
return transformed;
}
public static PsiSubstitutor substituteByParameterName(final PsiClass psiClass, final PsiSubstitutor parentSubstitutor) {
final Map<PsiTypeParameter, PsiType> substitutionMap = parentSubstitutor.getSubstitutionMap();
final List<PsiType> result = new ArrayList<PsiType>(substitutionMap.size());
for (PsiTypeParameter typeParameter : psiClass.getTypeParameters()) {
final String name = typeParameter.getName();
final PsiTypeParameter key = ContainerUtil.find(substitutionMap.keySet(), new Condition<PsiTypeParameter>() {
@Override
public boolean value(final PsiTypeParameter psiTypeParameter) {
return name.equals(psiTypeParameter.getName());
}
});
if (key != null) {
result.add(substitutionMap.get(key));
}
}
return PsiSubstitutor.EMPTY.putAll(psiClass, result.toArray(PsiType.createArray(result.size())));
}
public static PsiType eliminateWildcards(PsiType type) {
return eliminateWildcards(type, true);
}
public static PsiType eliminateWildcards(PsiType type, final boolean eliminateInTypeArguments) {
if (eliminateInTypeArguments && type instanceof PsiClassType) {
PsiClassType classType = (PsiClassType)type;
JavaResolveResult resolveResult = classType.resolveGenerics();
PsiClass aClass = (PsiClass)resolveResult.getElement();
if (aClass != null) {
PsiManager manager = aClass.getManager();
PsiTypeParameter[] typeParams = aClass.getTypeParameters();
Map<PsiTypeParameter, PsiType> map = new HashMap<PsiTypeParameter, PsiType>();
for (PsiTypeParameter typeParam : typeParams) {
PsiType substituted = resolveResult.getSubstitutor().substitute(typeParam);
if (substituted instanceof PsiWildcardType) {
substituted = ((PsiWildcardType)substituted).getBound();
if (substituted instanceof PsiCapturedWildcardType) {
substituted = ((PsiCapturedWildcardType)substituted).getWildcard().getBound();
}
if (substituted == null) substituted = TypeConversionUtil.typeParameterErasure(typeParam);
}
map.put(typeParam, substituted);
}
PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
PsiSubstitutor substitutor = factory.createSubstitutor(map);
type = factory.createType(aClass, substitutor);
}
}
else if (type instanceof PsiArrayType) {
return eliminateWildcards(((PsiArrayType)type).getComponentType(), false).createArrayType();
}
else if (type instanceof PsiWildcardType) {
final PsiType bound = ((PsiWildcardType)type).getBound();
return eliminateWildcards(bound != null ? bound : ((PsiWildcardType)type).getExtendsBound(), false);//object
} else if (type instanceof PsiCapturedWildcardType && !eliminateInTypeArguments) {
return eliminateWildcards(((PsiCapturedWildcardType)type).getWildcard(), eliminateInTypeArguments);
}
return type;
}
public static boolean checkNotInBounds(PsiType type, PsiType bound, PsiReferenceParameterList referenceParameterList) {
//allow unchecked conversions in method calls but not in type declaration
return checkNotInBounds(type, bound, referenceParameterList.getParent() instanceof PsiReferenceExpression);
}
public static boolean checkNotInBounds(PsiType type, PsiType bound, boolean uncheckedConversionByDefault) {
if (type instanceof PsiClassType) {
return checkNotAssignable(bound, type, allowUncheckedConversions((PsiClassType)type, uncheckedConversionByDefault));
}
if (type instanceof PsiWildcardType) {
if (((PsiWildcardType)type).isExtends()) {
return checkExtendsWildcardCaptureFailure((PsiWildcardType)type, bound);
}
else if (((PsiWildcardType)type).isSuper()) {
final PsiType superBound = ((PsiWildcardType)type).getSuperBound();
if (PsiUtil.resolveClassInType(superBound) instanceof PsiTypeParameter) return TypesDistinctProver.provablyDistinct(type, bound);
return checkNotAssignable(bound, superBound, false);
}
}
else if (type instanceof PsiArrayType) {
return checkNotAssignable(bound, type, true);
}
else if (type instanceof PsiIntersectionType) {
for (PsiType psiType : ((PsiIntersectionType)type).getConjuncts()) {
if (!checkNotInBounds(psiType, bound, uncheckedConversionByDefault)) {
return false;
}
}
return true;
}
return false;
}
//JLS 5.1.10
private static boolean checkExtendsWildcardCaptureFailure(PsiWildcardType type, PsiType bound) {
LOG.assertTrue(type.isExtends());
final PsiType extendsBound = type.getExtendsBound();
PsiType boundBound = bound;
if (bound instanceof PsiWildcardType) {
if (((PsiWildcardType)bound).isBounded()) {
boundBound = ((PsiWildcardType)bound).isSuper()
? ((PsiWildcardType)bound).getSuperBound()
: ((PsiWildcardType)bound).getExtendsBound();
}
else {
return false;
}
}
final PsiClass extendsBoundClass = PsiUtil.resolveClassInClassTypeOnly(extendsBound);
final PsiClass boundBoundClass = PsiUtil.resolveClassInClassTypeOnly(boundBound);
if (boundBoundClass != null && extendsBoundClass != null && !boundBoundClass.isInterface() && !extendsBoundClass.isInterface()) {
return !InheritanceUtil.isInheritorOrSelf(boundBoundClass, extendsBoundClass, true) &&
!InheritanceUtil.isInheritorOrSelf(extendsBoundClass, boundBoundClass, true);
}
return !TypeConversionUtil.areTypesConvertible(boundBound, extendsBound) &&
!TypeConversionUtil.areTypesConvertible(extendsBound, boundBound);
}
private static boolean checkNotAssignable(final PsiType bound,
final PsiType type,
final boolean allowUncheckedConversion) {
if (bound instanceof PsiWildcardType) {
if (((PsiWildcardType)bound).isBounded()) {
final PsiType boundBound = ((PsiWildcardType)bound).isExtends()
? ((PsiWildcardType)bound).getExtendsBound()
: ((PsiWildcardType)bound).getSuperBound();
return !TypeConversionUtil.isAssignable(boundBound, type, allowUncheckedConversion);
}
else {
return true;
}
}
else {
return !TypeConversionUtil.isAssignable(bound, type, allowUncheckedConversion);
}
}
private static boolean allowUncheckedConversions(PsiClassType type, boolean uncheckedConversionByDefault) {
final PsiClass psiClass = type.resolve();
if (psiClass != null) {
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(psiClass)) {
if (parameter.getExtendsListTypes().length != 0) {
return false;
}
}
if (psiClass instanceof PsiTypeParameter && psiClass.getExtendsListTypes().length != 0) return false;
}
if (!type.isRaw()) return true;
return uncheckedConversionByDefault;
}
}