summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRoman Shevchenko <roman.shevchenko@jetbrains.com>2014-09-04 14:30:28 +0400
committerRoman Shevchenko <roman.shevchenko@jetbrains.com>2014-09-04 14:33:34 +0400
commit1cea85e49ae7659e7124383b619730ba6053bb46 (patch)
tree9893c2ed765e9f1dfa887b7123dd034569e12549 /src
parentf4f9e8be28142ebb4b85026eef6505055a31b68a (diff)
downloadfernflower-1cea85e49ae7659e7124383b619730ba6053bb46.tar
fernflower-1cea85e49ae7659e7124383b619730ba6053bb46.tar.gz
fernflower-1cea85e49ae7659e7124383b619730ba6053bb46.tar.lz
fernflower-1cea85e49ae7659e7124383b619730ba6053bb46.tar.xz
fernflower-1cea85e49ae7659e7124383b619730ba6053bb46.zip
java-decompiler: optimization (less string buffer allocations on generating text)
Diffstat (limited to 'src')
-rw-r--r--src/org/jetbrains/java/decompiler/main/ClassWriter.java1409
-rw-r--r--src/org/jetbrains/java/decompiler/main/ClassesProcessor.java69
-rw-r--r--src/org/jetbrains/java/decompiler/main/Fernflower.java8
-rw-r--r--src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java38
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java35
-rw-r--r--src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java32
-rw-r--r--src/org/jetbrains/java/decompiler/util/InterpreterUtil.java10
7 files changed, 706 insertions, 895 deletions
diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java
index ffc57d8..29307e5 100644
--- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java
+++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java
@@ -32,6 +32,7 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructField;
+import org.jetbrains.java.decompiler.struct.StructMember;
import org.jetbrains.java.decompiler.struct.StructMethod;
import org.jetbrains.java.decompiler.struct.attr.*;
import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
@@ -40,46 +41,14 @@ import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.gen.generics.*;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
-import org.jetbrains.java.decompiler.util.VBStyleCollection;
-
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
+
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
public class ClassWriter {
- private static final int[] modval_class = new int[]{CodeConstants.ACC_PUBLIC, CodeConstants.ACC_PROTECTED, CodeConstants.ACC_PRIVATE,
- CodeConstants.ACC_ABSTRACT, CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL, CodeConstants.ACC_STRICT};
-
- private static final String[] modstr_class =
- new String[]{"public ", "protected ", "private ", "abstract ", "static ", "final ", "strictfp "};
-
- private static final int[] modval_field = new int[]{CodeConstants.ACC_PUBLIC, CodeConstants.ACC_PROTECTED, CodeConstants.ACC_PRIVATE,
- CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL, CodeConstants.ACC_TRANSIENT, CodeConstants.ACC_VOLATILE};
-
- private static final String[] modstr_field =
- new String[]{"public ", "protected ", "private ", "static ", "final ", "transient ", "volatile "};
-
- private static final int[] modval_meth = new int[]{CodeConstants.ACC_PUBLIC, CodeConstants.ACC_PROTECTED, CodeConstants.ACC_PRIVATE,
- CodeConstants.ACC_ABSTRACT, CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL, CodeConstants.ACC_SYNCHRONIZED,
- CodeConstants.ACC_NATIVE, CodeConstants.ACC_STRICT};
-
- private static final String[] modstr_meth =
- new String[]{"public ", "protected ", "private ", "abstract ", "static ", "final ", "synchronized ", "native ", "strictfp "};
-
- private static final HashSet<Integer> mod_notinterface =
- new HashSet<Integer>(Arrays.asList(new Integer[]{CodeConstants.ACC_ABSTRACT, CodeConstants.ACC_STATIC}));
- private static final HashSet<Integer> mod_notinterface_fields =
- new HashSet<Integer>(Arrays.asList(new Integer[]{CodeConstants.ACC_PUBLIC, CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL}));
- private static final HashSet<Integer> mod_notinterface_meth =
- new HashSet<Integer>(Arrays.asList(new Integer[]{CodeConstants.ACC_PUBLIC, CodeConstants.ACC_ABSTRACT}));
-
private ClassReference14Processor ref14processor;
-
private PoolInterceptor interceptor;
public ClassWriter() {
@@ -87,9 +56,7 @@ public class ClassWriter {
interceptor = DecompilerContext.getPoolInterceptor();
}
-
private void invokeProcessors(ClassNode node) {
-
ClassWrapper wrapper = node.wrapper;
StructClass cl = wrapper.getClassStruct();
@@ -108,425 +75,330 @@ public class ClassWriter {
}
}
- public void classLambdaToJava(ClassNode node, BufferedWriter writer, Exprent method_object, int indent) throws IOException {
-
+ public void classLambdaToJava(ClassNode node, StringBuilder buffer, Exprent method_object, int indent) {
// get the class node with the content method
- ClassNode node_content = node;
- while (node_content != null && node_content.type == ClassNode.CLASS_LAMBDA) {
- node_content = node_content.parent;
+ ClassNode classNode = node;
+ while (classNode != null && classNode.type == ClassNode.CLASS_LAMBDA) {
+ classNode = classNode.parent;
}
-
- if (node_content == null) {
+ if (classNode == null) {
return;
}
- boolean lambda_to_anonymous = DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS);
+ boolean lambdaToAnonymous = DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS);
- ClassNode nodeold = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
+ ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node);
- ClassWrapper wrapper = node_content.wrapper;
- StructClass cl = wrapper.getClassStruct();
+ try {
+ ClassWrapper wrapper = classNode.wrapper;
+ StructClass cl = wrapper.getClassStruct();
- DecompilerContext.getLogger().startWriteClass(node.simpleName);
+ DecompilerContext.getLogger().startWriteClass(node.simpleName);
- if (node.lambda_information.is_method_reference) {
+ if (node.lambda_information.is_method_reference) {
+ if (!node.lambda_information.is_content_method_static && method_object != null) {
+ // reference to a virtual method
+ buffer.append(method_object.toJava(indent));
+ }
+ else {
+ // reference to a static method
+ buffer.append(ExprProcessor.getCastTypeName(new VarType(node.lambda_information.content_class_name, false)));
+ }
- if (!node.lambda_information.is_content_method_static && method_object != null) { // reference to a virtual method
- writer.write(method_object.toJava(indent));
+ buffer.append("::");
+ buffer.append(node.lambda_information.content_method_name);
}
- else { // reference to a static method
- writer.write(ExprProcessor.getCastTypeName(new VarType(node.lambda_information.content_class_name, false)));
- }
-
- writer.write("::");
- writer.write(node.lambda_information.content_method_name);
-
- writer.flush();
- }
- else {
-
- // lambda method
- StructMethod mt = cl.getMethod(node.lambda_information.content_method_key);
- MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
-
- MethodDescriptor md_content = MethodDescriptor.parseDescriptor(node.lambda_information.content_method_descriptor);
- MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(node.lambda_information.method_descriptor);
-
- if (!lambda_to_anonymous) { // lambda parameters '() ->'
-
- StringBuilder buff = new StringBuilder("(");
-
- boolean firstpar = true;
- int index = node.lambda_information.is_content_method_static ? 0 : 1;
-
- int start_index = md_content.params.length - md_lambda.params.length;
-
- for (int i = 0; i < md_content.params.length; i++) {
+ else {
+ // lambda method
+ StructMethod mt = cl.getMethod(node.lambda_information.content_method_key);
+ MethodWrapper methodWrapper = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
+ MethodDescriptor md_content = MethodDescriptor.parseDescriptor(node.lambda_information.content_method_descriptor);
+ MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(node.lambda_information.method_descriptor);
+
+ if (!lambdaToAnonymous) {
+ buffer.append('(');
+
+ boolean firstParameter = true;
+ int index = node.lambda_information.is_content_method_static ? 0 : 1;
+ int start_index = md_content.params.length - md_lambda.params.length;
+
+ for (int i = 0; i < md_content.params.length; i++) {
+ if (i >= start_index) {
+ if (!firstParameter) {
+ buffer.append(", ");
+ }
- if (i >= start_index) {
+ String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0));
+ buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors
- if (!firstpar) {
- buff.append(", ");
+ firstParameter = false;
}
- String parname = meth.varproc.getVarName(new VarVersionPaar(index, 0));
- buff.append(parname == null ? "param" + index : parname); // null iff decompiled with errors
-
- firstpar = false;
+ index += md_content.params[i].stack_size;
}
- index += md_content.params[i].stack_size;
+ buffer.append(") ->");
}
- buff.append(") ->");
- writer.write(buff.toString());
- }
+ buffer.append(" {");
+ buffer.append(DecompilerContext.getNewLineSeparator());
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
+ methodLambdaToJava(node, classNode, mt, buffer, indent + 1, !lambdaToAnonymous);
- if (lambda_to_anonymous) {
- methodLambdaToJava(node, node_content, mt, bufstrwriter, indent + 1, false);
- }
- else {
- methodLambdaToJava(node, node_content, mt, bufstrwriter, indent, true);
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append("}");
}
-
- bufstrwriter.flush();
-
- // closing up class definition
- writer.write(" {");
- writer.write(DecompilerContext.getNewLineSeparator());
-
- writer.write(strwriter.toString());
-
- writer.write(InterpreterUtil.getIndentString(indent));
- writer.write("}");
- writer.flush();
}
-
- DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, nodeold);
+ finally {
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, outerNode);
+ }
DecompilerContext.getLogger().endWriteClass();
}
- public void classToJava(ClassNode node, BufferedWriter writer, int indent) throws IOException {
-
- ClassWrapper wrapper = node.wrapper;
- StructClass cl = wrapper.getClassStruct();
-
- ClassNode nodeold = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
+ public void classToJava(ClassNode node, StringBuilder buffer, int indent) {
+ ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node);
- // last minute processing
- invokeProcessors(node);
-
- DecompilerContext.getLogger().startWriteClass(cl.qualifiedName);
+ try {
+ // last minute processing
+ invokeProcessors(node);
- writeClassDefinition(node, writer, indent);
-
- // methods
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
-
- boolean firstmt = true;
- boolean mthidden = false;
+ ClassWrapper wrapper = node.wrapper;
+ StructClass cl = wrapper.getClassStruct();
- for (StructMethod mt : cl.getMethods()) {
- boolean isSynthetic = mt.isSynthetic();
- boolean isBridge = mt.hasModifier(CodeConstants.ACC_BRIDGE);
+ DecompilerContext.getLogger().startWriteClass(cl.qualifiedName);
- if ((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) &&
- (!isBridge || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE)) &&
- !wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()))) {
- if (!mthidden && (!firstmt || node.type != ClassNode.CLASS_ANONYMOUS)) {
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- firstmt = false;
- }
+ String lineSeparator = DecompilerContext.getNewLineSeparator();
- mthidden = !methodToJava(node, mt, bufstrwriter, indent + 1);
- }
- }
- bufstrwriter.flush();
+ writeClassDefinition(node, buffer, indent);
- StringWriter strwriter1 = new StringWriter();
- BufferedWriter bufstrwriter1 = new BufferedWriter(strwriter1);
+ boolean hasContent = false;
- int fields_count = 0;
+ // fields
+ boolean enumFields = false;
- boolean enumfields = false;
+ 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;
- // fields
- 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) {
boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
if (isEnum) {
- if (enumfields) {
- bufstrwriter1.write(",");
- bufstrwriter1.write(DecompilerContext.getNewLineSeparator());
- }
- else {
- enumfields = true;
+ if (enumFields) {
+ buffer.append(',');
+ buffer.append(lineSeparator);
}
+ enumFields = true;
}
- else {
- if (enumfields) {
- bufstrwriter1.write(";");
- bufstrwriter1.write(DecompilerContext.getNewLineSeparator());
- enumfields = false;
- }
+ else if (enumFields) {
+ buffer.append(';');
+ buffer.append(lineSeparator);
+ buffer.append(lineSeparator);
+ enumFields = false;
}
- fieldToJava(wrapper, cl, fd, bufstrwriter1, indent + 1);
- fields_count++;
+ fieldToJava(wrapper, cl, fd, buffer, indent + 1);
+
+ hasContent = true;
}
- }
- if (enumfields) {
- bufstrwriter1.write(";");
- bufstrwriter1.write(DecompilerContext.getNewLineSeparator());
- }
+ if (enumFields) {
+ buffer.append(';');
+ buffer.append(lineSeparator);
+ }
- bufstrwriter1.flush();
+ // 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;
- if (fields_count > 0) {
- writer.write(DecompilerContext.getNewLineSeparator());
- writer.write(strwriter1.toString());
- writer.write(DecompilerContext.getNewLineSeparator());
- }
+ int position = buffer.length();
+ if (hasContent) {
+ buffer.append(lineSeparator);
+ }
+ boolean methodSkipped = !methodToJava(node, mt, buffer, indent + 1);
+ if (!methodSkipped) {
+ hasContent = true;
+ }
+ else {
+ buffer.setLength(position);
+ }
+ }
+ // 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;
- // methods
- writer.write(strwriter.toString());
+ if (hasContent) {
+ buffer.append(lineSeparator);
+ }
+ classToJava(inner, buffer, indent + 1);
- // 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) {
- writer.write(DecompilerContext.getNewLineSeparator());
- classToJava(inner, writer, indent + 1);
+ hasContent = true;
}
}
- }
- writer.write(InterpreterUtil.getIndentString(indent));
- writer.write("}");
- if (node.type != ClassNode.CLASS_ANONYMOUS) {
- writer.write(DecompilerContext.getNewLineSeparator());
- }
- writer.flush();
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append('}');
- DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, nodeold);
+ if (node.type != ClassNode.CLASS_ANONYMOUS) {
+ buffer.append(lineSeparator);
+ }
+ }
+ finally {
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, outerNode);
+ }
DecompilerContext.getLogger().endWriteClass();
}
- private void writeClassDefinition(ClassNode node, BufferedWriter writer, int indent) throws IOException {
+ private void writeClassDefinition(ClassNode node, StringBuilder buffer, int indent) {
+ String lineSeparator = DecompilerContext.getNewLineSeparator();
+ String indentString = InterpreterUtil.getIndentString(indent);
if (node.type == ClassNode.CLASS_ANONYMOUS) {
- writer.write(" {");
- writer.write(DecompilerContext.getNewLineSeparator());
+ buffer.append(" {");
+ buffer.append(lineSeparator);
+ return;
}
- else {
-
- String indstr = InterpreterUtil.getIndentString(indent);
-
- ClassWrapper wrapper = node.wrapper;
- StructClass cl = wrapper.getClassStruct();
- int flags = node.type == ClassNode.CLASS_ROOT ? cl.getAccessFlags() : node.access;
- boolean isInterface = (flags & CodeConstants.ACC_INTERFACE) != 0;
- boolean isAnnotation = (flags & CodeConstants.ACC_ANNOTATION) != 0;
- boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0;
+ ClassWrapper wrapper = node.wrapper;
+ StructClass cl = wrapper.getClassStruct();
- boolean isDeprecated = cl.getAttributes().containsKey("Deprecated");
+ int flags = node.type == ClassNode.CLASS_ROOT ? cl.getAccessFlags() : node.access;
+ boolean isDeprecated = cl.getAttributes().containsKey("Deprecated");
+ boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic");
+ boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0;
+ boolean isInterface = (flags & CodeConstants.ACC_INTERFACE) != 0;
+ boolean isAnnotation = (flags & CodeConstants.ACC_ANNOTATION) != 0;
- if (interceptor != null) {
- String oldname = interceptor.getOldName(cl.qualifiedName);
- if (oldname != null) {
- writer.write(indstr);
- writer.write("// $FF: renamed from: " + getDescriptorPrintOut(oldname, 0));
- writer.write(DecompilerContext.getNewLineSeparator());
- }
- }
+ if (isDeprecated) {
+ appendDeprecation(buffer, indentString, lineSeparator);
+ }
- if (isDeprecated) {
- writer.write(indstr);
- writer.write("/** @deprecated */");
- writer.write(DecompilerContext.getNewLineSeparator());
- }
+ if (interceptor != null) {
+ String oldName = interceptor.getOldName(cl.qualifiedName);
+ appendRenameComment(buffer, oldName, MType.CLASS, indent, lineSeparator);
+ }
- // class annotations
- List<AnnotationExprent> lstAnn = getAllAnnotations(cl.getAttributes());
- for (AnnotationExprent annexpr : lstAnn) {
- writer.write(annexpr.toJava(indent));
- writer.write(DecompilerContext.getNewLineSeparator());
- }
+ if (isSynthetic) {
+ appendComment(buffer, "synthetic class", indentString, lineSeparator);
+ }
- boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic");
+ appendAnnotations(buffer, cl, indent, lineSeparator);
- if (isSynthetic) {
- writer.write(indstr);
- writer.write("// $FF: synthetic class");
- writer.write(DecompilerContext.getNewLineSeparator());
- }
+ buffer.append(indentString);
- writer.write(indstr);
+ if (isEnum) {
+ // remove abstract and final flags (JLS 8.9 Enums)
+ flags &= ~CodeConstants.ACC_ABSTRACT;
+ flags &= ~CodeConstants.ACC_FINAL;
+ }
- if (isEnum) {
- // remove abstract and final flags (JLS 8.9 Enums)
- flags &= ~CodeConstants.ACC_ABSTRACT;
- flags &= ~CodeConstants.ACC_FINAL;
- }
+ appendModifiers(buffer, flags, CLASS_ALLOWED, isInterface, CLASS_EXCLUDED);
- for (int i = 0; i < modval_class.length; i++) {
- if (!isInterface || !mod_notinterface.contains(modval_class[i])) {
- if ((flags & modval_class[i]) != 0) {
- writer.write(modstr_class[i]);
- }
- }
+ if (isEnum) {
+ buffer.append("enum ");
+ }
+ else if (isInterface) {
+ if (isAnnotation) {
+ buffer.append('@');
}
+ buffer.append("interface ");
+ }
+ else {
+ buffer.append("class ");
+ }
- if (isEnum) {
- writer.write("enum ");
- }
- else if (isInterface) {
- if (isAnnotation) {
- writer.write("@");
- }
- writer.write("interface ");
- }
- else {
- writer.write("class ");
+ GenericClassDescriptor descriptor = null;
+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
+ StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)cl.getAttributes().getWithKey("Signature");
+ if (attr != null) {
+ descriptor = GenericMain.parseClassSignature(attr.getSignature());
}
+ }
- GenericClassDescriptor descriptor = null;
- if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
- StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)cl.getAttributes().getWithKey("Signature");
- if (attr != null) {
- descriptor = GenericMain.parseClassSignature(attr.getSignature());
- }
- }
+ buffer.append(node.simpleName);
- writer.write(node.simpleName);
- if (descriptor != null && !descriptor.fparameters.isEmpty()) {
- writer.write("<");
- for (int i = 0; i < descriptor.fparameters.size(); i++) {
- if (i > 0) {
- writer.write(", ");
- }
- writer.write(descriptor.fparameters.get(i));
+ if (descriptor != null && !descriptor.fparameters.isEmpty()) {
+ appendTypeParameters(buffer, descriptor.fparameters, descriptor.fbounds);
+ }
- List<GenericType> lstBounds = descriptor.fbounds.get(i);
- if (lstBounds.size() > 1 || !"java/lang/Object".equals(lstBounds.get(0).value)) {
- writer.write(" extends ");
- writer.write(GenericMain.getGenericCastTypeName(lstBounds.get(0)));
+ buffer.append(' ');
- for (int j = 1; j < lstBounds.size(); j++) {
- writer.write(" & " + GenericMain.getGenericCastTypeName(lstBounds.get(j)));
- }
- }
+ if (!isEnum && !isInterface && cl.superClass != null) {
+ VarType supertype = new VarType(cl.superClass.getString(), true);
+ if (!VarType.VARTYPE_OBJECT.equals(supertype)) {
+ buffer.append("extends ");
+ if (descriptor != null) {
+ buffer.append(GenericMain.getGenericCastTypeName(descriptor.superclass));
+ }
+ else {
+ buffer.append(ExprProcessor.getCastTypeName(supertype));
}
- writer.write(">");
+ buffer.append(' ');
}
- writer.write(" ");
+ }
- if (!isEnum && !isInterface && cl.superClass != null) {
- VarType supertype = new VarType(cl.superClass.getString(), true);
- if (!VarType.VARTYPE_OBJECT.equals(supertype)) {
- writer.write("extends ");
+ if (!isAnnotation) {
+ int[] interfaces = cl.getInterfaces();
+ if (interfaces.length > 0) {
+ buffer.append(isInterface ? "extends " : "implements ");
+ for (int i = 0; i < interfaces.length; i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
if (descriptor != null) {
- writer.write(GenericMain.getGenericCastTypeName(descriptor.superclass));
+ buffer.append(GenericMain.getGenericCastTypeName(descriptor.superinterfaces.get(i)));
}
else {
- writer.write(ExprProcessor.getCastTypeName(supertype));
+ buffer.append(ExprProcessor.getCastTypeName(new VarType(cl.getInterface(i), true)));
}
- writer.write(" ");
}
+ buffer.append(' ');
}
-
- if (!isAnnotation) {
- int[] interfaces = cl.getInterfaces();
- if (interfaces.length > 0) {
- writer.write(isInterface ? "extends " : "implements ");
- for (int i = 0; i < interfaces.length; i++) {
- if (i > 0) {
- writer.write(", ");
- }
- if (descriptor != null) {
- writer.write(GenericMain.getGenericCastTypeName(descriptor.superinterfaces.get(i)));
- }
- else {
- writer.write(ExprProcessor.getCastTypeName(new VarType(cl.getInterface(i), true)));
- }
- }
- writer.write(" ");
- }
- }
-
- writer.write("{");
- writer.write(DecompilerContext.getNewLineSeparator());
}
- }
- private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, BufferedWriter writer, int indent) throws IOException {
+ buffer.append('{');
+ buffer.append(lineSeparator);
+ }
- String indstr = InterpreterUtil.getIndentString(indent);
+ private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, StringBuilder buffer, int indent) {
+ String indentString = InterpreterUtil.getIndentString(indent);
+ String lineSeparator = DecompilerContext.getNewLineSeparator();
boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);
-
- if (interceptor != null) {
- String oldname = interceptor.getOldName(cl.qualifiedName + " " + fd.getName() + " " + fd.getDescriptor());
- if (oldname != null) {
- String[] element = oldname.split(" ");
-
- writer.write(indstr);
- writer.write("// $FF: renamed from: " + element[1] + " " + getDescriptorPrintOut(element[2], 1));
- writer.write(DecompilerContext.getNewLineSeparator());
- }
- }
-
boolean isDeprecated = fd.getAttributes().containsKey("Deprecated");
+ boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
if (isDeprecated) {
- writer.write(indstr);
- writer.write("/** @deprecated */");
- writer.write(DecompilerContext.getNewLineSeparator());
+ appendDeprecation(buffer, indentString, lineSeparator);
}
- // field annotations
- List<AnnotationExprent> lstAnn = getAllAnnotations(fd.getAttributes());
- for (AnnotationExprent annexpr : lstAnn) {
- writer.write(annexpr.toJava(indent));
- writer.write(DecompilerContext.getNewLineSeparator());
+ if (interceptor != null) {
+ String oldName = interceptor.getOldName(cl.qualifiedName + " " + fd.getName() + " " + fd.getDescriptor());
+ appendRenameComment(buffer, oldName, MType.FIELD, indent, lineSeparator);
}
- boolean isSynthetic = fd.isSynthetic();
- boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
-
- if (isSynthetic) {
- writer.write(indstr);
- writer.write("// $FF: synthetic field");
- writer.write(DecompilerContext.getNewLineSeparator());
+ if (fd.isSynthetic()) {
+ appendComment(buffer, "synthetic field", indentString, lineSeparator);
}
- writer.write(indstr);
+ appendAnnotations(buffer, fd, indent, lineSeparator);
+
+ buffer.append(indentString);
if (!isEnum) {
- for (int i = 0; i < modval_field.length; i++) {
- if (!isInterface || !mod_notinterface_fields.contains(modval_field[i])) {
- if (fd.hasModifier(modval_field[i])) {
- writer.write(modstr_field[i]);
- }
- }
- }
+ appendModifiers(buffer, fd.getAccessFlags(), FIELD_ALLOWED, isInterface, FIELD_EXCLUDED);
}
VarType fieldType = new VarType(fd.getDescriptor(), false);
@@ -541,15 +413,15 @@ public class ClassWriter {
if (!isEnum) {
if (descriptor != null) {
- writer.write(GenericMain.getGenericCastTypeName(descriptor.type));
+ buffer.append(GenericMain.getGenericCastTypeName(descriptor.type));
}
else {
- writer.write(ExprProcessor.getCastTypeName(fieldType));
+ buffer.append(ExprProcessor.getCastTypeName(fieldType));
}
- writer.write(" ");
+ buffer.append(' ');
}
- writer.write(fd.getName());
+ buffer.append(fd.getName());
Exprent initializer;
if (fd.hasModifier(CodeConstants.ACC_STATIC)) {
@@ -558,569 +430,556 @@ public class ClassWriter {
else {
initializer = wrapper.getDynamicFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
}
-
if (initializer != null) {
if (isEnum && initializer.type == Exprent.EXPRENT_NEW) {
NewExprent nexpr = (NewExprent)initializer;
nexpr.setEnumconst(true);
- writer.write(nexpr.toJava(indent));
+ buffer.append(nexpr.toJava(indent));
}
else {
- writer.write(" = ");
- writer.write(initializer.toJava(indent));
+ buffer.append(" = ");
+ buffer.append(initializer.toJava(indent));
}
}
else if (fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_STATIC)) {
StructConstantValueAttribute attr =
(StructConstantValueAttribute)fd.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_CONSTANT_VALUE);
if (attr != null) {
- PrimitiveConstant cnst = cl.getPool().getPrimitiveConstant(attr.getIndex());
- writer.write(" = ");
- writer.write(new ConstExprent(fieldType, cnst.value).toJava(indent));
+ PrimitiveConstant constant = cl.getPool().getPrimitiveConstant(attr.getIndex());
+ buffer.append(" = ");
+ buffer.append(new ConstExprent(fieldType, constant.value).toJava(indent));
}
}
if (!isEnum) {
- writer.write(";");
- writer.write(DecompilerContext.getNewLineSeparator());
+ buffer.append(";");
+ buffer.append(lineSeparator);
}
}
- public boolean methodLambdaToJava(ClassNode node_lambda,
- ClassNode node_content,
- StructMethod mt,
- BufferedWriter writer,
- int indent,
- boolean code_only) throws IOException {
-
- ClassWrapper wrapper = node_content.wrapper;
-
- MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
-
- MethodWrapper methold = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
- DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, meth);
+ private static void methodLambdaToJava(ClassNode lambdaNode,
+ ClassNode classNode,
+ StructMethod mt,
+ StringBuilder buffer,
+ int indent,
+ boolean codeOnly) {
+ ClassWrapper classWrapper = classNode.wrapper;
+ MethodWrapper methodWrapper = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
+
+ MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper);
+
+ try {
+ String method_name = lambdaNode.lambda_information.method_name;
+ MethodDescriptor md_content = MethodDescriptor.parseDescriptor(lambdaNode.lambda_information.content_method_descriptor);
+ MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(lambdaNode.lambda_information.method_descriptor);
+
+ if (!codeOnly) {
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append("public ");
+ buffer.append(method_name);
+ buffer.append("(");
+
+ boolean firstParameter = true;
+ int index = lambdaNode.lambda_information.is_content_method_static ? 0 : 1;
+ int start_index = md_content.params.length - md_lambda.params.length;
- String indstr = InterpreterUtil.getIndentString(indent);
+ for (int i = 0; i < md_content.params.length; i++) {
+ if (i >= start_index) {
+ if (!firstParameter) {
+ buffer.append(", ");
+ }
- String method_name = node_lambda.lambda_information.method_name;
- MethodDescriptor md_content = MethodDescriptor.parseDescriptor(node_lambda.lambda_information.content_method_descriptor);
- MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(node_lambda.lambda_information.method_descriptor);
+ String typeName = ExprProcessor.getCastTypeName(md_content.params[i].copy());
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
+ }
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
+ buffer.append(typeName);
+ buffer.append(" ");
- if (!code_only) {
- bufstrwriter.write(indstr);
- bufstrwriter.write("public ");
- bufstrwriter.write(method_name);
- bufstrwriter.write("(");
+ String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0));
+ buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors
- boolean firstpar = true;
- int index = node_lambda.lambda_information.is_content_method_static ? 0 : 1;
+ firstParameter = false;
+ }
- int start_index = md_content.params.length - md_lambda.params.length;
+ index += md_content.params[i].stack_size;
+ }
- for (int i = 0; i < md_content.params.length; i++) {
+ buffer.append(") {");
+ buffer.append(DecompilerContext.getNewLineSeparator());
- if (i >= start_index) {
+ indent += 1;
+ }
- if (!firstpar) {
- bufstrwriter.write(", ");
+ if (!methodWrapper.decompiledWithErrors) {
+ RootStatement root = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
+ if (root != null) { // check for existence
+ try {
+ buffer.append(root.toJava(indent));
}
-
- VarType partype = md_content.params[i].copy();
-
- String strpartype = ExprProcessor.getCastTypeName(partype);
- if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(strpartype) &&
- DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
- strpartype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
+ catch (Throwable ex) {
+ DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.", ex);
+ methodWrapper.decompiledWithErrors = true;
}
-
- bufstrwriter.write(strpartype);
- bufstrwriter.write(" ");
-
- String parname = meth.varproc.getVarName(new VarVersionPaar(index, 0));
- bufstrwriter.write(parname == null ? "param" + index : parname); // null iff decompiled with errors
-
- firstpar = false;
}
-
- index += md_content.params[i].stack_size;
}
- bufstrwriter.write(")");
- bufstrwriter.write(" ");
- bufstrwriter.write("{");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
+ if (methodWrapper.decompiledWithErrors) {
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append("// $FF: Couldn't be decompiled");
+ buffer.append(DecompilerContext.getNewLineSeparator());
+ }
- RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
+ if (!codeOnly) {
+ indent -= 1;
- if (root != null && !meth.decompiledWithErrors) { // check for existence
- try {
- String code = root.toJava(indent + 1);
- bufstrwriter.write(code);
- }
- catch (Throwable ex) {
- DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.", ex);
- meth.decompiledWithErrors = true;
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append('}');
+ buffer.append(DecompilerContext.getNewLineSeparator());
}
}
-
- if (meth.decompiledWithErrors) {
- bufstrwriter.write(InterpreterUtil.getIndentString(indent + 1));
- bufstrwriter.write("// $FF: Couldn't be decompiled");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
-
- if (!code_only) {
- bufstrwriter.write(indstr + "}");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ finally {
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper);
}
-
- bufstrwriter.flush();
-
- writer.write(strwriter.toString());
-
- DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methold);
-
- return true;
}
- public boolean methodToJava(ClassNode node, StructMethod mt, BufferedWriter writer, int indent) throws IOException {
-
+ private boolean methodToJava(ClassNode node, StructMethod mt, StringBuilder buffer, int indent) {
ClassWrapper wrapper = node.wrapper;
StructClass cl = wrapper.getClassStruct();
+ MethodWrapper methodWrapper = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
- MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
+ boolean hideMethod = false;
- MethodWrapper methold = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
- DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, meth);
+ MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper);
- boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);
- boolean isAnnotation = cl.hasModifier(CodeConstants.ACC_ANNOTATION);
- boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
- boolean isDeprecated = mt.getAttributes().containsKey("Deprecated");
-
- String indstr = InterpreterUtil.getIndentString(indent);
- boolean clinit = false, init = false, dinit = false;
+ try {
+ boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);
+ boolean isAnnotation = cl.hasModifier(CodeConstants.ACC_ANNOTATION);
+ boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
+ boolean isDeprecated = mt.getAttributes().containsKey("Deprecated");
+ boolean clinit = false, init = false, dinit = false;
- MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+ String indentString = InterpreterUtil.getIndentString(indent);
+ String lineSeparator = DecompilerContext.getNewLineSeparator();
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
- int flags = mt.getAccessFlags();
- if ((flags & CodeConstants.ACC_NATIVE) != 0) {
- flags &= ~CodeConstants.ACC_STRICT; // compiler bug: a strictfp class sets all methods to strictfp
- }
- if ("<clinit>".equals(mt.getName())) {
- flags &= CodeConstants.ACC_STATIC; // ignore all modifiers except 'static' in a static initializer
- }
+ int flags = mt.getAccessFlags();
+ if ((flags & CodeConstants.ACC_NATIVE) != 0) {
+ flags &= ~CodeConstants.ACC_STRICT; // compiler bug: a strictfp class sets all methods to strictfp
+ }
+ if ("<clinit>".equals(mt.getName())) {
+ flags &= CodeConstants.ACC_STATIC; // ignore all modifiers except 'static' in a static initializer
+ }
- if (interceptor != null) {
- String oldname = interceptor.getOldName(cl.qualifiedName + " " + mt.getName() + " " + mt.getDescriptor());
- if (oldname != null) {
- String[] element = oldname.split(" ");
+ if (isDeprecated) {
+ appendDeprecation(buffer, indentString, lineSeparator);
+ }
- bufstrwriter.write(indstr);
- bufstrwriter.write("// $FF: renamed from: " + element[1] + " " + getDescriptorPrintOut(element[2], 2));
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ if (interceptor != null) {
+ String oldName = interceptor.getOldName(cl.qualifiedName + " " + mt.getName() + " " + mt.getDescriptor());
+ appendRenameComment(buffer, oldName, MType.METHOD, indent, lineSeparator);
}
- }
- if (isDeprecated) {
- writer.write(indstr);
- writer.write("/** @deprecated */");
- writer.write(DecompilerContext.getNewLineSeparator());
- }
+ boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic");
+ boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0;
+ if (isSynthetic) {
+ appendComment(buffer, "synthetic method", indentString, lineSeparator);
+ }
+ if (isBridge) {
+ appendComment(buffer, "bridge method", indentString, lineSeparator);
+ }
- // method annotations
- List<AnnotationExprent> lstAnn = getAllAnnotations(mt.getAttributes());
- for (AnnotationExprent annexpr : lstAnn) {
- bufstrwriter.write(annexpr.toJava(indent));
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
+ appendAnnotations(buffer, mt, indent, lineSeparator);
- boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic");
- boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0;
+ buffer.append(indentString);
- if (isSynthetic) {
- bufstrwriter.write(indstr);
- bufstrwriter.write("// $FF: synthetic method");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
+ appendModifiers(buffer, flags, METHOD_ALLOWED, isInterface, METHOD_EXCLUDED);
- if (isBridge) {
- bufstrwriter.write(indstr);
- bufstrwriter.write("// $FF: bridge method");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
+ if (isInterface && mt.containsCode()) {
+ // 'default' modifier (Java 8)
+ buffer.append("default ");
+ }
- bufstrwriter.write(indstr);
- for (int i = 0; i < modval_meth.length; i++) {
- if (!isInterface || !mod_notinterface_meth.contains(modval_meth[i])) {
- if ((flags & modval_meth[i]) != 0) {
- bufstrwriter.write(modstr_meth[i]);
+ String name = mt.getName();
+ if ("<init>".equals(name)) {
+ if (node.type == ClassNode.CLASS_ANONYMOUS) {
+ name = "";
+ dinit = true;
+ }
+ else {
+ name = node.simpleName;
+ init = true;
}
}
- }
-
- // 'default' modifier (Java 8)
- if (isInterface && mt.containsCode()) {
- bufstrwriter.write("default ");
- }
-
- String name = mt.getName();
- if ("<init>".equals(name)) {
- if (node.type == ClassNode.CLASS_ANONYMOUS) {
+ else if ("<clinit>".equals(name)) {
name = "";
- dinit = true;
+ clinit = true;
}
- else {
- name = node.simpleName;
- init = true;
- }
- }
- else if ("<clinit>".equals(name)) {
- name = "";
- clinit = true;
- }
- GenericMethodDescriptor descriptor = null;
- if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
- StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)mt.getAttributes().getWithKey("Signature");
- if (attr != null) {
- descriptor = GenericMain.parseMethodSignature(attr.getSignature());
- int actualParams = md.params.length;
- if (isEnum && init) actualParams -= 2;
- if (actualParams != descriptor.params.size()) {
- DecompilerContext.getLogger()
- .writeMessage("Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor(), IFernflowerLogger.WARNING);
- descriptor = null;
+ GenericMethodDescriptor descriptor = null;
+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
+ StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)mt.getAttributes().getWithKey("Signature");
+ if (attr != null) {
+ descriptor = GenericMain.parseMethodSignature(attr.getSignature());
+ int actualParams = md.params.length;
+ if (isEnum && init) actualParams -= 2;
+ if (actualParams != descriptor.params.size()) {
+ String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor();
+ DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.WARNING);
+ descriptor = null;
+ }
}
}
- }
-
- boolean throwsExceptions = false;
- int param_count_explicit = 0;
+ boolean throwsExceptions = false;
+ int paramCount = 0;
- if (!clinit && !dinit) {
+ if (!clinit && !dinit) {
+ boolean thisVar = !mt.hasModifier(CodeConstants.ACC_STATIC);
- boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
+ if (descriptor != null && !descriptor.fparameters.isEmpty()) {
+ appendTypeParameters(buffer, descriptor.fparameters, descriptor.fbounds);
+ buffer.append(' ');
+ }
- // formal type parameters
- if (descriptor != null && !descriptor.fparameters.isEmpty()) {
- bufstrwriter.write("<");
- for (int i = 0; i < descriptor.fparameters.size(); i++) {
- if (i > 0) {
- bufstrwriter.write(", ");
+ if (!init) {
+ if (descriptor != null) {
+ buffer.append(GenericMain.getGenericCastTypeName(descriptor.ret));
}
- bufstrwriter.write(descriptor.fparameters.get(i));
-
- List<GenericType> lstBounds = descriptor.fbounds.get(i);
- if (lstBounds.size() > 1 || !"java/lang/Object".equals(lstBounds.get(0).value)) {
- bufstrwriter.write(" extends ");
- bufstrwriter.write(GenericMain.getGenericCastTypeName(lstBounds.get(0)));
-
- for (int j = 1; j < lstBounds.size(); j++) {
- bufstrwriter.write(" & " + GenericMain.getGenericCastTypeName(lstBounds.get(j)));
- }
+ else {
+ buffer.append(ExprProcessor.getCastTypeName(md.ret));
}
+ buffer.append(' ');
}
- bufstrwriter.write("> ");
- }
- if (!init) {
- if (descriptor != null) {
- bufstrwriter.write(GenericMain.getGenericCastTypeName(descriptor.ret));
- }
- else {
- bufstrwriter.write(ExprProcessor.getCastTypeName(md.ret));
- }
- bufstrwriter.write(" ");
- }
+ buffer.append(name);
+ buffer.append('(');
- bufstrwriter.write(name);
- bufstrwriter.write("(");
+ // parameters
+ List<VarVersionPaar> signFields = methodWrapper.signatureFields;
- // parameter annotations
- List<List<AnnotationExprent>> lstParAnn = getAllParameterAnnotations(mt.getAttributes());
+ int lastVisibleParameterIndex = -1;
+ for (int i = 0; i < md.params.length; i++) {
+ if (signFields == null || signFields.get(i) == null) {
+ lastVisibleParameterIndex = i;
+ }
+ }
- List<VarVersionPaar> signFields = meth.signatureFields;
+ boolean firstParameter = true;
+ int index = isEnum && init ? 3 : thisVar ? 1 : 0;
+ int start = isEnum && init && descriptor == null ? 2 : 0;
+ int params = descriptor == null ? md.params.length : descriptor.params.size();
+ for (int i = start; i < params; i++) {
+ if (signFields == null || signFields.get(i) == null) {
+ if (!firstParameter) {
+ buffer.append(", ");
+ }
- // compute last visible parameter
- int lastparam_index = -1;
- for (int i = 0; i < md.params.length; i++) {
- if (signFields == null || signFields.get(i) == null) {
- lastparam_index = i;
- }
- }
+ appendParameterAnnotations(buffer, mt, paramCount);
- boolean firstpar = true;
- int index = isEnum && init ? 3 : thisvar ? 1 : 0;
- int start = isEnum && init && descriptor == null ? 2 : 0;
- int params = descriptor == null ? md.params.length : descriptor.params.size();
- for (int i = start; i < params; i++) {
- if (signFields == null || signFields.get(i) == null) {
+ if (methodWrapper.varproc.getVarFinal(new VarVersionPaar(index, 0)) == VarTypeProcessor.VAR_FINALEXPLICIT) {
+ buffer.append("final ");
+ }
- if (!firstpar) {
- bufstrwriter.write(", ");
- }
+ if (descriptor != null) {
+ GenericType parameterType = descriptor.params.get(i);
- if (lstParAnn.size() > param_count_explicit) {
- List<AnnotationExprent> annotations = lstParAnn.get(param_count_explicit);
- for (int j = 0; j < annotations.size(); j++) {
- AnnotationExprent annexpr = annotations.get(j);
- if (annexpr.getAnnotationType() == AnnotationExprent.ANNOTATION_NORMAL) {
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- bufstrwriter.write(annexpr.toJava(indent + 1));
+ boolean isVarArg = (i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.arraydim > 0);
+ if (isVarArg) {
+ parameterType.arraydim--;
}
- else {
- bufstrwriter.write(annexpr.toJava(0));
+
+ String typeName = GenericMain.getGenericCastTypeName(parameterType);
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
}
- bufstrwriter.write(" ");
- }
- }
- if (meth.varproc.getVarFinal(new VarVersionPaar(index, 0)) == VarTypeProcessor.VAR_FINALEXPLICIT) {
- bufstrwriter.write("final ");
- }
+ buffer.append(typeName);
+ if (isVarArg) {
+ buffer.append("...");
+ }
+ }
+ else {
+ VarType parameterType = md.params[i].copy();
- if (descriptor != null) {
- GenericType partype = descriptor.params.get(i);
+ boolean isVarArg = (i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.arraydim > 0);
+ if (isVarArg) {
+ parameterType.decArrayDim();
+ }
- boolean isVarArgs = (i == lastparam_index && mt.hasModifier(CodeConstants.ACC_VARARGS) && partype.arraydim > 0);
+ String typeName = ExprProcessor.getCastTypeName(parameterType);
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
+ }
- if (isVarArgs) {
- partype.arraydim--;
- }
+ buffer.append(typeName);
- String strpartype = GenericMain.getGenericCastTypeName(partype);
- if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(strpartype) &&
- DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
- strpartype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
+ if (isVarArg) {
+ buffer.append("...");
+ }
}
- bufstrwriter.write(strpartype);
+ buffer.append(' ');
+ String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0));
+ buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors
- if (isVarArgs) {
- bufstrwriter.write(" ...");
- }
+ firstParameter = false;
+ paramCount++;
}
- else {
- VarType partype = md.params[i].copy();
-
- boolean isVarArgs = (i == lastparam_index && mt.hasModifier(CodeConstants.ACC_VARARGS) && partype.arraydim > 0);
- if (isVarArgs) {
- partype.decArrayDim();
- }
+ index += md.params[i].stack_size;
+ }
- String strpartype = ExprProcessor.getCastTypeName(partype);
- if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(strpartype) &&
- DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
- strpartype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
- }
+ buffer.append(')');
- bufstrwriter.write(strpartype);
+ StructExceptionsAttribute attr = (StructExceptionsAttribute)mt.getAttributes().getWithKey("Exceptions");
+ if ((descriptor != null && !descriptor.exceptions.isEmpty()) || attr != null) {
+ throwsExceptions = true;
+ buffer.append(" throws ");
- if (isVarArgs) {
- bufstrwriter.write(" ...");
+ for (int i = 0; i < attr.getThrowsExceptions().size(); i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ if (descriptor != null && !descriptor.exceptions.isEmpty()) {
+ GenericType type = descriptor.exceptions.get(i);
+ buffer.append(GenericMain.getGenericCastTypeName(type));
+ }
+ else {
+ VarType type = new VarType(attr.getExcClassname(i, cl.getPool()), true);
+ buffer.append(ExprProcessor.getCastTypeName(type));
}
}
+ }
+ }
- bufstrwriter.write(" ");
- String parname = meth.varproc.getVarName(new VarVersionPaar(index, 0));
- bufstrwriter.write(parname == null ? "param" + index : parname); // null iff decompiled with errors
- firstpar = false;
- param_count_explicit++;
+ if ((flags & (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_NATIVE)) != 0) { // native or abstract method (explicit or interface)
+ if (isAnnotation) {
+ StructAnnDefaultAttribute attr = (StructAnnDefaultAttribute)mt.getAttributes().getWithKey("AnnotationDefault");
+ if (attr != null) {
+ buffer.append(" default ");
+ buffer.append(attr.getDefaultValue().toJava(indent + 1));
+ }
}
- index += md.params[i].stack_size;
+ buffer.append(';');
+ buffer.append(lineSeparator);
}
+ else {
+ if (!clinit && !dinit) {
+ buffer.append(' ');
+ }
- bufstrwriter.write(")");
+ buffer.append('{');
+ buffer.append(lineSeparator);
- StructExceptionsAttribute attr = (StructExceptionsAttribute)mt.getAttributes().getWithKey("Exceptions");
- if ((descriptor != null && !descriptor.exceptions.isEmpty()) || attr != null) {
- throwsExceptions = true;
- bufstrwriter.write(" throws ");
+ RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
- for (int i = 0; i < attr.getThrowsExceptions().size(); i++) {
- if (i > 0) {
- bufstrwriter.write(", ");
+ if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence
+ try {
+ String code = root.toJava(indent + 1);
+
+ hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0;
+
+ buffer.append(code);
}
- if (descriptor != null && !descriptor.exceptions.isEmpty()) {
- bufstrwriter.write(GenericMain.getGenericCastTypeName(descriptor.exceptions.get(i)));
- }
- else {
- VarType exctype = new VarType(attr.getExcClassname(i, cl.getPool()), true);
- bufstrwriter.write(ExprProcessor.getCastTypeName(exctype));
+ catch (Throwable ex) {
+ DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.", ex);
+ methodWrapper.decompiledWithErrors = true;
}
}
- }
- }
-
- boolean hidemethod = false;
- if ((flags & (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_NATIVE)) != 0) { // native or abstract method (explicit or interface)
- if (isAnnotation) {
- StructAnnDefaultAttribute attr = (StructAnnDefaultAttribute)mt.getAttributes().getWithKey("AnnotationDefault");
- if (attr != null) {
- bufstrwriter.write(" default ");
- bufstrwriter.write(attr.getDefaultValue().toJava(indent + 1));
+ if (methodWrapper.decompiledWithErrors) {
+ buffer.append(InterpreterUtil.getIndentString(indent + 1));
+ buffer.append("// $FF: Couldn't be decompiled");
+ buffer.append(lineSeparator);
}
- }
- bufstrwriter.write(";");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
- }
- else {
- if (!clinit && !dinit) {
- bufstrwriter.write(" ");
+ buffer.append(indentString);
+ buffer.append('}');
+ buffer.append(lineSeparator);
}
- bufstrwriter.write("{");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
-
- RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
-
- if (root != null && !meth.decompiledWithErrors) { // check for existence
- try {
- String code = root.toJava(indent + 1);
-
- boolean singleinit = false;
- if (init &&
- param_count_explicit == 0 &&
- !throwsExceptions &&
- DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) {
- int init_counter = 0;
- for (MethodWrapper mth : wrapper.getMethods()) {
- if ("<init>".equals(mth.methodStruct.getName())) {
- init_counter++;
- }
- }
- singleinit = (init_counter == 1);
- }
+ }
+ finally {
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper);
+ }
- hidemethod = (clinit || dinit || singleinit) && code.length() == 0;
+ return !hideMethod;
+ }
- bufstrwriter.write(code);
- }
- catch (Throwable ex) {
- DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.", ex);
- meth.decompiledWithErrors = true;
- }
- }
+ private static boolean hideConstructor(ClassWrapper wrapper, boolean init, boolean throwsExceptions, int paramCount) {
+ if (!init || throwsExceptions || paramCount > 0 || !DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) {
+ return false;
+ }
- if (meth.decompiledWithErrors) {
- bufstrwriter.write(InterpreterUtil.getIndentString(indent + 1));
- bufstrwriter.write("// $FF: Couldn't be decompiled");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
+ int count = 0;
+ for (StructMethod mt : wrapper.getClassStruct().getMethods()) {
+ if ("<init>".equals(mt.getName())) {
+ if (++count > 1) {
+ return false;
+ }
}
-
- bufstrwriter.write(indstr + "}");
- bufstrwriter.write(DecompilerContext.getNewLineSeparator());
}
- bufstrwriter.flush();
+ return true;
+ }
- if (!hidemethod) {
- writer.write(strwriter.toString());
- }
+ private static void appendDeprecation(StringBuilder buffer, String indentString, String lineSeparator) {
+ buffer.append(indentString).append("/** @deprecated */").append(lineSeparator);
+ }
- DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methold);
+ private enum MType {CLASS, FIELD, METHOD}
- return !hidemethod;
- }
+ private static void appendRenameComment(StringBuilder buffer, String oldName, MType type, int indent, String lineSeparator) {
+ if (oldName == null) return;
- private static List<AnnotationExprent> getAllAnnotations(VBStyleCollection<StructGeneralAttribute, String> attributes) {
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append("// $FF: renamed from: ");
- String[] annattrnames = new String[]{StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS,
- StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS};
+ switch (type) {
+ case CLASS:
+ buffer.append(ExprProcessor.buildJavaClassName(oldName));
+ break;
- List<AnnotationExprent> lst = new ArrayList<AnnotationExprent>();
+ case FIELD:
+ String[] fParts = oldName.split(" ");
+ FieldDescriptor fd = FieldDescriptor.parseDescriptor(fParts[2]);
+ buffer.append(fParts[1]);
+ buffer.append(' ');
+ buffer.append(getTypePrintOut(fd.type));
+ break;
- for (String attrname : annattrnames) {
- StructAnnotationAttribute attr = (StructAnnotationAttribute)attributes.getWithKey(attrname);
- if (attr != null) {
- lst.addAll(attr.getAnnotations());
- }
+ default:
+ String[] mParts = oldName.split(" ");
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mParts[2]);
+ buffer.append(mParts[1]);
+ buffer.append(" (");
+ boolean first = true;
+ for (VarType paramType : md.params) {
+ if (!first) {
+ buffer.append(", ");
+ }
+ first = false;
+ buffer.append(getTypePrintOut(paramType));
+ }
+ buffer.append(") ");
+ buffer.append(getTypePrintOut(md.ret));
}
- return lst;
+ buffer.append(lineSeparator);
}
- private static List<List<AnnotationExprent>> getAllParameterAnnotations(VBStyleCollection<StructGeneralAttribute, String> attributes) {
-
- String[] annattrnames = new String[]{StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS,
- StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS};
+ private static String getTypePrintOut(VarType type) {
+ String typeText = ExprProcessor.getCastTypeName(type, false);
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeText) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ typeText = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT, false);
+ }
+ return typeText;
+ }
- List<List<AnnotationExprent>> ret = new ArrayList<List<AnnotationExprent>>();
+ private static void appendComment(StringBuilder buffer, String comment, String indentString, String lineSeparator) {
+ buffer.append(indentString).append("// $FF: ").append(comment).append(lineSeparator);
+ }
- for (String attrname : annattrnames) {
- StructAnnotationParameterAttribute attr = (StructAnnotationParameterAttribute)attributes.getWithKey(attrname);
- if (attr != null) {
- for (int i = 0; i < attr.getParamAnnotations().size(); i++) {
- List<AnnotationExprent> lst = new ArrayList<AnnotationExprent>();
- boolean isnew = (ret.size() <= i);
+ private static final String[] ANNOTATION_ATTRIBUTES = {
+ StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS};
- if (!isnew) {
- lst = ret.get(i);
- }
- lst.addAll(attr.getParamAnnotations().get(i));
+ private static void appendAnnotations(StringBuilder buffer, StructMember mb, int indent, String lineSeparator) {
+ for (String name : ANNOTATION_ATTRIBUTES) {
+ StructAnnotationAttribute attribute = (StructAnnotationAttribute)mb.getAttributes().getWithKey(name);
+ if (attribute != null) {
+ for (AnnotationExprent annotation : attribute.getAnnotations()) {
+ buffer.append(annotation.toJava(indent)).append(lineSeparator);
+ }
+ }
+ }
+ }
- if (isnew) {
- ret.add(lst);
- }
- else {
- ret.set(i, lst);
+ private static final String[] PARAMETER_ANNOTATION_ATTRIBUTES = {
+ StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS};
+
+ private static void appendParameterAnnotations(StringBuilder buffer, StructMethod mt, int param) {
+ for (String name : PARAMETER_ANNOTATION_ATTRIBUTES) {
+ StructAnnotationParameterAttribute attribute = (StructAnnotationParameterAttribute)mt.getAttributes().getWithKey(name);
+ if (attribute != null) {
+ List<List<AnnotationExprent>> annotations = attribute.getParamAnnotations();
+ if (param < annotations.size()) {
+ for (AnnotationExprent annotation : annotations.get(param)) {
+ buffer.append(annotation.toJava(0)).append(' ');
}
}
}
}
+ }
- return ret;
+ private static final Map<Integer, String> MODIFIERS = new LinkedHashMap<Integer, String>() {{
+ put(CodeConstants.ACC_PUBLIC, "public");
+ put(CodeConstants.ACC_PROTECTED, "protected");
+ put(CodeConstants.ACC_PRIVATE, "private");
+ put(CodeConstants.ACC_ABSTRACT, "abstract");
+ put(CodeConstants.ACC_STATIC, "static");
+ put(CodeConstants.ACC_FINAL, "final");
+ put(CodeConstants.ACC_STRICT, "strictfp");
+ put(CodeConstants.ACC_TRANSIENT, "transient");
+ put(CodeConstants.ACC_VOLATILE, "volatile");
+ put(CodeConstants.ACC_SYNCHRONIZED, "synchronized");
+ put(CodeConstants.ACC_NATIVE, "native");
+ }};
+
+ private static final int CLASS_ALLOWED =
+ CodeConstants.ACC_PUBLIC | CodeConstants.ACC_PROTECTED | CodeConstants.ACC_PRIVATE | CodeConstants.ACC_ABSTRACT |
+ CodeConstants.ACC_STATIC | CodeConstants.ACC_FINAL | CodeConstants.ACC_STRICT;
+ private static final int FIELD_ALLOWED =
+ CodeConstants.ACC_PUBLIC | CodeConstants.ACC_PROTECTED | CodeConstants.ACC_PRIVATE | CodeConstants.ACC_STATIC |
+ CodeConstants.ACC_FINAL | CodeConstants.ACC_TRANSIENT | CodeConstants.ACC_VOLATILE;
+ private static final int METHOD_ALLOWED =
+ CodeConstants.ACC_PUBLIC | CodeConstants.ACC_PROTECTED | CodeConstants.ACC_PRIVATE | CodeConstants.ACC_ABSTRACT |
+ CodeConstants.ACC_STATIC | CodeConstants.ACC_FINAL | CodeConstants.ACC_SYNCHRONIZED | CodeConstants.ACC_NATIVE | CodeConstants.ACC_STRICT;
+
+ private static final int CLASS_EXCLUDED = CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_STATIC;
+ private static final int FIELD_EXCLUDED = CodeConstants.ACC_PUBLIC | CodeConstants.ACC_STATIC | CodeConstants.ACC_FINAL;
+ private static final int METHOD_EXCLUDED = CodeConstants.ACC_PUBLIC | CodeConstants.ACC_ABSTRACT;
+
+ private static void appendModifiers(StringBuilder buffer, int flags, int allowed, boolean isInterface, int excluded) {
+ flags &= allowed;
+ if (!isInterface) excluded = 0;
+ for (int modifier : MODIFIERS.keySet()) {
+ if ((flags & modifier) == modifier && (modifier & excluded) == 0) {
+ buffer.append(MODIFIERS.get(modifier)).append(' ');
+ }
+ }
}
- private static String getDescriptorPrintOut(String descriptor, int element) {
+ private static void appendTypeParameters(StringBuilder buffer, List<String> parameters, List<List<GenericType>> bounds) {
+ buffer.append('<');
- switch (element) {
- case 0: // class
- return ExprProcessor.buildJavaClassName(descriptor);
- case 1: // field
- return getTypePrintOut(FieldDescriptor.parseDescriptor(descriptor).type);
- case 2: // method
- default:
- MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor);
+ for (int i = 0; i < parameters.size(); i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
- StringBuilder buffer = new StringBuilder("(");
+ buffer.append(parameters.get(i));
- boolean first = true;
- for (VarType partype : md.params) {
- if (first) {
- first = false;
- }
- else {
- buffer.append(", ");
- }
- buffer.append(getTypePrintOut(partype));
+ List<GenericType> parameterBounds = bounds.get(i);
+ if (parameterBounds.size() > 1 || !"java/lang/Object".equals(parameterBounds.get(0).value)) {
+ buffer.append(" extends ");
+ buffer.append(GenericMain.getGenericCastTypeName(parameterBounds.get(0)));
+ for (int j = 1; j < parameterBounds.size(); j++) {
+ buffer.append(" & ");
+ buffer.append(GenericMain.getGenericCastTypeName(parameterBounds.get(j)));
}
- buffer.append(") ");
- buffer.append(getTypePrintOut(md.ret));
-
- return buffer.toString();
+ }
}
- }
- private static String getTypePrintOut(VarType type) {
- String strtype = ExprProcessor.getCastTypeName(type, false);
- if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(strtype) &&
- DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
- strtype = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT, false);
- }
- return strtype;
+ buffer.append('>');
}
}
diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
index 034efb1..0fc74fd 100644
--- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
+++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
@@ -34,15 +34,13 @@ import org.jetbrains.java.decompiler.struct.attr.StructInnerClassesAttribute;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
-import java.io.BufferedWriter;
import java.io.IOException;
-import java.io.StringWriter;
import java.util.*;
import java.util.Map.Entry;
public class ClassesProcessor {
- private HashMap<String, ClassNode> mapRootClasses = new HashMap<String, ClassNode>();
+ private Map<String, ClassNode> mapRootClasses = new HashMap<String, ClassNode>();
public ClassesProcessor(StructContext context) {
@@ -96,7 +94,7 @@ public class ClassesProcessor {
arr[3] = entry[3];
// enclosing class
- String enclClassName = null;
+ String enclClassName;
if (entry[1] != 0) {
enclClassName = strentry[1];
}
@@ -186,9 +184,9 @@ public class ClassesProcessor {
Object[] arr = mapInnerClasses.get(nestedClass);
- if ((Integer)arr[2] == ClassNode.CLASS_MEMBER) {
+ //if ((Integer)arr[2] == ClassNode.CLASS_MEMBER) {
// FIXME: check for consistent naming
- }
+ //}
nestednode.type = (Integer)arr[2];
nestednode.simpleName = (String)arr[1];
@@ -234,56 +232,49 @@ public class ClassesProcessor {
}
}
-
- public void writeClass(StructClass cl, BufferedWriter writer) throws IOException {
-
+ public void writeClass(StructClass cl, StringBuilder buffer) throws IOException {
ClassNode root = mapRootClasses.get(cl.qualifiedName);
if (root.type != ClassNode.CLASS_ROOT) {
return;
}
try {
- DecompilerContext.setImportCollector(new ImportCollector(root));
+ ImportCollector importCollector = new ImportCollector(root);
+ DecompilerContext.setImportCollector(importCollector);
DecompilerContext.setCounterContainer(new CounterContainer());
- // lambda processing
- LambdaProcessor lambda_proc = new LambdaProcessor();
- lambda_proc.processClass(root);
+ new LambdaProcessor().processClass(root);
// add simple class names to implicit import
- addClassnameToImport(root, DecompilerContext.getImportCollector());
- // build wrappers for all nested classes
- // that's where the actual processing takes place
+ addClassnameToImport(root, importCollector);
+
+ // build wrappers for all nested classes (that's where actual processing takes place)
initWrappers(root);
- NestedClassProcessor nestedproc = new NestedClassProcessor();
- nestedproc.processClass(root, root);
+ new NestedClassProcessor().processClass(root, root);
- NestedMemberAccess nstmember = new NestedMemberAccess();
- nstmember.propagateMemberAccess(root);
+ new NestedMemberAccess().propagateMemberAccess(root);
- ClassWriter clwriter = new ClassWriter();
+ StringBuilder classBuffer = new StringBuilder();
+ new ClassWriter().classToJava(root, classBuffer, 0);
- StringWriter strwriter = new StringWriter();
- clwriter.classToJava(root, new BufferedWriter(strwriter), 0);
+ String lineSeparator = DecompilerContext.getNewLineSeparator();
int index = cl.qualifiedName.lastIndexOf("/");
if (index >= 0) {
String packageName = cl.qualifiedName.substring(0, index).replace('/', '.');
- writer.write("package ");
- writer.write(packageName);
- writer.write(";");
- writer.write(DecompilerContext.getNewLineSeparator());
- writer.write(DecompilerContext.getNewLineSeparator());
+ buffer.append("package ");
+ buffer.append(packageName);
+ buffer.append(";");
+ buffer.append(lineSeparator);
+ buffer.append(lineSeparator);
}
- DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, root);
-
- DecompilerContext.getImportCollector().writeImports(writer);
- writer.write(DecompilerContext.getNewLineSeparator());
+ if (importCollector.writeImports(buffer)) {
+ buffer.append(lineSeparator);
+ }
- writer.write(strwriter.toString());
- writer.flush();
+ buffer.append(classBuffer);
}
finally {
destroyWrappers(root);
@@ -327,7 +318,7 @@ public class ClassesProcessor {
}
}
- public HashMap<String, ClassNode> getMapRootClasses() {
+ public Map<String, ClassNode> getMapRootClasses() {
return mapRootClasses;
}
@@ -369,7 +360,7 @@ public class ClassesProcessor {
public ClassNode(String content_class_name,
String content_method_name,
String content_method_descriptor,
- int content_method_invokation_type,
+ int content_method_invocation_type,
String lambda_class_name,
String lambda_method_name,
String lambda_method_descriptor,
@@ -386,7 +377,7 @@ public class ClassesProcessor {
lambda_information.content_class_name = content_class_name;
lambda_information.content_method_name = content_method_name;
lambda_information.content_method_descriptor = content_method_descriptor;
- lambda_information.content_method_invokation_type = content_method_invokation_type;
+ lambda_information.content_method_invocation_type = content_method_invocation_type;
lambda_information.content_method_key =
InterpreterUtil.makeUniqueKey(lambda_information.content_method_name, lambda_information.content_method_descriptor);
@@ -401,7 +392,7 @@ public class ClassesProcessor {
lambda_information.is_method_reference = is_method_reference;
lambda_information.is_content_method_static =
- (lambda_information.content_method_invokation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic); // FIXME: redundant?
+ (lambda_information.content_method_invocation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic); // FIXME: redundant?
}
public ClassNode(int type, StructClass classStruct) {
@@ -428,7 +419,7 @@ public class ClassesProcessor {
public String content_class_name;
public String content_method_name;
public String content_method_descriptor;
- public int content_method_invokation_type; // values from CONSTANT_MethodHandle_REF_*
+ public int content_method_invocation_type; // values from CONSTANT_MethodHandle_REF_*
public String content_method_key;
diff --git a/src/org/jetbrains/java/decompiler/main/Fernflower.java b/src/org/jetbrains/java/decompiler/main/Fernflower.java
index 67596be..34f9196 100644
--- a/src/org/jetbrains/java/decompiler/main/Fernflower.java
+++ b/src/org/jetbrains/java/decompiler/main/Fernflower.java
@@ -26,8 +26,6 @@ import org.jetbrains.java.decompiler.struct.StructClass;
import org.jetbrains.java.decompiler.struct.StructContext;
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
-import java.io.BufferedWriter;
-import java.io.StringWriter;
import java.util.Map;
@@ -81,9 +79,9 @@ public class Fernflower implements IDecompiledData {
public String getClassContent(StructClass cl) {
try {
- StringWriter writer = new StringWriter();
- classesProcessor.writeClass(cl, new BufferedWriter(writer));
- return writer.toString();
+ StringBuilder buffer = new StringBuilder();
+ classesProcessor.writeClass(cl, buffer);
+ return buffer.toString();
}
catch (Throwable ex) {
DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", ex);
diff --git a/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java b/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
index 6480963..9b6f7ed 100644
--- a/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
+++ b/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
@@ -20,8 +20,6 @@ import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.struct.StructContext;
-import java.io.BufferedWriter;
-import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
@@ -30,12 +28,9 @@ public class ImportCollector {
private static final String JAVA_LANG_PACKAGE = "java.lang";
- private HashMap<String, String> mapSimpleNames = new HashMap<String, String>();
-
- private HashSet<String> setNotImportedNames = new HashSet<String>();
-
+ private Map<String, String> mapSimpleNames = new HashMap<String, String>();
+ private Set<String> setNotImportedNames = new HashSet<String>();
private String currentPackageSlash = "";
-
private String currentPackagePoint = "";
public ImportCollector(ClassNode root) {
@@ -77,7 +72,7 @@ public class ImportCollector {
return retname;
}
}
- else if (node == null || !node.classStruct.isOwn()) {
+ else {
fullname = fullname.replace('$', '.');
}
@@ -112,18 +107,20 @@ public class ImportCollector {
return retname == null ? nshort : retname;
}
- public void writeImports(BufferedWriter writer) throws IOException {
+ public boolean writeImports(StringBuilder buffer) {
+ List<String> imports = packImports();
- for (String s : packImports()) {
- writer.write("import ");
- writer.write(s);
- writer.write(";");
- writer.write(DecompilerContext.getNewLineSeparator());
+ for (String s : imports) {
+ buffer.append("import ");
+ buffer.append(s);
+ buffer.append(";");
+ buffer.append(DecompilerContext.getNewLineSeparator());
}
+
+ return imports.size() > 0;
}
private List<String> packImports() {
-
List<Entry<String, String>> lst = new ArrayList<Entry<String, String>>(mapSimpleNames.entrySet());
Collections.sort(lst, new Comparator<Entry<String, String>>() {
@@ -138,12 +135,11 @@ public class ImportCollector {
List<String> res = new ArrayList<String>();
for (Entry<String, String> ent : lst) {
- if (!setNotImportedNames.contains(ent.getKey()) // not the current class or one of the nested ones. Also not the empty package.
- && !JAVA_LANG_PACKAGE.equals(ent.getValue())
- && ent.getValue().length() > 0) {
-
- String imp = ent.getValue() + "." + ent.getKey();
- res.add(imp);
+ // exclude a current class or one of the nested ones, java.lang and empty packages
+ if (!setNotImportedNames.contains(ent.getKey()) &&
+ !JAVA_LANG_PACKAGE.equals(ent.getValue()) &&
+ !ent.getValue().isEmpty()) {
+ res.add(ent.getValue() + "." + ent.getKey());
}
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java
index 395df1b..416b831 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java
@@ -28,9 +28,6 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import org.jetbrains.java.decompiler.util.ListStack;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -260,29 +257,16 @@ public class NewExprent extends Exprent {
buf.setLength(0);
}
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
-
- ClassWriter clwriter = new ClassWriter();
- try {
- if (lambda) {
- clwriter.classLambdaToJava(child, bufstrwriter, (constructor == null ? null : constructor.getInstance()), indent);
- }
- else {
- clwriter.classToJava(child, bufstrwriter, indent);
+ if (lambda) {
+ if (!DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) {
+ buf.setLength(0); // remove the usual 'new <class>()', it will be replaced with lambda style '() ->'
}
- bufstrwriter.flush();
- }
- catch (IOException ex) {
- throw new RuntimeException(ex);
+ Exprent methodObject = constructor == null ? null : constructor.getInstance();
+ new ClassWriter().classLambdaToJava(child, buf, methodObject, indent);
}
-
- if (lambda && !DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) {
- buf.setLength(0); // remove the usual 'new <class>()', it will
- // be replaced with lambda style '() ->'
+ else {
+ new ClassWriter().classToJava(child, buf, indent);
}
-
- buf.append(strwriter.toString());
}
else if (directArrayInit) {
VarType leftType = newtype.copy();
@@ -293,10 +277,7 @@ public class NewExprent extends Exprent {
if (i > 0) {
buf.append(", ");
}
- StringBuilder buff = new StringBuilder();
- ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buff, indent, false);
-
- buf.append(buff);
+ ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buf, indent, false);
}
buf.append("}");
}
diff --git a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java
index 709b6fe..3523501 100644
--- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java
+++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java
@@ -26,9 +26,6 @@ import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
@@ -84,24 +81,11 @@ public class VarExprent extends Exprent {
}
public String toJava(int indent) {
+ StringBuilder buffer = new StringBuilder();
if (classdef) {
-
ClassNode child = DecompilerContext.getClassProcessor().getMapRootClasses().get(vartype.value);
-
- StringWriter strwriter = new StringWriter();
- BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
-
- ClassWriter clwriter = new ClassWriter();
- try {
- clwriter.classToJava(child, bufstrwriter, indent);
- bufstrwriter.flush();
- }
- catch (IOException ex) {
- throw new RuntimeException(ex);
- }
-
- return strwriter.toString();
+ new ClassWriter().classToJava(child, buffer, indent);
}
else {
String name = null;
@@ -109,18 +93,16 @@ public class VarExprent extends Exprent {
name = processor.getVarName(new VarVersionPaar(index, version));
}
- StringBuilder buf = new StringBuilder();
-
if (definition) {
if (processor != null && processor.getVarFinal(new VarVersionPaar(index, version)) == VarTypeProcessor.VAR_FINALEXPLICIT) {
- buf.append("final ");
+ buffer.append("final ");
}
- buf.append(ExprProcessor.getCastTypeName(getVartype())).append(" ");
+ buffer.append(ExprProcessor.getCastTypeName(getVartype())).append(" ");
}
- buf.append(name == null ? ("var" + index + (version == 0 ? "" : "_" + version)) : name);
-
- return buf.toString();
+ buffer.append(name == null ? ("var" + index + (version == 0 ? "" : "_" + version)) : name);
}
+
+ return buffer.toString();
}
public boolean equals(Object o) {
diff --git a/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java b/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java
index cc4e4bd..5f48e32 100644
--- a/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java
+++ b/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java
@@ -60,12 +60,16 @@ public class InterpreterUtil {
}
public static String getIndentString(int length) {
- String indent = (String)DecompilerContext.getProperty(IFernflowerPreferences.INDENT_STRING);
StringBuilder buf = new StringBuilder();
+ appendIndent(buf, length);
+ return buf.toString();
+ }
+
+ public static void appendIndent(StringBuilder buffer, int length) {
+ String indent = (String)DecompilerContext.getProperty(IFernflowerPreferences.INDENT_STRING);
while (length-- > 0) {
- buf.append(indent);
+ buffer.append(indent);
}
- return buf.toString();
}
public static boolean equalSets(Collection<?> c1, Collection<?> c2) {