@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;
 }
  @Nullable
  private static PsiType doNormalizeWildcardByPosition(
      final PsiType type, final GrExpression expression, final GrExpression toplevel) {
    if (type instanceof PsiCapturedWildcardType) {
      return doNormalizeWildcardByPosition(
          ((PsiCapturedWildcardType) type).getWildcard(), expression, toplevel);
    }

    if (type instanceof PsiWildcardType) {
      final PsiWildcardType wildcardType = (PsiWildcardType) type;

      if (PsiUtil.isAccessedForWriting(toplevel)) {
        return wildcardType.isSuper()
            ? wildcardType.getBound()
            : PsiCapturedWildcardType.create(wildcardType, expression);
      } else {
        if (wildcardType.isExtends()) {
          return wildcardType.getBound();
        } else {
          return PsiType.getJavaLangObject(expression.getManager(), expression.getResolveScope());
        }
      }
    } else if (type instanceof PsiArrayType) {
      final PsiType componentType = ((PsiArrayType) type).getComponentType();
      final PsiType normalizedComponentType =
          doNormalizeWildcardByPosition(componentType, expression, toplevel);
      if (normalizedComponentType != componentType) {
        assert normalizedComponentType != null;
        return normalizedComponentType.createArrayType();
      }
    }

    return type;
  }
  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;
  }
 @Override
 public PsiType visitCapturedWildcardType(PsiCapturedWildcardType capturedWildcardType) {
   return capturedWildcardType.getUpperBound().accept(this);
 }