Search in sources :

Example 1 with EvalExceptionWithJavaCause

use of com.google.devtools.build.lib.syntax.EvalException.EvalExceptionWithJavaCause in project bazel by bazelbuild.

the class FuncallExpression method invokeObjectMethod.

/**
   * Call a method depending on the type of an object it is called on.
   *
   * <p>Public for reflection by the compiler and access from generated byte code.
   *
   * @param positionals The first object is expected to be the object the method is called on.
   * @param call the original expression that caused this call, needed for rules especially
   */
public Object invokeObjectMethod(String method, ImmutableList<Object> positionals, ImmutableMap<String, Object> keyWordArgs, FuncallExpression call, Environment env) throws EvalException, InterruptedException {
    Location location = call.getLocation();
    Object value = positionals.get(0);
    ImmutableList<Object> positionalArgs = positionals.subList(1, positionals.size());
    BaseFunction function = Runtime.getFunction(EvalUtils.getSkylarkType(value.getClass()), method);
    if (function != null) {
        if (!isNamespace(value.getClass())) {
            // Use self as an implicit parameter in front.
            positionalArgs = positionals;
        }
        return function.call(positionalArgs, ImmutableMap.<String, Object>copyOf(keyWordArgs), call, env);
    } else if (value instanceof ClassObject) {
        Object fieldValue = ((ClassObject) value).getValue(method);
        if (fieldValue == null) {
            throw new EvalException(location, String.format("struct has no method '%s'", method));
        }
        if (!(fieldValue instanceof BaseFunction)) {
            throw new EvalException(location, String.format("struct field '%s' is not a function", method));
        }
        function = (BaseFunction) fieldValue;
        return function.call(positionalArgs, ImmutableMap.<String, Object>copyOf(keyWordArgs), call, env);
    } else {
        // When calling a Java method, the name is not in the Environment,
        // so evaluating 'func' would fail.
        Class<?> objClass;
        Object obj;
        if (value instanceof Class<?>) {
            // Static call
            obj = null;
            objClass = (Class<?>) value;
        } else {
            obj = value;
            objClass = value.getClass();
        }
        Pair<MethodDescriptor, List<Object>> javaMethod = call.findJavaMethod(objClass, method, positionalArgs, keyWordArgs);
        if (javaMethod.first.getAnnotation().structField()) {
            // Not a method but a callable attribute
            try {
                return callFunction(javaMethod.first.getMethod().invoke(obj), env);
            } catch (IllegalAccessException e) {
                throw new EvalException(getLocation(), "method invocation failed: " + e);
            } catch (InvocationTargetException e) {
                if (e.getCause() instanceof FuncallException) {
                    throw new EvalException(getLocation(), e.getCause().getMessage());
                } else if (e.getCause() != null) {
                    throw new EvalExceptionWithJavaCause(getLocation(), e.getCause());
                } else {
                    // This is unlikely to happen
                    throw new EvalException(getLocation(), "method invocation failed: " + e);
                }
            }
        }
        return callMethod(javaMethod.first, method, obj, javaMethod.second.toArray(), location, env);
    }
}
Also used : EvalExceptionWithJavaCause(com.google.devtools.build.lib.syntax.EvalException.EvalExceptionWithJavaCause) InvocationTargetException(java.lang.reflect.InvocationTargetException) Location(com.google.devtools.build.lib.events.Location) Pair(com.google.devtools.build.lib.util.Pair)

Example 2 with EvalExceptionWithJavaCause

use of com.google.devtools.build.lib.syntax.EvalException.EvalExceptionWithJavaCause in project bazel by bazelbuild.

the class FuncallExpression method callMethod.

static Object callMethod(MethodDescriptor methodDescriptor, String methodName, Object obj, Object[] args, Location loc, Environment env) throws EvalException {
    try {
        Method method = methodDescriptor.getMethod();
        if (obj == null && !Modifier.isStatic(method.getModifiers())) {
            throw new EvalException(loc, "method '" + methodName + "' is not static");
        }
        // This happens when the interface is public but the implementation classes
        // have reduced visibility.
        method.setAccessible(true);
        Object result = method.invoke(obj, args);
        if (method.getReturnType().equals(Void.TYPE)) {
            return Runtime.NONE;
        }
        if (result == null) {
            if (methodDescriptor.getAnnotation().allowReturnNones()) {
                return Runtime.NONE;
            } else {
                throw new EvalException(loc, "method invocation returned None, please file a bug report: " + methodName + Printer.listString(ImmutableList.copyOf(args), "(", ", ", ")", null));
            }
        }
        // TODO(bazel-team): get rid of this, by having everyone use the Skylark data structures
        result = SkylarkType.convertToSkylark(result, method, env);
        if (result != null && !EvalUtils.isSkylarkAcceptable(result.getClass())) {
            throw new EvalException(loc, Printer.format("method '%s' returns an object of invalid type %r", methodName, result.getClass()));
        }
        return result;
    } catch (IllegalAccessException e) {
        // and an argument is missing or has the wrong type.
        throw new EvalException(loc, "Method invocation failed: " + e);
    } catch (InvocationTargetException e) {
        if (e.getCause() instanceof FuncallException) {
            throw new EvalException(loc, e.getCause().getMessage());
        } else if (e.getCause() != null) {
            throw new EvalExceptionWithJavaCause(loc, e.getCause());
        } else {
            // This is unlikely to happen
            throw new EvalException(loc, "method invocation failed: " + e);
        }
    }
}
Also used : EvalExceptionWithJavaCause(com.google.devtools.build.lib.syntax.EvalException.EvalExceptionWithJavaCause) Method(java.lang.reflect.Method) InvocationTargetException(java.lang.reflect.InvocationTargetException)

Aggregations

EvalExceptionWithJavaCause (com.google.devtools.build.lib.syntax.EvalException.EvalExceptionWithJavaCause)2 InvocationTargetException (java.lang.reflect.InvocationTargetException)2 Location (com.google.devtools.build.lib.events.Location)1 Pair (com.google.devtools.build.lib.util.Pair)1 Method (java.lang.reflect.Method)1