diff options
author | md_5 <git@md-5.net> | 2018-12-06 10:00:00 +1100 |
---|---|---|
committer | md_5 <git@md-5.net> | 2018-12-06 10:00:00 +1100 |
commit | 88d3d7481fb0d3f908ef19a220453ffbceeffc62 (patch) | |
tree | 9a2ce100f987925e853ab65c2fb8b57eb581def6 /src/org/jetbrains/java/decompiler/main | |
parent | e0f22e66296eeaf1e2a9af73af0c7f9ba28521b1 (diff) | |
download | fernflower-code-cleanup.tar fernflower-code-cleanup.tar.gz fernflower-code-cleanup.tar.lz fernflower-code-cleanup.tar.xz fernflower-code-cleanup.zip |
Clean up old decompiler changes + add new sugaringcode-cleanup
Contains code from:
Alexandru-Constantin Bledea - Boxing
Dmitry Cherniachenko - Vararg parameters, Boxing
Egor Ushakov - Lambda, String Quoting
Lex Manos - Switch decompilation
Thinkofdeath - Formatting
Diffstat (limited to 'src/org/jetbrains/java/decompiler/main')
9 files changed, 213 insertions, 47 deletions
diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 2b61dc2..3aa552f 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -42,6 +42,7 @@ 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.Util; import java.util.LinkedHashMap; import java.util.List; @@ -110,7 +111,7 @@ public class ClassWriter { } buffer.append("::"); - buffer.append(node.lambda_information.content_method_name); + buffer.append("<init>".equals(node.lambda_information.content_method_name) ? "new" : node.lambda_information.content_method_name); } else { // lambda method @@ -132,7 +133,13 @@ public class ClassWriter { buffer.append(", "); } - String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0)); + 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); + } + + String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0, typeName, false)); buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors firstParameter = false; @@ -179,7 +186,17 @@ public class ClassWriter { // write class definition int start_class_def = buffer.length(); - writeClassDefinition(node, buffer, indent); + boolean empty = cl.getFields().isEmpty() && cl.getMethods().isEmpty(); + if (cl.hasModifier(CodeConstants.ACC_ENUM)) { + empty = true; + for (StructField fd : cl.getFields()) { + if (fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM)) { + empty = false; + break; + } + } + } + writeClassDefinition(node, buffer, indent, empty); // // count lines in class definition the easiest way // total_offset_lines = buffer.substring(start_class_def).toString().split(lineSeparator, -1).length - 1; @@ -277,12 +294,12 @@ public class ClassWriter { DecompilerContext.getLogger().endWriteClass(); } - private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent) { + private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent, boolean empty) { String lineSeparator = DecompilerContext.getNewLineSeparator(); if (node.type == ClassNode.CLASS_ANONYMOUS) { buffer.append(" {"); - buffer.append(lineSeparator); + if (!empty) buffer.append(lineSeparator); return; } @@ -384,7 +401,10 @@ public class ClassWriter { } buffer.append('{'); - buffer.append(lineSeparator); + if (!empty) { + buffer.append(lineSeparator); + buffer.append(lineSeparator); // Spigot + } } private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) { @@ -514,7 +534,7 @@ public class ClassWriter { buffer.append(typeName); buffer.append(" "); - String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0)); + String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0, typeName, false)); // Spigot buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors firstParameter = false; @@ -701,6 +721,10 @@ public class ClassWriter { 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++) { + // Spigot Start + String typeName; + boolean isVarArg; + // Spigot end if (signFields == null || signFields.get(i) == null) { if (!firstParameter) { buffer.append(", "); @@ -715,12 +739,12 @@ public class ClassWriter { if (descriptor != null) { GenericType parameterType = descriptor.params.get(i); - boolean isVarArg = (i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.arraydim > 0); + isVarArg = (i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.arraydim > 0); // Spigot if (isVarArg) { parameterType.arraydim--; } - String typeName = GenericMain.getGenericCastTypeName(parameterType); + typeName = GenericMain.getGenericCastTypeName(parameterType); // Spigot if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) && DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) { typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT); @@ -735,12 +759,12 @@ public class ClassWriter { else { VarType parameterType = md.params[i].copy(); - boolean isVarArg = (i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.arraydim > 0); + isVarArg = (i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.arraydim > 0); // Spigot if (isVarArg) { parameterType.decArrayDim(); } - String typeName = ExprProcessor.getCastTypeName(parameterType); + typeName = ExprProcessor.getCastTypeName(parameterType); // Spigot if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) && DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) { typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT); @@ -754,7 +778,7 @@ public class ClassWriter { } buffer.append(' '); - String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0)); + String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0, typeName, isVarArg)); // Spigot buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors firstParameter = false; @@ -806,9 +830,10 @@ public class ClassWriter { //TODO: for now only start line set buffer.setCurrentLine(startLine); - buffer.append('{').appendLineSeparator(); + buffer.append('{'); RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root; + boolean empty = false; if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence try { @@ -816,8 +841,15 @@ public class ClassWriter { String code = root.toJava(indent + 1, tracer); + if (Util.rtrim(code).isEmpty()) code = ""; + hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0; + if (!code.isEmpty()) { + buffer.appendLineSeparator(); + } else { + empty = true; + } buffer.append(code); } catch (Throwable ex) { @@ -832,7 +864,10 @@ public class ClassWriter { buffer.append(lineSeparator); } - buffer.appendIndent(indent).append('}').appendLineSeparator(); + if (!empty) { + buffer.appendIndent(indent); + } + buffer.append('}').appendLineSeparator(); } } finally { @@ -918,7 +953,7 @@ public class ClassWriter { } private static void appendComment(TextBuffer buffer, String comment, int indent, String lineSeparator) { - buffer.appendIndent(indent).append("// $FF: ").append(comment).append(lineSeparator); + // buffer.appendIndent(indent).append("// $FF: ").append(comment).append(lineSeparator); // Spigot: Squash comments } private static final String[] ANNOTATION_ATTRIBUTES = { diff --git a/src/org/jetbrains/java/decompiler/main/Fernflower.java b/src/org/jetbrains/java/decompiler/main/Fernflower.java index 15baac5..85d9b00 100644 --- a/src/org/jetbrains/java/decompiler/main/Fernflower.java +++ b/src/org/jetbrains/java/decompiler/main/Fernflower.java @@ -85,7 +85,7 @@ public class Fernflower implements IDecompiledData { TextBuffer buffer = new TextBuffer(ClassesProcessor.AVERAGE_CLASS_SIZE); buffer.append(DecompilerContext.getProperty(IFernflowerPreferences.BANNER).toString()); classesProcessor.writeClass(cl, buffer); - return buffer.toString(); + return org.spigotmc.fernflower.EclipseFormatter.format(buffer.toString()); // Spigot } catch (Throwable ex) { DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", ex); diff --git a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java index aabea15..4c3f625 100644 --- a/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java @@ -139,7 +139,7 @@ public class InitializerProcessor { if (fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) && cl.hasField(fexpr.getName(), fexpr.getDescriptor().descriptorString)) { - if (isExprentIndependent(asexpr.getRight(), meth)) { + if (true || isExprentIndependent(asexpr.getRight(), meth)) { // Spigot String keyField = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString); if (!wrapper.getStaticFieldInitializers().containsKey(keyField)) { diff --git a/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java b/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java index c66a3e0..fae600a 100644 --- a/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java +++ b/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java @@ -145,7 +145,7 @@ public class ImportCollector { // 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()) { + !ent.getValue().isEmpty() && !ent.getValue().equals(this.currentPackagePoint)) { // Spigot: Remove same package imports res.add(ent.getValue() + "." + ent.getKey()); } } diff --git a/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java b/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java index dfde971..8d9d5c0 100644 --- a/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java +++ b/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java @@ -15,6 +15,7 @@ */ package org.jetbrains.java.decompiler.main.collectors; +import java.util.Collection; import java.util.HashSet; public class VarNamesCollector { @@ -24,7 +25,7 @@ public class VarNamesCollector { public VarNamesCollector() { } - public VarNamesCollector(HashSet<String> setNames) { + public VarNamesCollector(Collection<String> setNames) { usedNames.addAll(setNames); } diff --git a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java index 677d05d..7d96e62 100644 --- a/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java +++ b/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java @@ -91,6 +91,6 @@ public interface IFernflowerPreferences { put(MAX_PROCESSING_METHOD, "0"); put(RENAME_ENTITIES, "0"); put(NEW_LINE_SEPARATOR, (InterpreterUtil.IS_WINDOWS ? "0" : "1")); - put(INDENT_STRING, " "); + put(INDENT_STRING, " "); }}); } diff --git a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java index 4a32179..b89bcd2 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java +++ b/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java @@ -131,7 +131,7 @@ public class ClassWrapper { int varindex = 0; for (int i = 0; i < paramcount; i++) { - varproc.setVarName(new VarVersionPaar(varindex, 0), vc.getFreeName(varindex)); + varproc.setVarName(new VarVersionPaar(varindex, 0, classStruct.qualifiedName, false), vc.getFreeName(varindex)); if (thisvar) { if (i == 0) { diff --git a/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java index 743ce12..437568b 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java @@ -36,10 +36,9 @@ import java.util.*; public class LambdaProcessor { - private static final String JAVAC_LAMBDA_CLASS = "java/lang/invoke/LambdaMetafactory"; - private static final String JAVAC_LAMBDA_METHOD = "metafactory"; - private static final String JAVAC_LAMBDA_METHOD_DESCRIPTOR = - "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"; + @SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_CLASS = "java/lang/invoke/LambdaMetafactory"; + @SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_METHOD = "metafactory"; + @SuppressWarnings("SpellCheckingInspection") private static final String JAVAC_LAMBDA_ALT_METHOD = "altMetafactory"; public void processClass(ClassNode node) throws IOException { @@ -47,9 +46,7 @@ public class LambdaProcessor { processClass(child); } - if (node.nested.isEmpty()) { - hasLambda(node); - } + hasLambda(node); } public boolean hasLambda(ClassNode node) throws IOException { @@ -67,17 +64,16 @@ public class LambdaProcessor { return false; // no bootstrap constants in pool } - Set<Integer> lambda_methods = new HashSet<Integer>(); + BitSet lambda_methods = new BitSet(); // find lambda bootstrap constants for (int i = 0; i < bootstrap.getMethodsNumber(); ++i) { LinkConstant method_ref = bootstrap.getMethodReference(i); // method handle + // FIXME: extend for Eclipse etc. at some point if (JAVAC_LAMBDA_CLASS.equals(method_ref.classname) && - JAVAC_LAMBDA_METHOD.equals(method_ref.elementname) && - JAVAC_LAMBDA_METHOD_DESCRIPTOR - .equals(method_ref.descriptor)) { // check for javac lambda structure. FIXME: extend for Eclipse etc. at some point - lambda_methods.add(i); + (JAVAC_LAMBDA_METHOD.equals(method_ref.elementname) || JAVAC_LAMBDA_ALT_METHOD.equals(method_ref.elementname))) { + lambda_methods.set(i); } } @@ -101,7 +97,7 @@ public class LambdaProcessor { if (instr.opcode == CodeConstants.opc_invokedynamic) { LinkConstant invoke_dynamic = cl.getPool().getLinkConstant(instr.getOperand(0)); - if (lambda_methods.contains(invoke_dynamic.index1)) { // lambda invocation found + if (lambda_methods.get(invoke_dynamic.index1)) { // lambda invocation found List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_dynamic.index1); MethodDescriptor md = MethodDescriptor.parseDescriptor(invoke_dynamic.descriptor); @@ -122,7 +118,9 @@ public class LambdaProcessor { node_lambda.parent = node; clprocessor.getMapRootClasses().put(node_lambda.simpleName, node_lambda); - mapMethodsLambda.put(node_lambda.lambda_information.content_method_key, node_lambda.simpleName); + if (!node_lambda.lambda_information.is_method_reference) { + mapMethodsLambda.put(node_lambda.lambda_information.content_method_key, node_lambda.simpleName); + } } } } diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java index 25ff812..23ad443 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -16,6 +16,7 @@ package org.jetbrains.java.decompiler.main.rels; import org.jetbrains.java.decompiler.code.CodeConstants; +import org.jetbrains.java.decompiler.code.cfg.BasicBlock; import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.collectors.CounterContainer; @@ -25,8 +26,11 @@ import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.modules.decompiler.exps.*; import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph; import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode; +import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement; +import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement; import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar; @@ -40,6 +44,7 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil; import java.util.*; import java.util.Map.Entry; +import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; public class NestedClassProcessor { @@ -58,6 +63,10 @@ public class NestedClassProcessor { return; } + if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM)) { + gatherEnumSwitchMaps(node); + } + if (node.type != ClassNode.CLASS_LAMBDA) { computeLocalVarsAndDefinitions(node); @@ -102,9 +111,131 @@ public class NestedClassProcessor { } } + /** + * When Java introduced Enums they aded the ability to use them in Switch statements. + * This was done in a purely syntax sugar way using the old switch on int methods. + * The compiler creates a synthetic class with a static int array field. + * To support enums changing post compile, It initializes this field with a length of the current enum length. + * And then for every referenced enum value it adds a mapping in the form of: + * try { + * field[Enum.VALUE.ordinal()] = 1; + * } catch (FieldNotFoundException e) {} + * + * If a class has multiple switches on multiple enums, the compiler adds the init and try list to the BEGINNING of the static initalizer. + * But they add the field to the END of the fields list. + */ + private void gatherEnumSwitchMaps(ClassNode node) { + if (node.wrapper == null) { + return; + } + for (ClassNode child : node.nested) { + gatherEnumSwitchMaps(child); + } + + MethodWrapper clinit = node.wrapper.getMethodWrapper("<clinit>", "()V"); + if (clinit == null || clinit.root == null || clinit.root.getFirst().type != Statement.TYPE_SEQUENCE) { + return; + } + + final int STATIC_FINAL_SYNTHETIC = CodeConstants.ACC_STATIC | CodeConstants.ACC_FINAL | CodeConstants.ACC_SYNTHETIC; + Set<String> potentialFields = new HashSet<String>(); + for (StructField fd : node.classStruct.getFields()) { + if ((fd.getAccessFlags() & STATIC_FINAL_SYNTHETIC) == STATIC_FINAL_SYNTHETIC && "[I".equals(fd.getDescriptor())) { + potentialFields.add(fd.getName()); + } + } + + if (potentialFields.size() == 0) { + return; + } + + SequenceStatement seq = (SequenceStatement)clinit.root.getFirst(); + for (int x = 0; x < seq.getStats().size();) { + Statement stat = seq.getStats().get(x); + if (stat.type != Statement.TYPE_BASICBLOCK || stat.getExprents() == null || stat.getExprents().size() != 1 || stat.getExprents().get(0).type != Exprent.EXPRENT_ASSIGNMENT) { + break; + } + AssignmentExprent ass = (AssignmentExprent)stat.getExprents().get(0); + if (ass.getLeft().type != Exprent.EXPRENT_FIELD || ass.getRight().type != Exprent.EXPRENT_NEW) { + break; + } + FieldExprent mapField = (FieldExprent)ass.getLeft(); + NewExprent _new = ((NewExprent)ass.getRight()); + if (!mapField.getClassname().equals(node.classStruct.qualifiedName) || !potentialFields.contains(mapField.getName()) || + _new.getNewtype().type != CodeConstants.TYPE_INT || _new.getNewtype().arraydim != 1 || + _new.getLstDims().size() != 1 || _new.getLstDims().get(0).type != Exprent.EXPRENT_FUNCTION) { + break; + } + FunctionExprent func = (FunctionExprent)_new.getLstDims().get(0); + if (func.getFunctype() != FunctionExprent.FUNCTION_ARRAYLENGTH || func.getLstOperands().size() != 1 || func.getLstOperands().get(0).type != Exprent.EXPRENT_INVOCATION) { + break; + } + InvocationExprent invoc = (InvocationExprent)func.getLstOperands().get(0); + if (!"values".equals(invoc.getName()) || !("()[L" + invoc.getClassname() + ";").equals(invoc.getStringDescriptor())) { + break; + } + + String fieldName = mapField.getName(); + String enumName = invoc.getClassname(); + Map<Integer, String> idToName = new HashMap<Integer, String>(); + + boolean replace = false; + int y = x; + while (++y < seq.getStats().size()) { + if (seq.getStats().get(y).type != Statement.TYPE_TRYCATCH) { + break; + } + CatchStatement _try = (CatchStatement)seq.getStats().get(y); + Statement first = _try.getFirst(); + List<Exprent> exprents = first.getExprents(); + if (_try.getVars().size() != 1 || !"java/lang/NoSuchFieldError".equals(_try.getVars().get(0).getVartype().value) || + first.type != Statement.TYPE_BASICBLOCK || exprents == null || exprents.size() != 1 || exprents.get(0).type != Exprent.EXPRENT_ASSIGNMENT) { + break; + } + ass = (AssignmentExprent)exprents.get(0); + if (ass.getRight().type != Exprent.EXPRENT_CONST || (!(((ConstExprent)ass.getRight()).getValue() instanceof Integer)) || + ass.getLeft().type != Exprent.EXPRENT_ARRAY){ + break; + } + ArrayExprent array = (ArrayExprent)ass.getLeft(); + if (array.getArray().type != Exprent.EXPRENT_FIELD || !array.getArray().equals(mapField) || array.getIndex().type != Exprent.EXPRENT_INVOCATION) { + break; + } + invoc = (InvocationExprent)array.getIndex(); + if (!enumName.equals(invoc.getClassname()) || !"ordinal".equals(invoc.getName()) || !"()I".equals(invoc.getStringDescriptor()) || + invoc.getInstance().type != Exprent.EXPRENT_FIELD) { + break; + } + + FieldExprent enumField = (FieldExprent)invoc.getInstance(); + if (!enumName.equals(enumField.getClassname()) || !enumField.isStatic()) { + break; + } + + idToName.put((Integer)((ConstExprent)ass.getRight()).getValue(), enumField.getName()); + seq.replaceStatement(_try, getNewEmptyStatement()); + replace = true; + } + + if (replace) { + seq.replaceStatement(seq.getStats().get(x), getNewEmptyStatement()); + node.classStruct.enumSwitchMap.put(fieldName, idToName); + node.wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fieldName, "[I")); + } + x = y; + } + } + + private Statement getNewEmptyStatement() { + BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock( + DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER))); + bstat.setExprents(new ArrayList<Exprent>()); + return bstat; + } + private static void setLambdaVars(ClassNode parent, ClassNode child) { - if (child.lambda_information.is_method_reference) { // method reference, no code and no parameters + if (parent.wrapper == null || child.lambda_information.is_method_reference) { // method reference, no code and no parameters return; } @@ -147,6 +278,7 @@ public class NestedClassProcessor { if (expr.type == Exprent.EXPRENT_NEW) { NewExprent new_expr = (NewExprent)expr; + VarNamesCollector enclosingCollector = new VarNamesCollector(encmeth.varproc.getVarNames()); if (new_expr.isLambda() && lambda_class_type.equals(new_expr.getNewtype())) { InvocationExprent inv_dynamic = new_expr.getConstructor(); @@ -154,16 +286,16 @@ public class NestedClassProcessor { int param_index = is_static_lambda_content ? 0 : 1; int varindex = is_static_lambda_content ? 0 : 1; - for (int i = 0; i < vars_count; ++i) { - - Exprent param = inv_dynamic.getLstParameters().get(param_index + i); - - if (param.type == Exprent.EXPRENT_VAR) { - VarVersionPaar enc_varpaar = new VarVersionPaar((VarExprent)param); - String enc_varname = encmeth.varproc.getVarName(enc_varpaar); + for (int i = 0; i < md_content.params.length; ++i) { + VarVersionPaar varVersion = new VarVersionPaar(varindex, 0, ExprProcessor.getCastTypeName(md_content.params[i].copy()), false); + if (i < vars_count) { + Exprent param = inv_dynamic.getLstParameters().get(param_index + i); - //meth.varproc.setVarName(new VarVersionPaar(varindex, 0), enc_varname); - mapNewNames.put(new VarVersionPaar(varindex, 0), enc_varname); + if (param.type == Exprent.EXPRENT_VAR) { + mapNewNames.put(varVersion, encmeth.varproc.getVarName(new VarVersionPaar((VarExprent) param))); + } + } else { + mapNewNames.put(varVersion, enclosingCollector.getFreeName(meth.varproc.getVarName(varVersion))); } varindex += md_content.params[i].stack_size; @@ -222,7 +354,7 @@ public class NestedClassProcessor { if (!hasEnclosing) { if (child.type == ClassNode.CLASS_ANONYMOUS) { String message = "Unreferenced anonymous class " + child.classStruct.qualifiedName + "!"; - DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); + DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.TRACE); } else if (child.type == ClassNode.CLASS_LOCAL) { String message = "Unreferenced local class " + child.classStruct.qualifiedName + "!"; @@ -276,7 +408,7 @@ public class NestedClassProcessor { HashMap<String, List<VarFieldPair>> mask = getMaskLocalVars(nd.wrapper); if (mask.isEmpty()) { String message = "Nested class " + nd.classStruct.qualifiedName + " has no constructor!"; - DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); + DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.TRACE); } else { mapVarMasks.put(nd.classStruct.qualifiedName, mask); |