/** Invokes a given method via {@link Method#invoke(Object, Object...)}. */
  default Object invoke(ResolvedJavaMethod method, Object receiver, Object... args) {
    try {
      JavaType[] parameterTypes = method.toParameterTypes();
      Class<?>[] parameterClasses = new Class<?>[parameterTypes.length];
      for (int i = 0; i < parameterClasses.length; ++i) {
        JavaType type = parameterTypes[i];
        if (type.getJavaKind() != JavaKind.Object) {
          parameterClasses[i] = type.getJavaKind().toJavaClass();
        } else {
          parameterClasses[i] = resolveClassForSnippet(parameterTypes[i]);
        }
      }

      Class<?> c = resolveClassForSnippet(method.getDeclaringClass());
      if (method.isConstructor()) {
        Constructor<?> javaConstructor = c.getDeclaredConstructor(parameterClasses);
        javaConstructor.setAccessible(true);
        return javaConstructor.newInstance(args);
      } else {
        Method javaMethod = c.getDeclaredMethod(method.getName(), parameterClasses);
        javaMethod.setAccessible(true);
        return javaMethod.invoke(receiver, args);
      }
    } catch (IllegalAccessException
        | InstantiationException
        | InvocationTargetException
        | ClassNotFoundException
        | NoSuchMethodException ex) {
      throw new IllegalArgumentException(ex);
    }
  }