@Nullable
  public static Type resolveVariable(
      TypeVariable variable, final Class classType, boolean resolveInInterfacesOnly) {
    final Class aClass = getRawType(classType);
    int index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(aClass), variable);
    if (index >= 0) {
      return variable;
    }

    final Class[] classes = ReflectionCache.getInterfaces(aClass);
    final Type[] genericInterfaces = ReflectionCache.getGenericInterfaces(aClass);
    for (int i = 0; i <= classes.length; i++) {
      Class anInterface;
      if (i < classes.length) {
        anInterface = classes[i];
      } else {
        anInterface = ReflectionCache.getSuperClass(aClass);
        if (resolveInInterfacesOnly || anInterface == null) {
          continue;
        }
      }
      final Type resolved = resolveVariable(variable, anInterface);
      if (resolved instanceof Class || resolved instanceof ParameterizedType) {
        return resolved;
      }
      if (resolved instanceof TypeVariable) {
        final TypeVariable typeVariable = (TypeVariable) resolved;
        index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(anInterface), typeVariable);
        if (index < 0) {
          LOG.error(
              "Cannot resolve type variable:\n"
                  + "typeVariable = "
                  + typeVariable
                  + "\n"
                  + "genericDeclaration = "
                  + declarationToString(typeVariable.getGenericDeclaration())
                  + "\n"
                  + "searching in "
                  + declarationToString(anInterface));
        }
        final Type type =
            i < genericInterfaces.length ? genericInterfaces[i] : aClass.getGenericSuperclass();
        if (type instanceof Class) {
          return Object.class;
        }
        if (type instanceof ParameterizedType) {
          return getActualTypeArguments((ParameterizedType) type)[index];
        }
        throw new AssertionError("Invalid type: " + type);
      }
    }
    return null;
  }
  private void reportNullableArgumentsPassedToNonAnnotated(
      DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors) {
    for (PsiElement expr :
        visitor.getProblems(NullabilityProblem.passingNullableArgumentToNonAnnotatedParameter)) {
      if (reportedAnchors.contains(expr)) continue;

      final String text =
          isNullLiteralExpression(expr)
              ? "Passing <code>null</code> argument to non annotated parameter"
              : "Argument <code>#ref</code> #loc might be null but passed to non annotated parameter";
      LocalQuickFix[] fixes =
          createNPEFixes((PsiExpression) expr, (PsiExpression) expr, holder.isOnTheFly());
      final PsiElement parent = expr.getParent();
      if (parent instanceof PsiExpressionList) {
        final int idx = ArrayUtilRt.find(((PsiExpressionList) parent).getExpressions(), expr);
        if (idx > -1) {
          final PsiElement gParent = parent.getParent();
          if (gParent instanceof PsiCallExpression) {
            final PsiMethod psiMethod = ((PsiCallExpression) gParent).resolveMethod();
            if (psiMethod != null
                && psiMethod.getManager().isInProject(psiMethod)
                && AnnotationUtil.isAnnotatingApplicable(psiMethod)) {
              final PsiParameter[] parameters = psiMethod.getParameterList().getParameters();
              if (idx < parameters.length) {
                final AddNullableAnnotationFix addNullableAnnotationFix =
                    new AddNullableAnnotationFix(parameters[idx]);
                fixes =
                    fixes == null
                        ? new LocalQuickFix[] {addNullableAnnotationFix}
                        : ArrayUtil.append(fixes, addNullableAnnotationFix);
                holder.registerProblem(expr, text, fixes);
                reportedAnchors.add(expr);
              }
            }
          }
        }
      }
    }
  }
 @Nullable
 public static Class<?> substituteGenericType(final Type genericType, final Type classType) {
   if (genericType instanceof TypeVariable) {
     final Class<?> aClass = getRawType(classType);
     final Type type = resolveVariable((TypeVariable) genericType, aClass);
     if (type instanceof Class) {
       return (Class) type;
     }
     if (type instanceof ParameterizedType) {
       return (Class<?>) ((ParameterizedType) type).getRawType();
     }
     if (type instanceof TypeVariable && classType instanceof ParameterizedType) {
       final int index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(aClass), type);
       if (index >= 0) {
         return getRawType(getActualTypeArguments((ParameterizedType) classType)[index]);
       }
     }
   } else {
     return getRawType(genericType);
   }
   return null;
 }