Set<PsiClass> (@NotNull List<? extends PsiMember> candidates, @NotNull Set<? extends PsiClass> qualifierType) { Set<PsiClass> possibleTypes = new HashSet<>(); for (PsiMember candidate : candidates) { if (candidate instanceof PsiClass) { possibleTypes.add((PsiClass)candidate); } else if (candidate instanceof PsiMethod && ((PsiMethod)candidate).isConstructor()) { ContainerUtil.addIfNotNull(possibleTypes, candidate.getContainingClass()); } else { //noinspection ConstantConditions PsiType type = candidate instanceof PsiField ? ((PsiField)candidate).getType() : ((PsiMethod)candidate).getReturnType(); if (type instanceof PsiPrimitiveType) continue; if (type instanceof PsiArrayType) { type = PsiType.getJavaLangObject(candidate.getManager(), candidate.getResolveScope()); } PsiClass typeClass = PsiUtil.resolveClassInClassTypeOnly(type); if (typeClass == null) return null; if (typeClass instanceof PsiTypeParameter) { PsiClass containingClass = candidate.getContainingClass(); if (containingClass == null) return null; typeClass = null; // Sometimes we have Child extends Parent<Bar> and Parent<T> { T foo(); } // In this case it's still desired to resolve that child.foo() returns Bar for (PsiClass qualifierClass : qualifierType) { PsiSubstitutor substitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(containingClass, qualifierClass, PsiSubstitutor.EMPTY); if (substitutor != null) { PsiClass substitutedTypeClass = PsiUtil.resolveClassInClassTypeOnly(substitutor.substitute(type)); if (substitutedTypeClass instanceof PsiTypeParameter || substitutedTypeClass == null || (typeClass != null && substitutedTypeClass != typeClass)) { return null; } typeClass = substitutedTypeClass; } } if (typeClass == null) { return null; } } possibleTypes.add(typeClass); } } return possibleTypes; }