This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push: new d82ae1715e GROOVY-11341: select non-bridge method from super class d82ae1715e is described below commit d82ae1715efff292e48f712d71aee8f4b9d7ab77 Author: Eric Milles <eric.mil...@thomsonreuters.com> AuthorDate: Fri Mar 22 09:45:45 2024 -0500 GROOVY-11341: select non-bridge method from super class --- .../java/org/codehaus/groovy/ast/ClassNode.java | 22 +++--- .../transform/stc/StaticTypeCheckingSupport.java | 2 +- .../groovy/transform/stc/MethodCallsSTCTest.groovy | 80 +++++++++++++++++++--- .../transform/stc/vm6/MethodCallsSTCTest.groovy | 40 ----------- .../sc/vm6/MethodCallsStaticCompilationTest.groovy | 25 ------- 5 files changed, 85 insertions(+), 84 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/ast/ClassNode.java b/src/main/java/org/codehaus/groovy/ast/ClassNode.java index 2e843e7bb6..47220eb468 100644 --- a/src/main/java/org/codehaus/groovy/ast/ClassNode.java +++ b/src/main/java/org/codehaus/groovy/ast/ClassNode.java @@ -1044,29 +1044,35 @@ public class ClassNode extends AnnotatedNode { public MethodNode getGetterMethod(String getterName, boolean searchSuperClasses) { MethodNode getterMethod = null; + + java.util.function.Predicate<MethodNode> isNullOrSynthetic = (method) -> + (method == null || (method.getModifiers() & ACC_SYNTHETIC) != 0); + boolean booleanReturnOnly = getterName.startsWith("is"); for (MethodNode method : getDeclaredMethods(getterName)) { if (method.getName().equals(getterName) && method.getParameters().length == 0 && (booleanReturnOnly ? ClassHelper.isPrimitiveBoolean(method.getReturnType()) : !method.isVoidMethod())) { - // GROOVY-7363: There can be multiple matches for a getter returning a generic parameter type, due to + // GROOVY-7363, GROOVY-11341: There can be multiple matches if a method returns a non-final type due to // the generation of a bridge method. The real getter is really the non-bridge, non-synthetic one as it // has the most specific and exact return type of the two. Picking the bridge method results in loss of // type information, as it down-casts the return type to the lower bound of the generic parameter. - if (getterMethod == null || getterMethod.isSynthetic()) { + if (isNullOrSynthetic.test(getterMethod)) { getterMethod = method; } } } - if (getterMethod != null) { - return getterMethod; - } - if (searchSuperClasses) { + + if (searchSuperClasses && isNullOrSynthetic.test(getterMethod)) { ClassNode parent = getSuperClass(); if (parent != null) { - return parent.getGetterMethod(getterName); + MethodNode method = parent.getGetterMethod(getterName); + if (getterMethod == null || !isNullOrSynthetic.test(method)) { + getterMethod = method; + } } } - return null; + + return getterMethod; } public MethodNode getSetterMethod(String setterName) { diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java index 55c293cd5c..daf7b32818 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java @@ -1208,7 +1208,7 @@ public abstract class StaticTypeCheckingSupport { if (toBeRemoved.contains(two)) continue; if (one.getParameters().length == two.getParameters().length) { ClassNode oneDC = one.getDeclaringClass(), twoDC = two.getDeclaringClass(); - if (oneDC == twoDC) { + if (oneDC == twoDC || isSynthetic(one,two)||isSynthetic(two,one)) { // GROOVY-11341 if (ParameterUtils.parametersEqual(one.getParameters(), two.getParameters())) { ClassNode oneRT = one.getReturnType(), twoRT = two.getReturnType(); if (isCovariant(oneRT, twoRT)) { diff --git a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy index c5876589cd..544bbbfe7d 100644 --- a/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy +++ b/src/test/groovy/transform/stc/MethodCallsSTCTest.groovy @@ -19,6 +19,7 @@ package groovy.transform.stc import org.codehaus.groovy.control.MultipleCompilationErrorsException +import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit import static org.codehaus.groovy.control.customizers.builder.CompilerCustomizationBuilder.withConfig @@ -1602,6 +1603,18 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { ''' } + // GROOVY-5525 + void testShouldFindArraysCopyOf() { + assertScript ''' + class CopyOf { + public static void main(String[] args) { + def copy = Arrays.copyOf(args, 1) + assert copy.length == 1 + } + } + ''' + } + // GROOVY-5702 void testShouldFindInterfaceMethod() { assertScript ''' @@ -1884,24 +1897,71 @@ class MethodCallsSTCTest extends StaticTypeCheckingTestCase { } // GROOVY-6751 - void testMethodInBothInterfaceAndSuperclass() { + void testMethodInBothInterfaceAndSuperclass1() { assertScript ''' - interface Ifc { + interface Face { Object getProperty(String s) } - - class DuplicateMethodInIfc implements Ifc {} // implemented in groovy.lang.GroovyObject - - class Tester { - DuplicateMethodInIfc dup = new DuplicateMethodInIfc() - Object obj = dup.getProperty("foo") + class Impl implements Face { // implemented in groovy.lang.GroovyObject } - try { new Tester()} - catch(groovy.lang.MissingPropertyException expected) {} + try { + Impl impl = new Impl() + impl.getProperty('xx') + } + catch(MissingPropertyException expected) { + } ''' } + // GROOVY-11341 + void testMethodInBothInterfaceAndSuperclass2() { + File parentDir = File.createTempDir() + config.with { + targetDirectory = File.createTempDir() + jointCompilationOptions = [memStub: true] + } + try { + new File(parentDir, 'p').mkdir() + + def a = new File(parentDir, 'p/A.java') + a.write '''package p; + public interface A { + Object getValue(); + } + ''' + def b = new File(parentDir, 'p/B.java') + b.write '''package p; + public class B { + public Long getValue() { return 21L; } + } + ''' + def c = new File(parentDir, 'p/C.java') + c.write '''package p; + public class C extends B implements A { + // public bridge Object getValue() { ... } + } + ''' + def d = new File(parentDir, 'D.groovy') + d.write ''' + def pojo = new p.C() + Long value = pojo.getValue() // Cannot assign value of type Object to variable of type Long + value += pojo.value + assert value == 42L + ''' + + def loader = new GroovyClassLoader(this.class.classLoader) + def cu = new JavaAwareCompilationUnit(config, loader) + cu.addSources(a, b, c, d) + cu.compile() + + loader.loadClass('D').main() + } finally { + parentDir.deleteDir() + config.targetDirectory.deleteDir() + } + } + // GROOVY-7987 void testNonStaticMethodViaStaticReceiver() { shouldFailWithMessages ''' diff --git a/src/test/groovy/transform/stc/vm6/MethodCallsSTCTest.groovy b/src/test/groovy/transform/stc/vm6/MethodCallsSTCTest.groovy deleted file mode 100644 index 0e1bcfac66..0000000000 --- a/src/test/groovy/transform/stc/vm6/MethodCallsSTCTest.groovy +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.transform.stc.vm6 - -import groovy.transform.stc.StaticTypeCheckingTestCase - -/** - * Unit tests for static type checking : method calls. - */ -class MethodCallsSTCTest extends StaticTypeCheckingTestCase { - // GROOVY-5525 - void testFindMethodFromArraysClass() { - assertScript '''import groovy.transform.TypeChecked - import java.util.Arrays - - class ArrayCopying { - public static void main(String[] args) { - def acopy = Arrays.copyOf(args, 1) - } - - } - ''' - } -} diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/vm6/MethodCallsStaticCompilationTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/vm6/MethodCallsStaticCompilationTest.groovy deleted file mode 100644 index ff759c175e..0000000000 --- a/src/test/org/codehaus/groovy/classgen/asm/sc/vm6/MethodCallsStaticCompilationTest.groovy +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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 org.codehaus.groovy.classgen.asm.sc.vm6 - -import groovy.transform.stc.vm6.MethodCallsSTCTest -import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport - -public class MethodCallsStaticCompilationTest extends MethodCallsSTCTest implements StaticCompilationTestSupport { -}