You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2021/01/25 17:57:03 UTC
[groovy] 01/01: GROOVY-9906: check index before comparing parameters
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY-9906
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit fcd7ab1c62048530005773fdd0878c3744f05e94
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Jan 25 11:52:16 2021 -0600
GROOVY-9906: check index before comparing parameters
---
.../java/org/codehaus/groovy/ast/ClassNode.java | 55 ++++++++++------------
src/test/groovy/bugs/Groovy9906.groovy | 42 +++++++++++++++++
2 files changed, 66 insertions(+), 31 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassNode.java b/src/main/java/org/codehaus/groovy/ast/ClassNode.java
index 49d2524..75c8eaa 100644
--- a/src/main/java/org/codehaus/groovy/ast/ClassNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/ClassNode.java
@@ -1285,67 +1285,60 @@ public class ClassNode extends AnnotatedNode {
// TODO: this won't strictly be true when using list expansion in argument calls
TupleExpression args = (TupleExpression) arguments;
- int count = args.getExpressions().size();
- MethodNode res = null;
+ int nArgs = args.getExpressions().size();
+ MethodNode method = null;
for (ClassNode cn = this; cn != null; cn = cn.getSuperClass()) {
for (MethodNode mn : cn.getDeclaredMethods(name)) {
- if (hasCompatibleNumberOfArgs(mn, count)) {
+ if (hasCompatibleNumberOfArgs(mn, nArgs)) {
boolean match = true;
- for (int i = 0; i < count; i += 1) {
+ for (int i = 0; i < nArgs; i += 1) {
if (!hasCompatibleType(args, mn, i)) {
match = false;
break;
}
}
if (match) {
- if (res == null) {
- res = mn;
+ if (method == null) {
+ method = mn;
+ } else if (cn.equals(this)
+ || method.getParameters().length != nArgs) {
+ return null;
} else {
- if (res.getParameters().length != count)
- return null;
- if (cn.equals(this))
- return null;
-
- match = true;
- for (int i = 0; i < count; i += 1) {
+ for (int i = 0; i < nArgs; i += 1) {
// prefer super method if it matches better
- if (!hasExactMatchingCompatibleType(res, mn, i)) {
- match = false;
- break;
+ if (!hasExactMatchingCompatibleType(method, mn, i)) {
+ return null;
}
}
- if (!match) {
- return null;
- }
}
}
}
}
}
- return res;
+ return method;
}
- private boolean hasExactMatchingCompatibleType(MethodNode current, MethodNode newCandidate, int i) {
- int lastParamIndex = newCandidate.getParameters().length - 1;
- return current.getParameters()[i].getType().equals(newCandidate.getParameters()[i].getType())
- || (isPotentialVarArg(newCandidate, lastParamIndex) && i >= lastParamIndex && current.getParameters()[i].getType().equals(newCandidate.getParameters()[lastParamIndex].getType().componentType));
+ private static boolean hasExactMatchingCompatibleType(final MethodNode match, final MethodNode maybe, final int i) {
+ int lastParamIndex = maybe.getParameters().length - 1;
+ return (i <= lastParamIndex && match.getParameters()[i].getType().equals(maybe.getParameters()[i].getType()))
+ || (i >= lastParamIndex && isPotentialVarArg(maybe, lastParamIndex) && match.getParameters()[i].getType().equals(maybe.getParameters()[lastParamIndex].getType().getComponentType()));
}
- private boolean hasCompatibleType(TupleExpression args, MethodNode method, int i) {
+ private static boolean hasCompatibleType(final TupleExpression args, final MethodNode method, final int i) {
int lastParamIndex = method.getParameters().length - 1;
return (i <= lastParamIndex && args.getExpression(i).getType().isDerivedFrom(method.getParameters()[i].getType()))
- || (isPotentialVarArg(method, lastParamIndex) && i >= lastParamIndex && args.getExpression(i).getType().isDerivedFrom(method.getParameters()[lastParamIndex].getType().componentType));
+ || (i >= lastParamIndex && isPotentialVarArg(method, lastParamIndex) && args.getExpression(i).getType().isDerivedFrom(method.getParameters()[lastParamIndex].getType().getComponentType()));
}
- private boolean hasCompatibleNumberOfArgs(MethodNode method, int count) {
+ private static boolean hasCompatibleNumberOfArgs(final MethodNode method, final int nArgs) {
int lastParamIndex = method.getParameters().length - 1;
- return method.getParameters().length == count || (isPotentialVarArg(method, lastParamIndex) && count >= lastParamIndex);
+ return nArgs == method.getParameters().length || (nArgs >= lastParamIndex && isPotentialVarArg(method, lastParamIndex));
}
- private boolean isPotentialVarArg(MethodNode newCandidate, int lastParamIndex) {
- return lastParamIndex >= 0 && newCandidate.getParameters()[lastParamIndex].getType().isArray();
+ private static boolean isPotentialVarArg(final MethodNode method, final int lastParamIndex) {
+ return lastParamIndex >= 0 && method.getParameters()[lastParamIndex].getType().isArray();
}
/**
@@ -1356,7 +1349,7 @@ public class ClassNode extends AnnotatedNode {
* @param arguments the arguments to match against
* @return {@code true} if a matching method was found
*/
- public boolean hasPossibleStaticMethod(String name, Expression arguments) {
+ public boolean hasPossibleStaticMethod(final String name, final Expression arguments) {
return ClassNodeUtils.hasPossibleStaticMethod(this, name, arguments, false);
}
diff --git a/src/test/groovy/bugs/Groovy9906.groovy b/src/test/groovy/bugs/Groovy9906.groovy
new file mode 100644
index 0000000..12e433d
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy9906.groovy
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.bugs
+
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy9906 {
+
+ @Test
+ void testSuperClassOverloads() {
+ assertScript '''
+ abstract class A {
+ void m(String a, String b, String c) {}
+ void m(String a, String... zeroPlus) {}
+ }
+ class C extends A {
+ void test() {
+ m('x', 'y', 'z') // ArrayIndexOutOfBoundsException: Index 2 out of bounds for length 2
+ }
+ }
+ new C().test()
+ '''
+ }
+}