You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2018/11/10 07:29:09 UTC

[1/2] groovy git commit: GROOVY-8872: Populate the parameter names from the byte code when available (closes #820)

Repository: groovy
Updated Branches:
  refs/heads/master 603d6e711 -> 2193eaf8c


GROOVY-8872: Populate the parameter names from the byte code when available (closes #820)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/e1d5c7b6
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/e1d5c7b6
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/e1d5c7b6

Branch: refs/heads/master
Commit: e1d5c7b6de5ea24d0cea3fbebba18cabd0292a12
Parents: 603d6e7
Author: jameskleeh <ja...@gmail.com>
Authored: Thu Nov 8 23:44:59 2018 -0500
Committer: Paul King <pa...@asert.com.au>
Committed: Sat Nov 10 17:26:27 2018 +1000

----------------------------------------------------------------------
 .../groovy/ast/decompiled/AsmDecompiler.java    |  6 ++
 .../groovy/ast/decompiled/ClassStub.java        |  1 +
 .../ast/decompiled/MemberSignatureParser.java   | 10 ++-
 .../groovy/groovy/ant/Groovy8872Test.groovy     | 88 ++++++++++++++++++++
 4 files changed, 104 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/e1d5c7b6/src/main/java/org/codehaus/groovy/ast/decompiled/AsmDecompiler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/AsmDecompiler.java b/src/main/java/org/codehaus/groovy/ast/decompiled/AsmDecompiler.java
index 6286ff9..4e0f922 100644
--- a/src/main/java/org/codehaus/groovy/ast/decompiled/AsmDecompiler.java
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/AsmDecompiler.java
@@ -158,6 +158,12 @@ public abstract class AsmDecompiler {
                             }
                         };
                     }
+
+                    @Override
+                    public void visitParameter(String name, int access) {
+                        if (stub.parameterNames == null) stub.parameterNames = new ArrayList<String>();
+                        stub.parameterNames.add(name);
+                    }
                 };
             }
             return null;

http://git-wip-us.apache.org/repos/asf/groovy/blob/e1d5c7b6/src/main/java/org/codehaus/groovy/ast/decompiled/ClassStub.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/ClassStub.java b/src/main/java/org/codehaus/groovy/ast/decompiled/ClassStub.java
index 43b10df..96df728 100644
--- a/src/main/java/org/codehaus/groovy/ast/decompiled/ClassStub.java
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/ClassStub.java
@@ -65,6 +65,7 @@ class MethodStub extends MemberStub {
     final String signature;
     final String[] exceptions;
     Map<Integer, List<AnnotationStub>> parameterAnnotations;
+    List<String> parameterNames;
     Object annotationDefault;
 
     public MethodStub(String methodName, int accessModifiers, String desc, String signature, String[] exceptions) {

http://git-wip-us.apache.org/repos/asf/groovy/blob/e1d5c7b6/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java b/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java
index ecb1028..436c02c 100644
--- a/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java
@@ -97,8 +97,16 @@ class MemberSignatureParser {
         }
 
         Parameter[] parameters = new Parameter[parameterTypes.length];
+        List<String> parameterNames = method.parameterNames;
         for (int i = 0; i < parameterTypes.length; i++) {
-            parameters[i] = new Parameter(parameterTypes[i], "param" + i);
+            String parameterName = "param" + i;
+            if (parameterNames != null && i < parameterNames.size()) {
+                String decompiledName = parameterNames.get(i);
+                if (decompiledName != null) {
+                    parameterName = decompiledName;
+                }
+            }
+            parameters[i] = new Parameter(parameterTypes[i], parameterName);
         }
 
         if (method.parameterAnnotations != null) {

http://git-wip-us.apache.org/repos/asf/groovy/blob/e1d5c7b6/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
new file mode 100644
index 0000000..1cd46e7
--- /dev/null
+++ b/subprojects/groovy-ant/src/test/groovy/groovy/ant/Groovy8872Test.groovy
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+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
+    '''
+
+    private scriptNoAnnotationOnPath = '''
+    // class should be usable but won't have annotations
+    assert !AnnotatedClass.annotations
+    '''
+
+    void testCreateZip() {
+//        def debugLogger = new org.apache.tools.ant.DefaultLogger()
+//        debugLogger.setMessageOutputLevel(4)
+//        debugLogger.setOutputPrintStream(System.out)
+//        debugLogger.setErrorPrintStream(System.err)
+
+        doInTmpDir { ant, baseDir ->
+            baseDir.src {
+                'ValueClass.java'('''
+                    public class ValueClass{ }
+                ''')
+                'MyAnnotation.java'('''
+                    import java.lang.annotation.*;
+
+                    @Target(ElementType.TYPE)
+                    @Retention(RetentionPolicy.RUNTIME)
+                    public @interface MyAnnotation {
+                        Class<ValueClass> value();
+                    }
+                ''')
+                'AnnotatedClass.java'('''
+                    @MyAnnotation(ValueClass.class)
+                    class AnnotatedClass { }
+                ''')
+            }
+//            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")
+            }
+            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') }
+            }
+        }
+    }
+}


[2/2] groovy git commit: GROOVY-8872: Populate the parameter names from the byte code when available (add test)

Posted by pa...@apache.org.
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/2193eaf8
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/2193eaf8
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/2193eaf8

Branch: refs/heads/master
Commit: 2193eaf8cc454d0d6e38fa02d32271a24d6b43da
Parents: e1d5c7b
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 17:28:56 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/2193eaf8/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 2e6ebea..06755ee 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
@@ -622,6 +622,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/2193eaf8/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') }
             }
         }
     }