|
18 | 18 | */ |
19 | 19 | package org.codehaus.groovy.control.customizers |
20 | 20 |
|
| 21 | +import groovy.transform.AnnotationCollector |
21 | 22 | import groovy.transform.AutoFinal |
22 | 23 | import groovy.transform.CompilationUnitAware |
23 | 24 | import groovy.transform.CompileStatic |
@@ -195,22 +196,87 @@ class ASTTransformationCustomizer extends CompilationCustomizer implements Compi |
195 | 196 |
|
196 | 197 | @SuppressWarnings('ClassForName') |
197 | 198 | private static Class<ASTTransformation> findASTTransformationClass(Class<? extends Annotation> anAnnotationClass, ClassLoader transformationClassLoader) { |
| 199 | + List<Class<ASTTransformation>> classes = findASTTransformationClasses(anAnnotationClass, transformationClassLoader) |
| 200 | + if (classes.size() > 1) { |
| 201 | + throw new IllegalArgumentException("AST transformation customizer doesn't support AST transforms with multiple classes; use ASTTransformationCustomizer.forAnnotation(...) to obtain one customizer per transform class") |
| 202 | + } |
| 203 | + classes[0] |
| 204 | + } |
| 205 | + |
| 206 | + @SuppressWarnings('ClassForName') |
| 207 | + private static List<Class<ASTTransformation>> findASTTransformationClasses(Class<? extends Annotation> anAnnotationClass, ClassLoader transformationClassLoader) { |
198 | 208 | GroovyASTTransformationClass annotation = anAnnotationClass.getAnnotation(GroovyASTTransformationClass) |
199 | 209 | if (annotation == null) throw new IllegalArgumentException("Provided class doesn't look like an AST @interface") |
200 | 210 |
|
201 | | - Class[] classes = annotation.classes() |
202 | | - String[] classesAsStrings = annotation.value() |
203 | | - if (classes.length + classesAsStrings.length > 1) { |
204 | | - throw new IllegalArgumentException("AST transformation customizer doesn't support AST transforms with multiple classes") |
| 211 | + ClassLoader loader = transformationClassLoader ?: anAnnotationClass.classLoader |
| 212 | + List<Class<ASTTransformation>> result = [] |
| 213 | + annotation.classes().each { Class c -> result << (c as Class<ASTTransformation>) } |
| 214 | + annotation.value().each { String name -> result << (Class.forName(name, true, loader) as Class<ASTTransformation>) } |
| 215 | + if (result.isEmpty()) { |
| 216 | + throw new IllegalArgumentException("No AST transformation class found for ${anAnnotationClass.name}") |
205 | 217 | } |
206 | | - classes ? classes[0] : (Class) Class.forName(classesAsStrings[0], true, transformationClassLoader ?: anAnnotationClass.classLoader) |
| 218 | + result |
207 | 219 | } |
208 | 220 |
|
209 | 221 | @SuppressWarnings('ClassForName') |
210 | 222 | private static Class<ASTTransformation> findASTTransformationClass(Class<? extends Annotation> anAnnotationClass, String astTransformationClassName, ClassLoader transformationClassLoader) { |
211 | 223 | Class.forName(astTransformationClassName, true, transformationClassLoader ?: anAnnotationClass.classLoader) as Class<ASTTransformation> |
212 | 224 | } |
213 | 225 |
|
| 226 | + /** |
| 227 | + * Creates one {@link ASTTransformationCustomizer} per AST transformation class declared by the |
| 228 | + * given annotation's {@link GroovyASTTransformationClass} list. This is the way to use the |
| 229 | + * customizer with annotations whose implementation is split across multiple transforms running |
| 230 | + * at different compile phases (e.g. {@link groovy.transform.Sealed}, {@link groovy.transform.RecordBase}). |
| 231 | + * <p> |
| 232 | + * Spread the result into {@link org.codehaus.groovy.control.CompilerConfiguration#addCompilationCustomizers}: |
| 233 | + * <pre> |
| 234 | + * configuration.addCompilationCustomizers(*ASTTransformationCustomizer.forAnnotation(Sealed)) |
| 235 | + * </pre> |
| 236 | + * |
| 237 | + * @since 6.0.0 |
| 238 | + */ |
| 239 | + static List<ASTTransformationCustomizer> forAnnotation(Class<? extends Annotation> transformationAnnotation) { |
| 240 | + forAnnotation([:], transformationAnnotation, transformationAnnotation.classLoader) |
| 241 | + } |
| 242 | + |
| 243 | + /** |
| 244 | + * @see #forAnnotation(Class) |
| 245 | + * @since 6.0.0 |
| 246 | + */ |
| 247 | + static List<ASTTransformationCustomizer> forAnnotation(Class<? extends Annotation> transformationAnnotation, ClassLoader transformationClassLoader) { |
| 248 | + forAnnotation([:], transformationAnnotation, transformationClassLoader) |
| 249 | + } |
| 250 | + |
| 251 | + /** |
| 252 | + * @see #forAnnotation(Class) |
| 253 | + * @since 6.0.0 |
| 254 | + */ |
| 255 | + static List<ASTTransformationCustomizer> forAnnotation(Map annotationParams, Class<? extends Annotation> transformationAnnotation) { |
| 256 | + forAnnotation(annotationParams, transformationAnnotation, transformationAnnotation.classLoader) |
| 257 | + } |
| 258 | + |
| 259 | + /** |
| 260 | + * @see #forAnnotation(Class) |
| 261 | + * @since 6.0.0 |
| 262 | + */ |
| 263 | + static List<ASTTransformationCustomizer> forAnnotation(Map annotationParams, Class<? extends Annotation> transformationAnnotation, ClassLoader transformationClassLoader) { |
| 264 | + // expand @AnnotationCollector aliases (e.g. @AutoExternalize -> @ExternalizeMethods + @ExternalizeVerifier) |
| 265 | + AnnotationCollector collector = transformationAnnotation.getAnnotation(AnnotationCollector) |
| 266 | + if (collector != null) { |
| 267 | + List<ASTTransformationCustomizer> result = [] |
| 268 | + for (Class<? extends Annotation> aliased : collector.value()) { |
| 269 | + result.addAll(forAnnotation(annotationParams, aliased, transformationClassLoader)) |
| 270 | + } |
| 271 | + return result |
| 272 | + } |
| 273 | + findASTTransformationClasses(transformationAnnotation, transformationClassLoader).collect { Class<ASTTransformation> txClass -> |
| 274 | + annotationParams |
| 275 | + ? new ASTTransformationCustomizer(annotationParams, transformationAnnotation, txClass.name, transformationClassLoader) |
| 276 | + : new ASTTransformationCustomizer(transformationAnnotation, txClass.name, transformationClassLoader) |
| 277 | + } |
| 278 | + } |
| 279 | + |
214 | 280 | private static CompilePhase findPhase(ASTTransformation transformation) { |
215 | 281 | if (transformation == null) throw new IllegalArgumentException('Provided transformation must not be null') |
216 | 282 | Class<?> clazz = transformation.class |
|
0 commit comments