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 0e33c73ee4 GROOVY-11413: interfaces and modifiers of array class 0e33c73ee4 is described below commit 0e33c73ee40d5672efad6d2fd27cd0700a337278 Author: Eric Milles <eric.mil...@thomsonreuters.com> AuthorDate: Thu Jun 20 16:18:36 2024 -0500 GROOVY-11413: interfaces and modifiers of array class --- .../options/ImmutablePropertyHandler.java | 46 ++++++++++------------ .../groovy/ast/tools/ImmutablePropertyUtils.java | 9 ++--- .../java/org/codehaus/groovy/ast/ClassHelper.java | 1 + .../java/org/codehaus/groovy/ast/ClassNode.java | 4 +- .../transform/AutoCloneASTTransformation.java | 4 +- .../org/codehaus/groovy/ast/ClassNodeTest.java | 17 ++++++++ 6 files changed, 46 insertions(+), 35 deletions(-) diff --git a/src/main/java/groovy/transform/options/ImmutablePropertyHandler.java b/src/main/java/groovy/transform/options/ImmutablePropertyHandler.java index 935eaf6f4a..726b09c354 100644 --- a/src/main/java/groovy/transform/options/ImmutablePropertyHandler.java +++ b/src/main/java/groovy/transform/options/ImmutablePropertyHandler.java @@ -22,7 +22,6 @@ import groovy.lang.ReadOnlyPropertyException; import groovy.transform.stc.POJO; import org.apache.groovy.ast.tools.ImmutablePropertyUtils; import org.codehaus.groovy.ast.AnnotationNode; -import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.FieldNode; import org.codehaus.groovy.ast.Parameter; @@ -42,10 +41,7 @@ import org.codehaus.groovy.transform.ImmutableASTTransformation; import org.codehaus.groovy.transform.MapConstructorASTTransformation; import org.codehaus.groovy.transform.NullCheckASTTransformation; -import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; @@ -54,8 +50,13 @@ import static org.apache.groovy.ast.tools.ImmutablePropertyUtils.cloneArrayOrClo import static org.apache.groovy.ast.tools.ImmutablePropertyUtils.cloneDateExpr; import static org.apache.groovy.ast.tools.ImmutablePropertyUtils.derivesFromDate; import static org.apache.groovy.ast.tools.ImmutablePropertyUtils.implementsCloneable; +import static org.codehaus.groovy.ast.ClassHelper.CLONEABLE_TYPE; +import static org.codehaus.groovy.ast.ClassHelper.COLLECTION_TYPE; +import static org.codehaus.groovy.ast.ClassHelper.LIST_TYPE; +import static org.codehaus.groovy.ast.ClassHelper.MAP_TYPE; +import static org.codehaus.groovy.ast.ClassHelper.SET_TYPE; +import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType; import static org.codehaus.groovy.ast.ClassHelper.make; -import static org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching; import static org.codehaus.groovy.ast.tools.GeneralUtils.args; import static org.codehaus.groovy.ast.tools.GeneralUtils.assignNullS; import static org.codehaus.groovy.ast.tools.GeneralUtils.assignS; @@ -81,17 +82,12 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.throwS; import static org.codehaus.groovy.ast.tools.GeneralUtils.varX; public class ImmutablePropertyHandler extends PropertyHandler { - private static final ClassNode CLONEABLE_TYPE = make(Cloneable.class); - private static final ClassNode COLLECTION_TYPE = makeWithoutCaching(Collection.class, false); + private static final ClassNode POJO_TYPE = make(POJO.class); + private static final ClassNode SORTEDMAP_TYPE = make(SortedMap.class); + private static final ClassNode SORTEDSET_TYPE = make(SortedSet.class); private static final ClassNode DGM_TYPE = make(DefaultGroovyMethods.class); - private static final ClassNode SELF_TYPE = make(ImmutableASTTransformation.class); - private static final ClassNode MAP_TYPE = makeWithoutCaching(Map.class, false); - private static final ClassNode SORTEDSET_CLASSNODE = make(SortedSet.class); - private static final ClassNode SORTEDMAP_CLASSNODE = make(SortedMap.class); - private static final ClassNode SET_CLASSNODE = make(Set.class); - private static final ClassNode MAP_CLASSNODE = make(Map.class); + private static final ClassNode XFORM_TYPE = make(ImmutableASTTransformation.class); private static final ClassNode READONLYEXCEPTION_TYPE = make(ReadOnlyPropertyException.class); - private static final ClassNode POJO_TYPE = make(POJO.class); @Override public Statement createPropGetter(final PropertyNode pNode) { @@ -159,16 +155,14 @@ public class ImmutablePropertyHandler extends PropertyHandler { } protected Expression cloneCollectionExpr(final Expression fieldExpr, final ClassNode type) { - return castX(type, createIfInstanceOfAsImmutableS(fieldExpr, SORTEDSET_CLASSNODE, - createIfInstanceOfAsImmutableS(fieldExpr, SORTEDMAP_CLASSNODE, - createIfInstanceOfAsImmutableS(fieldExpr, SET_CLASSNODE, - createIfInstanceOfAsImmutableS(fieldExpr, MAP_CLASSNODE, - createIfInstanceOfAsImmutableS(fieldExpr, ClassHelper.LIST_TYPE, - createAsImmutableX(fieldExpr, COLLECTION_TYPE)) - ) - ) - ) - )); + // priority is low to high -- SortedSet comes first and Collection is last + Expression asImmutableX = createAsImmutableX(fieldExpr, COLLECTION_TYPE); + asImmutableX = createIfInstanceOfAsImmutableS(fieldExpr, LIST_TYPE, asImmutableX); + asImmutableX = createIfInstanceOfAsImmutableS(fieldExpr, MAP_TYPE , asImmutableX); + asImmutableX = createIfInstanceOfAsImmutableS(fieldExpr, SET_TYPE , asImmutableX); + asImmutableX = createIfInstanceOfAsImmutableS(fieldExpr, SORTEDMAP_TYPE, asImmutableX); + asImmutableX = createIfInstanceOfAsImmutableS(fieldExpr, SORTEDSET_TYPE, asImmutableX); + return castX(type, asImmutableX); } private Expression createIfInstanceOfAsImmutableS(final Expression expr, final ClassNode type, final Expression elseStatement) { @@ -214,7 +208,7 @@ public class ImmutablePropertyHandler extends PropertyHandler { Expression initExpr = fNode.getInitialValueExpression(); Statement assignInit; if (initExpr == null || (initExpr instanceof ConstantExpression && ((ConstantExpression) initExpr).isNullExpression())) { - if (ClassHelper.isPrimitiveType(fType)) { + if (isPrimitiveType(fType)) { assignInit = EmptyStatement.INSTANCE; } else { assignInit = shouldNullCheck ? NullCheckASTTransformation.makeThrowStmt(fNode.getName()) : assignNullS(fieldExpr); @@ -262,7 +256,7 @@ public class ImmutablePropertyHandler extends PropertyHandler { // check at runtime since classes might not be resolved private static Expression createCheckImmutable(final FieldNode fNode, final Expression value, final List<String> knownImmutables, final List<String> knownImmutableClasses) { Expression args = args(callThisX("getClass"), constX(fNode.getName()), value, list2args(knownImmutables), classList2args(knownImmutableClasses)); - return callX(SELF_TYPE, "checkImmutable", args); + return callX(XFORM_TYPE, "checkImmutable", args); } private Statement createConstructorStatementCollection(final FieldNode fNode, final Parameter namedArgsMap, final boolean shouldNullCheck) { diff --git a/src/main/java/org/apache/groovy/ast/tools/ImmutablePropertyUtils.java b/src/main/java/org/apache/groovy/ast/tools/ImmutablePropertyUtils.java index 182508780c..f5e140e238 100644 --- a/src/main/java/org/apache/groovy/ast/tools/ImmutablePropertyUtils.java +++ b/src/main/java/org/apache/groovy/ast/tools/ImmutablePropertyUtils.java @@ -48,8 +48,6 @@ import java.util.Date; import java.util.List; import java.util.Set; -import static org.codehaus.groovy.ast.ClassHelper.make; -import static org.codehaus.groovy.ast.ClassHelper.makeWithoutCaching; import static org.codehaus.groovy.ast.tools.GeneralUtils.args; import static org.codehaus.groovy.ast.tools.GeneralUtils.callX; import static org.codehaus.groovy.ast.tools.GeneralUtils.castX; @@ -58,9 +56,8 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX; import static org.codehaus.groovy.ast.tools.GeneralUtils.isOrImplements; public class ImmutablePropertyUtils { - private static final ClassNode DATE_TYPE = make(Date.class); - private static final ClassNode CLONEABLE_TYPE = make(Cloneable.class); - public static final ClassNode IMMUTABLE_OPTIONS_TYPE = makeWithoutCaching(ImmutableOptions.class, false); + private static final ClassNode DATE_TYPE = ClassHelper.make(Date.class); + public static final ClassNode IMMUTABLE_OPTIONS_TYPE = ClassHelper.makeWithoutCaching(ImmutableOptions.class, false); private static final String MEMBER_KNOWN_IMMUTABLE_CLASSES = "knownImmutableClasses"; private static final String MEMBER_KNOWN_IMMUTABLES = "knownImmutables"; @@ -185,7 +182,7 @@ public class ImmutablePropertyUtils { } public static boolean implementsCloneable(final ClassNode fieldType) { - return isOrImplements(fieldType, CLONEABLE_TYPE); + return isOrImplements(fieldType, ClassHelper.CLONEABLE_TYPE); } public static Expression cloneDateExpr(final Expression origDate) { diff --git a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java index c6cb4cfd16..b79a07ec51 100644 --- a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java +++ b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java @@ -142,6 +142,7 @@ public class ClassHelper { Annotation_TYPE = makeCached(Annotation.class), ELEMENT_TYPE_TYPE = makeCached(ElementType.class), AUTOCLOSEABLE_TYPE = makeCached(AutoCloseable.class), + CLONEABLE_TYPE = makeCached(Cloneable.class), SERIALIZABLE_TYPE = makeCached(Serializable.class), SERIALIZEDLAMBDA_TYPE = makeCached(SerializedLambda.class), SEALED_TYPE = makeCached(Sealed.class), diff --git a/src/main/java/org/codehaus/groovy/ast/ClassNode.java b/src/main/java/org/codehaus/groovy/ast/ClassNode.java index 2d2ec5b86a..c211c0f6d9 100644 --- a/src/main/java/org/codehaus/groovy/ast/ClassNode.java +++ b/src/main/java/org/codehaus/groovy/ast/ClassNode.java @@ -59,6 +59,7 @@ import static org.codehaus.groovy.transform.trait.Traits.isTrait; import static org.objectweb.asm.Opcodes.ACC_ABSTRACT; import static org.objectweb.asm.Opcodes.ACC_ANNOTATION; import static org.objectweb.asm.Opcodes.ACC_ENUM; +import static org.objectweb.asm.Opcodes.ACC_FINAL; import static org.objectweb.asm.Opcodes.ACC_INTERFACE; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_STATIC; @@ -239,7 +240,8 @@ public class ClassNode extends AnnotatedNode { * Constructor used by {@code makeArray()} if no real class is available. */ private ClassNode(final ClassNode componentType) { - this(componentType.getName() + "[]", ACC_PUBLIC, ClassHelper.OBJECT_TYPE); + this(componentType.getName() + "[]", ACC_ABSTRACT | ACC_FINAL | ACC_PUBLIC, ClassHelper.OBJECT_TYPE, + new ClassNode[]{ClassHelper.CLONEABLE_TYPE, ClassHelper.SERIALIZABLE_TYPE}, MixinNode.EMPTY_ARRAY); this.componentType = componentType.redirect(); this.isPrimaryNode = false; } diff --git a/src/main/java/org/codehaus/groovy/transform/AutoCloneASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/AutoCloneASTTransformation.java index fe318a0912..0916d79dcc 100644 --- a/src/main/java/org/codehaus/groovy/transform/AutoCloneASTTransformation.java +++ b/src/main/java/org/codehaus/groovy/transform/AutoCloneASTTransformation.java @@ -54,6 +54,8 @@ import java.util.List; import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedConstructor; import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedMethod; +import static org.codehaus.groovy.ast.ClassHelper.CLONEABLE_TYPE; +import static org.codehaus.groovy.ast.ClassHelper.isObjectType; import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType; import static org.codehaus.groovy.ast.ClassHelper.make; import static org.codehaus.groovy.ast.tools.GeneralUtils.args; @@ -83,7 +85,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS; import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt; import static org.codehaus.groovy.ast.tools.GeneralUtils.ternaryX; import static org.codehaus.groovy.ast.tools.GeneralUtils.varX; -import static org.codehaus.groovy.ast.ClassHelper.isObjectType; import static org.codehaus.groovy.transform.sc.StaticCompilationVisitor.COMPILESTATIC_CLASSNODE; import static org.codehaus.groovy.transform.stc.StaticTypesMarker.DIRECT_METHOD_CALL_TARGET; import static org.objectweb.asm.Opcodes.ACC_FINAL; @@ -98,7 +99,6 @@ public class AutoCloneASTTransformation extends AbstractASTTransformation { static final Class MY_CLASS = AutoClone.class; static final ClassNode MY_TYPE = make(MY_CLASS); static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage(); - private static final ClassNode CLONEABLE_TYPE = make(Cloneable.class); private static final ClassNode BAOS_TYPE = make(ByteArrayOutputStream.class); private static final ClassNode BAIS_TYPE = make(ByteArrayInputStream.class); private static final ClassNode OOS_TYPE = make(ObjectOutputStream.class); diff --git a/src/test/org/codehaus/groovy/ast/ClassNodeTest.java b/src/test/org/codehaus/groovy/ast/ClassNodeTest.java index 3759da76ed..f42934aad1 100644 --- a/src/test/org/codehaus/groovy/ast/ClassNodeTest.java +++ b/src/test/org/codehaus/groovy/ast/ClassNodeTest.java @@ -23,6 +23,7 @@ import org.codehaus.groovy.ast.tools.GenericsUtils; import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -42,6 +43,22 @@ public final class ClassNodeTest { classNode.addField("field", ACC_PUBLIC, ClassHelper.STRING_TYPE, null); } + @Test // GROOVY-11413 + public void testArrayClass() { + ClassNode array1 = ClassHelper.make(Integer[].class); + ClassNode array2 = classNode.makeArray(); + + assertEquals(array1.getModifiers(), array2.getModifiers()); + assertEquals(array1.getSuperClass(), array2.getSuperClass()); + assertArrayEquals(array1.getInterfaces(), array2.getInterfaces()); + + // members; TODO: "length" and "clone()" + assertTrue(array1.getFields().isEmpty()); + assertTrue(array2.getFields().isEmpty()); + assertTrue(array1.getMethods().isEmpty()); + assertTrue(array2.getMethods().isEmpty()); + } + @Test public void testOuterClass() { assertNull(classNode.getOuterClass());