private void addPhaseOperations()

in src/main/java/org/codehaus/groovy/control/CompilationUnit.java [188:390]


    private void addPhaseOperations() {
        addPhaseOperation(SourceUnit::parse, Phases.PARSING);

        addPhaseOperation(source -> {
            source.convert();
            // add module to compile unit
            getAST().addModule(source.getAST());
            Optional.ofNullable(getProgressCallback())
                .ifPresent(callback -> callback.call(source, getPhase()));
        }, Phases.CONVERSION);

        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
            GroovyClassVisitor visitor = new EnumVisitor(this, source);
            visitor.visitClass(classNode);
        }, Phases.CONVERSION);
        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
            GroovyClassVisitor visitor = new PlaceholderVisitor(this, source);
            visitor.visitClass(classNode);
        }, Phases.CONVERSION);

        addPhaseOperation(source -> {
            try {
                resolveVisitor.phase = 1; // resolve head of each class
                resolveVisitor.setClassNodeResolver(classNodeResolver);
                for (ClassNode classNode : source.getAST().getClasses()) {
                    resolveVisitor.startResolving(classNode, source);
                }
            } finally {
                resolveVisitor.phase = 0;
            }
        }, Phases.SEMANTIC_ANALYSIS);

        addPhaseOperation(source -> {
            try {
                resolveVisitor.phase = 2; // resolve body of each class
                for (ClassNode classNode : source.getAST().getClasses()) {
                    resolveVisitor.startResolving(classNode, source);
                }
            } finally {
                resolveVisitor.phase = 0;
            }
        }, Phases.SEMANTIC_ANALYSIS);

        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
            GroovyClassVisitor visitor = new StaticImportVisitor(classNode, source);
            visitor.visitClass(classNode);
        }, Phases.SEMANTIC_ANALYSIS);

        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
            GroovyClassVisitor visitor = new InnerClassVisitor(this, source);
            visitor.visitClass(classNode);
        }, Phases.SEMANTIC_ANALYSIS);

        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
            if (!classNode.isSynthetic()) {
                GroovyClassVisitor visitor = new GenericsVisitor(source);
                visitor.visitClass(classNode);
            }
        }, Phases.SEMANTIC_ANALYSIS);

        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
            AnnotationCollectorTransform.ClassChanger xformer = new AnnotationCollectorTransform.ClassChanger();
            xformer.transformClass(classNode);
        }, Phases.SEMANTIC_ANALYSIS);

        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
            TraitComposer.doExtendTraits(classNode, source, this);
        }, Phases.CANONICALIZATION);

        addPhaseOperation(source -> {
            List<ClassNode> classes = source.getAST().getClasses();
            for (ClassNode node : classes) {
                CompileUnit cu = node.getCompileUnit();
                for (Iterator<String> it = cu.getClassesToCompile().keySet().iterator(); it.hasNext(); ) {
                    String name = it.next();
                    StringBuilder message = new StringBuilder("Compilation incomplete: expected to find the class ")
                            .append(name)
                            .append(" in ")
                            .append(source.getName())
                            .append(", but the file ");
                    if (classes.isEmpty()) {
                        message.append("seems not to contain any classes");
                    } else {
                        message.append("contains the classes: ");
                        boolean first = true;
                        for (ClassNode cn : classes) {
                            if (first) {
                                first = false;
                            } else {
                                message.append(", ");
                            }
                            message.append(cn.getName());
                        }
                    }

                    getErrorCollector().addErrorAndContinue(Message.create(message.toString(), this));

                    it.remove();
                }
            }
        }, Phases.CANONICALIZATION);

        addPhaseOperation(source -> {
            for (ClassNode cn : source.getAST().getClasses()) {
                // GROOVY-10540: add GroovyObject before STC and classgen
                if (!cn.isInterface() && !cn.isDerivedFromGroovyObject()) {
                    boolean cs = false, pojo = false, trait = false;
                    for (AnnotationNode an : cn.getAnnotations()) {
                        switch (an.getClassNode().getName()) {
                        case "groovy.transform.CompileStatic":
                            cs = true; break;
                        case "groovy.transform.stc.POJO":
                            pojo = true; break;
                        case "groovy.transform.Trait":
                            trait = true; break;
                        }
                    }
                    if (!(cs && pojo) && !trait)
                        cn.addInterface(ClassHelper.GROOVY_OBJECT_TYPE);
                }
            }
        }, Phases.INSTRUCTION_SELECTION);

        addPhaseOperation(verification, Phases.CLASS_GENERATION);

        addPhaseOperation(classgen, Phases.CLASS_GENERATION);

        addPhaseOperation(groovyClass -> {
            String name = groovyClass.getName().replace('.', File.separatorChar) + ".class";
            File path = new File(getConfiguration().getTargetDirectory(), name);

            // ensure the path is ready for the file
            File directory = path.getParentFile();
            if (directory != null && !directory.exists()) {
                directory.mkdirs();
            }

            // create the file and write out the data
            try (FileOutputStream stream = new FileOutputStream(path)) {
                stream.write(groovyClass.getBytes());
            } catch (IOException e) {
                getErrorCollector().addError(Message.create(e.getMessage(), this));
            }
        });

        ASTTransformationVisitor.addPhaseOperations(this);

        // post-transform operations:

        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
            StaticVerifier verifier = new StaticVerifier();
            verifier.visitClass(classNode, source);
        }, Phases.SEMANTIC_ANALYSIS);

        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
            GroovyClassVisitor visitor = new InnerClassCompletionVisitor(this, source);
            visitor.visitClass(classNode);

            visitor = new EnumCompletionVisitor(this, source);
            visitor.visitClass(classNode);
        }, Phases.CANONICALIZATION);

        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
            Object callback = classNode.getNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK);
            if (callback instanceof IPrimaryClassNodeOperation) {
                ((IPrimaryClassNodeOperation) callback).call(source, context, classNode);
                classNode.removeNodeMetaData(DYNAMIC_OUTER_NODE_CALLBACK);
            }
        }, Phases.INSTRUCTION_SELECTION);

        addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
            // TODO: Can this be moved into org.codehaus.groovy.transform.sc.transformers.VariableExpressionTransformer?
            GroovyClassVisitor visitor = new ClassCodeExpressionTransformer() {
                @Override
                protected SourceUnit getSourceUnit() {
                    return source;
                }

                @Override
                public Expression transform(final Expression expression) {
                    if (expression instanceof VariableExpression) {
                        // check for "switch(enumType) { case CONST: ... }"
                        ClassNode enumType = expression.getNodeMetaData(SWITCH_CONDITION_EXPRESSION_TYPE);
                        if (enumType != null) {
                            // replace "CONST" variable expression with "EnumType.CONST" property expression
                            Expression propertyExpression = propX(classX(enumType), expression.getText());
                            setSourcePosition(propertyExpression, expression);
                            return propertyExpression;
                        }
                    } else if (expression instanceof MethodCallExpression) {
                        // we wrap SwitchExpressions into a method call on a ClosureExpression
                        MethodCallExpression mce = (MethodCallExpression) expression;
                        if (mce.getObjectExpression() instanceof ClosureExpression) {
                            expression.visit(this);
                            return expression;
                        }
                    }
                    return expression;
                }
            };
            visitor.visitClass(classNode);
        }, Phases.INSTRUCTION_SELECTION);
    }