in src/org/jetbrains/java/decompiler/main/ClassWriter.java [236:361]
public void classToJava(ClassNode node, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) {
ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node);
int startLine = tracer != null ? tracer.getCurrentSourceLine() : 0;
BytecodeMappingTracer dummy_tracer = new BytecodeMappingTracer(startLine);
try {
// last minute processing
invokeProcessors(node);
ClassWrapper wrapper = node.getWrapper();
StructClass cl = wrapper.getClassStruct();
DecompilerContext.getLogger().startWriteClass(cl.qualifiedName);
// write class definition
int start_class_def = buffer.length();
writeClassDefinition(node, buffer, indent);
boolean hasContent = false;
boolean enumFields = false;
dummy_tracer.incrementCurrentSourceLine(buffer.countLines(start_class_def));
List<StructRecordComponent> components = cl.getRecordComponents();
for (StructField fd : cl.getFields()) {
boolean hide = fd.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||
wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
if (hide) continue;
if (components != null && fd.getAccessFlags() == (CodeConstants.ACC_FINAL | CodeConstants.ACC_PRIVATE) &&
components.stream().anyMatch(c -> c.getName().equals(fd.getName()) && c.getDescriptor().equals(fd.getDescriptor()))) {
// Record component field: skip it
continue;
}
boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
if (isEnum) {
if (enumFields) {
buffer.append(',').appendLineSeparator();
dummy_tracer.incrementCurrentSourceLine();
}
enumFields = true;
}
else if (enumFields) {
buffer.append(';');
buffer.appendLineSeparator();
buffer.appendLineSeparator();
dummy_tracer.incrementCurrentSourceLine(2);
enumFields = false;
}
fieldToJava(wrapper, cl, fd, buffer, indent + 1, dummy_tracer); // FIXME: insert real tracer
hasContent = true;
}
if (enumFields) {
buffer.append(';').appendLineSeparator();
dummy_tracer.incrementCurrentSourceLine();
}
// FIXME: fields don't matter at the moment
startLine += buffer.countLines(start_class_def);
// methods
for (StructMethod mt : cl.getMethods()) {
boolean hide = mt.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||
mt.hasModifier(CodeConstants.ACC_BRIDGE) && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE) ||
wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
if (hide) continue;
int position = buffer.length();
int storedLine = startLine;
if (hasContent) {
buffer.appendLineSeparator();
startLine++;
}
BytecodeMappingTracer method_tracer = new BytecodeMappingTracer(startLine);
boolean methodSkipped = !methodToJava(node, mt, buffer, indent + 1, method_tracer);
if (!methodSkipped) {
hasContent = true;
addTracer(cl, mt, method_tracer);
startLine = method_tracer.getCurrentSourceLine();
}
else {
buffer.setLength(position);
startLine = storedLine;
}
}
// member classes
for (ClassNode inner : node.nested) {
if (inner.type == ClassNode.CLASS_MEMBER) {
StructClass innerCl = inner.classStruct;
boolean isSynthetic = (inner.access & CodeConstants.ACC_SYNTHETIC) != 0 || innerCl.isSynthetic();
boolean hide = isSynthetic && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||
wrapper.getHiddenMembers().contains(innerCl.qualifiedName);
if (hide) continue;
if (hasContent) {
buffer.appendLineSeparator();
startLine++;
}
BytecodeMappingTracer class_tracer = new BytecodeMappingTracer(startLine);
classToJava(inner, buffer, indent + 1, class_tracer);
startLine = buffer.countLines();
hasContent = true;
}
}
buffer.appendIndent(indent).append('}');
if (node.type != ClassNode.CLASS_ANONYMOUS) {
buffer.appendLineSeparator();
}
}
finally {
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, outerNode);
}
DecompilerContext.getLogger().endWriteClass();
}