You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2022/06/10 17:50:53 UTC
[groovy] branch GROOVY_2_5_X updated: GROOVY-10654: `ASTTransformationCustomizer`: enum and array parameters
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
new da71231417 GROOVY-10654: `ASTTransformationCustomizer`: enum and array parameters
da71231417 is described below
commit da712314173eb69201ef08d0a850376fba16bdf7
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Jun 10 10:25:33 2022 -0500
GROOVY-10654: `ASTTransformationCustomizer`: enum and array parameters
2_5_X backport
---
.../customizers/ASTTransformationCustomizer.groovy | 104 ++++----
.../ASTTransformationCustomizerTest.groovy | 288 +++++++++++----------
2 files changed, 210 insertions(+), 182 deletions(-)
diff --git a/src/main/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizer.groovy b/src/main/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizer.groovy
index d6ac4aaccf..40591a3bae 100644
--- a/src/main/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizer.groovy
+++ b/src/main/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizer.groovy
@@ -18,14 +18,13 @@
*/
package org.codehaus.groovy.control.customizers
+import groovy.transform.AutoFinal
import groovy.transform.CompilationUnitAware
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.AnnotationNode
import org.codehaus.groovy.ast.ClassHelper
import org.codehaus.groovy.ast.ClassNode
-import org.codehaus.groovy.ast.expr.ClosureExpression
import org.codehaus.groovy.ast.expr.Expression
-import org.codehaus.groovy.ast.expr.ListExpression
import org.codehaus.groovy.classgen.GeneratorContext
import org.codehaus.groovy.control.CompilationUnit
import org.codehaus.groovy.control.CompilePhase
@@ -38,6 +37,8 @@ import java.lang.annotation.Annotation
import static org.codehaus.groovy.ast.tools.GeneralUtils.classX
import static org.codehaus.groovy.ast.tools.GeneralUtils.constX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.listX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
/**
* This customizer allows applying an AST transformation to a source unit with
@@ -82,12 +83,13 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.constX
* @since 1.8.0
*
*/
+@AutoFinal
class ASTTransformationCustomizer extends CompilationCustomizer implements CompilationUnitAware {
- private final AnnotationNode annotationNode
- final ASTTransformation transformation
+ private boolean applied // global xforms
protected CompilationUnit compilationUnit
- private boolean applied = false // used for global AST transformations
+ private final AnnotationNode annotationNode
+ final ASTTransformation transformation
/**
* Creates an AST transformation customizer using the specified annotation. The transformation classloader can
@@ -98,9 +100,9 @@ class ASTTransformationCustomizer extends CompilationCustomizer implements Compi
* @param astTransformationClassName
* @param transformationClassLoader
*/
- ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName, ClassLoader transformationClassLoader) {
+ ASTTransformationCustomizer(Class<? extends Annotation> transformationAnnotation, String astTransformationClassName, ClassLoader transformationClassLoader) {
super(findPhase(transformationAnnotation, astTransformationClassName, transformationClassLoader))
- final Class<ASTTransformation> clazz = findASTTransformationClass(transformationAnnotation, astTransformationClassName, transformationClassLoader)
+ Class<ASTTransformation> clazz = findASTTransformationClass(transformationAnnotation, astTransformationClassName, transformationClassLoader)
this.transformation = clazz.newInstance()
this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
}
@@ -112,7 +114,7 @@ class ASTTransformationCustomizer extends CompilationCustomizer implements Compi
* @param transformationAnnotation
* @param astTransformationClassName
*/
- ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName) {
+ ASTTransformationCustomizer(Class<? extends Annotation> transformationAnnotation, String astTransformationClassName) {
this(transformationAnnotation, astTransformationClassName, transformationAnnotation.classLoader)
}
@@ -126,15 +128,15 @@ class ASTTransformationCustomizer extends CompilationCustomizer implements Compi
* @param astTransformationClassName
* @param transformationClassLoader
*/
- ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName, ClassLoader transformationClassLoader) {
+ ASTTransformationCustomizer(Map annotationParams, Class<? extends Annotation> transformationAnnotation, String astTransformationClassName, ClassLoader transformationClassLoader) {
super(findPhase(transformationAnnotation, astTransformationClassName, transformationClassLoader))
- final Class<ASTTransformation> clazz = findASTTransformationClass(transformationAnnotation, astTransformationClassName, transformationClassLoader)
+ Class<ASTTransformation> clazz = findASTTransformationClass(transformationAnnotation, astTransformationClassName, transformationClassLoader)
this.transformation = clazz.newInstance()
this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
this.annotationParameters = annotationParams
}
- ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName) {
+ ASTTransformationCustomizer(Map annotationParams, Class<? extends Annotation> transformationAnnotation, String astTransformationClassName) {
this(annotationParams, transformationAnnotation, transformationAnnotation.classLoader)
}
@@ -144,9 +146,9 @@ class ASTTransformationCustomizer extends CompilationCustomizer implements Compi
* @param transformationAnnotation
* @param transformationClassLoader
*/
- ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation, ClassLoader transformationClassLoader) {
+ ASTTransformationCustomizer(Class<? extends Annotation> transformationAnnotation, ClassLoader transformationClassLoader) {
super(findPhase(transformationAnnotation, transformationClassLoader))
- final Class<ASTTransformation> clazz = findASTTransformationClass(transformationAnnotation, transformationClassLoader)
+ Class<ASTTransformation> clazz = findASTTransformationClass(transformationAnnotation, transformationClassLoader)
this.transformation = clazz.newInstance()
this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
}
@@ -155,14 +157,14 @@ class ASTTransformationCustomizer extends CompilationCustomizer implements Compi
* Creates an AST transformation customizer using the specified annotation.
* @param transformationAnnotation
*/
- ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation) {
+ ASTTransformationCustomizer(Class<? extends Annotation> transformationAnnotation) {
this(transformationAnnotation, transformationAnnotation.classLoader)
}
/**
* Creates an AST transformation customizer using the specified transformation.
*/
- ASTTransformationCustomizer(final ASTTransformation transformation) {
+ ASTTransformationCustomizer(ASTTransformation transformation) {
super(findPhase(transformation))
this.transformation = transformation
this.annotationNode = null
@@ -175,19 +177,19 @@ class ASTTransformationCustomizer extends CompilationCustomizer implements Compi
* @param transformationAnnotation
* @param transformationClassLoader
*/
- ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation, ClassLoader transformationClassLoader) {
+ ASTTransformationCustomizer(Map annotationParams, Class<? extends Annotation> transformationAnnotation, ClassLoader transformationClassLoader) {
super(findPhase(transformationAnnotation, transformationClassLoader))
- final Class<ASTTransformation> clazz = findASTTransformationClass(transformationAnnotation, transformationClassLoader)
+ Class<ASTTransformation> clazz = findASTTransformationClass(transformationAnnotation, transformationClassLoader)
this.transformation = clazz.newInstance()
this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
this.annotationParameters = annotationParams
}
- ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation) {
+ ASTTransformationCustomizer(Map annotationParams, Class<? extends Annotation> transformationAnnotation) {
this(annotationParams, transformationAnnotation, transformationAnnotation.classLoader)
}
- ASTTransformationCustomizer(final Map annotationParams, final ASTTransformation transformation) {
+ ASTTransformationCustomizer(Map annotationParams, ASTTransformation transformation) {
this(transformation)
this.annotationParameters = annotationParams
}
@@ -198,7 +200,7 @@ class ASTTransformationCustomizer extends CompilationCustomizer implements Compi
@SuppressWarnings('ClassForName')
private static Class<ASTTransformation> findASTTransformationClass(Class<? extends Annotation> anAnnotationClass, ClassLoader transformationClassLoader) {
- final GroovyASTTransformationClass annotation = anAnnotationClass.getAnnotation(GroovyASTTransformationClass)
+ GroovyASTTransformationClass annotation = anAnnotationClass.getAnnotation(GroovyASTTransformationClass)
if (annotation == null) throw new IllegalArgumentException("Provided class doesn't look like an AST @interface")
Class[] classes = annotation.classes()
@@ -216,8 +218,8 @@ class ASTTransformationCustomizer extends CompilationCustomizer implements Compi
private static CompilePhase findPhase(ASTTransformation transformation) {
if (transformation == null) throw new IllegalArgumentException('Provided transformation must not be null')
- final Class<?> clazz = transformation.class
- final GroovyASTTransformation annotation = clazz.getAnnotation(GroovyASTTransformation)
+ Class<?> clazz = transformation.class
+ GroovyASTTransformation annotation = clazz.getAnnotation(GroovyASTTransformation)
if (annotation == null) throw new IllegalArgumentException("Provided ast transformation is not annotated with $GroovyASTTransformation.name")
annotation.phase()
@@ -236,57 +238,59 @@ class ASTTransformationCustomizer extends CompilationCustomizer implements Compi
}
/**
- * Specify annotation parameters. For example, if the annotation is :
+ * Specify annotation parameters. For example, if the annotation is:
* <pre>@Log(value='logger')</pre>
* You could create an AST transformation customizer and specify the "value" parameter thanks to this method:
- * <pre>annotationParameters = [value: 'logger']
+ * <pre>annotationParameters = [value: 'logger']</pre>
*
* Note that you cannot specify annotation closure values directly. If the annotation you want to add takes
* a closure as an argument, you will have to set a {@link ClosureExpression} instead. This can be done by either
* creating a custom {@link ClosureExpression} from code, or using the {@link org.codehaus.groovy.ast.builder.AstBuilder}.
- *
- * Here is an example :
+ * <p>
+ * Here is an example:
* <pre>
- * // add @Contract({distance >= 0 })
- * customizer = new ASTTransformationCustomizer(Contract)
- * final expression = new AstBuilder().buildFromCode(CompilePhase.CONVERSION) {->
- * distance >= 0
- * }.expression[0]
- * customizer.annotationParameters = [value: expression]</pre>
+ * // add @Contract({distance >= 0 })
+ * def customizer = new ASTTransformationCustomizer(Contract)
+ * def expression = new AstBuilder().buildFromCode(CompilePhase.CONVERSION) { ->
+ * distance >= 0
+ * }.expression[0]
+ * customizer.annotationParameters = [value: expression]</pre>
*
* @param params the annotation parameters
*
* @since 1.8.1
*/
- @SuppressWarnings('Instanceof')
void setAnnotationParameters(Map<String, Object> params) {
- if (params == null || annotationNode == null) return
- params.each { key, value ->
- if (!annotationNode.classNode.getMethod(key)) {
- throw new IllegalArgumentException("${annotationNode.classNode.name} does not accept any [$key] parameter")
+ if (annotationNode == null || params == null || params.isEmpty()) return
+ params.each { name, value ->
+ if (!annotationNode.classNode.getMethod(name)) {
+ throw new IllegalArgumentException("${annotationNode.classNode.name} does not accept any [$name] parameter")
}
if (value instanceof Closure) {
- throw new IllegalArgumentException('Direct usage of closure is not supported by the AST ' +
- 'compilation customizer. Please use ClosureExpression instead.')
- } else if (value instanceof Expression) {
+ throw new IllegalArgumentException('Direct usage of closure is not supported by the AST compilation customizer. Please use ClosureExpression instead.')
+ }
+
+ Expression valueExpression
+
+ if (value instanceof Expression) {
+ valueExpression = value
// avoid NPEs due to missing source code
- value.lineNumber = 0
- value.lastLineNumber = 0
- annotationNode.addMember(key, value)
+ value.lineNumber = 0; value.lastLineNumber = 0
} else if (value instanceof Class) {
- annotationNode.addMember(key, classX(value))
- } else if (value instanceof List) {
- annotationNode.addMember(key, new ListExpression(value.collect {
- it instanceof Class ? classX(it) : constX(it)
- }))
+ valueExpression = classX(value)
+ } else if (value instanceof Enum) {
+ valueExpression = propX(classX(ClassHelper.make(value.getClass())), value.toString())
+ } else if (value instanceof List || value.getClass().isArray()) {
+ valueExpression = listX(value.collect { it instanceof Class ? classX(it) : constX(it) })
} else {
- annotationNode.addMember(key, constX(value))
+ valueExpression = constX(value)
}
+
+ annotationNode.addMember(name, valueExpression)
}
}
@Override
- @SuppressWarnings('Instanceof')
void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
if (transformation instanceof CompilationUnitAware) {
transformation.compilationUnit = compilationUnit
diff --git a/src/test/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy b/src/test/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy
index 8b6caa6ad1..cb30c55f9e 100644
--- a/src/test/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy
+++ b/src/test/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy
@@ -18,224 +18,248 @@
*/
package org.codehaus.groovy.control.customizers
+import groovy.transform.ConditionalInterrupt
import groovy.transform.TimedInterrupt
+import groovy.util.logging.Log
+import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.ClassHelper
-import org.codehaus.groovy.ast.expr.ClassExpression
-import org.codehaus.groovy.ast.expr.PropertyExpression
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.builder.AstBuilder
+import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.control.CompilerConfiguration
-import groovy.util.logging.Log
-
-import java.util.concurrent.TimeUnit
-import java.util.logging.Logger
+import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.transform.ASTTransformation
import org.codehaus.groovy.transform.GroovyASTTransformation
-import org.codehaus.groovy.control.CompilePhase
-import java.util.concurrent.atomic.AtomicBoolean
-import org.codehaus.groovy.ast.ASTNode
-import org.codehaus.groovy.control.SourceUnit
-import java.lang.annotation.Retention
-import java.lang.annotation.Target
import org.codehaus.groovy.transform.GroovyASTTransformationClass
+import org.junit.Test
+
import java.lang.annotation.ElementType
+import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
-import org.codehaus.groovy.ast.ClassNode
-import org.objectweb.asm.Opcodes
-import org.codehaus.groovy.ast.builder.AstBuilder
-import groovy.transform.ConditionalInterrupt
+import java.lang.annotation.Target
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicBoolean
+
+import static groovy.test.GroovyAssert.shouldFail
+import static org.codehaus.groovy.ast.tools.GeneralUtils.classX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
/**
* Tests the {@link ASTTransformationCustomizer}.
*/
-class ASTTransformationCustomizerTest extends GroovyTestCase {
- CompilerConfiguration configuration
- ASTTransformationCustomizer customizer
+final class ASTTransformationCustomizerTest {
- void setUp() {
- configuration = new CompilerConfiguration()
- }
+ private final CompilerConfiguration config = new CompilerConfiguration()
+ private final GroovyShell shell = new GroovyShell(config)
+ @Test
void testLocalTransformation() {
- customizer = new ASTTransformationCustomizer(Log)
- configuration.addCompilationCustomizers(customizer)
- def shell = new GroovyShell(configuration)
- def result = shell.evaluate("""
+ def customizer = new ASTTransformationCustomizer(Log)
+ config.addCompilationCustomizers(customizer)
+ def result = shell.evaluate '''
class MyClass {}
new MyClass()
- """)
- assert result.log.class == Logger
+ '''
+ assert result.log.class == java.util.logging.Logger
}
- void testLocalTransformationAndCustomClassLoader() {
- ClassLoader loader = new URLClassLoader([]as URL[]) {
+ @Test
+ void testLocalTransformationClassLoader() {
+ def loader = new URLClassLoader() {
@Override
Class<?> loadClass(String name) {
- null
}
}
shouldFail(ClassNotFoundException) {
- customizer = new ASTTransformationCustomizer(Log, loader)
+ new ASTTransformationCustomizer(Log, loader)
}
}
- void testLocalTransformationWithAnnotationParameter() {
- customizer = new ASTTransformationCustomizer(Log)
+ @Test
+ void testLocalTransformationStringParameter() {
+ def customizer = new ASTTransformationCustomizer(Log)
customizer.annotationParameters = [value: 'logger']
- configuration.addCompilationCustomizers(customizer)
- def shell = new GroovyShell(configuration)
- def result = shell.evaluate("""
+ config.addCompilationCustomizers(customizer)
+ def result = shell.evaluate '''
class MyClass {}
new MyClass()
- """)
- assert result.logger.class == Logger
+ '''
+ assert result.logger.class == java.util.logging.Logger
}
- void testLocalTransformationWithInvalidAnnotationParameter() {
- customizer = new ASTTransformationCustomizer(Log)
+ @Test
+ void testLocalTransformationUnknownParameter() {
+ def customizer = new ASTTransformationCustomizer(Log)
shouldFail(IllegalArgumentException) {
customizer.annotationParameters = [invalid: 'logger']
}
}
- void testLocalTransformationWithClosureAnnotationParameter() {
- // add @Contract({distance = 1 })
- customizer = new ASTTransformationCustomizer(Contract)
- final expression = new AstBuilder().buildFromCode(CompilePhase.CONVERSION) {->
- distance = 1
- }.expression[0]
+ @Test
+ void testLocalTransformationListOfClassParameter() {
+ def customizer = new ASTTransformationCustomizer(Newify)
+ customizer.annotationParameters = [value: [Integer, Long]]
+ config.addCompilationCustomizers(customizer)
+ def result = shell.evaluate '''
+ Integer(11) + Long(31)
+ '''
+ assert result == 42
+ }
+
+ @Test
+ void testLocalTransformationArrayOfClassParameter() {
+ def customizer = new ASTTransformationCustomizer(Newify)
+ customizer.annotationParameters = [value: [Integer, Long] as Class[]]
+ config.addCompilationCustomizers(customizer)
+ def result = shell.evaluate '''
+ Integer(11) + Long(31)
+ '''
+ assert result == 42
+ }
+
+ @Test
+ void testLocalTransformationClosureExpressionParameter() {
+ // add @ConditionalInterrupt(value={ true }, thrown=SecurityException)
+ def expression = new AstBuilder().buildFromCode(CompilePhase.CONVERSION) { -> true }.expression[0]
+ def customizer = new ASTTransformationCustomizer(ConditionalInterrupt, value: expression, thrown: SecurityException)
+ config.addCompilationCustomizers(customizer)
+ shouldFail(SecurityException) {
+ shell.evaluate '''
+ class MyClass {
+ void doIt() { }
+ }
+ new MyClass().doIt()
+ '''
+ }
+ }
+
+ @Test
+ void testLocalTransformationClosureExpressionParameter2() {
+ // add @Contract({ distance = 1 })
+ def expression = new AstBuilder().buildFromCode(CompilePhase.CONVERSION) { -> distance = 1 }.expression[0]
+ def customizer = new ASTTransformationCustomizer(Contract)
customizer.annotationParameters = [value: expression]
- configuration.addCompilationCustomizers(customizer)
- def shell = new GroovyShell(configuration)
- def result = shell.evaluate("""
+ config.addCompilationCustomizers(customizer)
+ def result = shell.evaluate '''
class MyClass {
int distance
MyClass() {}
}
new MyClass()
- """)
+ '''
assert result.distance == 1
}
- void testLocalTransformationWithClosureAnnotationParameter_notAnnotatedAsASTInterface() {
- // add @Contract2({distance = 1 })
- customizer = new ASTTransformationCustomizer(Contract2, "org.codehaus.groovy.control.customizers.ContractAnnotation")
- final expression = new AstBuilder().buildFromCode(CompilePhase.CONVERSION) {->
- distance = 1
- }.expression[0]
+ @Test
+ void testLocalTransformationClosureExpressionParameter3() {
+ // add @Contract2({ distance = 1 })
+ def expression = new AstBuilder().buildFromCode(CompilePhase.CONVERSION) { -> distance = 1 }.expression[0]
+ def customizer = new ASTTransformationCustomizer(Contract2, 'org.codehaus.groovy.control.customizers.ContractAnnotation')
customizer.annotationParameters = [value: expression]
- configuration.addCompilationCustomizers(customizer)
- def shell = new GroovyShell(configuration)
- def result = shell.evaluate("""
+ config.addCompilationCustomizers(customizer)
+ def result = shell.evaluate '''
class MyClass {
int distance
MyClass() {}
}
new MyClass()
- """)
+ '''
assert result.distance == 1
}
- void testLocalTransformationWithClassAnnotationParameter() {
- // add @ConditionalInterrupt(value={ true }, thrown=SecurityException)
- final expression = new AstBuilder().buildFromCode(CompilePhase.CONVERSION) {->
- true
- }.expression[0]
- customizer = new ASTTransformationCustomizer(ConditionalInterrupt, value:expression, thrown:SecurityException)
- configuration.addCompilationCustomizers(customizer)
- def shell = new GroovyShell(configuration)
- shouldFail(SecurityException) {
- shell.evaluate("""
- class MyClass {
- void doIt() { }
+ @Test
+ void testLocalTransformationPropertyExpressionParameter() {
+ def customizer = new ASTTransformationCustomizer(TimedInterrupt)
+ customizer.annotationParameters = [value: 300, unit: propX(classX(ClassHelper.make(TimeUnit)),'MILLISECONDS')]
+ config.addCompilationCustomizers(customizer)
+ assert shell.evaluate('''import java.util.concurrent.TimeoutException
+ boolean interrupted = false
+ try {
+ 10.times {
+ sleep 100
}
- new MyClass().doIt()
- """)
- }
+ } catch (TimeoutException ignore) {
+ interrupted = true
+ }
+ interrupted
+ ''')
}
+ @Test // GROOVY-10654
+ void testLocalTransformationEnumerationConstantParameter() {
+ def customizer = new ASTTransformationCustomizer(TimedInterrupt)
+ customizer.annotationParameters = [value: 300, unit: TimeUnit.MILLISECONDS]
+ config.addCompilationCustomizers(customizer)
+ assert shell.evaluate('''import java.util.concurrent.TimeoutException
+ boolean interrupted = false
+ try {
+ 10.times {
+ sleep 100
+ }
+ } catch (TimeoutException ignore) {
+ interrupted = true
+ }
+ interrupted
+ ''')
+ }
+
+ //--------------------------------------------------------------------------
+
+ @Test
void testGlobalTransformation() {
- final TestTransformation transformation = new TestTransformation()
- customizer = new ASTTransformationCustomizer(transformation)
- configuration.addCompilationCustomizers(customizer)
- def shell = new GroovyShell(configuration)
+ TestTransformation transformation = new TestTransformation()
+ config.addCompilationCustomizers(new ASTTransformationCustomizer(transformation))
assert shell.evaluate('true')
- assert transformation.applied.get()
+ assert transformation.applied
}
+ @Test
void testGlobalTransformation2() {
- final TestTransformation transformation = new TestTransformation()
- customizer = new ASTTransformationCustomizer(transformation)
- configuration.addCompilationCustomizers(customizer)
- def shell = new GroovyShell(configuration)
- assert shell.evaluate("""
+ TestTransformation transformation = new TestTransformation()
+ config.addCompilationCustomizers(new ASTTransformationCustomizer(transformation))
+ assert shell.evaluate('''
class A {}
class B {}
true
- """)
- assert transformation.applied.get()
- }
-
- void testLocalTransformationWithListOfClassAnnotationParameter() {
- customizer = new ASTTransformationCustomizer(Newify, value: [Integer, Long])
- configuration.addCompilationCustomizers(customizer)
- def shell = new GroovyShell(configuration)
- def result = shell.evaluate '''
- Integer(11) + Long(31)
- '''
- assert result == 42
- }
-
- void testAnyExpressionAsParameterValue() {
- customizer = new ASTTransformationCustomizer(value:100, unit: new PropertyExpression(new ClassExpression(ClassHelper.make(TimeUnit)),'MILLISECONDS'), TimedInterrupt)
- configuration.addCompilationCustomizers(customizer)
- def shell = new GroovyShell(configuration)
- def result = shell.evaluate '''import java.util.concurrent.TimeoutException
-
-boolean interrupted = false
-try {
- 100.times {
- Thread.sleep(100)
- }
-} catch (TimeoutException e) {
- interrupted = true
-}
-
-interrupted'''
- assert result
+ ''')
+ assert transformation.applied
}
@GroovyASTTransformation(phase=CompilePhase.CONVERSION)
private static class TestTransformation implements ASTTransformation {
- private AtomicBoolean applied = new AtomicBoolean(false)
+ private final applied = new AtomicBoolean()
+
+ boolean isApplied() { return applied.get() }
+ @Override
void visit(ASTNode[] nodes, SourceUnit source) {
if (applied.getAndSet(true)) {
- throw new Exception("Global AST transformation should only be applied once")
+ throw new Exception('Global AST transformation should only be applied once')
}
}
-
}
-
-}
-
-@Retention(RetentionPolicy.SOURCE)
-@Target([ElementType.TYPE])
-@GroovyASTTransformationClass("org.codehaus.groovy.control.customizers.ContractAnnotation")
-protected @interface Contract {
- Class value();
}
@GroovyASTTransformation(phase=CompilePhase.CONVERSION)
-protected class ContractAnnotation implements ASTTransformation, Opcodes {
+protected class ContractAnnotation implements ASTTransformation {
+ @Override
void visit(ASTNode[] nodes, SourceUnit source) {
def node = nodes[0]
- def member = node.getMember("value")
- ((ClassNode)nodes[1]).getDeclaredConstructors()[0].code = member.code
+ def member = node.getMember('value')
+ ((ClassNode) nodes[1]).getDeclaredConstructors()[0].code = member.code
}
}
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.SOURCE)
+@GroovyASTTransformationClass('org.codehaus.groovy.control.customizers.ContractAnnotation')
+protected @interface Contract {
+ Class value();
+}
+
+@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
-@Target([ElementType.TYPE])
protected @interface Contract2 {
Class value();
}