docs: Type resolveTypeVariables(final Type type) {
          if (type instanceof Class<?>) {
              // Arrays and non-generic classes have no type variables
              return type;
  
          } else if (type instanceof ParameterizedType) {
              // Recursively resolve parameterized types
              final ParameterizedType parameterizedType = (ParameterizedType) type;
              final Type[] typeArgs = parameterizedType.getActualTypeArguments();
              Type[] typeArgsResolved = null;
              for (int i = 0; i < typeArgs.length; i++) {
                  // Recursively revolve each parameter of the type
                  final Type typeArgResolved = resolveTypeVariables(typeArgs[i]);
                  // Only compare typeArgs to typeArgResolved until the first difference is found
                  if (typeArgsResolved == null) {
                      if (!typeArgResolved.equals(typeArgs[i])) {
                          // After the first difference is found, lazily allocate typeArgsResolved 
                          typeArgsResolved = new Type[typeArgs.length];
                          // Go back and copy all the previous args
                          System.arraycopy(typeArgs, 0, typeArgsResolved, 0, i);
                          // Insert the first different arg
                          typeArgsResolved[i] = typeArgResolved;
                      }
                  } else {
                      // After the first difference is found, keep copying the resolved args into the array 
                      typeArgsResolved[i] = typeArgResolved;
                  }
              }
              if (typeArgsResolved == null) {
                  // There were no type parameters to resolve
                  return type;
              } else {
                  // Return new ParameterizedType that wraps the resolved type args
                  return new ParameterizedTypeImpl((Class<?>) parameterizedType.getRawType(), typeArgsResolved,
                          parameterizedType.getOwnerType());
              }
  
          } else if (type instanceof TypeVariable<?>) {
              // Look up concrete type for type variable
              final TypeVariable<?> typeVariable = (TypeVariable<?>) type;
              for (int i = 0; i < typeVariables.length; i++) {
                  if (typeVariables[i].getName().equals(typeVariable.getName())) {
                      return resolvedTypeArguments[i];
                  }
              }
              // Could not resolve type variable
              return type;
  
          } else if (type instanceof GenericArrayType) {
              // Count the array dimensions, and resolve the innermost type of the array
              int numArrayDims = 0;
              Type t = type;
              while (t instanceof GenericArrayType) {
                  numArrayDims++;
                  t = ((GenericArrayType) t).getGenericComponentType();
              }
              final Type innermostType = t;
              final Type innermostTypeResolved = resolveTypeVariables(innermostType);
              if (!(innermostTypeResolved instanceof Class<?>)) {
                  throw new IllegalArgumentException("Could not resolve generic array type " + type);
              }
              final Class<?> innermostTypeResolvedClass = (Class<?>) innermostTypeResolved;
  
              // Build an array to hold the size of each dimension, filled with zeroes
              final int[] dims = (int[]) Array.newInstance(int.class, numArrayDims);
  
              // Build a zero-sized array of the required number of dimensions, using the resolved innermost class 
              final Object arrayInstance = Array.newInstance(innermostTypeResolvedClass, dims);
  
              // Get the class of this array instance -- this is the resolved array type
              return arrayInstance.getClass();
  
          } else if (type instanceof WildcardType) {
              // TODO: Support WildcardType
              throw ClassGraphException.newClassGraphException("WildcardType not yet supported: " + type);
  
          } else {
              throw ClassGraphException.newClassGraphException("Got unexpected type: " + type);
          }
      }