in src/main/java/org/codehaus/groovy/tools/javac/JavaStubGenerator.java [226:405]
private void printClassContents(PrintWriter out, ClassNode classNode) {
if (classNode instanceof InnerClassNode && ((InnerClassNode) classNode).isAnonymous()) {
// if it is an anonymous inner class, don't generate the stub code for it.
return;
}
try {
Verifier verifier = new Verifier() {
@Override
public void visitClass(ClassNode node) {
List<Statement> savedStatements = new ArrayList<>(node.getObjectInitializerStatements());
super.visitClass(node);
node.getObjectInitializerStatements().addAll(savedStatements);
for (ClassNode trait : findTraits(node)) {
// GROOVY-9031: replace property type placeholder with resolved type from trait generics
Map<String, ClassNode> generics = trait.isUsingGenerics() ? createGenericsSpec(trait) : null;
for (PropertyNode traitProperty : trait.getProperties()) {
ClassNode traitPropertyType = traitProperty.getType();
traitProperty.setType(correctToGenericsSpecRecurse(generics, traitPropertyType));
super.visitProperty(traitProperty);
traitProperty.setType(traitPropertyType);
}
}
}
@Override
public void visitConstructor(ConstructorNode node) {
Statement stmt = node.getCode();
if (stmt != null) {
stmt.visit(new VerifierCodeVisitor(getClassNode()));
}
}
@Override
public void visitProperty(PropertyNode pn) {
// GROOVY-8233 skip static properties for traits since they don't make the interface
if (!pn.isStatic() || !Traits.isTrait(pn.getDeclaringClass())) {
super.visitProperty(pn);
}
}
@Override
public void addCovariantMethods(ClassNode cn) {}
@Override
protected void addInitialization(ClassNode cn) {}
@Override
protected void addInitialization(ClassNode cn, ConstructorNode c) {}
@Override
protected void addPropertyMethod(MethodNode mn) {
markAsGenerated(getClassNode(), mn);
doAddMethod(mn);
}
@Override
protected void addReturnIfNeeded(MethodNode mn) {}
private MethodNode doAddMethod(MethodNode mn) {
propertyMethods.putIfAbsent(mn.getTypeDescriptor(), mn);
return mn;
}
@Override
protected MethodNode addMethod(ClassNode cn, boolean shouldBeSynthetic, String name, int modifiers, ClassNode returnType, Parameter[] parameters, ClassNode[] exceptions, Statement code) {
if (!shouldBeSynthetic) modifiers &= ~Opcodes.ACC_SYNTHETIC;
return doAddMethod(new MethodNode(name, modifiers, returnType, parameters, exceptions, code));
}
@Override
protected void addConstructor(Parameter[] params, ConstructorNode ctor, Statement code, ClassNode node) {
if (!(code instanceof BlockStatement)) { // GROOVY-4508
Statement stmt = code;
code = new BlockStatement();
((BlockStatement) code).addStatement(stmt);
}
ConstructorNode newCtor = new ConstructorNode(ctor.getModifiers(), params, ctor.getExceptions(), code);
newCtor.setDeclaringClass(node);
markAsGenerated(node, newCtor);
constructors.add(newCtor);
}
@Override
protected void addDefaultConstructor(ClassNode node) {
// not required for stub generation
}
@Override
protected void addDefaultParameters(DefaultArgsAction action, MethodNode method) {
Parameter[] parameters = method.getParameters();
Expression[] arguments = new Expression[parameters.length];
for (int i = 0; i < parameters.length; ++i) {
if (parameters[i].hasInitialExpression())
arguments[i] = parameters[i].getInitialExpression();
}
super.addDefaultParameters(action, method);
for (int i = 0; i < parameters.length; ++i) {
if (arguments[i] != null)
parameters[i].setInitialExpression(arguments[i]);
}
}
@Override
protected FinalVariableAnalyzer.VariableNotFinalCallback getFinalVariablesCallback() {
return null;
}
};
int constructorCount = classNode.getDeclaredConstructors().size();
verifier.visitClass(classNode);
// undo unwanted side effect of Verifier
if (constructorCount == 0 && classNode.getDeclaredConstructors().size() == 1) {
classNode.getDeclaredConstructors().clear();
}
boolean isEnum = classNode.isEnum();
boolean isInterface = !isEnum && isInterfaceOrTrait(classNode);
boolean isAnnotationDefinition = classNode.isAnnotationDefinition();
printAnnotations(out, classNode);
int flags = classNode.getModifiers();
if (isEnum) flags &= ~Opcodes.ACC_FINAL;
if (isEnum || isInterface) flags &= ~Opcodes.ACC_ABSTRACT;
if (classNode.isSyntheticPublic() && hasPackageScopeXform(classNode,
PackageScopeTarget.CLASS)) flags &= ~Opcodes.ACC_PUBLIC;
printModifiers(out, flags);
if (isInterface) {
if (isAnnotationDefinition) {
out.print("@");
}
out.print("interface ");
} else if (isEnum) {
out.print("enum ");
} else {
out.print("class ");
}
String className = classNode.getNameWithoutPackage();
if (classNode instanceof InnerClassNode)
className = className.substring(className.lastIndexOf('$') + 1);
out.println(className);
printTypeParameters(out, classNode.getGenericsTypes());
ClassNode superClass = classNode.getUnresolvedSuperClass(false);
if (!isInterface && !isEnum) {
out.print(" extends ");
printType(out, superClass);
}
ClassNode[] interfaces = classNode.getInterfaces();
if (interfaces != null && interfaces.length > 0 && !isAnnotationDefinition) {
if (isInterface) {
out.println(" extends");
} else {
out.println(" implements");
}
for (int i = 0; i < interfaces.length - 1; ++i) {
out.print(" ");
printType(out, interfaces[i]);
out.print(",");
}
out.print(" ");
printType(out, interfaces[interfaces.length - 1]);
}
out.println(" {");
printFields(out, classNode, isInterface);
printMethods(out, classNode, isEnum);
for (Iterator<InnerClassNode> inner = classNode.getInnerClasses(); inner.hasNext(); ) {
// GROOVY-4004: clear the methods from the outer class so that they don't get duplicated in inner ones
constructors.clear();
propertyMethods.clear();
printClassContents(out, inner.next());
}
out.println("}");
} finally {
constructors.clear();
propertyMethods.clear();
}
}