This is an automated email from the ASF dual-hosted git repository. paulk pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 75b71337571bcf3517aec7b3a89b3603fac1d329 Author: Esko Toivonen <[email protected]> AuthorDate: Tue Mar 30 11:12:26 2021 +0300 GROOVY-9649: Rework range creation to also allow left- and full-open ranges This commit also adds a new parameter to MethodCaller which is used in AsmClassGenerator to access the createRange method. This new parameter is needed because the three-parameter version has to be left in for backwards compatibility, and without the additional parameter in MethodCaller the wrong method would be found. --- .../groovy/classgen/AsmClassGenerator.java | 9 ++++--- .../codehaus/groovy/classgen/asm/MethodCaller.java | 29 ++++++++++++++++++---- .../org/codehaus/groovy/runtime/InvokerHelper.java | 9 +++++-- .../groovy/runtime/ScriptBytecodeAdapter.java | 8 +++++- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java index bfbd856..be5047d 100644 --- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java +++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java @@ -216,7 +216,9 @@ public class AsmClassGenerator extends ClassGenerator { // type conversions private static final MethodCaller createMapMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createMap"); private static final MethodCaller createListMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createList"); - private static final MethodCaller createRangeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createRange"); + // The 3-parameter version of createRange is kept in for backwards compatibility, so we need to specify the + // parameter count here + private static final MethodCaller createRangeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createRange", 4); private static final MethodCaller createPojoWrapperMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createPojoWrapper"); private static final MethodCaller createGroovyObjectWrapperMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createGroovyObjectWrapper"); @@ -1526,10 +1528,11 @@ public class AsmClassGenerator extends ClassGenerator { operandStack.box(); expression.getTo().visit(this); operandStack.box(); - operandStack.pushBool(expression.isInclusive()); + operandStack.pushBool(expression.isExclusiveLeft()); + operandStack.pushBool(expression.isExclusiveRight()); createRangeMethod.call(controller.getMethodVisitor()); - operandStack.replace(ClassHelper.RANGE_TYPE, 3); + operandStack.replace(ClassHelper.RANGE_TYPE, 4); } @Override diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java b/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java index 91a5988..faf3390 100644 --- a/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java +++ b/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java @@ -38,11 +38,17 @@ public class MethodCaller { private String name; private Class theClass; private String methodDescriptor; + private int parameterCount; + private static final int ANY_PARAMETER_COUNT = -1; public static MethodCaller newStatic(Class theClass, String name) { return new MethodCaller(INVOKESTATIC, theClass, name); } + public static MethodCaller newStatic(Class theClass, String name, int parameterCount) { + return new MethodCaller(INVOKESTATIC, theClass, name, parameterCount); + } + public static MethodCaller newInterface(Class theClass, String name) { return new MethodCaller(INVOKEINTERFACE, theClass, name); } @@ -57,11 +63,15 @@ public class MethodCaller { protected MethodCaller() {} public MethodCaller(int opcode, Class theClass, String name) { + this(opcode, theClass, name, ANY_PARAMETER_COUNT); + } + + public MethodCaller(int opcode, Class theClass, String name, int parameterCount) { this.opcode = opcode; this.internalName = Type.getInternalName(theClass); this.theClass = theClass; this.name = name; - + this.parameterCount = parameterCount; } public void call(MethodVisitor methodVisitor) { @@ -78,11 +88,20 @@ public class MethodCaller { protected Method getMethod() { Method[] methods = theClass.getMethods(); - for (Method method : methods) { - if (method.getName().equals(name)) { - return method; + if (parameterCount != ANY_PARAMETER_COUNT) { + for (Method method : methods) { + if (method.getName().equals(name) && method.getParameterCount() == parameterCount) { + return method; + } + } + } else { + for (Method method : methods) { + if (method.getName().equals(name)) { + return method; + } } } - throw new ClassGeneratorException("Could not find method: " + name + " on class: " + theClass); + throw new ClassGeneratorException("Could not find method: " + name + + (parameterCount >= 0 ? " with parameter count " + parameterCount : "") + " on class: " + theClass); } } diff --git a/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java index 82a8868..6d64276 100644 --- a/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java +++ b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java @@ -933,9 +933,9 @@ public class InvokerHelper { return toArrayString(arguments, false, maxSize, safe); } - public static List createRange(Object from, Object to, boolean inclusive) { + public static List createRange(Object from, Object to, boolean exclusiveLeft, boolean exclusiveRight) { try { - return ScriptBytecodeAdapter.createRange(from, to, inclusive); + return ScriptBytecodeAdapter.createRange(from, to, exclusiveLeft, exclusiveRight); } catch (RuntimeException | Error re) { throw re; } catch (Throwable t) { @@ -943,6 +943,11 @@ public class InvokerHelper { } } + // Kept in for backwards compatibility + public static List createRange(Object from, Object to, boolean inclusive) { + return createRange(from, to, false, !inclusive); + } + public static Object bitwiseNegate(Object value) { if (value instanceof Integer) { Integer number = (Integer) value; diff --git a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java index 69cd50f..e02bc62 100644 --- a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java +++ b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java @@ -635,7 +635,8 @@ public class ScriptBytecodeAdapter { return InvokerHelper.createMap(values); } - public static List createRange(Object from, Object to, boolean inclusive) throws Throwable { + public static List createRange(Object from, Object to, boolean exclusiveLeft, boolean exclusiveRight) throws Throwable { + boolean inclusive = !exclusiveRight; if (from instanceof Integer && to instanceof Integer) { int ifrom = (Integer) from; int ito = (Integer) to; @@ -660,6 +661,11 @@ public class ScriptBytecodeAdapter { return new ObjectRange((Comparable) from, (Comparable) to); } + // Kept in for backwards compatibility + public static List createRange(Object from, Object to, boolean inclusive) throws Throwable { + return createRange(from, to, false, !inclusive); + } + @SuppressWarnings("unchecked") private static <T extends Number & Comparable> T comparableNumber(Number n) { return (T) n;
