GROOVY-8872: Populate the parameter names from the byte code when available (add test)
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/66c87071 Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/66c87071 Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/66c87071 Branch: refs/heads/GROOVY_2_5_X Commit: 66c8707165081d201d90dd79e9ff9610147dd4c6 Parents: c8944a5 Author: Paul King <pa...@asert.com.au> Authored: Sat Nov 10 17:28:56 2018 +1000 Committer: Paul King <pa...@asert.com.au> Committed: Sat Nov 10 20:39:48 2018 +1000 ---------------------------------------------------------------------- .../codehaus/groovy/ast/tools/GeneralUtils.java | 4 + .../groovy/groovy/ant/Groovy8872Test.groovy | 100 +++++++++++-------- 2 files changed, 61 insertions(+), 43 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/66c87071/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java index a312b2f..f0b20e0 100644 --- a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java +++ b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java @@ -619,6 +619,10 @@ public class GeneralUtils { return new BooleanExpression(new BinaryExpression(expr, EQ, new ConstantExpression(0))); } + public static ListExpression listX(List<Expression> args) { + return new ListExpression(args); + } + public static ListExpression list2args(List args) { ListExpression result = new ListExpression(); for (Object o : args) { http://git-wip-us.apache.org/repos/asf/groovy/blob/66c87071/subprojects/groovy-ant/src/test/groovy/groovy/ant/Groovy8872Test.groovy ---------------------------------------------------------------------- diff --git a/subprojects/groovy-ant/src/test/groovy/groovy/ant/Groovy8872Test.groovy b/subprojects/groovy-ant/src/test/groovy/groovy/ant/Groovy8872Test.groovy index 1cd46e7..e43714a 100644 --- a/subprojects/groovy-ant/src/test/groovy/groovy/ant/Groovy8872Test.groovy +++ b/subprojects/groovy-ant/src/test/groovy/groovy/ant/Groovy8872Test.groovy @@ -18,26 +18,19 @@ */ package groovy.ant -class Groovy8669Test extends AntTestCase { - private scriptAllOnPath = ''' - def anno = AnnotatedClass.annotations[0] - def type = anno.annotationType() - assert type.name == 'MyAnnotation' - assert type.getDeclaredMethod('value').invoke(anno).name == 'ValueClass' - ''' - - private scriptNoValueClass = ''' - // using annotations will cause ValueClass not to be found - // but should still be able to use the class otherwise - assert AnnotatedClass.name.size() == 14 - ''' +class Groovy8872Test extends AntTestCase { + private scriptParamNameCheck = ''' + @ExtractParamNames + abstract class DummyClass implements JavaInterface, GroovyInterface {} - private scriptNoAnnotationOnPath = ''' - // class should be usable but won't have annotations - assert !AnnotatedClass.annotations + def paramNames = DummyClass.paramNames + assert paramNames == [ + ['name', 'dob', 'vip'], + ['id', 'eventName', 'dateOfEvent'] + ] ''' - void testCreateZip() { + void testParameterNamesSeenInAST() { // def debugLogger = new org.apache.tools.ant.DefaultLogger() // debugLogger.setMessageOutputLevel(4) // debugLogger.setOutputPrintStream(System.out) @@ -45,43 +38,64 @@ class Groovy8669Test extends AntTestCase { doInTmpDir { ant, baseDir -> baseDir.src { - 'ValueClass.java'(''' - public class ValueClass{ } + 'JavaInterface.java'(''' + import java.util.Date; + + public interface JavaInterface { + void addPerson(String name, Date dob, boolean vip); + } + ''') + 'GroovyInterface.groovy'(''' + interface GroovyInterface { + void addEvent(int id, String eventName, Date dateOfEvent) + } ''') - 'MyAnnotation.java'(''' - import java.lang.annotation.*; + 'ExtractParamNames.groovy'(''' + import org.codehaus.groovy.transform.GroovyASTTransformationClass + import java.lang.annotation.* + /** + * Test transform adds a static method to a class that returns a map from the name + * for each found method to its parameter names. + */ + @java.lang.annotation.Documented + @Retention(RetentionPolicy.SOURCE) @Target(ElementType.TYPE) - @Retention(RetentionPolicy.RUNTIME) - public @interface MyAnnotation { - Class<ValueClass> value(); - } + @GroovyASTTransformationClass("ExtractParamNamesTransformation") + @interface ExtractParamNames { } ''') - 'AnnotatedClass.java'(''' - @MyAnnotation(ValueClass.class) - class AnnotatedClass { } + 'ExtractParamNamesTransformation.groovy'(''' + import org.codehaus.groovy.ast.* + import org.codehaus.groovy.ast.expr.* + import org.codehaus.groovy.ast.stmt.* + import org.codehaus.groovy.transform.* + import org.codehaus.groovy.control.* + import static org.codehaus.groovy.ast.tools.GeneralUtils.* + + @GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION) + class ExtractParamNamesTransformation extends AbstractASTTransformation { + void visit(ASTNode[] nodes, SourceUnit source) { + init(nodes, source) + def classNode = nodes[1] + assert classNode instanceof ClassNode + def result = listX(classNode.abstractMethods.collect{ list2args(it.parameters.name) }) + classNode.addField(new FieldNode("paramNames", ACC_PUBLIC+ACC_STATIC+ACC_FINAL, + ClassHelper.LIST_TYPE.plainNodeReference, classNode, result)) + } + } ''') } // ant.project.addBuildListener(debugLogger) ant.mkdir(dir: 'build') ant.javac(classpath: '.', destdir: 'build', srcdir: 'src', - includes: '*.java', includeantruntime: 'false', fork: 'true') - ['ValueClass', 'MyAnnotation', 'AnnotatedClass'].each { name -> - ant.mkdir(dir: "build$name") - ant.copy(file: "build/${name}.class", todir: "build$name") + includes: '*.java', includeantruntime: 'false', fork: 'true') { + compilerarg(value: '-parameters') } + ant.taskdef(name: 'groovyc', classname: 'org.codehaus.groovy.ant.Groovyc') + ant.groovyc(srcdir: 'src', destdir: 'build', parameters: 'true') ant.taskdef(name: 'groovy', classname: 'org.codehaus.groovy.ant.Groovy') - ant.groovy(scriptAllOnPath) { - classpath { pathelement(path: 'buildValueClass') } - classpath { pathelement(path: 'buildMyAnnotation') } - classpath { pathelement(path: 'buildAnnotatedClass') } - } - ant.groovy(scriptNoValueClass) { - classpath { pathelement(path: 'buildMyAnnotation') } - classpath { pathelement(path: 'buildAnnotatedClass') } - } - ant.groovy(scriptNoAnnotationOnPath) { - classpath { pathelement(path: 'buildAnnotatedClass') } + ant.groovy(scriptParamNameCheck) { + classpath { pathelement(path: 'build') } } } }