From 45a41684e6dc257808615b35841f617cea926f72 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Tue, 10 Nov 2015 19:48:44 +0100 Subject: [PATCH] [java-decompiler] cleanup (arrays to data classes; formatting; typos; dead code) --- .../java/decompiler/main/ClassWriter.java | 29 +- .../decompiler/main/ClassesProcessor.java | 78 +- .../collectors/BytecodeMappingTracer.java | 12 +- .../main/rels/NestedClassProcessor.java | 724 ++++++++---------- .../modules/decompiler/exps/NewExprent.java | 209 +++-- .../attr/StructInnerClassesAttribute.java | 62 +- .../java/decompiler/util/InterpreterUtil.java | 25 +- 7 files changed, 495 insertions(+), 644 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index f84e05c..b55f29d 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -46,7 +46,6 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil; import java.util.*; public class ClassWriter { - private final ClassReference14Processor ref14processor; private final PoolInterceptor interceptor; @@ -154,15 +153,6 @@ public class ClassWriter { DecompilerContext.getLogger().endWriteClass(); } - private static void addTracer(StructClass cls, StructMethod method, BytecodeMappingTracer tracer) { - StructLineNumberTableAttribute lineNumberTable = - (StructLineNumberTableAttribute)method.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE); - tracer.setLineNumberTable(lineNumberTable); - DecompilerContext.getBytecodeSourceMapper().addTracer(cls.qualifiedName, - InterpreterUtil.makeUniqueKey(method.getName(), method.getDescriptor()), - tracer); - } - public void classToJava(ClassNode node, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) { ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE); DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node); @@ -183,12 +173,7 @@ public class ClassWriter { int start_class_def = buffer.length(); writeClassDefinition(node, buffer, indent); -// // count lines in class definition the easiest way -// startLine = buffer.substring(start_class_def).toString().split(lineSeparator, -1).length - 1; - boolean hasContent = false; - - // fields boolean enumFields = false; dummy_tracer.incrementCurrentSourceLine(buffer.countLines(start_class_def)); @@ -287,6 +272,13 @@ public class ClassWriter { DecompilerContext.getLogger().endWriteClass(); } + private static void addTracer(StructClass cls, StructMethod method, BytecodeMappingTracer tracer) { + StructLineNumberTableAttribute table = (StructLineNumberTableAttribute)method.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE); + tracer.setLineNumberTable(table); + String key = InterpreterUtil.makeUniqueKey(method.getName(), method.getDescriptor()); + DecompilerContext.getBytecodeSourceMapper().addTracer(cls.qualifiedName, key, tracer); + } + private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent) { if (node.type == ClassNode.CLASS_ANONYMOUS) { buffer.append(" {").appendLineSeparator(); @@ -567,7 +559,7 @@ public class ClassWriter { } } - public static String toValidJavaIdentifier(String name) { + private static String toValidJavaIdentifier(String name) { if (name == null || name.isEmpty()) return name; boolean changed = false; @@ -833,8 +825,6 @@ public class ClassWriter { } // We do not have line information for method start, lets have it here for now - StructLineNumberTableAttribute lineNumberTable = - (StructLineNumberTableAttribute)mt.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE); buffer.append('{').appendLineSeparator(); tracer.incrementCurrentSourceLine(); @@ -842,8 +832,6 @@ public class ClassWriter { if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence try { - int startLine = tracer.getCurrentSourceLine(); - TextBuffer code = root.toJava(indent + 1, tracer); hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0; @@ -960,7 +948,6 @@ public class ClassWriter { StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS}; private static void appendAnnotations(TextBuffer buffer, StructMember mb, int indent) { - BytecodeMappingTracer tracer_dummy = new BytecodeMappingTracer(); // FIXME: replace with a real one for (String name : ANNOTATION_ATTRIBUTES) { diff --git a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java index 5a56641..17331e9 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java @@ -40,14 +40,22 @@ import java.util.*; import java.util.Map.Entry; public class ClassesProcessor { - public static final int AVERAGE_CLASS_SIZE = 16 * 1024; private final Map mapRootClasses = new HashMap(); - public ClassesProcessor(StructContext context) { + private static class Inner { + private String simpleName; + private int type; + private int accessFlags; + + private static boolean equal(Inner o1, Inner o2) { + return o1.type == o2.type && o1.accessFlags == o2.accessFlags && InterpreterUtil.equalObjects(o1.simpleName, o2.simpleName); + } + } - Map mapInnerClasses = new HashMap(); + public ClassesProcessor(StructContext context) { + Map mapInnerClasses = new HashMap(); Map> mapNestedClassReferences = new HashMap>(); Map> mapEnclosingClassReferences = new HashMap>(); Map mapNewSimpleNames = new HashMap(); @@ -57,25 +65,16 @@ public class ClassesProcessor { // create class nodes for (StructClass cl : context.getClasses().values()) { if (cl.isOwn() && !mapRootClasses.containsKey(cl.qualifiedName)) { - if (bDecompileInner) { StructInnerClassesAttribute inner = (StructInnerClassesAttribute)cl.getAttributes().getWithKey("InnerClasses"); - if (inner != null) { - - for (int i = 0; i < inner.getClassEntries().size(); i++) { - - int[] entry = inner.getClassEntries().get(i); - String[] strEntry = inner.getStringEntries().get(i); - Object[] arr = new Object[4]; // arr[0] not used - String innerName = strEntry[0]; - // nested class type - arr[2] = entry[1] == 0 ? (entry[2] == 0 ? ClassNode.CLASS_ANONYMOUS : ClassNode.CLASS_LOCAL) : ClassNode.CLASS_MEMBER; + if (inner != null) { + for (StructInnerClassesAttribute.Entry entry : inner.getEntries()) { + String innerName = entry.innerName; // original simple name - String simpleName = strEntry[2]; + String simpleName = entry.simpleName; String savedName = mapNewSimpleNames.get(innerName); - if (savedName != null) { simpleName = savedName; } @@ -87,15 +86,15 @@ public class ClassesProcessor { } } - arr[1] = simpleName; - - // original access flags - arr[3] = entry[3]; + Inner rec = new Inner(); + rec.simpleName = simpleName; + rec.type = entry.outerNameIdx != 0 ? ClassNode.CLASS_MEMBER : entry.simpleNameIdx != 0 ? ClassNode.CLASS_LOCAL : ClassNode.CLASS_ANONYMOUS; + rec.accessFlags = entry.accessFlags; // enclosing class String enclClassName; - if (entry[1] != 0) { - enclClassName = strEntry[1]; + if (entry.outerNameIdx != 0) { + enclClassName = entry.enclosingName; } else { enclClassName = cl.qualifiedName; @@ -105,11 +104,11 @@ public class ClassesProcessor { StructClass enclosing_class = context.getClasses().get(enclClassName); if (enclosing_class != null && enclosing_class.isOwn()) { // own classes only - Object[] arrOld = mapInnerClasses.get(innerName); - if (arrOld == null) { - mapInnerClasses.put(innerName, arr); + Inner existingRec = mapInnerClasses.get(innerName); + if (existingRec == null) { + mapInnerClasses.put(innerName, rec); } - else if (!InterpreterUtil.equalObjectArrays(arrOld, arr)) { + else if (!Inner.equal(existingRec, rec)) { String message = "Inconsistent inner class entries for " + innerName + "!"; DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); } @@ -140,12 +139,10 @@ public class ClassesProcessor { } if (bDecompileInner) { - // connect nested classes for (Entry ent : mapRootClasses.entrySet()) { // root class? if (!mapInnerClasses.containsKey(ent.getKey())) { - Set setVisited = new HashSet(); LinkedList stack = new LinkedList(); @@ -153,7 +150,6 @@ public class ClassesProcessor { setVisited.add(ent.getKey()); while (!stack.isEmpty()) { - String superClass = stack.removeFirst(); ClassNode superNode = mapRootClasses.get(superClass); @@ -163,13 +159,13 @@ public class ClassesProcessor { StructClass scl = superNode.classStruct; StructInnerClassesAttribute inner = (StructInnerClassesAttribute)scl.getAttributes().getWithKey("InnerClasses"); - if (inner == null || inner.getStringEntries().isEmpty()) { + if (inner == null || inner.getEntries().isEmpty()) { DecompilerContext.getLogger().writeMessage(superClass + " does not contain inner classes!", IFernflowerLogger.Severity.WARN); continue; } - for (int i = 0; i < inner.getStringEntries().size(); i++) { - String nestedClass = inner.getStringEntries().get(i)[0]; + for (StructInnerClassesAttribute.Entry entry : inner.getEntries()) { + String nestedClass = entry.innerName; if (!setNestedClasses.contains(nestedClass)) { continue; } @@ -184,21 +180,20 @@ public class ClassesProcessor { continue; } - Object[] arr = mapInnerClasses.get(nestedClass); + Inner rec = mapInnerClasses.get(nestedClass); //if ((Integer)arr[2] == ClassNode.CLASS_MEMBER) { // FIXME: check for consistent naming //} - nestedNode.type = (Integer)arr[2]; - nestedNode.simpleName = (String)arr[1]; - nestedNode.access = (Integer)arr[3]; + nestedNode.simpleName = rec.simpleName; + nestedNode.type = rec.type; + nestedNode.access = rec.accessFlags; if (nestedNode.type == ClassNode.CLASS_ANONYMOUS) { StructClass cl = nestedNode.classStruct; - // remove static if anonymous class - // a common compiler bug + // remove static if anonymous class (a common compiler bug) nestedNode.access &= ~CodeConstants.ACC_STATIC; int[] interfaces = cl.getInterfaces(); @@ -215,8 +210,7 @@ public class ClassesProcessor { } } else if (nestedNode.type == ClassNode.CLASS_LOCAL) { - // only abstract and final are permitted - // a common compiler bug + // only abstract and final are permitted (a common compiler bug) nestedNode.access &= (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_FINAL); } @@ -301,7 +295,6 @@ public class ClassesProcessor { } private static void initWrappers(ClassNode node) throws IOException { - if (node.type == ClassNode.CLASS_LAMBDA) { return; } @@ -317,7 +310,6 @@ public class ClassesProcessor { } private static void addClassnameToImport(ClassNode node, ImportCollector imp) { - if (node.simpleName != null && node.simpleName.length() > 0) { imp.getShortName(node.type == ClassNode.CLASS_ROOT ? node.classStruct.qualifiedName : node.simpleName, false); } @@ -328,7 +320,6 @@ public class ClassesProcessor { } private static void destroyWrappers(ClassNode node) { - node.wrapper = null; node.classStruct.releaseResources(); @@ -343,7 +334,6 @@ public class ClassesProcessor { public static class ClassNode { - public static final int CLASS_ROOT = 0; public static final int CLASS_MEMBER = 1; public static final int CLASS_ANONYMOUS = 2; diff --git a/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java b/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java index e25cca2..94c2993 100644 --- a/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java +++ b/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java @@ -21,13 +21,9 @@ import java.util.*; import java.util.Map.Entry; public class BytecodeMappingTracer { - private int currentSourceLine; - private StructLineNumberTableAttribute lineNumberTable = null; - - // bytecode offset, source line - private final Map mapping = new HashMap(); + private final Map mapping = new HashMap(); // bytecode offset, source line public BytecodeMappingTracer() { } @@ -43,12 +39,6 @@ public class BytecodeMappingTracer { currentSourceLine += number_lines; } - public void shiftSourceLines(int shift) { - for (Entry entry : mapping.entrySet()) { - entry.setValue(entry.getValue() + shift); - } - } - public void addMapping(int bytecode_offset) { if (!mapping.containsKey(bytecode_offset)) { mapping.put(bytecode_offset, currentSourceLine); diff --git a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java index 798010e..6963f1d 100644 --- a/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java +++ b/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java @@ -43,9 +43,7 @@ import java.util.Map.Entry; public class NestedClassProcessor { - public void processClass(ClassNode root, ClassNode node) { - // hide synthetic lambda content methods if (node.type == ClassNode.CLASS_LAMBDA && !node.lambdaInformation.is_method_reference) { ClassNode node_content = DecompilerContext.getClassProcessor().getMapRootClasses().get(node.classStruct.qualifiedName); @@ -59,7 +57,6 @@ public class NestedClassProcessor { } if (node.type != ClassNode.CLASS_LAMBDA) { - computeLocalVarsAndDefinitions(node); // for each local or anonymous class ensure not empty enclosing method @@ -102,13 +99,12 @@ public class NestedClassProcessor { } private static void setLambdaVars(ClassNode parent, ClassNode child) { - if (child.lambdaInformation.is_method_reference) { // method reference, no code and no parameters return; } - final MethodWrapper meth = parent.getWrapper().getMethods().getWithKey(child.lambdaInformation.content_method_key); - final MethodWrapper encmeth = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod); + MethodWrapper method = parent.getWrapper().getMethods().getWithKey(child.lambdaInformation.content_method_key); + final MethodWrapper enclosingMethod = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod); MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(child.lambdaInformation.method_descriptor); final MethodDescriptor md_content = MethodDescriptor.parseDescriptor(child.lambdaInformation.content_method_descriptor); @@ -120,52 +116,45 @@ public class NestedClassProcessor { final boolean is_static_lambda_content = child.lambdaInformation.is_content_method_static; - final String parent_class_name = parent.getWrapper().getClassStruct().qualifiedName; - final String lambda_class_name = child.simpleName; + String parent_class_name = parent.getWrapper().getClassStruct().qualifiedName; + String lambda_class_name = child.simpleName; final VarType lambda_class_type = new VarType(lambda_class_name, true); // this pointer if (!is_static_lambda_content && DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) { - meth.varproc.getThisVars().put(new VarVersionPair(0, 0), parent_class_name); - meth.varproc.setVarName(new VarVersionPair(0, 0), parent.simpleName + ".this"); + method.varproc.getThisVars().put(new VarVersionPair(0, 0), parent_class_name); + method.varproc.setVarName(new VarVersionPair(0, 0), parent.simpleName + ".this"); } - // local variables - DirectGraph graph = encmeth.getOrBuildGraph(); + final Map mapNewNames = new HashMap(); - final HashMap mapNewNames = new HashMap(); - - graph.iterateExprents(new DirectGraph.ExprentIterator() { + enclosingMethod.getOrBuildGraph().iterateExprents(new DirectGraph.ExprentIterator() { + @Override public int processExprent(Exprent exprent) { - List lst = exprent.getAllExprents(true); lst.add(exprent); for (Exprent expr : lst) { - if (expr.type == Exprent.EXPRENT_NEW) { NewExprent new_expr = (NewExprent)expr; - if (new_expr.isLambda() && lambda_class_type.equals(new_expr.getNewType())) { + if (new_expr.isLambda() && lambda_class_type.equals(new_expr.getNewType())) { InvocationExprent inv_dynamic = new_expr.getConstructor(); int param_index = is_static_lambda_content ? 0 : 1; - int varindex = 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) { - VarVersionPair enc_varpaar = new VarVersionPair((VarExprent)param); - String enc_varname = encmeth.varproc.getVarName(enc_varpaar); - - //meth.varproc.setVarName(new VarVersionPair(varindex, 0), enc_varname); - mapNewNames.put(new VarVersionPair(varindex, 0), enc_varname); + VarVersionPair pair = new VarVersionPair((VarExprent)param); + String name = enclosingMethod.varproc.getVarName(pair); + mapNewNames.put(new VarVersionPair(varIndex, 0), name); } - varindex += md_content.params[i].stackSize; + varIndex += md_content.params[i].stackSize; } } } @@ -176,36 +165,33 @@ public class NestedClassProcessor { }); // update names of local variables - HashSet setNewOuterNames = new HashSet(mapNewNames.values()); - setNewOuterNames.removeAll(meth.setOuterVarNames); + Set setNewOuterNames = new HashSet(mapNewNames.values()); + setNewOuterNames.removeAll(method.setOuterVarNames); - meth.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames)); - meth.setOuterVarNames.addAll(setNewOuterNames); + method.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames)); + method.setOuterVarNames.addAll(setNewOuterNames); - for (Entry entr : mapNewNames.entrySet()) { - meth.varproc.setVarName(entr.getKey(), entr.getValue()); + for (Entry entry : mapNewNames.entrySet()) { + method.varproc.setVarName(entry.getKey(), entry.getValue()); } } private static void checkNotFoundClasses(ClassNode root, ClassNode node) { + List copy = new ArrayList(node.nested); - List lstChildren = new ArrayList(node.nested); - - for (ClassNode child : lstChildren) { - + for (ClassNode child : copy) { if ((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_ANONYMOUS) && child.enclosingMethod == null) { - Set setEnclosing = child.enclosingClasses; if (setEnclosing.size() == 1) { StructEnclosingMethodAttribute attr = (StructEnclosingMethodAttribute)child.classStruct.getAttributes().getWithKey("EnclosingMethod"); - if (attr != null && attr.getMethodName() != null) { - if (node.classStruct.qualifiedName.equals(attr.getClassName()) && - node.classStruct.getMethod(attr.getMethodName(), attr.getMethodDescriptor()) != null) { - child.enclosingMethod = InterpreterUtil.makeUniqueKey(attr.getMethodName(), attr.getMethodDescriptor()); - continue; - } + if (attr != null && + attr.getMethodName() != null && + node.classStruct.qualifiedName.equals(attr.getClassName()) && + node.classStruct.getMethod(attr.getMethodName(), attr.getMethodDescriptor()) != null) { + child.enclosingMethod = InterpreterUtil.makeUniqueKey(attr.getMethodName(), attr.getMethodDescriptor()); + continue; } } @@ -235,14 +221,12 @@ public class NestedClassProcessor { } private static boolean insertNestedClass(ClassNode root, ClassNode child) { - Set setEnclosing = child.enclosingClasses; LinkedList stack = new LinkedList(); stack.add(root); while (!stack.isEmpty()) { - ClassNode node = stack.removeFirst(); if (setEnclosing.contains(node.classStruct.qualifiedName)) { @@ -259,109 +243,98 @@ public class NestedClassProcessor { return false; } - private static void computeLocalVarsAndDefinitions(final ClassNode node) { - // local var masks // class name, constructor descriptor, field mask - final HashMap>> mapVarMasks = new HashMap>>(); + final Map>> mapVarMasks = new HashMap>>(); - int cltypes = 0; + int clTypes = 0; for (ClassNode nd : node.nested) { - if (nd.type != ClassNode.CLASS_LAMBDA) { - if ((nd.access & CodeConstants.ACC_STATIC) == 0 && (nd.access & CodeConstants.ACC_INTERFACE) == 0) { - - cltypes |= nd.type; - - HashMap> mask = getMaskLocalVars(nd.getWrapper()); - if (mask.isEmpty()) { - if (!nd.classStruct.hasModifier(CodeConstants.ACC_SYNTHETIC)) { - String message = "Nested class " + nd.classStruct.qualifiedName + " has no constructor!"; - DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); - } - } - else { - mapVarMasks.put(nd.classStruct.qualifiedName, mask); + if (nd.type != ClassNode.CLASS_LAMBDA && + (nd.access & CodeConstants.ACC_STATIC) == 0 && + (nd.access & CodeConstants.ACC_INTERFACE) == 0) { + clTypes |= nd.type; + + Map> mask = getMaskLocalVars(nd.getWrapper()); + if (mask.isEmpty()) { + if (!nd.classStruct.hasModifier(CodeConstants.ACC_SYNTHETIC)) { + String message = "Nested class " + nd.classStruct.qualifiedName + " has no constructor!"; + DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); } } + else { + mapVarMasks.put(nd.classStruct.qualifiedName, mask); + } } } // local var masks - final HashMap>> mapVarFieldPairs = - new HashMap>>(); - - if (cltypes != ClassNode.CLASS_MEMBER) { + final Map>> mapVarFieldPairs = new HashMap>>(); + if (clTypes != ClassNode.CLASS_MEMBER) { // iterate enclosing class - for (final MethodWrapper meth : node.getWrapper().getMethods()) { - - if (meth.root != null) { // neither abstract, nor native - DirectGraph graph = meth.getOrBuildGraph(); - - graph.iterateExprents(new DirectGraph.ExprentIterator() { + for (final MethodWrapper method : node.getWrapper().getMethods()) { + if (method.root != null) { // neither abstract, nor native + method.getOrBuildGraph().iterateExprents(new DirectGraph.ExprentIterator() { + @Override public int processExprent(Exprent exprent) { List lst = exprent.getAllExprents(true); lst.add(exprent); for (Exprent expr : lst) { - if (expr.type == Exprent.EXPRENT_NEW) { - InvocationExprent constr = ((NewExprent)expr).getConstructor(); - - if (constr != null && mapVarMasks.containsKey(constr.getClassname())) { // non-static inner class constructor + InvocationExprent constructor = ((NewExprent)expr).getConstructor(); - String refclname = constr.getClassname(); - - ClassNode nestedClassNode = node.getClassNode(refclname); + if (constructor != null && mapVarMasks.containsKey(constructor.getClassname())) { // non-static inner class constructor + String refClassName = constructor.getClassname(); + ClassNode nestedClassNode = node.getClassNode(refClassName); if (nestedClassNode.type != ClassNode.CLASS_MEMBER) { + List mask = mapVarMasks.get(refClassName).get(constructor.getStringDescriptor()); - List mask = mapVarMasks.get(refclname).get(constr.getStringDescriptor()); - - if (!mapVarFieldPairs.containsKey(refclname)) { - mapVarFieldPairs.put(refclname, new HashMap>()); + if (!mapVarFieldPairs.containsKey(refClassName)) { + mapVarFieldPairs.put(refClassName, new HashMap>()); } List lstTemp = new ArrayList(); for (int i = 0; i < mask.size(); i++) { - Exprent param = constr.getLstParameters().get(i); + Exprent param = constructor.getLstParameters().get(i); VarFieldPair pair = null; if (param.type == Exprent.EXPRENT_VAR && mask.get(i) != null) { - VarVersionPair varpaar = new VarVersionPair((VarExprent)param); + VarVersionPair varPair = new VarVersionPair((VarExprent)param); - // FIXME: final flags of variables are wrong! Correct the entire final functionality. - // if(meth.varproc.getVarFinal(varpaar) != VarTypeProcessor.VAR_NON_FINAL) { - pair = new VarFieldPair(mask.get(i).keyfield, varpaar); - // } + // FIXME: flags of variables are wrong! Correct the entire functionality. + // if(method.varproc.getVarFinal(varPair) != VarTypeProcessor.VAR_NON_FINAL) { + pair = new VarFieldPair(mask.get(i).fieldKey, varPair); + // } } lstTemp.add(pair); } - List pairmask = mapVarFieldPairs.get(refclname).get(constr.getStringDescriptor()); - - if (pairmask == null) { - pairmask = lstTemp; + List pairMask = mapVarFieldPairs.get(refClassName).get(constructor.getStringDescriptor()); + if (pairMask == null) { + pairMask = lstTemp; } else { - for (int i = 0; i < pairmask.size(); i++) { - if (!InterpreterUtil.equalObjects(pairmask.get(i), lstTemp.get(i))) { - pairmask.set(i, null); + for (int i = 0; i < pairMask.size(); i++) { + if (!InterpreterUtil.equalObjects(pairMask.get(i), lstTemp.get(i))) { + pairMask.set(i, null); } } } - mapVarFieldPairs.get(refclname).put(constr.getStringDescriptor(), pairmask); + mapVarFieldPairs.get(refClassName).put(constructor.getStringDescriptor(), pairMask); nestedClassNode.enclosingMethod = - InterpreterUtil.makeUniqueKey(meth.methodStruct.getName(), meth.methodStruct.getDescriptor()); + InterpreterUtil.makeUniqueKey(method.methodStruct.getName(), method.methodStruct.getDescriptor()); } } } } + return 0; } }); @@ -370,219 +343,200 @@ public class NestedClassProcessor { } // merge var masks - for (Entry>> entcl : mapVarMasks.entrySet()) { - - ClassNode nestedNode = node.getClassNode(entcl.getKey()); + for (Entry>> enclosing : mapVarMasks.entrySet()) { + ClassNode nestedNode = node.getClassNode(enclosing.getKey()); // intersection - List intrPairMask = null; + List interPairMask = null; // merge referenced constructors - if (mapVarFieldPairs.containsKey(entcl.getKey())) { - for (List mask : mapVarFieldPairs.get(entcl.getKey()).values()) { - if (intrPairMask == null) { - intrPairMask = new ArrayList(mask); + if (mapVarFieldPairs.containsKey(enclosing.getKey())) { + for (List mask : mapVarFieldPairs.get(enclosing.getKey()).values()) { + if (interPairMask == null) { + interPairMask = new ArrayList(mask); } else { - mergeListSignatures(intrPairMask, mask, false); + mergeListSignatures(interPairMask, mask, false); } } } - List intrMask = null; + List interMask = null; // merge all constructors - for (List mask : entcl.getValue().values()) { - if (intrMask == null) { - intrMask = new ArrayList(mask); + for (List mask : enclosing.getValue().values()) { + if (interMask == null) { + interMask = new ArrayList(mask); } else { - mergeListSignatures(intrMask, mask, false); + mergeListSignatures(interMask, mask, false); } } - if (intrPairMask == null) { // member or local and never instantiated - intrPairMask = new ArrayList(intrMask); + if (interPairMask == null) { // member or local and never instantiated + interPairMask = interMask != null ? new ArrayList(interMask) : new ArrayList(); boolean found = false; - for (int i = 0; i < intrPairMask.size(); i++) { - if (intrPairMask.get(i) != null) { + for (int i = 0; i < interPairMask.size(); i++) { + if (interPairMask.get(i) != null) { if (found) { - intrPairMask.set(i, null); + interPairMask.set(i, null); } found = true; } } } - mergeListSignatures(intrPairMask, intrMask, true); + mergeListSignatures(interPairMask, interMask, true); - for (int i = 0; i < intrPairMask.size(); i++) { - VarFieldPair pair = intrPairMask.get(i); - if (pair != null && pair.keyfield.length() > 0) { - nestedNode.mapFieldsToVars.put(pair.keyfield, pair.varpaar); + for (VarFieldPair pair : interPairMask) { + if (pair != null && pair.fieldKey.length() > 0) { + nestedNode.mapFieldsToVars.put(pair.fieldKey, pair.varPair); } } // set resulting constructor signatures - for (Entry> entmt : entcl.getValue().entrySet()) { - mergeListSignatures(entmt.getValue(), intrPairMask, false); + for (Entry> entry : enclosing.getValue().entrySet()) { + mergeListSignatures(entry.getValue(), interPairMask, false); - MethodWrapper meth = nestedNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, entmt.getKey()); - meth.signatureFields = new ArrayList(); + MethodWrapper method = nestedNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, entry.getKey()); + method.signatureFields = new ArrayList(); - for (VarFieldPair pair : entmt.getValue()) { - meth.signatureFields.add(pair == null ? null : pair.varpaar); + for (VarFieldPair pair : entry.getValue()) { + method.signatureFields.add(pair == null ? null : pair.varPair); } } } } - private static void insertLocalVars(final ClassNode parent, final ClassNode child) { - + private static void insertLocalVars(ClassNode parent, final ClassNode child) { // enclosing method, is null iff member class - MethodWrapper encmeth = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod); + MethodWrapper enclosingMethod = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod); // iterate all child methods - for (final MethodWrapper meth : child.getWrapper().getMethods()) { - - if (meth.root != null) { // neither abstract nor native + for (final MethodWrapper method : child.getWrapper().getMethods()) { + if (method.root != null) { // neither abstract nor native + Map mapNewNames = new HashMap(); // local var names + Map mapNewTypes = new HashMap(); // local var types - // local var names - HashMap mapNewNames = new HashMap(); - // local var types - HashMap mapNewTypes = new HashMap(); + final Map mapParamsToNewVars = new HashMap(); + if (method.signatureFields != null) { + int index = 0, varIndex = 1; + MethodDescriptor md = MethodDescriptor.parseDescriptor(method.methodStruct.getDescriptor()); - final HashMap mapParamsToNewVars = new HashMap(); - if (meth.signatureFields != null) { - int index = 0; - int varindex = 1; - MethodDescriptor md = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor()); + for (VarVersionPair pair : method.signatureFields) { + if (pair != null) { + VarVersionPair newVar = new VarVersionPair(method.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0); - for (VarVersionPair paar : meth.signatureFields) { - if (paar != null) { - VarVersionPair newvar = new VarVersionPair(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0); + mapParamsToNewVars.put(varIndex, newVar); - mapParamsToNewVars.put(varindex, newvar); - - String varname = null; - VarType vartype = null; + String varName = null; + VarType varType = null; if (child.type != ClassNode.CLASS_MEMBER) { - varname = encmeth.varproc.getVarName(paar); - vartype = encmeth.varproc.getVarType(paar); + varName = enclosingMethod.varproc.getVarName(pair); + varType = enclosingMethod.varproc.getVarType(pair); - encmeth.varproc.setVarFinal(paar, VarTypeProcessor.VAR_EXPLICIT_FINAL); + enclosingMethod.varproc.setVarFinal(pair, VarTypeProcessor.VAR_EXPLICIT_FINAL); } - if (paar.var == -1 || "this".equals(varname)) { + if (pair.var == -1 || "this".equals(varName)) { if (parent.simpleName == null) { // anonymous enclosing class, no access to this - varname = VarExprent.VAR_NAMELESS_ENCLOSURE; + varName = VarExprent.VAR_NAMELESS_ENCLOSURE; } else { - varname = parent.simpleName + ".this"; + varName = parent.simpleName + ".this"; } - meth.varproc.getThisVars().put(newvar, parent.classStruct.qualifiedName); + method.varproc.getThisVars().put(newVar, parent.classStruct.qualifiedName); } - mapNewNames.put(newvar, varname); - mapNewTypes.put(newvar, vartype); + mapNewNames.put(newVar, varName); + mapNewTypes.put(newVar, varType); } - varindex += md.params[index++].stackSize; + + varIndex += md.params[index++].stackSize; } } - // new vars - final HashMap mapFieldsToNewVars = new HashMap(); - - for (ClassNode clnode = child; clnode != null; clnode = clnode.parent) { + final Map mapFieldsToNewVars = new HashMap(); + for (ClassNode classNode = child; classNode != null; classNode = classNode.parent) { + for (Entry entry : classNode.mapFieldsToVars.entrySet()) { + VarVersionPair newVar = new VarVersionPair(method.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0); - for (Entry entr : clnode.mapFieldsToVars.entrySet()) { - VarVersionPair newvar = new VarVersionPair(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0); + mapFieldsToNewVars.put(InterpreterUtil.makeUniqueKey(classNode.classStruct.qualifiedName, entry.getKey()), newVar); - mapFieldsToNewVars.put(InterpreterUtil.makeUniqueKey(clnode.classStruct.qualifiedName, entr.getKey()), newvar); + String varName = null; + VarType varType = null; - String varname = null; - VarType vartype = null; + if (classNode.type != ClassNode.CLASS_MEMBER) { + MethodWrapper enclosing_method = classNode.parent.getWrapper().getMethods().getWithKey(classNode.enclosingMethod); - if (clnode.type != ClassNode.CLASS_MEMBER) { + varName = enclosing_method.varproc.getVarName(entry.getValue()); + varType = enclosing_method.varproc.getVarType(entry.getValue()); - MethodWrapper enclosing_method = clnode.parent.getWrapper().getMethods().getWithKey(clnode.enclosingMethod); - - varname = enclosing_method.varproc.getVarName(entr.getValue()); - vartype = enclosing_method.varproc.getVarType(entr.getValue()); - - enclosing_method.varproc.setVarFinal(entr.getValue(), VarTypeProcessor.VAR_EXPLICIT_FINAL); + enclosing_method.varproc.setVarFinal(entry.getValue(), VarTypeProcessor.VAR_EXPLICIT_FINAL); } - if (entr.getValue().var == -1 || "this".equals(varname)) { - if (clnode.parent.simpleName == null) { + if (entry.getValue().var == -1 || "this".equals(varName)) { + if (classNode.parent.simpleName == null) { // anonymous enclosing class, no access to this - varname = VarExprent.VAR_NAMELESS_ENCLOSURE; + varName = VarExprent.VAR_NAMELESS_ENCLOSURE; } else { - varname = clnode.parent.simpleName + ".this"; + varName = classNode.parent.simpleName + ".this"; } - meth.varproc.getThisVars().put(newvar, clnode.parent.classStruct.qualifiedName); + method.varproc.getThisVars().put(newVar, classNode.parent.classStruct.qualifiedName); } - mapNewNames.put(newvar, varname); - mapNewTypes.put(newvar, vartype); + mapNewNames.put(newVar, varName); + mapNewTypes.put(newVar, varType); // hide synthetic field - if (clnode == child) { // fields higher up the chain were already handled with their classes - StructField fd = child.classStruct.getFields().getWithKey(entr.getKey()); + if (classNode == child) { // fields higher up the chain were already handled with their classes + StructField fd = child.classStruct.getFields().getWithKey(entry.getKey()); child.getWrapper().getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); } } } - HashSet setNewOuterNames = new HashSet(mapNewNames.values()); - setNewOuterNames.removeAll(meth.setOuterVarNames); + Set setNewOuterNames = new HashSet(mapNewNames.values()); + setNewOuterNames.removeAll(method.setOuterVarNames); - meth.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames)); - meth.setOuterVarNames.addAll(setNewOuterNames); + method.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames)); + method.setOuterVarNames.addAll(setNewOuterNames); - for (Entry entr : mapNewNames.entrySet()) { - VarVersionPair varpaar = entr.getKey(); - VarType vartype = mapNewTypes.get(varpaar); + for (Entry entry : mapNewNames.entrySet()) { + VarVersionPair pair = entry.getKey(); + VarType type = mapNewTypes.get(pair); - meth.varproc.setVarName(varpaar, entr.getValue()); - if (vartype != null) { - meth.varproc.setVarType(varpaar, vartype); + method.varproc.setVarName(pair, entry.getValue()); + if (type != null) { + method.varproc.setVarType(pair, type); } } - DirectGraph graph = meth.getOrBuildGraph(); - - graph.iterateExprents(new DirectGraph.ExprentIterator() { + method.getOrBuildGraph().iterateExprents(new DirectGraph.ExprentIterator() { + @Override public int processExprent(Exprent exprent) { - if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) { - AssignmentExprent asexpr = (AssignmentExprent)exprent; - if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) { - FieldExprent fexpr = (FieldExprent)asexpr.getLeft(); - - if (fexpr.getClassname().equals(child.classStruct.qualifiedName) && // process this class only - mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(child.classStruct.qualifiedName, - InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr - .getDescriptor().descriptorString)))) { + AssignmentExprent assignExpr = (AssignmentExprent)exprent; + if (assignExpr.getLeft().type == Exprent.EXPRENT_FIELD) { + FieldExprent fExpr = (FieldExprent)assignExpr.getLeft(); + String qName = child.classStruct.qualifiedName; + if (fExpr.getClassname().equals(qName) && // process this class only + mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(qName, fExpr.getName(), fExpr.getDescriptor().descriptorString))) { return 2; } - - //if(fexpr.getClassname().equals(child.classStruct.qualifiedName) && - // mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString))) { - // return 2; - //} } } - if (child.type == ClassNode.CLASS_ANONYMOUS && CodeConstants.INIT_NAME.equals(meth.methodStruct.getName()) - && exprent.type == Exprent.EXPRENT_INVOCATION) { - InvocationExprent invexpr = (InvocationExprent)exprent; - if (invexpr.getFunctype() == InvocationExprent.TYP_INIT) { + if (child.type == ClassNode.CLASS_ANONYMOUS && + CodeConstants.INIT_NAME.equals(method.methodStruct.getName()) && + exprent.type == Exprent.EXPRENT_INVOCATION) { + InvocationExprent invokeExpr = (InvocationExprent)exprent; + if (invokeExpr.getFunctype() == InvocationExprent.TYP_INIT) { // invocation of the super constructor in an anonymous class - child.superInvocation = invexpr; // FIXME: save original names of parameters + child.superInvocation = invokeExpr; // FIXME: save original names of parameters return 2; } } @@ -593,27 +547,23 @@ public class NestedClassProcessor { } private Exprent replaceExprent(Exprent exprent) { - if (exprent.type == Exprent.EXPRENT_VAR) { - int varindex = ((VarExprent)exprent).getIndex(); - if (mapParamsToNewVars.containsKey(varindex)) { - VarVersionPair newvar = mapParamsToNewVars.get(varindex); - meth.varproc.getExternalVars().add(newvar); - return new VarExprent(newvar.var, meth.varproc.getVarType(newvar), meth.varproc); + int varIndex = ((VarExprent)exprent).getIndex(); + if (mapParamsToNewVars.containsKey(varIndex)) { + VarVersionPair newVar = mapParamsToNewVars.get(varIndex); + method.varproc.getExternalVars().add(newVar); + return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc); } } else if (exprent.type == Exprent.EXPRENT_FIELD) { - FieldExprent fexpr = (FieldExprent)exprent; - - String keyField = InterpreterUtil.makeUniqueKey(fexpr.getClassname(), InterpreterUtil - .makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString)); - - if (mapFieldsToNewVars.containsKey(keyField)) { - //if(fexpr.getClassname().equals(child.classStruct.qualifiedName) && - // mapFieldsToNewVars.containsKey(keyField)) { - VarVersionPair newvar = mapFieldsToNewVars.get(keyField); - meth.varproc.getExternalVars().add(newvar); - return new VarExprent(newvar.var, meth.varproc.getVarType(newvar), meth.varproc); + FieldExprent fExpr = (FieldExprent)exprent; + String key = InterpreterUtil.makeUniqueKey(fExpr.getClassname(), fExpr.getName(), fExpr.getDescriptor().descriptorString); + if (mapFieldsToNewVars.containsKey(key)) { + //if(fExpr.getClassname().equals(child.classStruct.qualifiedName) && + // mapFieldsToNewVars.containsKey(key)) { + VarVersionPair newVar = mapFieldsToNewVars.get(key); + method.varproc.getExternalVars().add(newVar); + return new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc); } } @@ -622,9 +572,9 @@ public class NestedClassProcessor { replaced = false; for (Exprent expr : exprent.getAllExprents()) { - Exprent retexpr = replaceExprent(expr); - if (retexpr != null) { - exprent.replaceExprent(expr, retexpr); + Exprent retExpr = replaceExprent(expr); + if (retExpr != null) { + exprent.replaceExprent(expr, retExpr); replaced = true; break; } @@ -638,30 +588,28 @@ public class NestedClassProcessor { } } - private static HashMap> getMaskLocalVars(ClassWrapper wrapper) { - - HashMap> mapMasks = new HashMap>(); + private static Map> getMaskLocalVars(ClassWrapper wrapper) { + Map> mapMasks = new HashMap>(); StructClass cl = wrapper.getClassStruct(); // iterate over constructors for (StructMethod mt : cl.getMethods()) { if (CodeConstants.INIT_NAME.equals(mt.getName())) { - MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); - - MethodWrapper meth = wrapper.getMethodWrapper(CodeConstants.INIT_NAME, mt.getDescriptor()); - DirectGraph graph = meth.getOrBuildGraph(); + MethodWrapper method = wrapper.getMethodWrapper(CodeConstants.INIT_NAME, mt.getDescriptor()); + DirectGraph graph = method.getOrBuildGraph(); if (graph != null) { // something gone wrong, should not be null List fields = new ArrayList(); - int varindex = 1; + int varIndex = 1; for (int i = 0; i < md.params.length; i++) { // no static methods allowed - String keyField = getEnclosingVarField(cl, meth, graph, varindex); + String keyField = getEnclosingVarField(cl, method, graph, varIndex); fields.add(keyField == null ? null : new VarFieldPair(keyField, new VarVersionPair(-1, 0))); // TODO: null? - varindex += md.params[i].stackSize; + varIndex += md.params[i].stackSize; } + mapMasks.put(mt.getDescriptor(), fields); } } @@ -670,38 +618,35 @@ public class NestedClassProcessor { return mapMasks; } - private static String getEnclosingVarField(StructClass cl, MethodWrapper meth, DirectGraph graph, final int index) { - + private static String getEnclosingVarField(StructClass cl, MethodWrapper method, DirectGraph graph, int index) { String field = ""; // parameter variable final - if (meth.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarTypeProcessor.VAR_NON_FINAL) { + if (method.varproc.getVarFinal(new VarVersionPair(index, 0)) == VarTypeProcessor.VAR_NON_FINAL) { return null; } boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); // no loop at the begin - DirectNode firstnode = graph.first; - if (firstnode.preds.isEmpty()) { - // assignment to a final synthetic field? - for (Exprent exprent : firstnode.exprents) { + DirectNode firstNode = graph.first; + if (firstNode.preds.isEmpty()) { + // assignment to a synthetic field? + for (Exprent exprent : firstNode.exprents) { if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) { - AssignmentExprent asexpr = (AssignmentExprent)exprent; - if (asexpr.getRight().type == Exprent.EXPRENT_VAR && ((VarExprent)asexpr.getRight()).getIndex() == index) { - if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) { - - FieldExprent left = (FieldExprent)asexpr.getLeft(); - StructField fd = cl.getField(left.getName(), left.getDescriptor().descriptorString); - - if (fd != null) { // local (== not inherited) field - if (cl.qualifiedName.equals(left.getClassname()) && - fd.hasModifier(CodeConstants.ACC_FINAL) && - (fd.isSynthetic() || (noSynthFlag && fd.hasModifier(CodeConstants.ACC_PRIVATE)))) { - field = InterpreterUtil.makeUniqueKey(left.getName(), left.getDescriptor().descriptorString); - break; - } - } + AssignmentExprent assignExpr = (AssignmentExprent)exprent; + if (assignExpr.getRight().type == Exprent.EXPRENT_VAR && + ((VarExprent)assignExpr.getRight()).getIndex() == index && + assignExpr.getLeft().type == Exprent.EXPRENT_FIELD) { + FieldExprent left = (FieldExprent)assignExpr.getLeft(); + StructField fd = cl.getField(left.getName(), left.getDescriptor().descriptorString); + + if (fd != null && cl.qualifiedName.equals(left.getClassname()) && + fd.hasModifier(CodeConstants.ACC_FINAL) && + (fd.isSynthetic() || (noSynthFlag && fd.hasModifier(CodeConstants.ACC_PRIVATE)))) { + // local (== not inherited) field + field = InterpreterUtil.makeUniqueKey(left.getName(), left.getDescriptor().descriptorString); + break; } } } @@ -712,51 +657,31 @@ public class NestedClassProcessor { } private static void mergeListSignatures(List first, List second, boolean both) { - int i = 1; + while (true) { if (first.size() <= i || second.size() <= i) { break; } - VarFieldPair fobj = first.get(first.size() - i); - VarFieldPair sobj = second.get(second.size() - i); + VarFieldPair fObj = first.get(first.size() - i); + VarFieldPair sObj = second.get(second.size() - i); - boolean eq = false; - if (fobj == null || sobj == null) { - eq = (fobj == sobj); - } - else { - eq = true; - if (fobj.keyfield.length() == 0) { - fobj.keyfield = sobj.keyfield; - } - else if (sobj.keyfield.length() == 0) { - if (both) { - sobj.keyfield = fobj.keyfield; - } - } - else { - eq = fobj.keyfield.equals(sobj.keyfield); - } - } - - if (!eq) { + if (!isEqual(both, fObj, sObj)) { first.set(first.size() - i, null); if (both) { second.set(second.size() - i, null); } } - else { - if (fobj != null) { - if (fobj.varpaar.var == -1) { - fobj.varpaar = sobj.varpaar; - } - else { - sobj.varpaar = fobj.varpaar; - } + else if (fObj != null) { + if (fObj.varPair.var == -1) { + fObj.varPair = sObj.varPair; + } + else { + sObj.varPair = fObj.varPair; } } + i++; } @@ -780,64 +705,66 @@ public class NestedClassProcessor { first.set(0, null); } else { - VarFieldPair fobj = first.get(0); - VarFieldPair sobj = second.get(0); + VarFieldPair fObj = first.get(0); + VarFieldPair sObj = second.get(0); - boolean eq = false; - if (fobj == null || sobj == null) { - eq = (fobj == sobj); - } - else { - eq = true; - if (fobj.keyfield.length() == 0) { - fobj.keyfield = sobj.keyfield; - } - else if (sobj.keyfield.length() == 0) { - if (both) { - sobj.keyfield = fobj.keyfield; - } - } - else { - eq = fobj.keyfield.equals(sobj.keyfield); - } - } - - if (!eq) { + if (!isEqual(both, fObj, sObj)) { first.set(0, null); if (both) { second.set(0, null); } } - else if (fobj != null) { - if (fobj.varpaar.var == -1) { - fobj.varpaar = sobj.varpaar; + else if (fObj != null) { + if (fObj.varPair.var == -1) { + fObj.varPair = sObj.varPair; } else { - sobj.varpaar = fobj.varpaar; + sObj.varPair = fObj.varPair; } } } } + private static boolean isEqual(boolean both, VarFieldPair fObj, VarFieldPair sObj) { + boolean eq; + if (fObj == null || sObj == null) { + eq = (fObj == sObj); + } + else { + eq = true; + if (fObj.fieldKey.length() == 0) { + fObj.fieldKey = sObj.fieldKey; + } + else if (sObj.fieldKey.length() == 0) { + if (both) { + sObj.fieldKey = fObj.fieldKey; + } + } + else { + eq = fObj.fieldKey.equals(sObj.fieldKey); + } + } + return eq; + } - private static void setLocalClassDefinition(MethodWrapper meth, ClassNode node) { - - RootStatement root = meth.root; + private static void setLocalClassDefinition(MethodWrapper method, ClassNode node) { + RootStatement root = method.root; - HashSet setStats = new HashSet(); - VarType classtype = new VarType(node.classStruct.qualifiedName, true); + Set setStats = new HashSet(); + VarType classType = new VarType(node.classStruct.qualifiedName, true); - Statement stdef = getDefStatement(root, classtype, setStats); - if (stdef == null) { + Statement statement = getDefStatement(root, classType, setStats); + if (statement == null) { // unreferenced local class - stdef = root.getFirst(); + statement = root.getFirst(); } - Statement first = findFirstBlock(stdef, setStats); + Statement first = findFirstBlock(statement, setStats); List lst; + //noinspection Duplicates if (first == null) { - lst = stdef.getVarDefinitions(); + lst = statement.getVarDefinitions(); } else if (first.getExprents() == null) { lst = first.getVarDefinitions(); @@ -846,26 +773,22 @@ public class NestedClassProcessor { lst = first.getExprents(); } - - int addindex = 0; + int addIndex = 0; for (Exprent expr : lst) { - if (searchForClass(expr, classtype)) { + if (searchForClass(expr, classType)) { break; } - addindex++; + addIndex++; } - VarExprent var = new VarExprent(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), - classtype, meth.varproc); + VarExprent var = new VarExprent(method.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), classType, method.varproc); var.setDefinition(true); var.setClassDef(true); - lst.add(addindex, var); + lst.add(addIndex, var); } - - private static Statement findFirstBlock(Statement stat, HashSet setStats) { - + private static Statement findFirstBlock(Statement stat, Set setStats) { LinkedList stack = new LinkedList(); stack.add(stat); @@ -873,30 +796,25 @@ public class NestedClassProcessor { Statement st = stack.remove(0); if (stack.isEmpty() || setStats.contains(st)) { - - if (st.isLabeled() && !stack.isEmpty()) { + if (st.isLabeled() && !stack.isEmpty() || st.getExprents() != null) { return st; } - if (st.getExprents() != null) { - return st; - } - else { - stack.clear(); + stack.clear(); - switch (st.type) { - case Statement.TYPE_SEQUENCE: - stack.addAll(0, st.getStats()); - break; - case Statement.TYPE_IF: - case Statement.TYPE_ROOT: - case Statement.TYPE_SWITCH: - case Statement.TYPE_SYNCRONIZED: - stack.add(st.getFirst()); - break; - default: - return st; - } + //noinspection Duplicates + switch (st.type) { + case Statement.TYPE_SEQUENCE: + stack.addAll(0, st.getStats()); + break; + case Statement.TYPE_IF: + case Statement.TYPE_ROOT: + case Statement.TYPE_SWITCH: + case Statement.TYPE_SYNCRONIZED: + stack.add(st.getFirst()); + break; + default: + return st; } } } @@ -904,11 +822,9 @@ public class NestedClassProcessor { return null; } - - private static Statement getDefStatement(Statement stat, VarType classtype, HashSet setStats) { - - List condlst = new ArrayList(); - Statement retstat = null; + private static Statement getDefStatement(Statement stat, VarType classType, Set setStats) { + List lst = new ArrayList(); + Statement retStat = null; if (stat.getExprents() == null) { int counter = 0; @@ -917,65 +833,63 @@ public class NestedClassProcessor { if (obj instanceof Statement) { Statement st = (Statement)obj; - Statement stTemp = getDefStatement(st, classtype, setStats); + Statement stTemp = getDefStatement(st, classType, setStats); if (stTemp != null) { if (counter == 1) { - retstat = stat; + retStat = stat; break; } - retstat = stTemp; + retStat = stTemp; counter++; } - if (st.type == DoStatement.TYPE_DO) { + if (st.type == Statement.TYPE_DO) { DoStatement dost = (DoStatement)st; - condlst.addAll(dost.getInitExprentList()); - condlst.addAll(dost.getConditionExprentList()); + lst.addAll(dost.getInitExprentList()); + lst.addAll(dost.getConditionExprentList()); } } else if (obj instanceof Exprent) { - condlst.add((Exprent)obj); + lst.add((Exprent)obj); } } } else { - condlst = stat.getExprents(); + lst = stat.getExprents(); } - if (retstat != stat) { - for (Exprent exprent : condlst) { - if (exprent != null && searchForClass(exprent, classtype)) { - retstat = stat; + if (retStat != stat) { + for (Exprent exprent : lst) { + if (exprent != null && searchForClass(exprent, classType)) { + retStat = stat; break; } } } - if (retstat != null) { + if (retStat != null) { setStats.add(stat); } - return retstat; + return retStat; } - private static boolean searchForClass(Exprent exprent, VarType classtype) { - + private static boolean searchForClass(Exprent exprent, VarType classType) { List lst = exprent.getAllExprents(true); lst.add(exprent); - String classname = classtype.value; + String classname = classType.value; for (Exprent expr : lst) { - boolean res = false; switch (expr.type) { case Exprent.EXPRENT_CONST: - ConstExprent cexpr = (ConstExprent)expr; - res = (VarType.VARTYPE_CLASS.equals(cexpr.getConstType()) && classname.equals(cexpr.getValue()) || - classtype.equals(cexpr.getConstType())); + ConstExprent constExpr = (ConstExprent)expr; + res = (VarType.VARTYPE_CLASS.equals(constExpr.getConstType()) && classname.equals(constExpr.getValue()) || + classType.equals(constExpr.getConstType())); break; case Exprent.EXPRENT_FIELD: res = classname.equals(((FieldExprent)expr).getClassname()); @@ -988,10 +902,10 @@ public class NestedClassProcessor { res = newType.type == CodeConstants.TYPE_OBJECT && classname.equals(newType.value); break; case Exprent.EXPRENT_VAR: - VarExprent vexpr = (VarExprent)expr; - if (vexpr.isDefinition()) { - VarType vtype = vexpr.getVarType(); - if (classtype.equals(vtype) || (vtype.arrayDim > 0 && classtype.value.equals(vtype.value))) { + VarExprent varExpr = (VarExprent)expr; + if (varExpr.isDefinition()) { + VarType varType = varExpr.getVarType(); + if (classType.equals(varType) || (varType.arrayDim > 0 && classType.value.equals(varType.value))) { res = true; } } @@ -1005,15 +919,13 @@ public class NestedClassProcessor { return false; } - private static class VarFieldPair { + public String fieldKey = ""; + public VarVersionPair varPair; - public String keyfield = ""; - public VarVersionPair varpaar; - - public VarFieldPair(String field, VarVersionPair varpaar) { - this.keyfield = field; - this.varpaar = varpaar; + public VarFieldPair(String field, VarVersionPair varPair) { + this.fieldKey = field; + this.varPair = varPair; } @Override @@ -1022,12 +934,12 @@ public class NestedClassProcessor { if (o == null || !(o instanceof VarFieldPair)) return false; VarFieldPair pair = (VarFieldPair)o; - return keyfield.equals(pair.keyfield) && varpaar.equals(pair.varpaar); + return fieldKey.equals(pair.fieldKey) && varPair.equals(pair.varPair); } @Override public int hashCode() { - return keyfield.hashCode() + varpaar.hashCode(); + return fieldKey.hashCode() + varPair.hashCode(); } } } 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 b5ecd9e..fb0adb7 100644 --- a/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java +++ b/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java @@ -36,7 +36,6 @@ import java.util.List; import java.util.Set; public class NewExprent extends Exprent { - private InvocationExprent constructor; private final VarType newType; private List lstDims = new ArrayList(); @@ -80,12 +79,7 @@ public class NewExprent extends Exprent { @Override public VarType getExprType() { - if (anonymous) { - return DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.value).anonymousClassType; - } - else { - return newType; - } + return anonymous ? DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.value).anonymousClassType : newType; } @Override @@ -163,24 +157,22 @@ public class NewExprent extends Exprent { TextBuffer buf = new TextBuffer(); if (anonymous) { - ClassNode child = DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.value); buf.append("("); if (!lambda && constructor != null) { + InvocationExprent invSuper = child.superInvocation; - InvocationExprent invsuper = child.superInvocation; - - ClassNode newnode = DecompilerContext.getClassProcessor().getMapRootClasses().get(invsuper.getClassname()); + ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(invSuper.getClassname()); List sigFields = null; - if (newnode != null) { // own class - if (newnode.getWrapper() != null) { - sigFields = newnode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, invsuper.getStringDescriptor()).signatureFields; + if (newNode != null) { // own class + if (newNode.getWrapper() != null) { + sigFields = newNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, invSuper.getStringDescriptor()).signatureFields; } else { - if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0 && + if (newNode.type == ClassNode.CLASS_MEMBER && (newNode.access & CodeConstants.ACC_STATIC) == 0 && !constructor.getLstParameters().isEmpty()) { // member non-static class invoked with enclosing class instance sigFields = new ArrayList(Collections.nCopies(constructor.getLstParameters().size(), (VarVersionPair)null)); sigFields.set(0, new VarVersionPair(-1, 0)); @@ -188,31 +180,29 @@ public class NewExprent extends Exprent { } } - boolean firstpar = true; - int start = 0, end = invsuper.getLstParameters().size(); + boolean firstParam = true; + int start = 0, end = invSuper.getLstParameters().size(); if (enumConst) { start += 2; end -= 1; } for (int i = start; i < end; i++) { if (sigFields == null || sigFields.get(i) == null) { - if (!firstpar) { + if (!firstParam) { buf.append(", "); } - Exprent param = invsuper.getLstParameters().get(i); + Exprent param = invSuper.getLstParameters().get(i); if (param.type == Exprent.EXPRENT_VAR) { - int varindex = ((VarExprent)param).getIndex(); - if (varindex > 0 && varindex <= constructor.getLstParameters().size()) { - param = constructor.getLstParameters().get(varindex - 1); + int varIndex = ((VarExprent)param).getIndex(); + if (varIndex > 0 && varIndex <= constructor.getLstParameters().size()) { + param = constructor.getLstParameters().get(varIndex - 1); } } - TextBuffer buff = new TextBuffer(); - ExprProcessor.getCastedExprent(param, invsuper.getDescriptor().params[i], buff, indent, true, tracer); + ExprProcessor.getCastedExprent(param, invSuper.getDescriptor().params[i], buf, indent, true, tracer); - buf.append(buff); - firstpar = false; + firstParam = false; } } } @@ -226,14 +216,15 @@ public class NewExprent extends Exprent { String typename = ExprProcessor.getCastTypeName(child.anonymousClassType); if (enclosing != null) { - ClassNode anonimousNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(child.anonymousClassType.value); - if (anonimousNode != null) { - typename = anonimousNode.simpleName; + ClassNode anonymousNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(child.anonymousClassType.value); + if (anonymousNode != null) { + typename = anonymousNode.simpleName; } else { typename = typename.substring(typename.lastIndexOf('.') + 1); } } + buf.prepend("new " + typename); if (enclosing != null) { @@ -275,118 +266,108 @@ public class NewExprent extends Exprent { } buf.append("}"); } - else { - if (newType.arrayDim == 0) { + else if (newType.arrayDim == 0) { + if (constructor != null) { + List lstParameters = constructor.getLstParameters(); - if (constructor != null) { + ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(constructor.getClassname()); - List lstParameters = constructor.getLstParameters(); + List sigFields = null; + if (newNode != null) { // own class + if (newNode.getWrapper() != null) { + sigFields = newNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, constructor.getStringDescriptor()).signatureFields; + } + else if (newNode.type == ClassNode.CLASS_MEMBER && (newNode.access & CodeConstants.ACC_STATIC) == 0 && !constructor.getLstParameters().isEmpty()) { + // member non-static class invoked with enclosing class instance + sigFields = new ArrayList(Collections.nCopies(lstParameters.size(), (VarVersionPair)null)); + sigFields.set(0, new VarVersionPair(-1, 0)); + } + } - ClassNode newnode = DecompilerContext.getClassProcessor().getMapRootClasses().get(constructor.getClassname()); + int start = enumConst ? 2 : 0; + if (!enumConst || start < lstParameters.size()) { + buf.append("("); - List sigFields = null; - if (newnode != null) { // own class - if (newnode.getWrapper() != null) { - sigFields = newnode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, constructor.getStringDescriptor()).signatureFields; - } - else { - if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0 && - !constructor.getLstParameters().isEmpty()) { // member non-static class invoked with enclosing class instance - sigFields = new ArrayList(Collections.nCopies(lstParameters.size(), (VarVersionPair)null)); - sigFields.set(0, new VarVersionPair(-1, 0)); - } - } - } + boolean firstParam = true; + for (int i = start; i < lstParameters.size(); i++) { + if (sigFields == null || sigFields.get(i) == null) { + Exprent expr = lstParameters.get(i); + VarType leftType = constructor.getDescriptor().params[i]; - int start = enumConst ? 2 : 0; - if (!enumConst || start < lstParameters.size()) { - buf.append("("); - - boolean firstParam = true; - for (int i = start; i < lstParameters.size(); i++) { - if (sigFields == null || sigFields.get(i) == null) { - Exprent expr = lstParameters.get(i); - VarType leftType = constructor.getDescriptor().params[i]; - - if (i == lstParameters.size() - 1 && expr.getExprType() == VarType.VARTYPE_NULL) { - ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(leftType.value); - if (node != null && node.namelessConstructorStub) { - break; // skip last parameter of synthetic constructor call - } + if (i == lstParameters.size() - 1 && expr.getExprType() == VarType.VARTYPE_NULL) { + ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(leftType.value); + if (node != null && node.namelessConstructorStub) { + break; // skip last parameter of synthetic constructor call } + } - if (!firstParam) { - buf.append(", "); - } + if (!firstParam) { + buf.append(", "); + } - TextBuffer buff = new TextBuffer(); - ExprProcessor.getCastedExprent(expr, leftType, buff, indent, true, tracer); - buf.append(buff); + ExprProcessor.getCastedExprent(expr, leftType, buf, indent, true, tracer); - firstParam = false; - } + firstParam = false; } - - buf.append(")"); } + + buf.append(")"); } + } - if (!enumConst) { - String enclosing = null; - if (constructor != null) { - enclosing = getQualifiedNewInstance(newType.value, constructor.getLstParameters(), indent, tracer); - } + if (!enumConst) { + String enclosing = null; + if (constructor != null) { + enclosing = getQualifiedNewInstance(newType.value, constructor.getLstParameters(), indent, tracer); + } - String typename = ExprProcessor.getTypeName(newType); + String typename = ExprProcessor.getTypeName(newType); - if (enclosing != null) { - ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.value); - if (newNode != null) { - typename = newNode.simpleName; - } - else { - typename = typename.substring(typename.lastIndexOf('.') + 1); - } + if (enclosing != null) { + ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.value); + if (newNode != null) { + typename = newNode.simpleName; } - buf.prepend("new " + typename); - - if (enclosing != null) { - buf.prepend(enclosing + "."); + else { + typename = typename.substring(typename.lastIndexOf('.') + 1); } } + buf.prepend("new " + typename); + + if (enclosing != null) { + buf.prepend(enclosing + "."); + } } - else { - buf.append("new ").append(ExprProcessor.getTypeName(newType)); + } + else { + buf.append("new ").append(ExprProcessor.getTypeName(newType)); - if (lstArrayElements.isEmpty()) { - for (int i = 0; i < newType.arrayDim; i++) { - buf.append("["); - if (i < lstDims.size()) { - buf.append(lstDims.get(i).toJava(indent, tracer)); - } - buf.append("]"); + if (lstArrayElements.isEmpty()) { + for (int i = 0; i < newType.arrayDim; i++) { + buf.append("["); + if (i < lstDims.size()) { + buf.append(lstDims.get(i).toJava(indent, tracer)); } + buf.append("]"); + } + } + else { + for (int i = 0; i < newType.arrayDim; i++) { + buf.append("[]"); } - else { - for (int i = 0; i < newType.arrayDim; i++) { - buf.append("[]"); - } - - VarType leftType = newType.decreaseArrayDim(); - buf.append("{"); - for (int i = 0; i < lstArrayElements.size(); i++) { - if (i > 0) { - buf.append(", "); - } - TextBuffer buff = new TextBuffer(); - ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buff, indent, false, tracer); - buf.append(buff); + VarType leftType = newType.decreaseArrayDim(); + buf.append("{"); + for (int i = 0; i < lstArrayElements.size(); i++) { + if (i > 0) { + buf.append(", "); } - buf.append("}"); + ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buf, indent, false, tracer); } + buf.append("}"); } } + return buf; } diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java index 5969487..3c9f760 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,9 +24,27 @@ import java.util.Collections; import java.util.List; public class StructInnerClassesAttribute extends StructGeneralAttribute { + public static class Entry { + public final int innerNameIdx; + public final int outerNameIdx; + public final int simpleNameIdx; + public final int accessFlags; + public final String innerName; + public final String enclosingName; + public final String simpleName; - private List classEntries; - private List stringEntries; + private Entry(int innerNameIdx, int outerNameIdx, int simpleNameIdx, int accessFlags, String innerName, String enclosingName, String simpleName) { + this.innerNameIdx = innerNameIdx; + this.outerNameIdx = outerNameIdx; + this.simpleNameIdx = simpleNameIdx; + this.accessFlags = accessFlags; + this.innerName = innerName; + this.enclosingName = enclosingName; + this.simpleName = simpleName; + } + } + + private List entries; @Override public void initContent(ConstantPool pool) throws IOException { @@ -34,39 +52,27 @@ public class StructInnerClassesAttribute extends StructGeneralAttribute { int len = data.readUnsignedShort(); if (len > 0) { - classEntries = new ArrayList(len); - stringEntries = new ArrayList(len); + entries = new ArrayList(len); for (int i = 0; i < len; i++) { - int[] classEntry = new int[4]; - for (int j = 0; j < 4; j++) { - classEntry[j] = data.readUnsignedShort(); - } - classEntries.add(classEntry); + int innerNameIdx = data.readUnsignedShort(); + int outerNameIdx = data.readUnsignedShort(); + int simpleNameIdx = data.readUnsignedShort(); + int accessFlags = data.readUnsignedShort(); - // inner name, enclosing class, original simple name - String[] stringEntry = new String[3]; - stringEntry[0] = pool.getPrimitiveConstant(classEntry[0]).getString(); - if (classEntry[1] != 0) { - stringEntry[1] = pool.getPrimitiveConstant(classEntry[1]).getString(); - } - if (classEntry[2] != 0) { - stringEntry[2] = pool.getPrimitiveConstant(classEntry[2]).getString(); - } - stringEntries.add(stringEntry); + String innerName = pool.getPrimitiveConstant(innerNameIdx).getString(); + String outerName = outerNameIdx != 0 ? pool.getPrimitiveConstant(outerNameIdx).getString() : null; + String simpleName = simpleNameIdx != 0 ? pool.getPrimitiveConstant(simpleNameIdx).getString() : null; + + entries.add(new Entry(innerNameIdx, outerNameIdx, simpleNameIdx, accessFlags, innerName, outerName, simpleName)); } } else { - classEntries = Collections.emptyList(); - stringEntries = Collections.emptyList(); + entries = Collections.emptyList(); } } - public List getClassEntries() { - return classEntries; - } - - public List getStringEntries() { - return stringEntries; + public List getEntries() { + return entries; } } diff --git a/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java b/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java index b965009..8ec1aaa 100644 --- a/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java +++ b/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java @@ -120,25 +120,6 @@ public class InterpreterUtil { return first == null ? second == null : first.equals(second); } - public static boolean equalObjectArrays(Object[] first, Object[] second) { - if (first == null || second == null) { - return equalObjects(first, second); - } - else { - if (first.length != second.length) { - return false; - } - - for (int i = 0; i < first.length; i++) { - if (!equalObjects(first[i], second[i])) { - return false; - } - } - } - - return true; - } - public static boolean equalLists(List first, List second) { if (first == null) { return second == null; @@ -172,6 +153,10 @@ public class InterpreterUtil { } public static String makeUniqueKey(String name, String descriptor) { - return name + " " + descriptor; + return name + ' ' + descriptor; + } + + public static String makeUniqueKey(String name, String descriptor1, String descriptor2) { + return name + ' ' + descriptor1 + ' ' + descriptor2; } }