private ClassNode createHelperClass()

in src/main/java/org/codehaus/groovy/transform/trait/TraitASTTransformation.java [186:323]


    private ClassNode createHelperClass(final ClassNode cNode) {
        cNode.setModifiers(ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE
                | (cNode.getOuterClass() != null ? ACC_STATIC : 0)); // GROOVY-11600

        ClassNode helper = new InnerClassNode(
                cNode,
                Traits.helperClassName(cNode),
                ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_SYNTHETIC,
                OBJECT_TYPE,
                ClassNode.EMPTY_ARRAY,
                null
        );
        helper.setGenericsTypes(cNode.getGenericsTypes());
        helper.setStaticClass(true); // GROOVY-7242, GROOVY-7456, etc.

        MethodNode initializer = createInitMethod(false, helper);
        MethodNode staticInitializer = createInitMethod(true, helper);

        // apply the verifier to have the property nodes generated
        for (PropertyNode pNode : cNode.getProperties()) {
            processProperty(cNode, pNode);
        }

        // prepare fields
        List<FieldNode> fields = new ArrayList<>();
        Set<String> fieldNames = new HashSet<>();
        boolean hasStatic = false;
        for (FieldNode field : cNode.getFields()) {
            if (!"metaClass".equals(field.getName()) && (!field.isSynthetic() || field.getName().indexOf('$') < 0)) {
                fields.add(field);
                fieldNames.add(field.getName());
                if (field.isStatic()) {
                    hasStatic = true;
                }
            }
        }
        ClassNode fieldHelper = null;
        ClassNode staticFieldHelper = null;
        if (!fields.isEmpty()) {
            fieldHelper = new InnerClassNode(
                    cNode,
                    Traits.fieldHelperClassName(cNode),
                    ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_SYNTHETIC,
                    OBJECT_TYPE
            );
            fieldHelper.setGenericsTypes(cNode.getGenericsTypes());
            fieldHelper.setStaticClass(true);
            if (hasStatic) {
                staticFieldHelper = new InnerClassNode(
                        cNode,
                        Traits.staticFieldHelperClassName(cNode),
                        ACC_PUBLIC | ACC_STATIC | ACC_ABSTRACT | ACC_INTERFACE | ACC_SYNTHETIC,
                        OBJECT_TYPE
                );
                staticFieldHelper.setStaticClass(true);
            }
        }

        // add fields
        for (FieldNode field : fields) {
            processField(field, initializer, staticInitializer, fieldHelper, helper, staticFieldHelper, cNode, fieldNames);
        }

        // add methods
        List<MethodNode> nonPublicAPIMethods = new ArrayList<>();
        List<Statement> staticInitStatements = null;
        for (MethodNode methodNode : cNode.getMethods()) {
            if (!methodNode.isSynthetic() && (methodNode.isProtected() || methodNode.isPackageScope())) {
                sourceUnit.addError(new SyntaxException("Cannot have protected/package-private method in a trait (" + cNode.getName() + "#" + methodNode.getTypeDescriptor() + ")",
                        methodNode.getLineNumber(), methodNode.getColumnNumber()));
                return null;
            }
            if (!methodNode.isAbstract()) {
                MethodNode newMethod = processMethod(cNode, helper, methodNode, fieldHelper, fieldNames);
                if (methodNode.isStaticConstructor()) {
                    staticInitStatements = getCodeAsBlock(newMethod).getStatements();
                } else {
                    // add non-abstract methods; abstract methods covered from trait interface
                    helper.addMethod(newMethod);
                }
            }
            if (methodNode.isPrivate() || methodNode.isStatic()) {
                nonPublicAPIMethods.add(methodNode);
            }
        }

        // remove methods which should not appear in the trait interface
        for (MethodNode privateMethod : nonPublicAPIMethods) {
            cNode.removeMethod(privateMethod);
        }

        // copy statements from static and instance init blocks
        if (staticInitStatements != null) {
            BlockStatement toBlock = getBlockStatement(staticInitializer, staticInitializer.getCode());
            for (Statement next : staticInitStatements) {
                toBlock.addStatement(next);
            }
        }
        List<Statement> initStatements = cNode.getObjectInitializerStatements();
        Statement toCode = initializer.getCode();
        BlockStatement toBlock = getBlockStatement(initializer, toCode);
        for (Statement next : initStatements) {
            Parameter selfParam = createSelfParameter(cNode, false);
            toBlock.addStatement(processBody(varX(selfParam), next, cNode, helper, fieldHelper, fieldNames));
        }
        initStatements.clear();

        // clear properties to avoid generation of methods
        cNode.getProperties().clear();

        fields = new ArrayList<>(cNode.getFields()); // reuse the full list of fields
        for (FieldNode field : fields) {
            cNode.removeField(field.getName());
        }

        addMopMethods(helper);
        copyClassAnnotations(helper);
        registerASTTransformations(helper);

        addGeneratedInnerClass(cNode, helper);
        if (fieldHelper != null) {
            addGeneratedInnerClass(cNode, fieldHelper);
            if (staticFieldHelper != null) {
                addGeneratedInnerClass(cNode, staticFieldHelper);
            }
        }

        // resolve scope (for closures)
        resolveScope(helper);
        if (fieldHelper != null) {
            resolveScope(fieldHelper);
            if (staticFieldHelper != null) {
                resolveScope(staticFieldHelper);
            }
        }

        return helper;
    }