[java-decompiler] cleanup (arrays to data classes; formatting; typos; dead code)

master
Roman Shevchenko 9 years ago
parent 26ab681d56
commit 45a41684e6
  1. 29
      src/org/jetbrains/java/decompiler/main/ClassWriter.java
  2. 78
      src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
  3. 12
      src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java
  4. 724
      src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java
  5. 209
      src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java
  6. 62
      src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java
  7. 25
      src/org/jetbrains/java/decompiler/util/InterpreterUtil.java

@ -46,7 +46,6 @@ import org.jetbrains.java.decompiler.util.InterpreterUtil;
import java.util.*; import java.util.*;
public class ClassWriter { public class ClassWriter {
private final ClassReference14Processor ref14processor; private final ClassReference14Processor ref14processor;
private final PoolInterceptor interceptor; private final PoolInterceptor interceptor;
@ -154,15 +153,6 @@ public class ClassWriter {
DecompilerContext.getLogger().endWriteClass(); 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) { public void classToJava(ClassNode node, TextBuffer buffer, int indent, BytecodeMappingTracer tracer) {
ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE); ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node); DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node);
@ -183,12 +173,7 @@ public class ClassWriter {
int start_class_def = buffer.length(); int start_class_def = buffer.length();
writeClassDefinition(node, buffer, indent); 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; boolean hasContent = false;
// fields
boolean enumFields = false; boolean enumFields = false;
dummy_tracer.incrementCurrentSourceLine(buffer.countLines(start_class_def)); dummy_tracer.incrementCurrentSourceLine(buffer.countLines(start_class_def));
@ -287,6 +272,13 @@ public class ClassWriter {
DecompilerContext.getLogger().endWriteClass(); 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) { private void writeClassDefinition(ClassNode node, TextBuffer buffer, int indent) {
if (node.type == ClassNode.CLASS_ANONYMOUS) { if (node.type == ClassNode.CLASS_ANONYMOUS) {
buffer.append(" {").appendLineSeparator(); 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; if (name == null || name.isEmpty()) return name;
boolean changed = false; 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 // 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(); buffer.append('{').appendLineSeparator();
tracer.incrementCurrentSourceLine(); tracer.incrementCurrentSourceLine();
@ -842,8 +832,6 @@ public class ClassWriter {
if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence
try { try {
int startLine = tracer.getCurrentSourceLine();
TextBuffer code = root.toJava(indent + 1, tracer); TextBuffer code = root.toJava(indent + 1, tracer);
hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0; 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}; StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS};
private static void appendAnnotations(TextBuffer buffer, StructMember mb, int indent) { private static void appendAnnotations(TextBuffer buffer, StructMember mb, int indent) {
BytecodeMappingTracer tracer_dummy = new BytecodeMappingTracer(); // FIXME: replace with a real one BytecodeMappingTracer tracer_dummy = new BytecodeMappingTracer(); // FIXME: replace with a real one
for (String name : ANNOTATION_ATTRIBUTES) { for (String name : ANNOTATION_ATTRIBUTES) {

@ -40,14 +40,22 @@ import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
public class ClassesProcessor { public class ClassesProcessor {
public static final int AVERAGE_CLASS_SIZE = 16 * 1024; public static final int AVERAGE_CLASS_SIZE = 16 * 1024;
private final Map<String, ClassNode> mapRootClasses = new HashMap<String, ClassNode>(); private final Map<String, ClassNode> mapRootClasses = new HashMap<String, ClassNode>();
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<String, Object[]> mapInnerClasses = new HashMap<String, Object[]>(); public ClassesProcessor(StructContext context) {
Map<String, Inner> mapInnerClasses = new HashMap<String, Inner>();
Map<String, Set<String>> mapNestedClassReferences = new HashMap<String, Set<String>>(); Map<String, Set<String>> mapNestedClassReferences = new HashMap<String, Set<String>>();
Map<String, Set<String>> mapEnclosingClassReferences = new HashMap<String, Set<String>>(); Map<String, Set<String>> mapEnclosingClassReferences = new HashMap<String, Set<String>>();
Map<String, String> mapNewSimpleNames = new HashMap<String, String>(); Map<String, String> mapNewSimpleNames = new HashMap<String, String>();
@ -57,25 +65,16 @@ public class ClassesProcessor {
// create class nodes // create class nodes
for (StructClass cl : context.getClasses().values()) { for (StructClass cl : context.getClasses().values()) {
if (cl.isOwn() && !mapRootClasses.containsKey(cl.qualifiedName)) { if (cl.isOwn() && !mapRootClasses.containsKey(cl.qualifiedName)) {
if (bDecompileInner) { if (bDecompileInner) {
StructInnerClassesAttribute inner = (StructInnerClassesAttribute)cl.getAttributes().getWithKey("InnerClasses"); 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 if (inner != null) {
arr[2] = entry[1] == 0 ? (entry[2] == 0 ? ClassNode.CLASS_ANONYMOUS : ClassNode.CLASS_LOCAL) : ClassNode.CLASS_MEMBER; for (StructInnerClassesAttribute.Entry entry : inner.getEntries()) {
String innerName = entry.innerName;
// original simple name // original simple name
String simpleName = strEntry[2]; String simpleName = entry.simpleName;
String savedName = mapNewSimpleNames.get(innerName); String savedName = mapNewSimpleNames.get(innerName);
if (savedName != null) { if (savedName != null) {
simpleName = savedName; simpleName = savedName;
} }
@ -87,15 +86,15 @@ public class ClassesProcessor {
} }
} }
arr[1] = simpleName; Inner rec = new Inner();
rec.simpleName = simpleName;
// original access flags rec.type = entry.outerNameIdx != 0 ? ClassNode.CLASS_MEMBER : entry.simpleNameIdx != 0 ? ClassNode.CLASS_LOCAL : ClassNode.CLASS_ANONYMOUS;
arr[3] = entry[3]; rec.accessFlags = entry.accessFlags;
// enclosing class // enclosing class
String enclClassName; String enclClassName;
if (entry[1] != 0) { if (entry.outerNameIdx != 0) {
enclClassName = strEntry[1]; enclClassName = entry.enclosingName;
} }
else { else {
enclClassName = cl.qualifiedName; enclClassName = cl.qualifiedName;
@ -105,11 +104,11 @@ public class ClassesProcessor {
StructClass enclosing_class = context.getClasses().get(enclClassName); StructClass enclosing_class = context.getClasses().get(enclClassName);
if (enclosing_class != null && enclosing_class.isOwn()) { // own classes only if (enclosing_class != null && enclosing_class.isOwn()) { // own classes only
Object[] arrOld = mapInnerClasses.get(innerName); Inner existingRec = mapInnerClasses.get(innerName);
if (arrOld == null) { if (existingRec == null) {
mapInnerClasses.put(innerName, arr); mapInnerClasses.put(innerName, rec);
} }
else if (!InterpreterUtil.equalObjectArrays(arrOld, arr)) { else if (!Inner.equal(existingRec, rec)) {
String message = "Inconsistent inner class entries for " + innerName + "!"; String message = "Inconsistent inner class entries for " + innerName + "!";
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
} }
@ -140,12 +139,10 @@ public class ClassesProcessor {
} }
if (bDecompileInner) { if (bDecompileInner) {
// connect nested classes // connect nested classes
for (Entry<String, ClassNode> ent : mapRootClasses.entrySet()) { for (Entry<String, ClassNode> ent : mapRootClasses.entrySet()) {
// root class? // root class?
if (!mapInnerClasses.containsKey(ent.getKey())) { if (!mapInnerClasses.containsKey(ent.getKey())) {
Set<String> setVisited = new HashSet<String>(); Set<String> setVisited = new HashSet<String>();
LinkedList<String> stack = new LinkedList<String>(); LinkedList<String> stack = new LinkedList<String>();
@ -153,7 +150,6 @@ public class ClassesProcessor {
setVisited.add(ent.getKey()); setVisited.add(ent.getKey());
while (!stack.isEmpty()) { while (!stack.isEmpty()) {
String superClass = stack.removeFirst(); String superClass = stack.removeFirst();
ClassNode superNode = mapRootClasses.get(superClass); ClassNode superNode = mapRootClasses.get(superClass);
@ -163,13 +159,13 @@ public class ClassesProcessor {
StructClass scl = superNode.classStruct; StructClass scl = superNode.classStruct;
StructInnerClassesAttribute inner = (StructInnerClassesAttribute)scl.getAttributes().getWithKey("InnerClasses"); 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); DecompilerContext.getLogger().writeMessage(superClass + " does not contain inner classes!", IFernflowerLogger.Severity.WARN);
continue; continue;
} }
for (int i = 0; i < inner.getStringEntries().size(); i++) { for (StructInnerClassesAttribute.Entry entry : inner.getEntries()) {
String nestedClass = inner.getStringEntries().get(i)[0]; String nestedClass = entry.innerName;
if (!setNestedClasses.contains(nestedClass)) { if (!setNestedClasses.contains(nestedClass)) {
continue; continue;
} }
@ -184,21 +180,20 @@ public class ClassesProcessor {
continue; continue;
} }
Object[] arr = mapInnerClasses.get(nestedClass); Inner rec = mapInnerClasses.get(nestedClass);
//if ((Integer)arr[2] == ClassNode.CLASS_MEMBER) { //if ((Integer)arr[2] == ClassNode.CLASS_MEMBER) {
// FIXME: check for consistent naming // FIXME: check for consistent naming
//} //}
nestedNode.type = (Integer)arr[2]; nestedNode.simpleName = rec.simpleName;
nestedNode.simpleName = (String)arr[1]; nestedNode.type = rec.type;
nestedNode.access = (Integer)arr[3]; nestedNode.access = rec.accessFlags;
if (nestedNode.type == ClassNode.CLASS_ANONYMOUS) { if (nestedNode.type == ClassNode.CLASS_ANONYMOUS) {
StructClass cl = nestedNode.classStruct; StructClass cl = nestedNode.classStruct;
// remove static if anonymous class // remove static if anonymous class (a common compiler bug)
// a common compiler bug
nestedNode.access &= ~CodeConstants.ACC_STATIC; nestedNode.access &= ~CodeConstants.ACC_STATIC;
int[] interfaces = cl.getInterfaces(); int[] interfaces = cl.getInterfaces();
@ -215,8 +210,7 @@ public class ClassesProcessor {
} }
} }
else if (nestedNode.type == ClassNode.CLASS_LOCAL) { else if (nestedNode.type == ClassNode.CLASS_LOCAL) {
// only abstract and final are permitted // only abstract and final are permitted (a common compiler bug)
// a common compiler bug
nestedNode.access &= (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_FINAL); nestedNode.access &= (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_FINAL);
} }
@ -301,7 +295,6 @@ public class ClassesProcessor {
} }
private static void initWrappers(ClassNode node) throws IOException { private static void initWrappers(ClassNode node) throws IOException {
if (node.type == ClassNode.CLASS_LAMBDA) { if (node.type == ClassNode.CLASS_LAMBDA) {
return; return;
} }
@ -317,7 +310,6 @@ public class ClassesProcessor {
} }
private static void addClassnameToImport(ClassNode node, ImportCollector imp) { private static void addClassnameToImport(ClassNode node, ImportCollector imp) {
if (node.simpleName != null && node.simpleName.length() > 0) { if (node.simpleName != null && node.simpleName.length() > 0) {
imp.getShortName(node.type == ClassNode.CLASS_ROOT ? node.classStruct.qualifiedName : node.simpleName, false); 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) { private static void destroyWrappers(ClassNode node) {
node.wrapper = null; node.wrapper = null;
node.classStruct.releaseResources(); node.classStruct.releaseResources();
@ -343,7 +334,6 @@ public class ClassesProcessor {
public static class ClassNode { public static class ClassNode {
public static final int CLASS_ROOT = 0; public static final int CLASS_ROOT = 0;
public static final int CLASS_MEMBER = 1; public static final int CLASS_MEMBER = 1;
public static final int CLASS_ANONYMOUS = 2; public static final int CLASS_ANONYMOUS = 2;

@ -21,13 +21,9 @@ import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
public class BytecodeMappingTracer { public class BytecodeMappingTracer {
private int currentSourceLine; private int currentSourceLine;
private StructLineNumberTableAttribute lineNumberTable = null; private StructLineNumberTableAttribute lineNumberTable = null;
private final Map<Integer, Integer> mapping = new HashMap<Integer, Integer>(); // bytecode offset, source line
// bytecode offset, source line
private final Map<Integer, Integer> mapping = new HashMap<Integer, Integer>();
public BytecodeMappingTracer() { } public BytecodeMappingTracer() { }
@ -43,12 +39,6 @@ public class BytecodeMappingTracer {
currentSourceLine += number_lines; currentSourceLine += number_lines;
} }
public void shiftSourceLines(int shift) {
for (Entry<Integer, Integer> entry : mapping.entrySet()) {
entry.setValue(entry.getValue() + shift);
}
}
public void addMapping(int bytecode_offset) { public void addMapping(int bytecode_offset) {
if (!mapping.containsKey(bytecode_offset)) { if (!mapping.containsKey(bytecode_offset)) {
mapping.put(bytecode_offset, currentSourceLine); mapping.put(bytecode_offset, currentSourceLine);

@ -36,7 +36,6 @@ import java.util.List;
import java.util.Set; import java.util.Set;
public class NewExprent extends Exprent { public class NewExprent extends Exprent {
private InvocationExprent constructor; private InvocationExprent constructor;
private final VarType newType; private final VarType newType;
private List<Exprent> lstDims = new ArrayList<Exprent>(); private List<Exprent> lstDims = new ArrayList<Exprent>();
@ -80,12 +79,7 @@ public class NewExprent extends Exprent {
@Override @Override
public VarType getExprType() { public VarType getExprType() {
if (anonymous) { return anonymous ? DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.value).anonymousClassType : newType;
return DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.value).anonymousClassType;
}
else {
return newType;
}
} }
@Override @Override
@ -163,24 +157,22 @@ public class NewExprent extends Exprent {
TextBuffer buf = new TextBuffer(); TextBuffer buf = new TextBuffer();
if (anonymous) { if (anonymous) {
ClassNode child = DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.value); ClassNode child = DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.value);
buf.append("("); buf.append("(");
if (!lambda && constructor != null) { 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<VarVersionPair> sigFields = null; List<VarVersionPair> sigFields = null;
if (newnode != null) { // own class if (newNode != null) { // own class
if (newnode.getWrapper() != null) { if (newNode.getWrapper() != null) {
sigFields = newnode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, invsuper.getStringDescriptor()).signatureFields; sigFields = newNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, invSuper.getStringDescriptor()).signatureFields;
} }
else { 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 !constructor.getLstParameters().isEmpty()) { // member non-static class invoked with enclosing class instance
sigFields = new ArrayList<VarVersionPair>(Collections.nCopies(constructor.getLstParameters().size(), (VarVersionPair)null)); sigFields = new ArrayList<VarVersionPair>(Collections.nCopies(constructor.getLstParameters().size(), (VarVersionPair)null));
sigFields.set(0, new VarVersionPair(-1, 0)); sigFields.set(0, new VarVersionPair(-1, 0));
@ -188,31 +180,29 @@ public class NewExprent extends Exprent {
} }
} }
boolean firstpar = true; boolean firstParam = true;
int start = 0, end = invsuper.getLstParameters().size(); int start = 0, end = invSuper.getLstParameters().size();
if (enumConst) { if (enumConst) {
start += 2; start += 2;
end -= 1; end -= 1;
} }
for (int i = start; i < end; i++) { for (int i = start; i < end; i++) {
if (sigFields == null || sigFields.get(i) == null) { if (sigFields == null || sigFields.get(i) == null) {
if (!firstpar) { if (!firstParam) {
buf.append(", "); buf.append(", ");
} }
Exprent param = invsuper.getLstParameters().get(i); Exprent param = invSuper.getLstParameters().get(i);
if (param.type == Exprent.EXPRENT_VAR) { if (param.type == Exprent.EXPRENT_VAR) {
int varindex = ((VarExprent)param).getIndex(); int varIndex = ((VarExprent)param).getIndex();
if (varindex > 0 && varindex <= constructor.getLstParameters().size()) { if (varIndex > 0 && varIndex <= constructor.getLstParameters().size()) {
param = constructor.getLstParameters().get(varindex - 1); param = constructor.getLstParameters().get(varIndex - 1);
} }
} }
TextBuffer buff = new TextBuffer(); ExprProcessor.getCastedExprent(param, invSuper.getDescriptor().params[i], buf, indent, true, tracer);
ExprProcessor.getCastedExprent(param, invsuper.getDescriptor().params[i], buff, indent, true, tracer);
buf.append(buff); firstParam = false;
firstpar = false;
} }
} }
} }
@ -226,14 +216,15 @@ public class NewExprent extends Exprent {
String typename = ExprProcessor.getCastTypeName(child.anonymousClassType); String typename = ExprProcessor.getCastTypeName(child.anonymousClassType);
if (enclosing != null) { if (enclosing != null) {
ClassNode anonimousNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(child.anonymousClassType.value); ClassNode anonymousNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(child.anonymousClassType.value);
if (anonimousNode != null) { if (anonymousNode != null) {
typename = anonimousNode.simpleName; typename = anonymousNode.simpleName;
} }
else { else {
typename = typename.substring(typename.lastIndexOf('.') + 1); typename = typename.substring(typename.lastIndexOf('.') + 1);
} }
} }
buf.prepend("new " + typename); buf.prepend("new " + typename);
if (enclosing != null) { if (enclosing != null) {
@ -275,118 +266,108 @@ public class NewExprent extends Exprent {
} }
buf.append("}"); buf.append("}");
} }
else { else if (newType.arrayDim == 0) {
if (newType.arrayDim == 0) { if (constructor != null) {
List<Exprent> lstParameters = constructor.getLstParameters();
if (constructor != null) { ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(constructor.getClassname());
List<Exprent> lstParameters = constructor.getLstParameters(); List<VarVersionPair> 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<VarVersionPair>(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<VarVersionPair> sigFields = null; boolean firstParam = true;
if (newnode != null) { // own class for (int i = start; i < lstParameters.size(); i++) {
if (newnode.getWrapper() != null) { if (sigFields == null || sigFields.get(i) == null) {
sigFields = newnode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, constructor.getStringDescriptor()).signatureFields; Exprent expr = lstParameters.get(i);
} VarType leftType = constructor.getDescriptor().params[i];
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<VarVersionPair>(Collections.nCopies(lstParameters.size(), (VarVersionPair)null));
sigFields.set(0, new VarVersionPair(-1, 0));
}
}
}
int start = enumConst ? 2 : 0; if (i == lstParameters.size() - 1 && expr.getExprType() == VarType.VARTYPE_NULL) {
if (!enumConst || start < lstParameters.size()) { ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(leftType.value);
buf.append("("); if (node != null && node.namelessConstructorStub) {
break; // skip last parameter of synthetic constructor call
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 (!firstParam) { if (!firstParam) {
buf.append(", "); buf.append(", ");
} }
TextBuffer buff = new TextBuffer(); ExprProcessor.getCastedExprent(expr, leftType, buf, indent, true, tracer);
ExprProcessor.getCastedExprent(expr, leftType, buff, indent, true, tracer);
buf.append(buff);
firstParam = false; firstParam = false;
}
} }
buf.append(")");
} }
buf.append(")");
} }
}
if (!enumConst) { if (!enumConst) {
String enclosing = null; String enclosing = null;
if (constructor != null) { if (constructor != null) {
enclosing = getQualifiedNewInstance(newType.value, constructor.getLstParameters(), indent, tracer); enclosing = getQualifiedNewInstance(newType.value, constructor.getLstParameters(), indent, tracer);
} }
String typename = ExprProcessor.getTypeName(newType); String typename = ExprProcessor.getTypeName(newType);
if (enclosing != null) { if (enclosing != null) {
ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.value); ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(newType.value);
if (newNode != null) { if (newNode != null) {
typename = newNode.simpleName; typename = newNode.simpleName;
}
else {
typename = typename.substring(typename.lastIndexOf('.') + 1);
}
} }
buf.prepend("new " + typename); else {
typename = typename.substring(typename.lastIndexOf('.') + 1);
if (enclosing != null) {
buf.prepend(enclosing + ".");
} }
} }
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()) { if (lstArrayElements.isEmpty()) {
for (int i = 0; i < newType.arrayDim; i++) { for (int i = 0; i < newType.arrayDim; i++) {
buf.append("["); buf.append("[");
if (i < lstDims.size()) { if (i < lstDims.size()) {
buf.append(lstDims.get(i).toJava(indent, tracer)); buf.append(lstDims.get(i).toJava(indent, tracer));
}
buf.append("]");
} }
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; return buf;
} }

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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; import java.util.List;
public class StructInnerClassesAttribute extends StructGeneralAttribute { 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<int[]> classEntries; private Entry(int innerNameIdx, int outerNameIdx, int simpleNameIdx, int accessFlags, String innerName, String enclosingName, String simpleName) {
private List<String[]> stringEntries; this.innerNameIdx = innerNameIdx;
this.outerNameIdx = outerNameIdx;
this.simpleNameIdx = simpleNameIdx;
this.accessFlags = accessFlags;
this.innerName = innerName;
this.enclosingName = enclosingName;
this.simpleName = simpleName;
}
}
private List<Entry> entries;
@Override @Override
public void initContent(ConstantPool pool) throws IOException { public void initContent(ConstantPool pool) throws IOException {
@ -34,39 +52,27 @@ public class StructInnerClassesAttribute extends StructGeneralAttribute {
int len = data.readUnsignedShort(); int len = data.readUnsignedShort();
if (len > 0) { if (len > 0) {
classEntries = new ArrayList<int[]>(len); entries = new ArrayList<Entry>(len);
stringEntries = new ArrayList<String[]>(len);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
int[] classEntry = new int[4]; int innerNameIdx = data.readUnsignedShort();
for (int j = 0; j < 4; j++) { int outerNameIdx = data.readUnsignedShort();
classEntry[j] = data.readUnsignedShort(); int simpleNameIdx = data.readUnsignedShort();
} int accessFlags = data.readUnsignedShort();
classEntries.add(classEntry);
// inner name, enclosing class, original simple name String innerName = pool.getPrimitiveConstant(innerNameIdx).getString();
String[] stringEntry = new String[3]; String outerName = outerNameIdx != 0 ? pool.getPrimitiveConstant(outerNameIdx).getString() : null;
stringEntry[0] = pool.getPrimitiveConstant(classEntry[0]).getString(); String simpleName = simpleNameIdx != 0 ? pool.getPrimitiveConstant(simpleNameIdx).getString() : null;
if (classEntry[1] != 0) {
stringEntry[1] = pool.getPrimitiveConstant(classEntry[1]).getString(); entries.add(new Entry(innerNameIdx, outerNameIdx, simpleNameIdx, accessFlags, innerName, outerName, simpleName));
}
if (classEntry[2] != 0) {
stringEntry[2] = pool.getPrimitiveConstant(classEntry[2]).getString();
}
stringEntries.add(stringEntry);
} }
} }
else { else {
classEntries = Collections.emptyList(); entries = Collections.emptyList();
stringEntries = Collections.emptyList();
} }
} }
public List<int[]> getClassEntries() { public List<Entry> getEntries() {
return classEntries; return entries;
}
public List<String[]> getStringEntries() {
return stringEntries;
} }
} }

@ -120,25 +120,6 @@ public class InterpreterUtil {
return first == null ? second == null : first.equals(second); 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) { public static boolean equalLists(List<?> first, List<?> second) {
if (first == null) { if (first == null) {
return second == null; return second == null;
@ -172,6 +153,10 @@ public class InterpreterUtil {
} }
public static String makeUniqueKey(String name, String descriptor) { 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;
} }
} }

Loading…
Cancel
Save