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 f30978567e GROOVY-10380: return getter generated later by default argument(s) f30978567e is described below commit f30978567e5f77c6876e8b13e807d4cf329efc84 Author: Eric Milles <eric.mil...@thomsonreuters.com> AuthorDate: Sun May 19 09:40:34 2024 -0500 GROOVY-10380: return getter generated later by default argument(s) --- .../java/org/codehaus/groovy/ast/ClassNode.java | 29 +++- .../transform/DelegateASTTransformation.java | 2 +- .../stc/FieldsAndPropertiesSTCTest.groovy | 191 +++++++++++---------- 3 files changed, 123 insertions(+), 99 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/ast/ClassNode.java b/src/main/java/org/codehaus/groovy/ast/ClassNode.java index 47220eb468..b01d8770fc 100644 --- a/src/main/java/org/codehaus/groovy/ast/ClassNode.java +++ b/src/main/java/org/codehaus/groovy/ast/ClassNode.java @@ -18,6 +18,7 @@ */ package org.codehaus.groovy.ast; +import org.apache.groovy.ast.tools.AnnotatedNodeUtils; import org.apache.groovy.ast.tools.ClassNodeUtils; import org.apache.groovy.lang.annotation.Incubating; import org.codehaus.groovy.GroovyBugError; @@ -48,6 +49,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.IntStream; +import java.util.stream.Stream; import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toList; @@ -1050,14 +1052,25 @@ public class ClassNode extends AnnotatedNode { 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, 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 (isNullOrSynthetic.test(getterMethod)) { - getterMethod = method; + if (booleanReturnOnly ? ClassHelper.isPrimitiveBoolean(method.getReturnType()) : !method.isVoidMethod()) { + if (method.getParameters().length == 0) { + // 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 (isNullOrSynthetic.test(getterMethod)) { + getterMethod = method; + } + } else if (method.hasDefaultValue() && Stream.of(method.getParameters()).allMatch(Parameter::hasInitialExpression)) { + // GROOVY-11380: getter generated later by default arguments + if (isNullOrSynthetic.test(getterMethod)) { + getterMethod = new MethodNode(method.getName(), method.getModifiers() & ~ACC_ABSTRACT, method.getReturnType(), Parameter.EMPTY_ARRAY, method.getExceptions(), null); + getterMethod.setSynthetic(true); + getterMethod.setDeclaringClass(this); + getterMethod.addAnnotations(method.getAnnotations()); + AnnotatedNodeUtils.markAsGenerated(this, getterMethod); + getterMethod.setGenericsTypes(method.getGenericsTypes()); + } } } } diff --git a/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java index 2c79b242e3..38d586219b 100644 --- a/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java +++ b/src/main/java/org/codehaus/groovy/transform/DelegateASTTransformation.java @@ -310,7 +310,7 @@ public class DelegateASTTransformation extends AbstractASTTransformation { private static void addSetterIfNeeded(final DelegateDescription delegate, final PropertyNode prop, final String name, final boolean allNames) { String setterName = getSetterName(name); - if ((prop.getModifiers() & ACC_FINAL) == 0 + if (!prop.isFinal() && delegate.owner.getSetterMethod(setterName) == null && delegate.owner.getProperty(name) == null && !shouldSkipPropertyMethod(name, setterName, delegate.excludes, delegate.includes, allNames)) { addGeneratedMethod( diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy index 530f72c097..b078243307 100644 --- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy +++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy @@ -393,7 +393,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { ''' } - void testGetterForProperty1() { + void testGetterForProperty() { assertScript ''' class C { String p @@ -403,89 +403,14 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { ''' } - // GROOVY-10981 - void testGetterForProperty2() { - for (mode in ['', 'public', 'private', 'protected', '@groovy.transform.PackageScope']) { - assertScript """ - abstract class A { - $mode Object p = 'field' - CharSequence getP() { 'property' } - } - class C extends A { - def m() { - final int len = p.length() - if (p instanceof String) { - p.toLowerCase() - p.toUpperCase() - } - } - } - String which = new C().m() - assert which == 'PROPERTY' - """ - } - } - - // GROOVY-9973 - void testGetterForProperty3() { - assertScript ''' - class C { - private int f - int getP() { f } - Integer m() { 123456 - p } - Integer m(int i) { i - p } - } - def c = new C() - assert c.m() == 123456 // BUG! exception in phase 'class generation' ... - assert c.m(123) == 123 // ClassCastException: class org.codehaus.groovy.ast.Parameter cannot be cast to ... - ''' - } - - // GROOVY-11005 - void testGetterForProperty4() { - File parentDir = File.createTempDir() - config.with { - targetDirectory = File.createTempDir() - jointCompilationOptions = [memStub: true] - } - try { - def a = new File(parentDir, 'Pogo.groovy') - a.write ''' - class Pogo { - String value - String getValue() { value } - } - ''' - def b = new File(parentDir, 'Test.groovy') - b.write ''' - class Test extends Pogo { - void test() { - value = 'string' - } - } - ''' - - def loader = new GroovyClassLoader(this.class.classLoader) - def cu = new JavaAwareCompilationUnit(config, loader) - cu.addSources(a, b) - cu.compile() - - loader.loadClass('Test').newInstance().test() - } finally { - parentDir.deleteDir() - config.targetDirectory.deleteDir() - } - } - // GROOVY-5232 - void testSetterForProperty1() { + void testSetterForProperty() { assertScript ''' class Person { String name static Person create() { def p = new Person() p.setName("Guillaume") - // but p.name = "Guillaume" works return p } } @@ -493,16 +418,6 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { ''' } - // GROOVY-11372 - void testSetterForProperty2() { - assertScript ''' - def baos = new ByteArrayOutputStream() - assert baos.size() == 0 - baos.bytes= new byte[1] - assert baos.size() == 1 - ''' - } - // GROOVY-5443 void testFieldInitShouldPass() { assertScript ''' @@ -585,15 +500,27 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { ''' } + // GROOVY-10380 + void testGetterUsingPropertyNotation() { + assertScript ''' + class C { + def getFoo(foo = 'foo') { foo } + } + def c = new C() + def v = c.foo + assert v == 'foo' + ''' + } + void testSetterUsingPropertyNotation() { assertScript ''' class C { - boolean ok = false - void setFoo(String foo) { ok = (foo == 'foo') } + boolean set + void setFoo(foo) { set = (foo == 'foo') } } def c = new C() c.foo = 'foo' - assert c.ok + assert c.set ''' } @@ -611,6 +538,16 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { ''' } + // GROOVY-11372 + void testSetterUsingPropertyNotationViaExtension() { + assertScript ''' + def baos = new ByteArrayOutputStream() + assert baos.size() == 0 + baos.bytes= new byte[1] + assert baos.size() == 1 + ''' + } + void testListDotProperty1() { assertScript '''class Elem { int value } List<Elem> list = new LinkedList<Elem>() @@ -1163,6 +1100,65 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { ''' } + // GROOVY-10981 + void testSuperPropertyAccess4() { + for (mode in ['', 'public', 'private', 'protected', '@groovy.transform.PackageScope']) { + assertScript """ + abstract class A { + $mode Object p = 'field' + CharSequence getP() { 'property' } + } + class C extends A { + def m() { + final int len = p.length() + if (p instanceof String) { + p.toLowerCase() + p.toUpperCase() + } + } + } + String which = new C().m() + assert which == 'PROPERTY' + """ + } + } + + // GROOVY-11005 + void testSuperPropertyAccess5() { + File parentDir = File.createTempDir() + config.with { + targetDirectory = File.createTempDir() + jointCompilationOptions = [memStub: true] + } + try { + def a = new File(parentDir, 'Pogo.groovy') + a.write ''' + class Pogo { + String value + String getValue() { value } + } + ''' + def b = new File(parentDir, 'Test.groovy') + b.write ''' + class Test extends Pogo { + void test() { + value = 'string' + } + } + ''' + + def loader = new GroovyClassLoader(this.class.classLoader) + def cu = new JavaAwareCompilationUnit(config, loader) + cu.addSources(a, b) + cu.compile() + + loader.loadClass('Test').newInstance().test() + } finally { + parentDir.deleteDir() + config.targetDirectory.deleteDir() + } + } + void testPrivateFieldAccessInClosure1() { assertScript ''' class C { @@ -1251,6 +1247,21 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { ''' } + // GROOVY-9973 + void testPrivateFieldVersusPublicGetter() { + assertScript ''' + class C { + private int f + int getP() { f } + Integer m() { 123456 - p } + Integer m(int i) { i - p } + } + def c = new C() + assert c.m() == 123456 // BUG! exception in phase 'class generation' ... + assert c.m(123) == 123 // ClassCastException: class org.codehaus.groovy.ast.Parameter cannot be cast to ... + ''' + } + // GROOVY-6277 void testPublicFieldVersusPrivateGetter() { assertScript '''