From 676905a9e828adc5cf6f43893703f93568f37dfe Mon Sep 17 00:00:00 2001 From: Francois-Rene Rideau Date: Mon, 31 Aug 2015 15:39:09 +0000 Subject: Fixes to Skylark function call Allow a call to a struct's field when it's a function. Check whether a java method exists before issuing KwArg error. -- MOS_MIGRATED_REVID=101937143 --- .../build/lib/syntax/FuncallExpression.java | 40 ++++++++++++++++------ 1 file changed, 29 insertions(+), 11 deletions(-) (limited to 'src/main/java/com') diff --git a/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java index 2e90afd3f9..73e8d10c4f 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/FuncallExpression.java @@ -355,10 +355,19 @@ public final class FuncallExpression extends Expression { // exactly and copy that behaviour. // TODO(bazel-team): check if this and SkylarkBuiltInFunctions.createObject can be merged. private Object invokeJavaMethod( - Object obj, Class objClass, String methodName, List args) throws EvalException { + Object obj, Class objClass, String methodName, List args, boolean hasKwArgs) + throws EvalException { MethodDescriptor matchingMethod = null; List methods = getMethods(objClass, methodName, args.size(), getLocation()); if (methods != null) { + if (hasKwArgs) { + throw new EvalException( + func.getLocation(), + String.format( + "Keyword arguments are not allowed when calling a java method" + + "\nwhile calling method '%s' on object of type %s", + func.getName(), EvalUtils.getDataTypeNameFromClass(objClass))); + } for (MethodDescriptor method : methods) { Class[] params = method.getMethod().getParameterTypes(); int i = 0; @@ -508,25 +517,34 @@ public final class FuncallExpression extends Expression { return convertFromSkylark( function.call(posargs.build(), ImmutableMap.copyOf(kwargs), this, env), env); + } else if (objValue instanceof ClassObject) { + Object fieldValue = ((ClassObject) objValue).getValue(func.getName()); + if (fieldValue == null) { + throw new EvalException( + getLocation(), String.format("struct has no method '%s'", func.getName())); + } + if (!(fieldValue instanceof BaseFunction)) { + throw new EvalException( + getLocation(), String.format("struct field '%s' is not a function", func.getName())); + } + function = (BaseFunction) fieldValue; + evalArguments(posargs, kwargs, env, function); + return convertFromSkylark( + function.call(posargs.build(), ImmutableMap.copyOf(kwargs), this, env), + env); } else if (env.isSkylark()) { // Only allow native Java calls when using Skylark // When calling a Java method, the name is not in the Environment, // so evaluating 'func' would fail. evalArguments(posargs, kwargs, env, null); - if (!kwargs.isEmpty()) { - throw new EvalException( - func.getLocation(), - String.format( - "Keyword arguments are not allowed when calling a java method" - + "\nwhile calling method '%s' on object %s of type %s", - func.getName(), objValue, EvalUtils.getDataTypeName(objValue))); - } if (objValue instanceof Class) { // Static Java method call. We can return the value from here directly because // invokeJavaMethod() has special checks. - return invokeJavaMethod(null, (Class) objValue, func.getName(), posargs.build()); + return invokeJavaMethod( + null, (Class) objValue, func.getName(), posargs.build(), !kwargs.isEmpty()); } else { - return invokeJavaMethod(objValue, objValue.getClass(), func.getName(), posargs.build()); + return invokeJavaMethod( + objValue, objValue.getClass(), func.getName(), posargs.build(), !kwargs.isEmpty()); } } else { throw new EvalException( -- cgit v1.2.3