From 663631f0456fcc245dd835889f86541d75161c53 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 28 Aug 2014 20:52:43 +0400 Subject: java-decompiler: post-import cleanup (classes moved) --- .../java/decompiler/main/ClassWriter.java | 1107 ++++++++++++++++++++ 1 file changed, 1107 insertions(+) create mode 100644 src/org/jetbrains/java/decompiler/main/ClassWriter.java (limited to 'src/org/jetbrains/java/decompiler/main/ClassWriter.java') diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java new file mode 100644 index 0000000..c14fe79 --- /dev/null +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -0,0 +1,1107 @@ +/* + * Fernflower - The Analytical Java Decompiler + * http://www.reversed-java.com + * + * (C) 2008 - 2010, Stiver + * + * This software is NEITHER public domain NOR free software + * as per GNU License. See license.txt for more details. + * + * This software is distributed WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. + */ + +package org.jetbrains.java.decompiler.main; + +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.List; + +import org.jetbrains.java.decompiler.code.CodeConstants; +import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; +import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; +import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; +import org.jetbrains.java.decompiler.main.rels.ClassWrapper; +import org.jetbrains.java.decompiler.main.rels.MethodWrapper; +import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; +import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; +import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent; +import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; +import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor; +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.StructMethod; +import org.jetbrains.java.decompiler.struct.attr.StructAnnDefaultAttribute; +import org.jetbrains.java.decompiler.struct.attr.StructAnnotationAttribute; +import org.jetbrains.java.decompiler.struct.attr.StructAnnotationParameterAttribute; +import org.jetbrains.java.decompiler.struct.attr.StructConstantValueAttribute; +import org.jetbrains.java.decompiler.struct.attr.StructExceptionsAttribute; +import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute; +import org.jetbrains.java.decompiler.struct.attr.StructGenericSignatureAttribute; +import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant; +import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor; +import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; +import org.jetbrains.java.decompiler.struct.gen.VarType; +import org.jetbrains.java.decompiler.struct.gen.generics.GenericClassDescriptor; +import org.jetbrains.java.decompiler.struct.gen.generics.GenericFieldDescriptor; +import org.jetbrains.java.decompiler.struct.gen.generics.GenericMain; +import org.jetbrains.java.decompiler.struct.gen.generics.GenericMethodDescriptor; +import org.jetbrains.java.decompiler.struct.gen.generics.GenericType; +import org.jetbrains.java.decompiler.util.InterpreterUtil; +import org.jetbrains.java.decompiler.util.VBStyleCollection; + +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 mod_notinterface = new HashSet(Arrays.asList(new Integer[] {CodeConstants.ACC_ABSTRACT, CodeConstants.ACC_STATIC})); + private static final HashSet mod_notinterface_fields = new HashSet(Arrays.asList(new Integer[] {CodeConstants.ACC_PUBLIC, CodeConstants.ACC_STATIC, CodeConstants.ACC_FINAL})); + private static final HashSet mod_notinterface_meth = new HashSet(Arrays.asList(new Integer[] {CodeConstants.ACC_PUBLIC, CodeConstants.ACC_ABSTRACT})); + + private ClassReference14Processor ref14processor; + + private PoolInterceptor interceptor; + + public ClassWriter() { + ref14processor = new ClassReference14Processor(); + interceptor = DecompilerContext.getPoolInterceptor(); + } + + + private void invokeProcessors(ClassNode node) { + + ClassWrapper wrapper = node.wrapper; + StructClass cl = wrapper.getClassStruct(); + + InitializerProcessor.extractInitializers(wrapper); + + if(node.type == ClassNode.CLASS_ROOT && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4)) { + ref14processor.processClassReferences(node); + } + + if(DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (cl.access_flags & CodeConstants.ACC_ENUM) != 0) { + EnumProcessor.clearEnum(wrapper); + } + + if(DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ASSERTIONS)) { + AssertProcessor.buildAssertions(node); + } + + } + + public void classLambdaToJava(ClassNode node, BufferedWriter writer, Exprent method_object, int indent) throws IOException { + + // 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; + } + + if(node_content == null) { + return; + } + + boolean lambda_to_anonymous = DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS); + + ClassNode nodeold = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE); + DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, node); + + ClassWrapper wrapper = node_content.wrapper; + StructClass cl = wrapper.getClassStruct(); + + DecompilerContext.getLogger().startWriteClass(node.simpleName); + + if(node.lambda_information.is_method_reference) { + + if(!node.lambda_information.is_content_method_static && method_object != null) { // reference to a virtual method + writer.write(method_object.toJava(indent)); + } 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= start_index) { + + if(!firstpar) { + buff.append(", "); + } + + 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; + } + buff.append(") ->"); + + writer.write(buff.toString()); + } + + StringWriter strwriter = new StringWriter(); + BufferedWriter bufstrwriter = new BufferedWriter(strwriter); + + if(lambda_to_anonymous) { + methodLambdaToJava(node, node_content, mt, bufstrwriter, indent+1, false); + } else { + methodLambdaToJava(node, node_content, mt, bufstrwriter, indent, true); + } + + 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_CLASSNODE, nodeold); + + 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_CLASSNODE); + DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, node); + + // last minute processing + invokeProcessors(node); + + DecompilerContext.getLogger().startWriteClass(cl.qualifiedName); + + writeClassDefinition(node, writer, indent); + + // methods + StringWriter strwriter = new StringWriter(); + BufferedWriter bufstrwriter = new BufferedWriter(strwriter); + + boolean firstmt = true; + boolean mthidden = false; + + for(StructMethod mt : cl.getMethods()) { + + int flags = mt.getAccessFlags(); + + boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic"); + boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0; + + if((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) && + (!isBridge || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE)) && + !wrapper.getHideMembers().contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()))) { + if(!mthidden && (!firstmt || node.type != ClassNode.CLASS_ANONYMOUS)) { + bufstrwriter.write(DecompilerContext.getNewLineSeparator()); + firstmt = false; + } + + mthidden = !methodToJava(node, mt, bufstrwriter, indent+1); + } + } + bufstrwriter.flush(); + + StringWriter strwriter1 = new StringWriter(); + BufferedWriter bufstrwriter1 = new BufferedWriter(strwriter1); + + int fields_count = 0; + + boolean enumfields = false; + + // fields + for(StructField fd: cl.getFields()) { + int flags = fd.access_flags; + boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic"); + if((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) + && !wrapper.getHideMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()))) { + + boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0; + if(isEnum) { + if(enumfields) { + bufstrwriter1.write(","); + bufstrwriter1.write(DecompilerContext.getNewLineSeparator()); + } else { + enumfields = true; + } + } else { + if(enumfields) { + bufstrwriter1.write(";"); + bufstrwriter1.write(DecompilerContext.getNewLineSeparator()); + enumfields = false; + } + } + + fieldToJava(wrapper, cl, fd, bufstrwriter1, indent+1); + fields_count++; + } + } + + if(enumfields) { + bufstrwriter1.write(";"); + bufstrwriter1.write(DecompilerContext.getNewLineSeparator()); + } + + bufstrwriter1.flush(); + + if(fields_count > 0) { + writer.write(DecompilerContext.getNewLineSeparator()); + writer.write(strwriter1.toString()); + writer.write(DecompilerContext.getNewLineSeparator()); + } + + + // methods + writer.write(strwriter.toString()); + + // member classes + for(ClassNode inner : node.nested) { + if(inner.type == ClassNode.CLASS_MEMBER) { + StructClass innercl = inner.classStruct; + + boolean isSynthetic = ((inner.access | innercl.access_flags) & CodeConstants.ACC_SYNTHETIC) != 0 || innercl.getAttributes().containsKey("Synthetic"); + if((!isSynthetic || !DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC)) + && !wrapper.getHideMembers().contains(innercl.qualifiedName)) { + writer.write(DecompilerContext.getNewLineSeparator()); + classToJava(inner, writer, indent+1); + } + } + } + + writer.write(InterpreterUtil.getIndentString(indent)); + writer.write("}"); + if(node.type != ClassNode.CLASS_ANONYMOUS) { + writer.write(DecompilerContext.getNewLineSeparator()); + } + writer.flush(); + + DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, nodeold); + + DecompilerContext.getLogger().endWriteClass(); + } + + private void writeClassDefinition(ClassNode node, BufferedWriter writer, int indent) throws IOException { + + if(node.type == ClassNode.CLASS_ANONYMOUS) { + writer.write(" {"); + writer.write(DecompilerContext.getNewLineSeparator()); + } else { + + String indstr = InterpreterUtil.getIndentString(indent); + + ClassWrapper wrapper = node.wrapper; + StructClass cl = wrapper.getClassStruct(); + + int flags = node.type == ClassNode.CLASS_ROOT?cl.access_flags: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; + + boolean isDeprecated = cl.getAttributes().containsKey("Deprecated"); + + 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) { + writer.write(indstr); + writer.write("/** @deprecated */"); + writer.write(DecompilerContext.getNewLineSeparator()); + } + + // class annotations + List lstAnn = getAllAnnotations(cl.getAttributes()); + for(AnnotationExprent annexpr : lstAnn) { + writer.write(annexpr.toJava(indent)); + writer.write(DecompilerContext.getNewLineSeparator()); + } + + boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic"); + + if(isSynthetic) { + writer.write(indstr); + writer.write("// $FF: synthetic class"); + writer.write(DecompilerContext.getNewLineSeparator()); + } + + writer.write(indstr); + + if(isEnum) { + // remove abstract and final flags (JLS 8.9 Enums) + flags &=~CodeConstants.ACC_ABSTRACT; + flags &=~CodeConstants.ACC_FINAL; + } + + for(int i=0;i0) { + writer.write(", "); + } + writer.write(descriptor.fparameters.get(i)); + + List 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))); + + for(int j=1;j"); + } + 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(descriptor != null) { + writer.write(GenericMain.getGenericCastTypeName(descriptor.superclass)); + } else { + writer.write(ExprProcessor.getCastTypeName(supertype)); + } + writer.write(" "); + } + } + + if(!isAnnotation) { + int[] interfaces = cl.getInterfaces(); + if(interfaces.length > 0) { + writer.write(isInterface?"extends ":"implements "); + for(int i=0;i0) { + 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 { + + String indstr = InterpreterUtil.getIndentString(indent); + + boolean isInterface = (cl.access_flags & CodeConstants.ACC_INTERFACE) != 0; + int flags = fd.access_flags; + + 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"); + + if (isDeprecated) { + writer.write(indstr); + writer.write("/** @deprecated */"); + writer.write(DecompilerContext.getNewLineSeparator()); + } + + // field annotations + List lstAnn = getAllAnnotations(fd.getAttributes()); + for(AnnotationExprent annexpr : lstAnn) { + writer.write(annexpr.toJava(indent)); + writer.write(DecompilerContext.getNewLineSeparator()); + } + + boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || fd.getAttributes().containsKey("Synthetic"); + boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0; + + if(isSynthetic) { + writer.write(indstr); + writer.write("// $FF: synthetic field"); + writer.write(DecompilerContext.getNewLineSeparator()); + } + + writer.write(indstr); + + if(!isEnum) { + for(int i=0;i= start_index) { + + if(!firstpar) { + bufstrwriter.write(", "); + } + + 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); + } + + 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()); + } + + RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root; + + 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; + } + } + + 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()); + } + + 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 { + + ClassWrapper wrapper = node.wrapper; + StructClass cl = wrapper.getClassStruct(); + + MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()); + + MethodWrapper methold = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER); + DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, meth); + + boolean isInterface = (cl.access_flags & CodeConstants.ACC_INTERFACE) != 0; + boolean isAnnotation = (cl.access_flags & CodeConstants.ACC_ANNOTATION) != 0; + boolean isEnum = (cl.access_flags & CodeConstants.ACC_ENUM) != 0 && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM); + boolean isDeprecated = mt.getAttributes().containsKey("Deprecated"); + + String indstr = InterpreterUtil.getIndentString(indent); + boolean clinit = false, init = false, dinit = false; + + MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); + + StringWriter strwriter = new StringWriter(); + BufferedWriter bufstrwriter = new BufferedWriter(strwriter); + + 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("".equals(mt.getName())) { + flags &= CodeConstants.ACC_STATIC; // ingnore 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(" "); + + bufstrwriter.write(indstr); + bufstrwriter.write("// $FF: renamed from: "+element[1]+" "+getDescriptorPrintOut(element[2], 2)); + bufstrwriter.write(DecompilerContext.getNewLineSeparator()); + } + } + + if (isDeprecated) { + writer.write(indstr); + writer.write("/** @deprecated */"); + writer.write(DecompilerContext.getNewLineSeparator()); + } + + // method annotations + List lstAnn = getAllAnnotations(mt.getAttributes()); + for(AnnotationExprent annexpr : lstAnn) { + bufstrwriter.write(annexpr.toJava(indent)); + bufstrwriter.write(DecompilerContext.getNewLineSeparator()); + } + + boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic"); + boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0; + + if(isSynthetic) { + bufstrwriter.write(indstr); + bufstrwriter.write("// $FF: synthetic method"); + bufstrwriter.write(DecompilerContext.getNewLineSeparator()); + } + + if(isBridge) { + bufstrwriter.write(indstr); + bufstrwriter.write("// $FF: bridge method"); + bufstrwriter.write(DecompilerContext.getNewLineSeparator()); + } + + bufstrwriter.write(indstr); + for(int i=0;i".equals(name)) { + if (node.type == ClassNode.CLASS_ANONYMOUS) { + name = ""; + dinit = true; + } else { + name = node.simpleName; + init = true; + } + } else if ("".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; + } + } + } + + boolean throwsExceptions = false; + + int param_count_explicit = 0; + + if(!clinit && !dinit) { + + boolean thisvar = (mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0; + + // formal type parameters + if(descriptor != null && !descriptor.fparameters.isEmpty()) { + bufstrwriter.write("<"); + for(int i=0;i0) { + bufstrwriter.write(", "); + } + bufstrwriter.write(descriptor.fparameters.get(i)); + + List 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))); + } + } + } + bufstrwriter.write("> "); + } + + if(!init) { + if(descriptor != null) { + bufstrwriter.write(GenericMain.getGenericCastTypeName(descriptor.ret)); + } else { + bufstrwriter.write(ExprProcessor.getCastTypeName(md.ret)); + } + bufstrwriter.write(" "); + } + + bufstrwriter.write(name); + bufstrwriter.write("("); + + // parameter annotations + List> lstParAnn = getAllParameterAnnotations(mt.getAttributes()); + + List signFields = meth.signatureFields; + + // compute last visible parameter + int lastparam_index = -1; + for(int i=0;i param_count_explicit) { + List annotations = lstParAnn.get(param_count_explicit); + for(int j=0;j 0); + + if(isVarArgs) { + partype.arraydim--; + } + + 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); + } + + bufstrwriter.write(strpartype); + + if(isVarArgs) { + bufstrwriter.write(" ..."); + } + + } else { + VarType partype = md.params[i].copy(); + + boolean isVarArgs = (i == lastparam_index && (mt.getAccessFlags() & CodeConstants.ACC_VARARGS) != 0 + && partype.arraydim > 0); + + if(isVarArgs) { + partype.decArrayDim(); + } + + 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); + } + + bufstrwriter.write(strpartype); + + if(isVarArgs) { + bufstrwriter.write(" ..."); + } + } + + 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++; + } + + index+=md.params[i].stack_size; + } + + bufstrwriter.write(")"); + + StructExceptionsAttribute attr = (StructExceptionsAttribute)mt.getAttributes().getWithKey("Exceptions"); + if((descriptor!=null && !descriptor.exceptions.isEmpty()) || attr != null) { + throwsExceptions = true; + bufstrwriter.write(" throws "); + + for(int i=0;i0) { + bufstrwriter.write(", "); + } + 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)); + } + } + } + } + + 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)); + } + } + + bufstrwriter.write(";"); + bufstrwriter.write(DecompilerContext.getNewLineSeparator()); + } else { + if(!clinit && !dinit) { + bufstrwriter.write(" "); + } + 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("".equals(mth.methodStruct.getName())) { + init_counter++; + } + } + singleinit = (init_counter == 1); + } + + hidemethod = (clinit || dinit || singleinit) && code.length() == 0; + + bufstrwriter.write(code); + } catch(Throwable ex) { + DecompilerContext.getLogger().writeMessage("Method "+mt.getName()+" "+mt.getDescriptor()+" couldn't be written.", ex); + meth.decompiledWithErrors = true; + } + } + + if(meth.decompiledWithErrors) { + bufstrwriter.write(InterpreterUtil.getIndentString(indent+1)); + bufstrwriter.write("// $FF: Couldn't be decompiled"); + bufstrwriter.write(DecompilerContext.getNewLineSeparator()); + } + + bufstrwriter.write(indstr+"}"); + bufstrwriter.write(DecompilerContext.getNewLineSeparator()); + } + + bufstrwriter.flush(); + + if(!hidemethod) { + writer.write(strwriter.toString()); + } + + DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methold); + + return !hidemethod; + } + + private List getAllAnnotations(VBStyleCollection attributes) { + + String[] annattrnames = new String[] {StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, + StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS}; + + List lst = new ArrayList(); + + for(String attrname : annattrnames) { + StructAnnotationAttribute attr = (StructAnnotationAttribute)attributes.getWithKey(attrname); + if(attr != null) { + lst.addAll(attr.getAnnotations()); + } + } + + return lst; + } + + private List> getAllParameterAnnotations(VBStyleCollection attributes) { + + String[] annattrnames = new String[] {StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, + StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS}; + + List> ret = new ArrayList>(); + + for(String attrname : annattrnames) { + StructAnnotationParameterAttribute attr = (StructAnnotationParameterAttribute)attributes.getWithKey(attrname); + if(attr != null) { + for(int i=0;i lst = new ArrayList(); + boolean isnew = (ret.size()<=i); + + if(!isnew) { + lst = ret.get(i); + } + lst.addAll(attr.getParamAnnotations().get(i)); + + if(isnew) { + ret.add(lst); + } else { + ret.set(i, lst); + } + } + } + } + + return ret; + } + + private String getDescriptorPrintOut(String descriptor, int element) { + + 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); + + StringBuilder buffer = new StringBuilder("("); + + boolean first = true; + for(VarType partype : md.params) { + if(first) { + first = false; + } else { + buffer.append(", "); + } + buffer.append(getTypePrintOut(partype)); + } + buffer.append(") "); + buffer.append(getTypePrintOut(md.ret)); + + return buffer.toString(); + } + } + + private 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; + } +} -- cgit v1.2.3