@NotNull private static PsiType getLeastUpperBound( PsiType type1, PsiType type2, Set<Pair<PsiType, 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())); }
@NotNull private static PsiClassType getAnnotationSuperType( @NotNull PsiClass psiClass, @NotNull PsiElementFactory factory) { return factory.createTypeByFQClassName( "java.lang.annotation.Annotation", psiClass.getResolveScope()); }