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/03/25 17:46:12 UTC

[groovy] branch GROOVY_2_5_X updated: 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_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
     new ec1cdcd  GROOVY-9906: check index before comparing parameters
ec1cdcd is described below

commit ec1cdcd922b85587bdcfe1258a30d0c1251f4e6a
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Jan 25 11:52:16 2021 -0600

    GROOVY-9906: check index before comparing parameters
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/ast/ClassNode.java
---
 .../java/org/codehaus/groovy/ast/ClassNode.java    | 42 +++++++++++-----------
 src/test/groovy/bugs/Groovy9906.groovy             | 42 ++++++++++++++++++++++
 2 files changed, 63 insertions(+), 21 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/ClassNode.java b/src/main/java/org/codehaus/groovy/ast/ClassNode.java
index 4369c45..3935634 100644
--- a/src/main/java/org/codehaus/groovy/ast/ClassNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/ClassNode.java
@@ -1268,14 +1268,14 @@ public class ClassNode extends AnnotatedNode implements Opcodes {
 
         // 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;
@@ -1283,18 +1283,18 @@ public class ClassNode extends AnnotatedNode implements Opcodes {
                     }
 
                     if (match) {
-                        if (res == null) {
-                            res = mn;
+                        if (method == null) {
+                            method = mn;
                         } else {
-                            if (res.getParameters().length != count)
+                            if (method.getParameters().length != nArgs)
                                 return null;
                             if (cn.equals(this))
                                 return null;
 
                             match = true;
-                            for (int i = 0; i != count; ++i)
+                            for (int i = 0; i != nArgs; ++i)
                                 // prefer super method if it matches better
-                                if (!hasExactMatchingCompatibleType(res, mn, i)) {
+                                if (!hasExactMatchingCompatibleType(method, mn, i)) {
                                     match = false;
                                     break;
                                 }
@@ -1306,28 +1306,28 @@ public class ClassNode extends AnnotatedNode implements Opcodes {
             }
         }
 
-        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();
     }
 
     /**
@@ -1337,7 +1337,7 @@ public class ClassNode extends AnnotatedNode implements Opcodes {
      * @param arguments the arguments to match against
      * @return 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()
+        '''
+    }
+}