PsiType (PsiElement parent, PsiMethodCallExpression methodCall, final PsiTypeParameter typeParameter, PsiSubstitutor substitutor, ReductionSystem system) { PsiType type = null; if (parent instanceof PsiVariable && methodCall.equals(((PsiVariable)parent).getInitializer())) { type = getType(parent); } else if (parent instanceof PsiAssignmentExpression && methodCall.equals(((PsiAssignmentExpression)parent).getRExpression())) { type = evaluateType(((PsiAssignmentExpression)parent).getLExpression(), system); } else if (parent instanceof PsiTypeCastExpression && methodCall.equals(((PsiTypeCastExpression)parent).getOperand())) { type = evaluateType((PsiExpression)parent, system); } else if (parent instanceof PsiReturnStatement) { PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class); if (method != null) { type = getType(method); } } if (type == null) { type = PsiType.getJavaLangObject(methodCall.getManager(), methodCall.getResolveScope()); } PsiType returnType = ((PsiMethod)typeParameter.getOwner()).getReturnType(); PsiType guess = JavaPsiFacade.getInstance(parent.getProject()).getResolveHelper() .getSubstitutionForTypeParameter(typeParameter, returnType, type, false, PsiUtil.getLanguageLevel(parent)); if (PsiTypes.nullType().equals(guess)) { PsiType superType = substitutor.substitute(typeParameter.getSuperTypes()[0]); return superType == null ? PsiType.getJavaLangObject(methodCall.getManager(), methodCall.getResolveScope()) : superType; } //The following code is the result of deep thought, do not shit it out before discussing with [ven] if (returnType instanceof PsiClassType && typeParameter.equals(((PsiClassType)returnType).resolve())) { PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes(); PsiSubstitutor newSubstitutor = substitutor.put(typeParameter, guess); for (PsiClassType t : extendsTypes) { PsiType extendsType = newSubstitutor.substitute(t); if (!extendsType.isAssignableFrom(guess)) { if (guess.isAssignableFrom(extendsType)) { guess = extendsType; newSubstitutor = substitutor.put(typeParameter, guess); } else { break; } } } } return guess; }