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;
}