This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY_4_0_X in repository https://gitbox.apache.org/repos/asf/groovy.git
commit b7ff4541f3b9610c5a377ab9705e85912bee2daa Author: Eric Milles <[email protected]> AuthorDate: Thu Feb 23 17:52:50 2023 -0600 GROOVY-10937: update `record` component decompile --- .../ast/decompiled/ClassSignatureParser.java | 17 ++- .../org/codehaus/groovy/classgen/RecordTest.groovy | 156 +++++++++++---------- 2 files changed, 93 insertions(+), 80 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/ClassSignatureParser.java b/src/main/java/org/codehaus/groovy/ast/decompiled/ClassSignatureParser.java index 443a810dad..e3c7429257 100644 --- a/src/main/java/org/codehaus/groovy/ast/decompiled/ClassSignatureParser.java +++ b/src/main/java/org/codehaus/groovy/ast/decompiled/ClassSignatureParser.java @@ -27,7 +27,6 @@ import org.objectweb.asm.signature.SignatureVisitor; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; class ClassSignatureParser { @@ -60,7 +59,9 @@ class ClassSignatureParser { } if (!stub.recordComponents.isEmpty()) { - classNode.setRecordComponents(stub.recordComponents.stream().map(rc -> { + List<RecordComponentNode> recordComponents = + new ArrayList<>(stub.recordComponents.size()); + for (RecordComponentStub rc : stub.recordComponents) { ClassNode[] type = {resolver.resolveType(Type.getType(rc.descriptor))}; if (rc.signature != null) { new SignatureReader(rc.signature).accept(new TypeSignatureParser(resolver) { @@ -69,14 +70,16 @@ class ClassSignatureParser { type[0] = applyErasure(result, type[0]); } }); + } else { + type[0] = type[0].getPlainNodeReference(); } - ClassNode rcType = type[0]; - Annotations.addTypeAnnotations(rc, rcType, resolver); - RecordComponentNode recordComponent = new RecordComponentNode(classNode, rc.name, rcType); + RecordComponentNode recordComponent = new RecordComponentNode(classNode, rc.name, type[0]); Annotations.addAnnotations(rc, recordComponent, resolver); - return recordComponent; - }).collect(Collectors.toList())); + Annotations.addTypeAnnotations(rc, type[0], resolver); + recordComponents.add(recordComponent); + } + classNode.setRecordComponents(recordComponents); } } diff --git a/src/test/org/codehaus/groovy/classgen/RecordTest.groovy b/src/test/org/codehaus/groovy/classgen/RecordTest.groovy index 4c7c026ccd..2ebdc3c1ea 100644 --- a/src/test/org/codehaus/groovy/classgen/RecordTest.groovy +++ b/src/test/org/codehaus/groovy/classgen/RecordTest.groovy @@ -18,9 +18,9 @@ */ package org.codehaus.groovy.classgen -import org.codehaus.groovy.ast.AnnotationNode import org.codehaus.groovy.ast.ClassHelper import org.codehaus.groovy.ast.ClassNode +import org.codehaus.groovy.ast.RecordComponentNode import org.codehaus.groovy.ast.decompiled.AsmDecompiler import org.codehaus.groovy.ast.decompiled.AsmReferenceResolver import org.codehaus.groovy.ast.decompiled.DecompiledClassNode @@ -104,7 +104,7 @@ final class RecordTest { import java.lang.annotation.*; import java.util.*; - public record Person(@NotNull @NotNull2 String name, int age, @NotNull2 @NotNull3 List<String> locations, String[] titles) {} + public record Person(@NotNull @NotNull2 @NotNull3 String name, int age, @NotNull2 @NotNull3 List<String> locations, String[] titles) {} @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.RECORD_COMPONENT}) @@ -124,85 +124,95 @@ final class RecordTest { cu.addSources(a) cu.compile() - Class personClazz = loader.loadClass('Person') - Class notNullClazz = loader.loadClass('NotNull') - Class notNull2Clazz = loader.loadClass('NotNull2') - Class notNull3Clazz = loader.loadClass('NotNull3') - - def rcs = personClazz.recordComponents - assert rcs.length == 4 - - assert rcs[0].name == 'name' && rcs[0].type == String - def annotations = rcs[0].annotations - assert annotations.length == 2 - assert annotations[0].annotationType() == notNullClazz - assert annotations[1].annotationType() == notNull2Clazz - def typeAnnotations = rcs[0].getAnnotatedType().getAnnotations() - assert typeAnnotations.length == 1 - assert notNull2Clazz == typeAnnotations[0].annotationType() - - assert rcs[1].name == 'age' && rcs[1].type == int - assert rcs[2].name == 'locations' && rcs[2].type == List - assert rcs[3].name == 'titles' && rcs[3].type == String[] + def personClass = loader.loadClass('Person') + def notNullClass = loader.loadClass('NotNull') + def notNull2Class = loader.loadClass('NotNull2') + def notNull3Class = loader.loadClass('NotNull3') + + def personComponents = personClass.recordComponents + assert personComponents.size() == 4 + + assert personComponents[0].name == 'name' + assert personComponents[0].type == String + def annotations = personComponents[0].annotations + assert annotations.size() == 2 + assert annotations[0].annotationType() == notNullClass + assert annotations[1].annotationType() == notNull2Class + def typeAnnotations = personComponents[0].annotatedType.annotations + assert typeAnnotations.size() == 2 + assert typeAnnotations[0].annotationType() == notNull2Class + assert typeAnnotations[1].annotationType() == notNull3Class + + assert personComponents[1].name == 'age' && personComponents[1].type == int + assert personComponents[2].name == 'locations' && personComponents[2].type == List + assert personComponents[3].name == 'titles' && personComponents[3].type == String[] + + assert personComponents[2].annotations.size() == 1 + assert personComponents[2].annotations[0].annotationType() == notNull2Class + assert personComponents[2].genericSignature == 'Ljava/util/List<Ljava/lang/String;>;' + assert personComponents[2].genericType.toString() == 'java.util.List<java.lang.String>' + + typeAnnotations = personComponents[2].annotatedType.annotations + assert typeAnnotations.size() == 2 + assert typeAnnotations[0].annotationType() == notNull2Class + assert typeAnnotations[1].annotationType() == notNull3Class + + def personClassNode = ClassHelper.make(personClass) + def notNullClassNode = ClassHelper.make(notNullClass) + def notNull2ClassNode = ClassHelper.make(notNull2Class) + def notNull3ClassNode = ClassHelper.make(notNull3Class) + + def checkNativeRecordClassNode = { ClassNode classNode -> + assert classNode.isRecord() + assert classNode.recordComponents.size() == 4 + classNode.recordComponents.eachWithIndex { RecordComponentNode rcn, Integer index -> + switch (index) { + case 0: + assert rcn.name == 'name' + assert rcn.type == ClassHelper.STRING_TYPE + assert rcn.type !== ClassHelper.STRING_TYPE // GROOVY-10937 + assert rcn.annotations.size() == 2 + assert rcn.annotations[0].classNode == notNullClassNode + assert rcn.annotations[1].classNode == notNull2ClassNode + assert rcn.type.typeAnnotations.size() == 2 + assert rcn.type.typeAnnotations[0].classNode == notNull2ClassNode + assert rcn.type.typeAnnotations[1].classNode == notNull3ClassNode + break + case 1: + assert rcn.name == 'age' + assert rcn.type == ClassHelper.int_TYPE + break + case 2: + assert rcn.name == 'locations' + assert rcn.type == ClassHelper.LIST_TYPE + assert rcn.type !== ClassHelper.LIST_TYPE + assert rcn.type.genericsTypes.size() == 1 + assert rcn.type.genericsTypes[0].type == ClassHelper.STRING_TYPE + assert rcn.annotations.size() == 1 + assert rcn.annotations[0].classNode == notNull2ClassNode + assert rcn.type.typeAnnotations.size() == 2 + assert rcn.type.typeAnnotations[0].classNode == notNull2ClassNode + assert rcn.type.typeAnnotations[1].classNode == notNull3ClassNode + break + case 3: + assert rcn.name == 'titles' + assert rcn.type == ClassHelper.STRING_TYPE.makeArray() + } + } + } - assert rcs[2].genericSignature == 'Ljava/util/List<Ljava/lang/String;>;' - assert rcs[2].genericType as String == 'java.util.List<java.lang.String>' + checkNativeRecordClassNode(personClassNode) - def annotations2 = rcs[2].annotations - assert annotations2.length == 1 - assert annotations2[0].annotationType() == notNull2Clazz - def typeAnnotations2 = rcs[2].annotatedType.annotations - assert typeAnnotations2.length == 2 - assert typeAnnotations2[0].annotationType() == notNull2Clazz - assert typeAnnotations2[1].annotationType() == notNull3Clazz - - ClassNode personClassNode = ClassHelper.make(personClazz) - ClassNode notNullClassNode = ClassHelper.make(notNullClazz) - ClassNode notNull2ClassNode = ClassHelper.make(notNull2Clazz) - ClassNode notNull3ClassNode = ClassHelper.make(notNull3Clazz) - checkNativeRecordClassNode(personClassNode, notNullClassNode, notNull2ClassNode, notNull3ClassNode) - - def resource = loader.getResource(personClazz.getName().replace('.', '/') + '.class') - def stub = AsmDecompiler.parseClass(resource) - def unit = new CompilationUnit(loader) - def personDecompiledClassNode = new DecompiledClassNode(stub, new AsmReferenceResolver(new ClassNodeResolver(), unit)) - checkNativeRecordClassNode(personDecompiledClassNode, notNullClassNode, notNull2ClassNode, notNull3ClassNode) + def stub = AsmDecompiler.parseClass(loader.getResource(personClass.getName().replace('.', '/') + '.class')) + def resolver = new AsmReferenceResolver(new ClassNodeResolver(), new CompilationUnit(loader)) + def personDecompiledClassNode = new DecompiledClassNode(stub, resolver) + checkNativeRecordClassNode(personDecompiledClassNode) } finally { sourceDir.deleteDir() config.targetDirectory.deleteDir() } } - private static void checkNativeRecordClassNode(ClassNode personClassNode, ClassNode notNullClassNode, ClassNode notNull2ClassNode, ClassNode notNull3ClassNode) { - assert personClassNode.isRecord() - def rcns = personClassNode.getRecordComponents() - assert rcns.size() == 4 - assert rcns[0].name == 'name' && rcns[0].type == ClassHelper.STRING_TYPE - List<AnnotationNode> annotationNodes = rcns[0].getAnnotations() - assert annotationNodes.size() == 2 - assert annotationNodes[0].getClassNode() == notNullClassNode - assert annotationNodes[1].getClassNode() == notNull2ClassNode - def typeAnnotationNodes = rcns[0].getType().getTypeAnnotations() - assert typeAnnotationNodes.size() == 1 - assert typeAnnotationNodes[0].getClassNode() == notNull2ClassNode - - assert rcns[1].name == 'age' && rcns[1].type == ClassHelper.int_TYPE - - assert rcns[2].name == 'locations' && rcns[2].type == ClassHelper.LIST_TYPE - def genericsTypes = rcns[2].type.genericsTypes - assert genericsTypes.size() == 1 - assert genericsTypes[0].type == ClassHelper.STRING_TYPE - def annotationNodes2 = rcns[2].getAnnotations() - assert annotationNodes2.size() == 1 - assert annotationNodes2[0].getClassNode() == notNull2ClassNode - def typeAnnotationNodes2 = rcns[2].getType().getTypeAnnotations() - assert typeAnnotationNodes2.size() == 2 - assert typeAnnotationNodes2[0].getClassNode() == notNull2ClassNode - assert typeAnnotationNodes2[1].getClassNode() == notNull3ClassNode - - assert rcns[3].name == 'titles' && rcns[3].type == ClassHelper.STRING_TYPE.makeArray() - } - //-------------------------------------------------------------------------- private final GroovyShell shell = GroovyShell.withConfig {
