@Nullable
 private PsiType extractContentTypeFromType(PsiType collectionType) {
   if (!(collectionType instanceof PsiClassType)) {
     return null;
   }
   final PsiClassType classType = (PsiClassType) collectionType;
   final PsiType[] parameterTypes = classType.getParameters();
   if (parameterTypes.length == 0) {
     return null;
   }
   final PsiType parameterType = parameterTypes[0];
   if (parameterType == null) {
     return null;
   }
   if (parameterType instanceof PsiWildcardType) {
     final PsiWildcardType wildcardType = (PsiWildcardType) parameterType;
     return wildcardType.getExtendsBound();
   } else if (parameterType instanceof PsiCapturedWildcardType) {
     final PsiCapturedWildcardType capturedWildcardType =
         (PsiCapturedWildcardType) parameterType;
     final PsiWildcardType wildcardType = capturedWildcardType.getWildcard();
     return wildcardType.getExtendsBound();
   }
   return parameterType;
 }
  private PsiType addBounds(PsiType substituted, final PsiTypeParameter typeParameter) {
    PsiElement captureContext = null;
    if (substituted instanceof PsiCapturedWildcardType) {
      final PsiCapturedWildcardType captured = (PsiCapturedWildcardType) substituted;
      substituted = captured.getWildcard();
      captureContext = captured.getContext();
    }
    if (substituted instanceof PsiWildcardType && !((PsiWildcardType) substituted).isSuper()) {
      PsiType originalBound = ((PsiWildcardType) substituted).getBound();
      PsiManager manager = typeParameter.getManager();
      final PsiType[] boundTypes = typeParameter.getExtendsListTypes();
      for (PsiType boundType : boundTypes) {
        PsiType substitutedBoundType = boundType.accept(mySimpleSubstitutionVisitor);
        PsiWildcardType wildcardType = (PsiWildcardType) substituted;
        if (substitutedBoundType != null
            && !(substitutedBoundType instanceof PsiWildcardType)
            && !substitutedBoundType.equalsToText("java.lang.Object")) {
          if (originalBound == null
              || (!TypeConversionUtil.erasure(substitutedBoundType)
                      .isAssignableFrom(TypeConversionUtil.erasure(originalBound))
                  && !TypeConversionUtil.erasure(substitutedBoundType)
                      .isAssignableFrom(
                          originalBound))) { // erasure is essential to avoid infinite recursion
            if (wildcardType.isExtends()) {
              final PsiType glb =
                  GenericsUtil.getGreatestLowerBound(wildcardType.getBound(), substitutedBoundType);
              if (glb != null) {
                substituted = PsiWildcardType.createExtends(manager, glb);
              }
            } else {
              // unbounded
              substituted = PsiWildcardType.createExtends(manager, substitutedBoundType);
            }
          }
        }
      }
    }

    if (captureContext != null) {
      LOG.assertTrue(substituted instanceof PsiWildcardType);
      substituted = PsiCapturedWildcardType.create((PsiWildcardType) substituted, captureContext);
    }
    return substituted;
  }