// Path: asteroid-core/src/main/java/asteroid/utils/InternalUtils.java
// public static <T> List<T> collect(final Object iterable, final Closure<T> process) {
//     if (iterable == null) {
//         return new ArrayList<>();
//     }
// 
//     return DefaultGroovyMethods.collect(iterable, process);
// }
// 
// Path: asteroid-core/src/main/java/asteroid/A.java
// @SuppressWarnings("PMD.ShortClassName")
// public final class A {
// 
//     /**
//      * Entry point to get node builders.
//      *
//      * @since 0.1.0
//      */
//     public static final Nodes NODES = new Nodes();
// 
//     /**
//      * Entry point to access language modifiers
//      *
//      * @since 0.1.0
//      */
//     public static final Modifiers ACC = new Modifiers();
// 
//     /**
//      * Entry point to create statements.
//      *
//      * @since 0.1.0
//      */
//     public static final Statements STMT = new Statements();
// 
//     /**
//      * Entry point to create expressions
//      *
//      * @since 0.1.0
//      */
//     public static final Expressions EXPR = new Expressions();
// 
//     /**
//      * Entry point to get util functions
//      *
//      * @since 0.1.0
//      */
//     public static final Utils UTIL = new Utils();
// 
//     /**
//      * Entry point to get criterias
//      *
//      * @since 0.2.4
//      */
//     public static final Criterias CRITERIA = new Criterias();
// }


import static org.codehaus.groovy.runtime.DefaultGroovyMethods.first;
import static org.codehaus.groovy.runtime.DefaultGroovyMethods.last;
import static asteroid.utils.InternalUtils.collect;
import asteroid.A;
import asteroid.Local;
import groovy.lang.Closure;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.ListExpression;
import org.codehaus.groovy.ast.expr.PropertyExpression;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.transform.AbstractASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformationClass;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;
package asteroid.internal;




/**
 * Reduces the boiler plate code when declaring an annotation as possible target for a given
 * transformation.
 *
 * It adds code such as the {@link java.lang.annotation.Retention} and {@link java.lang.annotation.Target} annotations as well as the
 * {@link org.codehaus.groovy.transform.GroovyASTTransformationClass}.
 *
 * This code:
 *
 * <pre>
 * <code>
 *   import my.transformation.MyTransformation
 *
 *   {@literal @}Local(MyTransformation)
 *   public @interface MyAnnotation { }
 * </code>
 * </pre>
 *
 * Will become:
 *
 * <pre>
 * <code>
 *    {@literal @}Retention(RetentionPolicy.SOURCE)
 *    {@literal @}Target([ElementType.METHOD])
 *    {@literal @}GroovyASTTransformation("my.transformation.MyTransformation")
 *    public @interface MyAnnotation { }
 * </code>
 * </pre>
 *
 * @since 0.1.0
 *
 */
@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
public class LocalTransformation extends AbstractASTTransformation {

    /**
     * {@inheritDoc}
     *
     * @since 0.1.0
     */
    @Override
    public void visit(final ASTNode[] nodes, final SourceUnit source) {
        this.sourceUnit = source;

        if (!check(nodes)) {
            return;
        }

        final AnnotationNode annotationNode = A.UTIL.NODE.getFirstNodeAs(nodes, AnnotationNode.class);
        final ClassNode      annotatedNode  = A.UTIL.NODE.getLastNodeAs(nodes, ClassNode.class);

        addAnnotationsFromTo(annotationNode, annotatedNode);
    }

    private void addAnnotationsFromTo(final AnnotationNode annotationNode, final ClassNode annotatedNode) {
        final String qualifiedName = A.UTIL.NODE.get(annotationNode, String.class);
        final String target        = A.UTIL.NODE.get(annotationNode, "applyTo", String.class);

        annotatedNode.addAnnotation(getTargetAnnotation(target));
        annotatedNode.addAnnotation(getRetentionAnnotation());
        annotatedNode.addAnnotation(getGroovyAnnotationWith(qualifiedName));
    }

    private AnnotationNode getTargetAnnotation(final String resolvedTarget) {
        final List<ElementType> types = resolveAnnotationTarget(resolvedTarget);
// Path: asteroid-core/src/main/java/asteroid/utils/InternalUtils.java
// public static <T> List<T> collect(final Object iterable, final Closure<T> process) {
//     if (iterable == null) {
//         return new ArrayList<>();
//     }
// 
//     return DefaultGroovyMethods.collect(iterable, process);
// }
// 
// Path: asteroid-core/src/main/java/asteroid/A.java
// @SuppressWarnings("PMD.ShortClassName")
// public final class A {
// 
//     /**
//      * Entry point to get node builders.
//      *
//      * @since 0.1.0
//      */
//     public static final Nodes NODES = new Nodes();
// 
//     /**
//      * Entry point to access language modifiers
//      *
//      * @since 0.1.0
//      */
//     public static final Modifiers ACC = new Modifiers();
// 
//     /**
//      * Entry point to create statements.
//      *
//      * @since 0.1.0
//      */
//     public static final Statements STMT = new Statements();
// 
//     /**
//      * Entry point to create expressions
//      *
//      * @since 0.1.0
//      */
//     public static final Expressions EXPR = new Expressions();
// 
//     /**
//      * Entry point to get util functions
//      *
//      * @since 0.1.0
//      */
//     public static final Utils UTIL = new Utils();
// 
//     /**
//      * Entry point to get criterias
//      *
//      * @since 0.2.4
//      */
//     public static final Criterias CRITERIA = new Criterias();
// }


// Path: asteroid-core/src/main/java/asteroid/internal/LocalTransformation.java
import static org.codehaus.groovy.runtime.DefaultGroovyMethods.first;
import static org.codehaus.groovy.runtime.DefaultGroovyMethods.last;
import static asteroid.utils.InternalUtils.collect;
import asteroid.A;
import asteroid.Local;
import groovy.lang.Closure;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.expr.ClassExpression;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import org.codehaus.groovy.ast.expr.ListExpression;
import org.codehaus.groovy.ast.expr.PropertyExpression;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.transform.AbstractASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformation;
import org.codehaus.groovy.transform.GroovyASTTransformationClass;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.List;

package asteroid.internal;




/**
 * Reduces the boiler plate code when declaring an annotation as possible target for a given
 * transformation.
 *
 * It adds code such as the {@link java.lang.annotation.Retention} and {@link java.lang.annotation.Target} annotations as well as the
 * {@link org.codehaus.groovy.transform.GroovyASTTransformationClass}.
 *
 * This code:
 *
 * <pre>
 * <code>
 *   import my.transformation.MyTransformation
 *
 *   {@literal @}Local(MyTransformation)
 *   public @interface MyAnnotation { }
 * </code>
 * </pre>
 *
 * Will become:
 *
 * <pre>
 * <code>
 *    {@literal @}Retention(RetentionPolicy.SOURCE)
 *    {@literal @}Target([ElementType.METHOD])
 *    {@literal @}GroovyASTTransformation("my.transformation.MyTransformation")
 *    public @interface MyAnnotation { }
 * </code>
 * </pre>
 *
 * @since 0.1.0
 *
 */
@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
public class LocalTransformation extends AbstractASTTransformation {

    /**
     * {@inheritDoc}
     *
     * @since 0.1.0
     */
    @Override
    public void visit(final ASTNode[] nodes, final SourceUnit source) {
        this.sourceUnit = source;

        if (!check(nodes)) {
            return;
        }

        final AnnotationNode annotationNode = A.UTIL.NODE.getFirstNodeAs(nodes, AnnotationNode.class);
        final ClassNode      annotatedNode  = A.UTIL.NODE.getLastNodeAs(nodes, ClassNode.class);

        addAnnotationsFromTo(annotationNode, annotatedNode);
    }

    private void addAnnotationsFromTo(final AnnotationNode annotationNode, final ClassNode annotatedNode) {
        final String qualifiedName = A.UTIL.NODE.get(annotationNode, String.class);
        final String target        = A.UTIL.NODE.get(annotationNode, "applyTo", String.class);

        annotatedNode.addAnnotation(getTargetAnnotation(target));
        annotatedNode.addAnnotation(getRetentionAnnotation());
        annotatedNode.addAnnotation(getGroovyAnnotationWith(qualifiedName));
    }

    private AnnotationNode getTargetAnnotation(final String resolvedTarget) {
        final List<ElementType> types = resolveAnnotationTarget(resolvedTarget);
        final ListExpression listExpr = resolveTargetFromElementType(types);