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 2016/04/22 07:37:04 UTC

[2/3] groovy git commit: implement delegation to method

implement delegation to method


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

Branch: refs/heads/master
Commit: 87fe7865e40718789ea9337e6b50c36f7e64dbc6
Parents: c7e6d4c
Author: oreissig <or...@gmail.com>
Authored: Mon Feb 15 20:12:25 2016 +0100
Committer: paulk <pa...@asert.com.au>
Committed: Fri Apr 22 15:35:25 2016 +1000

----------------------------------------------------------------------
 src/main/groovy/lang/Delegate.java              |  3 +-
 .../transform/DelegateASTTransformation.java    | 38 +++++++++++++++-----
 .../transform/DelegateTransformTest.groovy      | 20 +++++++++++
 3 files changed, 52 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/87fe7865/src/main/groovy/lang/Delegate.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/lang/Delegate.java b/src/main/groovy/lang/Delegate.java
index e0e556a..aa61d85 100644
--- a/src/main/groovy/lang/Delegate.java
+++ b/src/main/groovy/lang/Delegate.java
@@ -26,6 +26,7 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+// TODO update javadoc for use on a getter method
 /**
  * Field annotation to automatically delegate part of the functionality of an owner class to the annotated field.
  * <p>
@@ -128,7 +129,7 @@ import java.lang.annotation.Target;
  */
 @java.lang.annotation.Documented
 @Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.FIELD})
+@Target({ElementType.FIELD, ElementType.METHOD})
 @GroovyASTTransformationClass("org.codehaus.groovy.transform.DelegateASTTransformation")
 public @interface Delegate {
     /**

http://git-wip-us.apache.org/repos/asf/groovy/blob/87fe7865/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java b/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java
index 5447acd..7434d8c 100644
--- a/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java
@@ -49,6 +49,7 @@ import java.util.Set;
 import static org.codehaus.groovy.ast.ClassHelper.make;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.assignS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callThisX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getAllMethods;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getAllProperties;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getInterfacesAndSuperInterfaces;
@@ -96,25 +97,46 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
 
         AnnotatedNode parent = (AnnotatedNode) nodes[1];
         AnnotationNode node = (AnnotationNode) nodes[0];
+        DelegateDescription delegate = null;
 
         if (parent instanceof FieldNode) {
             FieldNode fieldNode = (FieldNode) parent;
 
-            DelegateDescription delegate = new DelegateDescription();
+            delegate = new DelegateDescription();
             delegate.delegate = fieldNode;
             delegate.annotation = node;
-            delegate.delegateName = fieldNode.getName();
+            delegate.name = fieldNode.getName();
             delegate.type = fieldNode.getType();
             delegate.owner = fieldNode.getOwner();
             delegate.getOp = varX(fieldNode);
+        } else if (parent instanceof MethodNode) {
+            MethodNode methodNode = (MethodNode) parent;
 
+            delegate = new DelegateDescription();
+            delegate.delegate = methodNode;
+            delegate.annotation = node;
+            delegate.name = methodNode.getName();
+            delegate.type = methodNode.getReturnType();
+            delegate.owner = methodNode.getDeclaringClass();
+            delegate.getOp = callThisX(delegate.name);
+
+            if (methodNode.getParameters().length > 0) {
+                addError("You can only delegate to methods that take no parameters, but " +
+                         delegate.name + " takes " + methodNode.getParameters().length +
+                         " parameters.", parent);
+                return;
+            }
+        }
+
+        if (delegate != null) {
+            // TODO may also be a method
             if (delegate.type.equals(ClassHelper.OBJECT_TYPE) || delegate.type.equals(GROOVYOBJECT_TYPE)) {
-                addError(MY_TYPE_NAME + " field '" + delegate.delegateName + "' has an inappropriate type: " + delegate.type.getName() +
+                addError(MY_TYPE_NAME + " field '" + delegate.name + "' has an inappropriate type: " + delegate.type.getName() +
                         ". Please add an explicit type but not java.lang.Object or groovy.lang.GroovyObject.", parent);
                 return;
             }
             if (delegate.type.equals(delegate.owner)) {
-                addError(MY_TYPE_NAME + " field '" + delegate.delegateName + "' has an inappropriate type: " + delegate.type.getName() +
+                addError(MY_TYPE_NAME + " field '" + delegate.name + "' has an inappropriate type: " + delegate.type.getName() +
                         ". Delegation to own type not supported. Please use a different type.", parent);
                 return;
             }
@@ -251,7 +273,7 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
             List<String> currentMethodGenPlaceholders = genericPlaceholderNames(candidate);
             for (int i = 0; i < newParams.length; i++) {
                 ClassNode newParamType = correctToGenericsSpecRecurse(genericsSpec, params[i].getType(), currentMethodGenPlaceholders);
-                Parameter newParam = new Parameter(newParamType, getParamName(params, i, delegate.delegateName));
+                Parameter newParam = new Parameter(newParamType, getParamName(params, i, delegate.name));
                 newParam.setInitialExpression(params[i].getInitialExpression());
 
                 if (memberHasValue(delegate.annotation, MEMBER_PARAMETER_ANNOTATIONS, true)) {
@@ -264,8 +286,8 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
             boolean alsoLazy = !delegate.delegate.getAnnotations(LAZY_TYPE).isEmpty();
             // addMethod will ignore attempts to override abstract or static methods with same signature on self
             MethodCallExpression mce = callX(
-                    alsoLazy ? propX(varX("this"), delegate.delegateName.substring(1)) :
-                    varX(delegate.delegateName, correctToGenericsSpecRecurse(genericsSpec, delegate.type)),
+                    // use propX when lazy, because lazy is only allowed on fields
+                    alsoLazy ? propX(varX("this"), delegate.name.substring(1)) : delegate.getOp,
                     candidate.getName(),
                     args);
             mce.setSourcePosition(delegate.delegate);
@@ -314,7 +336,7 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
     static class DelegateDescription {
         AnnotationNode annotation;
         AnnotatedNode delegate;
-        String delegateName;
+        String name;
         ClassNode type;
         ClassNode owner;
         Expression getOp;

http://git-wip-us.apache.org/repos/asf/groovy/blob/87fe7865/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy b/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
index 61b6ab2..45218ed 100644
--- a/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
@@ -745,6 +745,15 @@ assert foo.dm.x == '123'
             assert delegates.respondsTo('set$')
         '''
     }
+
+    void testDelegateToGetterMethod() {
+        // given:
+        def delegate = { new DelegateFooImpl() }
+        // when:
+        def foo = new FooToMethod(delegate)
+        // then:
+        assert foo.foo() == delegate().foo()
+    }
 }
 
 interface DelegateFoo {
@@ -784,6 +793,17 @@ class Foo4244 {
     @Delegate Bar4244 bar = new Bar4244()
 }
 
+class FooToMethod {
+    private final Closure<DelegateFoo> strategy
+
+    FooToMethod(Closure<DelegateFoo> strategy) {
+        this.strategy = strategy
+    }
+
+    @Delegate
+    DelegateFoo getStrategy() { strategy() }
+}
+
 class Bar4244 {
     String nonFinalBaz = "Initial value - nonFinalBaz"
     final String finalBaz = "Initial value - finalBaz"