public static @Nullable PsiType getSubstitutedType(@NotNull PsiParameter parameter) {
    PsiType type = getType(parameter);

    if (type instanceof PsiArrayType) {
      return type;
    }

    PsiClassType.ClassResolveResult result = PsiUtil.resolveGenericsClassInType(type);
    PsiClass psiClass = result.getElement();
    if (psiClass == null) {
      return type;
    }

    Set<PsiTypeParameter> usedTypeParameters = new HashSet<>();
    CommonJavaRefactoringUtil.collectTypeParameters(usedTypeParameters, parameter);
    usedTypeParameters.removeIf(usedTypeParameter -> parameter.getDeclarationScope() != usedTypeParameter.getOwner());

    PsiSubstitutor subst = PsiSubstitutor.EMPTY;
    for (PsiTypeParameter usedTypeParameter : usedTypeParameters) {
      PsiType bound = TypeConversionUtil.typeParameterErasure(usedTypeParameter);
      PsiManager manager = usedTypeParameter.getManager();
      subst = subst.put(usedTypeParameter, bound == null ? PsiWildcardType.createUnbounded(manager) : bound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) ? bound : PsiWildcardType.createExtends(manager, bound));
    }

    PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
    Map<PsiTypeParameter, PsiType> typeMap = result.getSubstitutor().getSubstitutionMap();
    for (PsiTypeParameter typeParameter : typeMap.keySet()) {
      PsiType psiType = typeMap.get(typeParameter);
      substitutor = substitutor.put(typeParameter, psiType != null ? subst.substitute(psiType) : null);
    }

    if (psiClass instanceof PsiTypeParameter) {
      return GenericsUtil.getVariableTypeByExpressionType(subst.substitute((PsiTypeParameter)psiClass));
    }
    return JavaPsiFacade.getElementFactory(parameter.getProject()).createType(psiClass, substitutor);
  }
public static @Nullable PsiType getSubstitutedType(@NotNull PsiParameter parameter)