PsiType (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 PsiDisjunctionType) { return getLeastUpperBound(((PsiDisjunctionType)type1).getLeastUpperBound(), type2, compared, manager); } if (type2 instanceof PsiDisjunctionType) { return getLeastUpperBound(type1, ((PsiDisjunctionType)type2).getLeastUpperBound(), 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.getElementFactory(manager.getProject()); 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<>(); 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()); } final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(manager.getProject()); PsiClassType[] conjuncts = new PsiClassType[supers.length]; Set<Couple<PsiType>> siblings = new HashSet<>(); try { 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; final Couple<PsiType> types = Couple.of(elementFactory.createType(aSuper, subst1), elementFactory.createType(aSuper, subst2)); boolean skip = compared.contains(types); for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(aSuper)) { PsiType mapping1 = subst1.substitute(parameter); PsiType mapping2 = subst2.substitute(parameter); if (mapping1 != null && mapping2 != null) { if (skip) { substitutor = substitutor.put(parameter, PsiWildcardType.createUnbounded(manager)); } else { compared.add(types); try { PsiType argument = getLeastContainingTypeArgument(mapping1, mapping2, compared, manager); substitutor = substitutor.put(parameter, argument); } finally { siblings.add(types); } } } else { substitutor = substitutor.put(parameter, null); } } conjuncts[i] = elementFactory.createType(aSuper, substitutor); } } finally { compared.removeAll(siblings); } return PsiIntersectionType.createIntersection(conjuncts); } if (type2 instanceof PsiArrayType) { return getLeastUpperBound(type2, type1, compared, manager); } if (type1 instanceof PsiArrayType) { PsiElementFactory factory = JavaPsiFacade.getElementFactory(manager.getProject()); 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())); }