This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY_5_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/GROOVY_5_0_X by this push:
new 2e03004d8a GROOVY-11865: collect array or list elements using
expression conversion
2e03004d8a is described below
commit 2e03004d8af99e9662ddcdafd064e5f236315556
Author: Eric Milles <[email protected]>
AuthorDate: Fri Feb 27 10:33:13 2026 -0600
GROOVY-11865: collect array or list elements using expression conversion
---
.../customizers/ASTTransformationCustomizer.groovy | 92 ++++++++++++----------
.../ASTTransformationCustomizerTest.groovy | 38 ++++++++-
2 files changed, 85 insertions(+), 45 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 2d43061410..7160440fae 100644
---
a/src/main/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizer.groovy
+++
b/src/main/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizer.groovy
@@ -20,7 +20,6 @@ package org.codehaus.groovy.control.customizers
import groovy.transform.AutoFinal
import groovy.transform.CompilationUnitAware
-import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.AnnotationNode
@@ -49,7 +48,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
* Creating a customizer with the {@link
ASTTransformationCustomizer#ASTTransformationCustomizer(Class)
* class constructor} will trigger an AST transformation for
* each class node of a source unit. However, you cannot pass parameters to
the annotation so the default values
- * will be used. Writing :
+ * will be used. Writing:
* <pre>
* def configuration = new CompilerConfiguration()
* configuration.addCompilationCustomizers(new
ASTTransformationCustomizer(Log))
@@ -60,8 +59,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
* }""")
* </pre>
*
- * is equivalent to :
- *
+ * is equivalent to:
* <pre>
* def shell = new GroovyShell()
* shell.evaluate("""
@@ -195,10 +193,6 @@ class ASTTransformationCustomizer extends
CompilationCustomizer implements Compi
this.annotationParameters = annotationParams
}
- void setCompilationUnit(CompilationUnit unit) {
- compilationUnit = unit
- }
-
@SuppressWarnings('ClassForName')
private static Class<ASTTransformation> findASTTransformationClass(Class<?
extends Annotation> anAnnotationClass, ClassLoader transformationClassLoader) {
GroovyASTTransformationClass annotation =
anAnnotationClass.getAnnotation(GroovyASTTransformationClass)
@@ -257,53 +251,69 @@ class ASTTransformationCustomizer extends
CompilationCustomizer implements Compi
* }.expression[0]
* customizer.annotationParameters = [value: expression]</pre>
*
- * @param params the annotation parameters
- *
* @since 1.8.1
*/
- @CompileDynamic
- void setAnnotationParameters(Map<String, Object> params) {
- if (annotationNode == null || params == null || params.isEmpty())
return
- params.each { name, value ->
- if (!annotationNode.classNode.getMethod(name)) {
+ void setAnnotationParameters(Map<String, Object> parameters) {
+ if (!annotationNode) return
+ for (entry in parameters) {
+ String name = entry.getKey()
+ if (annotationNode.classNode.getMethod(name) == null) {
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.')
- }
+ annotationNode.addMember(name, toExpression(entry.getValue()))
+ }
+ }
- Expression valueExpression
-
- if (value instanceof Expression) {
- valueExpression = value
- // avoid NPEs due to missing source code
- value.lineNumber = 0; value.lastLineNumber = 0
- } else if (value instanceof Class) {
- 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 {
- valueExpression = constX(value)
- }
+ private static Expression toExpression(Object value) {
+ if (value instanceof Expression) {
+ // avoid exceptions due to missing source code
+ value.lineNumber = 0; value.lastLineNumber = 0
+ return value
+ }
+
+ if (value instanceof Closure) {
+ throw new IllegalArgumentException('Direct usage of closure is not
supported by the AST compilation customizer. Please use ClosureExpression
instead.')
+ }
+
+ if (value instanceof Class) {
+ return classX(value)
+ }
+
+ if (value instanceof Enum) {
+ return propX(classX(value.getClass()), value.toString())
+ }
- annotationNode.addMember(name, valueExpression)
+ if (value instanceof List) {
+ return listX(value.collect(this.&toExpression)) // GROOVY-11865
}
+
+ if (value.getClass().isArray()) {
+ def array = value as Object[]
+ return listX(array.collect(this.&toExpression)) // GROOVY-11865
+ }
+
+ return constX(value, true)
+ }
+
+
//--------------------------------------------------------------------------
+
+ @Override
+ void setCompilationUnit(CompilationUnit compilationUnit) {
+ this.compilationUnit = compilationUnit
}
@Override
- void call(SourceUnit source, GeneratorContext context, ClassNode
classNode) {
- if (transformation instanceof CompilationUnitAware) {
- ((CompilationUnitAware) transformation).compilationUnit =
compilationUnit
+ void call(SourceUnit sourceUnit, GeneratorContext context, ClassNode
classNode) {
+ if (transformation instanceof CompilationUnitAware unitAware) {
+ unitAware.compilationUnit = compilationUnit
}
if (annotationNode != null) {
- // this is a local ast transformation which is applied on every
class node
annotationNode.sourcePosition = classNode
- transformation.visit([annotationNode, classNode] as ASTNode[],
source)
- } else {
+ // this is a local ast transformation which is applied on every
class node
+ transformation.visit(new ASTNode[]{annotationNode, classNode},
sourceUnit)
+ } else if (!applied) {
// this is a global AST transformation
- if (!applied) transformation.visit(null, source)
+ transformation.visit(null, sourceUnit)
}
applied = true
}
diff --git
a/src/test/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy
b/src/test/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy
index 0d15d1263c..deb60aa235 100644
---
a/src/test/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy
+++
b/src/test/groovy/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy
@@ -18,10 +18,9 @@
*/
package org.codehaus.groovy.control.customizers
-import groovy.transform.TimedInterrupt
+import groovy.transform.*
import groovy.util.logging.Log
import org.codehaus.groovy.ast.ASTNode
-import org.codehaus.groovy.ast.ClassHelper
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.SourceUnit
@@ -33,6 +32,7 @@ import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicBoolean
import static groovy.test.GroovyAssert.shouldFail
+import static groovy.transform.PackageScopeTarget.METHODS
import static org.codehaus.groovy.ast.tools.GeneralUtils.classX
import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
@@ -110,7 +110,7 @@ final class ASTTransformationCustomizerTest {
@Test
void testLocalTransformationPropertyExpressionParameter() {
def shell = GroovyShell.withConfig {
- ast(TimedInterrupt, value:300,
unit:propX(classX(ClassHelper.make(TimeUnit)),'MILLISECONDS'))
+ ast(TimedInterrupt, value:300,
unit:propX(classX(TimeUnit),'MILLISECONDS'))
imports { normal 'java.util.concurrent.TimeoutException' }
}
assert shell.evaluate('''
@@ -127,7 +127,8 @@ final class ASTTransformationCustomizerTest {
''')
}
- @Test // GROOVY-10654
+ // GROOVY-10654
+ @Test
void testLocalTransformationEnumerationConstantParameter() {
def shell = GroovyShell.withConfig {
ast(TimedInterrupt, value:300, unit:TimeUnit.MILLISECONDS)
@@ -147,6 +148,35 @@ final class ASTTransformationCustomizerTest {
''')
}
+ // GROOVY-11865
+ @Test
+ void testLocalTransformationListOfEnumerationConstantParameter() {
+ def shell = GroovyShell.withConfig {
+ ast(PackageScope, value: [PackageScopeTarget.CONSTRUCTORS,
METHODS])
+ imports { staticStar 'java.lang.reflect.Modifier' }
+ }
+ shell.evaluate '''
+ class C {
+ C() {
+ }
+ def m() {
+ }
+ }
+
+ int mods = C.getModifiers()
+
+ assert isPublic(mods)
+
+ mods = C.getDeclaredConstructors().first().getModifiers()
+
+ assert !isPublic(mods) && !isPrivate(mods) && !isProtected(mods)
+
+ mods = C.getDeclaredMethod('m').getModifiers()
+
+ assert !isPublic(mods) && !isPrivate(mods) && !isProtected(mods)
+ '''
+ }
+
//--------------------------------------------------------------------------
@Test