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 2017/10/09 06:09:16 UTC

[3/4] groovy git commit: GROOVY-8347: @AutoFinal: Added support to auto-finalize closure parameters (allow disabling)

GROOVY-8347: @AutoFinal: Added support to auto-finalize closure parameters (allow disabling)


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

Branch: refs/heads/GROOVY_2_6_X
Commit: 7fa676088b5ca53efb7195b7f0e062f7815d7b6a
Parents: bb8f031
Author: paulk <pa...@asert.com.au>
Authored: Mon Oct 9 11:43:23 2017 +1000
Committer: paulk <pa...@asert.com.au>
Committed: Mon Oct 9 16:08:57 2017 +1000

----------------------------------------------------------------------
 src/main/groovy/transform/AutoFinal.java        | 17 +++++-
 .../transform/AutoFinalASTTransformation.java   | 61 ++++++++++++--------
 2 files changed, 52 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/7fa67608/src/main/groovy/transform/AutoFinal.java
----------------------------------------------------------------------
diff --git a/src/main/groovy/transform/AutoFinal.java b/src/main/groovy/transform/AutoFinal.java
index 1cc0ab6..58ce3ba 100644
--- a/src/main/groovy/transform/AutoFinal.java
+++ b/src/main/groovy/transform/AutoFinal.java
@@ -30,9 +30,11 @@ import java.lang.annotation.Target;
  * Annotation to automatically add the final qualifier to method, constructor,
  * and closure parameters.
  * <p>The annotation can be placed at the class level in which case it applies to
- * all methods, constructors, and closures within the class. It can also be applied
- * to an individual method, constructor, field with a Closure initial value
- * or a Closure assigned to a local variable.
+ * all methods, constructors, and closures within the class and any inner classes.
+ * It can also be applied to an individual method, constructor, field with a
+ * Closure initial value or a Closure assigned to a local variable. In the case
+ * of fields (or local variables) it only adjusts the parameters of the referenced
+ * Closure not the field (or local variable) itself.
  * <p>If you wish to automatically apply the
  * annotation to all classes of a project, consider using
  * {@code groovyc --configscript}. Google "Customising The Groovy Compiler",
@@ -85,4 +87,13 @@ import java.lang.annotation.Target;
 @Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE})
 @GroovyASTTransformationClass("org.codehaus.groovy.transform.AutoFinalASTTransformation")
 public @interface AutoFinal {
+    /**
+     * Indicates that adding final to parameters should not be applied on this node.
+     * <p>Normally not required since leaving off the annotation will achieve the same affect.
+     * However, it can be useful for selectively disabling this annotation in just a small part
+     * of an otherwise annotated class. As an example, it would make sense to set this to {@code false} on
+     * a method which altered parameters in a class already marked as {@code @AutoFinal}.
+     * All nodes in the class except that single method would be processed.
+     */
+    boolean enabled() default true;
 }

http://git-wip-us.apache.org/repos/asf/groovy/blob/7fa67608/src/main/org/codehaus/groovy/transform/AutoFinalASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/AutoFinalASTTransformation.java b/src/main/org/codehaus/groovy/transform/AutoFinalASTTransformation.java
index 4055f72..3717d24 100644
--- a/src/main/org/codehaus/groovy/transform/AutoFinalASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/AutoFinalASTTransformation.java
@@ -36,6 +36,7 @@ import org.codehaus.groovy.control.SourceUnit;
 
 import java.lang.reflect.Modifier;
 import java.util.Iterator;
+import java.util.List;
 
 import static org.codehaus.groovy.ast.ClassHelper.make;
 
@@ -104,34 +105,18 @@ public class AutoFinalASTTransformation extends AbstractASTTransformation {
         if (!MY_TYPE.equals(node.getClassNode())) return;
 
         if (candidate instanceof ClassNode) {
-            ClassNode cNode = (ClassNode) candidate;
-            processClass(cNode, visitor);
+            processClass((ClassNode) candidate, visitor);
         } else if (candidate instanceof MethodNode) {
-            // handles constructors and methods
-            MethodNode mNode = (MethodNode) candidate;
-            processConstructorOrMethod(mNode, visitor);
+            processConstructorOrMethod((MethodNode) candidate, visitor);
         } else if (candidate instanceof FieldNode) {
-            FieldNode fNode = (FieldNode) candidate;
-            processField(fNode, visitor);
+            processField((FieldNode) candidate, visitor);
         } else if (candidate instanceof DeclarationExpression) {
-            DeclarationExpression de = (DeclarationExpression) candidate;
-            processLocalVariable(de, visitor);
-        }
-    }
-
-    private void processLocalVariable(DeclarationExpression de, ClassCodeVisitorSupport visitor) {
-        if (de.getRightExpression() instanceof ClosureExpression) {
-            visitor.visitDeclarationExpression(de);
-        }
-    }
-
-    private void processField(FieldNode fNode, ClassCodeVisitorSupport visitor) {
-        if (fNode.hasInitialExpression() && fNode.getInitialExpression() instanceof ClosureExpression) {
-            visitor.visitField(fNode);
+            processLocalVariable((DeclarationExpression) candidate, visitor);
         }
     }
 
     private void processClass(ClassNode cNode, final ClassCodeVisitorSupport visitor) {
+        if (!isEnabled(cNode)) return;
         if (cNode.isInterface()) {
             addError("Error processing interface '" + cNode.getName() +
                     "'. " + MY_TYPE_NAME + " only allowed for classes.", cNode);
@@ -161,11 +146,22 @@ public class AutoFinalASTTransformation extends AbstractASTTransformation {
         visitor.visitClass(cNode);
     }
 
-    private boolean hasNoExplicitAutoFinal(AnnotatedNode node) {
-        return node.getAnnotations(MY_TYPE).isEmpty();
+    private void processLocalVariable(DeclarationExpression de, ClassCodeVisitorSupport visitor) {
+        if (!isEnabled(de)) return;
+        if (de.getRightExpression() instanceof ClosureExpression) {
+            visitor.visitDeclarationExpression(de);
+        }
+    }
+
+    private void processField(FieldNode fNode, ClassCodeVisitorSupport visitor) {
+        if (!isEnabled(fNode)) return;
+        if (fNode.hasInitialExpression() && fNode.getInitialExpression() instanceof ClosureExpression) {
+            visitor.visitField(fNode);
+        }
     }
 
     private void processConstructorOrMethod(MethodNode mNode, ClassCodeVisitorSupport visitor) {
+        if (!isEnabled(mNode)) return;
         if (mNode.isSynthetic()) return;
         Parameter[] origParams = mNode.getParameters();
         for (Parameter p : origParams) {
@@ -173,4 +169,23 @@ public class AutoFinalASTTransformation extends AbstractASTTransformation {
         }
         visitor.visitMethod(mNode);
     }
+
+    private boolean isEnabled(final AnnotatedNode node) {
+        if (node == null) return false;
+        List<AnnotationNode> annotations = node.getAnnotations(MY_TYPE);
+        if (annotations != null) {
+            // any explicit false for enabled disables functionality
+            // this allows, for example, configscript to set all
+            // classes to true and one class to be explicitly disabled
+            for (AnnotationNode anno : annotations) {
+                // abort if explicit false found
+                if (memberHasValue(anno, "enabled", false)) return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean hasNoExplicitAutoFinal(AnnotatedNode node) {
+        return node.getAnnotations(MY_TYPE).isEmpty();
+    }
 }