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();
+ }
}