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 <[email protected]>
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 '''