|
|
@ -18,33 +18,106 @@ |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
package jode.decompiler; |
|
|
|
package jode.decompiler; |
|
|
|
|
|
|
|
import jode.Decompiler; |
|
|
|
import jode.type.*; |
|
|
|
import jode.type.*; |
|
|
|
import jode.bytecode.ClassInfo; |
|
|
|
import jode.bytecode.ClassInfo; |
|
|
|
import jode.bytecode.FieldInfo; |
|
|
|
import jode.bytecode.FieldInfo; |
|
|
|
import jode.bytecode.MethodInfo; |
|
|
|
import jode.bytecode.MethodInfo; |
|
|
|
|
|
|
|
import jode.bytecode.InnerClassInfo; |
|
|
|
import jode.bytecode.ConstantPool; |
|
|
|
import jode.bytecode.ConstantPool; |
|
|
|
import jode.expr.Expression; |
|
|
|
import jode.expr.Expression; |
|
|
|
|
|
|
|
import jode.expr.ConstructorOperator; |
|
|
|
import jode.flow.TransformConstructors; |
|
|
|
import jode.flow.TransformConstructors; |
|
|
|
import java.util.NoSuchElementException; |
|
|
|
import java.util.NoSuchElementException; |
|
|
|
import java.lang.reflect.Modifier; |
|
|
|
import java.lang.reflect.Modifier; |
|
|
|
|
|
|
|
|
|
|
|
public class ClassAnalyzer implements Analyzer { |
|
|
|
public class ClassAnalyzer implements Analyzer, Scope { |
|
|
|
ImportHandler imports; |
|
|
|
ImportHandler imports; |
|
|
|
|
|
|
|
ClassInfo clazz; |
|
|
|
|
|
|
|
Object parent; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String name; |
|
|
|
FieldAnalyzer[] fields; |
|
|
|
FieldAnalyzer[] fields; |
|
|
|
MethodAnalyzer[] methods; |
|
|
|
MethodAnalyzer[] methods; |
|
|
|
|
|
|
|
ClassAnalyzer[] inners; |
|
|
|
|
|
|
|
|
|
|
|
MethodAnalyzer staticConstructor; |
|
|
|
MethodAnalyzer staticConstructor; |
|
|
|
MethodAnalyzer[] constructors; |
|
|
|
MethodAnalyzer[] constructors; |
|
|
|
|
|
|
|
|
|
|
|
ClassInfo clazz; |
|
|
|
|
|
|
|
ClassAnalyzer parent; |
|
|
|
public boolean isScopeOf(Object obj, int scopeType) { |
|
|
|
|
|
|
|
if (clazz.equals(obj) && scopeType == CLASSSCOPE) |
|
|
|
public ClassAnalyzer(ClassAnalyzer parent, ClassInfo clazz, |
|
|
|
return true; |
|
|
|
ImportHandler imports) |
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public boolean conflicts(String name, int usageType) { |
|
|
|
|
|
|
|
ClassInfo info = clazz; |
|
|
|
|
|
|
|
while (info != null) { |
|
|
|
|
|
|
|
if (usageType == METHODNAME) { |
|
|
|
|
|
|
|
MethodInfo[] minfos = info.getMethods(); |
|
|
|
|
|
|
|
for (int i = 0; i< minfos.length; i++) |
|
|
|
|
|
|
|
if (minfos[i].getName().equals(name)) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (usageType == FIELDNAME || usageType == AMBIGUOUSNAME) { |
|
|
|
|
|
|
|
FieldInfo[] finfos = info.getFields(); |
|
|
|
|
|
|
|
for (int i=0; i < finfos.length; i++) { |
|
|
|
|
|
|
|
if (finfos[i].getName().equals(name)) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (usageType == CLASSNAME || usageType == AMBIGUOUSNAME) { |
|
|
|
|
|
|
|
InnerClassInfo[] iinfos = info.getInnerClasses(); |
|
|
|
|
|
|
|
if (iinfos != null) { |
|
|
|
|
|
|
|
for (int i=0; i < iinfos.length; i++) { |
|
|
|
|
|
|
|
if (iinfos[i].name.equals(name)) |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
info = info.getSuperclass(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ClassAnalyzer(Object parent, |
|
|
|
|
|
|
|
ClassInfo clazz, ImportHandler imports) |
|
|
|
{ |
|
|
|
{ |
|
|
|
clazz.loadInfo(clazz.FULLINFO); |
|
|
|
clazz.loadInfo(clazz.FULLINFO); |
|
|
|
this.parent = parent; |
|
|
|
this.parent = parent; |
|
|
|
this.clazz = clazz; |
|
|
|
this.clazz = clazz; |
|
|
|
this.imports = imports; |
|
|
|
this.imports = imports; |
|
|
|
|
|
|
|
name = clazz.getName(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (parent != null) { |
|
|
|
|
|
|
|
InnerClassInfo[] outerInfos = clazz.getOuterClasses(); |
|
|
|
|
|
|
|
if (outerInfos[0].outer == null) { |
|
|
|
|
|
|
|
if (parent instanceof ClassAnalyzer) |
|
|
|
|
|
|
|
throw new jode.AssertError |
|
|
|
|
|
|
|
("ClassInfo Attributes are inconsistent: " |
|
|
|
|
|
|
|
+ clazz.getName()); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if (!(parent instanceof ClassAnalyzer) |
|
|
|
|
|
|
|
|| !(((ClassAnalyzer) parent).clazz.getName() |
|
|
|
|
|
|
|
.equals(outerInfos[0].outer)) |
|
|
|
|
|
|
|
|| outerInfos[0].name == null) |
|
|
|
|
|
|
|
throw new jode.AssertError |
|
|
|
|
|
|
|
("ClassInfo Attributes are inconsistent: " |
|
|
|
|
|
|
|
+ clazz.getName()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
name = outerInfos[0].name; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
name = clazz.getName(); |
|
|
|
|
|
|
|
int dot = name.lastIndexOf('.'); |
|
|
|
|
|
|
|
if (dot >= 0) |
|
|
|
|
|
|
|
name = name.substring(dot+1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ClassAnalyzer(ClassInfo clazz, ImportHandler imports) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
this(null, clazz, imports); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public FieldAnalyzer getField(String fieldName, Type fieldType) { |
|
|
|
public FieldAnalyzer getField(String fieldName, Type fieldType) { |
|
|
@ -67,6 +140,10 @@ public class ClassAnalyzer implements Analyzer { |
|
|
|
("Method "+methodType+" "+clazz.getName()+"."+methodName); |
|
|
|
("Method "+methodType+" "+clazz.getName()+"."+methodName); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Object getParent() { |
|
|
|
|
|
|
|
return parent; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public ClassInfo getClazz() { |
|
|
|
public ClassInfo getClazz() { |
|
|
|
return clazz; |
|
|
|
return clazz; |
|
|
|
} |
|
|
|
} |
|
|
@ -74,6 +151,8 @@ public class ClassAnalyzer implements Analyzer { |
|
|
|
public void analyze() { |
|
|
|
public void analyze() { |
|
|
|
FieldInfo[] finfos = clazz.getFields(); |
|
|
|
FieldInfo[] finfos = clazz.getFields(); |
|
|
|
MethodInfo[] minfos = clazz.getMethods(); |
|
|
|
MethodInfo[] minfos = clazz.getMethods(); |
|
|
|
|
|
|
|
InnerClassInfo[] innerInfos = clazz.getInnerClasses(); |
|
|
|
|
|
|
|
|
|
|
|
if (finfos == null) { |
|
|
|
if (finfos == null) { |
|
|
|
/* This means that the class could not be loaded. |
|
|
|
/* This means that the class could not be loaded. |
|
|
|
* give up. |
|
|
|
* give up. |
|
|
@ -81,12 +160,21 @@ public class ClassAnalyzer implements Analyzer { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((Decompiler.options & Decompiler.OPTION_INNER) != 0 |
|
|
|
|
|
|
|
&& innerInfos != null) { |
|
|
|
|
|
|
|
int innerCount = innerInfos.length; |
|
|
|
|
|
|
|
inners = new ClassAnalyzer[innerCount]; |
|
|
|
|
|
|
|
for (int i=0; i < innerCount; i++) { |
|
|
|
|
|
|
|
inners[i] = new ClassAnalyzer |
|
|
|
|
|
|
|
(this, ClassInfo.forName(innerInfos[i].inner), imports); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else |
|
|
|
|
|
|
|
inners = new ClassAnalyzer[0]; |
|
|
|
|
|
|
|
|
|
|
|
fields = new FieldAnalyzer[finfos.length]; |
|
|
|
fields = new FieldAnalyzer[finfos.length]; |
|
|
|
methods = new MethodAnalyzer[minfos.length]; |
|
|
|
methods = new MethodAnalyzer[minfos.length]; |
|
|
|
for (int j=0; j < finfos.length; j++) { |
|
|
|
for (int j=0; j < finfos.length; j++) |
|
|
|
fields[j] = new FieldAnalyzer(this, finfos[j], imports); |
|
|
|
fields[j] = new FieldAnalyzer(this, finfos[j], imports); |
|
|
|
fields[j].analyze(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
staticConstructor = null; |
|
|
|
staticConstructor = null; |
|
|
|
java.util.Vector constrVector = new java.util.Vector(); |
|
|
|
java.util.Vector constrVector = new java.util.Vector(); |
|
|
@ -99,23 +187,36 @@ public class ClassAnalyzer implements Analyzer { |
|
|
|
else |
|
|
|
else |
|
|
|
constrVector.addElement(methods[j]); |
|
|
|
constrVector.addElement(methods[j]); |
|
|
|
} |
|
|
|
} |
|
|
|
// First analyze only synthetic methods.
|
|
|
|
|
|
|
|
if (methods[j].isSynthetic()) |
|
|
|
|
|
|
|
methods[j].analyze(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
for (int j=0; j < methods.length; j++) { |
|
|
|
// First analyze fields
|
|
|
|
// Now analyze the remaining methods
|
|
|
|
for (int j=0; j < fields.length; j++) |
|
|
|
if (!methods[j].isSynthetic()) |
|
|
|
fields[j].analyze(); |
|
|
|
methods[j].analyze(); |
|
|
|
|
|
|
|
} |
|
|
|
// now analyze constructors:
|
|
|
|
constructors = new MethodAnalyzer[constrVector.size()]; |
|
|
|
constructors = new MethodAnalyzer[constrVector.size()]; |
|
|
|
if (constructors.length > 0) { |
|
|
|
if (constructors.length > 0) { |
|
|
|
constrVector.copyInto(constructors); |
|
|
|
constrVector.copyInto(constructors); |
|
|
|
TransformConstructors.transform(this, false, constructors); |
|
|
|
for (int j=0; j< constructors.length; j++) |
|
|
|
|
|
|
|
constructors[j].analyze(); |
|
|
|
|
|
|
|
TransformConstructors.transform |
|
|
|
|
|
|
|
(this, false, parent instanceof ClassAnalyzer, |
|
|
|
|
|
|
|
parent instanceof ConstructorOperator, constructors); |
|
|
|
} |
|
|
|
} |
|
|
|
if (staticConstructor != null) |
|
|
|
if (staticConstructor != null) { |
|
|
|
TransformConstructors.transform(this, true, new MethodAnalyzer[] |
|
|
|
staticConstructor.analyze(); |
|
|
|
{ staticConstructor }); |
|
|
|
TransformConstructors.transform(this, true, false, false, |
|
|
|
|
|
|
|
new MethodAnalyzer[] |
|
|
|
|
|
|
|
{ staticConstructor }); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Now analyze remaining methods.
|
|
|
|
|
|
|
|
for (int j=0; j < methods.length; j++) { |
|
|
|
|
|
|
|
if (!methods[j].isConstructor()) |
|
|
|
|
|
|
|
methods[j].analyze(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Now analyze the inner classes.
|
|
|
|
|
|
|
|
for (int j=0; j < inners.length; j++) |
|
|
|
|
|
|
|
inners[j].analyze(); |
|
|
|
|
|
|
|
|
|
|
|
imports.useClass(clazz); |
|
|
|
imports.useClass(clazz); |
|
|
|
if (clazz.getSuperclass() != null) |
|
|
|
if (clazz.getSuperclass() != null) |
|
|
@ -125,6 +226,14 @@ public class ClassAnalyzer implements Analyzer { |
|
|
|
imports.useClass(interfaces[j]); |
|
|
|
imports.useClass(interfaces[j]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public String getName() { |
|
|
|
|
|
|
|
return name; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void setName(String name) { |
|
|
|
|
|
|
|
this.name = name; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException |
|
|
|
public void dumpSource(TabbedPrintWriter writer) throws java.io.IOException |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (fields == null) { |
|
|
|
if (fields == null) { |
|
|
@ -133,6 +242,7 @@ public class ClassAnalyzer implements Analyzer { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
writer.pushScope(this); |
|
|
|
int modifiedModifiers = clazz.getModifiers() & ~Modifier.SYNCHRONIZED; |
|
|
|
int modifiedModifiers = clazz.getModifiers() & ~Modifier.SYNCHRONIZED; |
|
|
|
if (clazz.isInterface()) |
|
|
|
if (clazz.isInterface()) |
|
|
|
modifiedModifiers &= ~Modifier.ABSTRACT; |
|
|
|
modifiedModifiers &= ~Modifier.ABSTRACT; |
|
|
@ -142,33 +252,64 @@ public class ClassAnalyzer implements Analyzer { |
|
|
|
/*interface is in modif*/ |
|
|
|
/*interface is in modif*/ |
|
|
|
if (!clazz.isInterface()) |
|
|
|
if (!clazz.isInterface()) |
|
|
|
writer.print("class "); |
|
|
|
writer.print("class "); |
|
|
|
writer.println(imports.getClassString(clazz)); |
|
|
|
if (parent != null && name == null) { |
|
|
|
writer.tab(); |
|
|
|
/* This is an anonymous class */ |
|
|
|
ClassInfo superClazz = clazz.getSuperclass(); |
|
|
|
ClassInfo superClazz = clazz.getSuperclass(); |
|
|
|
if (superClazz != null && |
|
|
|
ClassInfo[] interfaces = clazz.getInterfaces(); |
|
|
|
superClazz != ClassInfo.javaLangObject) { |
|
|
|
if (interfaces.length == 1 |
|
|
|
writer.println("extends "+imports.getClassString(superClazz)); |
|
|
|
&& (superClazz == null |
|
|
|
} |
|
|
|
|| superClazz == ClassInfo.javaLangObject)) { |
|
|
|
ClassInfo[] interfaces = clazz.getInterfaces(); |
|
|
|
writer.print(writer.getClassString(interfaces[0])); |
|
|
|
if (interfaces.length > 0) { |
|
|
|
} else { |
|
|
|
writer.print(clazz.isInterface() ? "extends " : "implements "); |
|
|
|
if (interfaces.length > 0) { |
|
|
|
for (int i=0; i < interfaces.length; i++) { |
|
|
|
writer.print("/*too many supers*/ "); |
|
|
|
if (i > 0) |
|
|
|
for (int i=0; i< interfaces.length; i++) |
|
|
|
writer.print(", "); |
|
|
|
writer.print(writer.getClassString(interfaces[i])+","); |
|
|
|
writer.print(imports.getClassString(interfaces[i])); |
|
|
|
} |
|
|
|
|
|
|
|
if (superClazz == null) |
|
|
|
|
|
|
|
writer.print(writer.getClassString |
|
|
|
|
|
|
|
(ClassInfo.javaLangObject)); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
writer.print(writer.getClassString(superClazz)); |
|
|
|
} |
|
|
|
} |
|
|
|
writer.println(""); |
|
|
|
} else { |
|
|
|
|
|
|
|
writer.println(name); |
|
|
|
|
|
|
|
writer.tab(); |
|
|
|
|
|
|
|
ClassInfo superClazz = clazz.getSuperclass(); |
|
|
|
|
|
|
|
if (superClazz != null && |
|
|
|
|
|
|
|
superClazz != ClassInfo.javaLangObject) { |
|
|
|
|
|
|
|
writer.println("extends "+writer.getClassString(superClazz)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ClassInfo[] interfaces = clazz.getInterfaces(); |
|
|
|
|
|
|
|
if (interfaces.length > 0) { |
|
|
|
|
|
|
|
writer.print(clazz.isInterface() ? "extends " : "implements "); |
|
|
|
|
|
|
|
for (int i=0; i < interfaces.length; i++) { |
|
|
|
|
|
|
|
if (i > 0) |
|
|
|
|
|
|
|
writer.print(", "); |
|
|
|
|
|
|
|
writer.print(writer.getClassString(interfaces[i])); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
writer.println(""); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
writer.untab(); |
|
|
|
} |
|
|
|
} |
|
|
|
writer.untab(); |
|
|
|
|
|
|
|
writer.openBrace(); |
|
|
|
writer.openBrace(); |
|
|
|
writer.tab(); |
|
|
|
writer.tab(); |
|
|
|
|
|
|
|
|
|
|
|
for (int i=0; i< fields.length; i++) |
|
|
|
for (int i=0; i< fields.length; i++) |
|
|
|
fields[i].dumpSource(writer); |
|
|
|
fields[i].dumpSource(writer); |
|
|
|
|
|
|
|
for (int i=0; i< inners.length; i++) { |
|
|
|
|
|
|
|
writer.println(""); |
|
|
|
|
|
|
|
inners[i].dumpSource(writer); |
|
|
|
|
|
|
|
} |
|
|
|
for (int i=0; i< methods.length; i++) |
|
|
|
for (int i=0; i< methods.length; i++) |
|
|
|
methods[i].dumpSource(writer); |
|
|
|
methods[i].dumpSource(writer); |
|
|
|
writer.untab(); |
|
|
|
writer.untab(); |
|
|
|
writer.closeBrace(); |
|
|
|
if (parent != null && name == null) { |
|
|
|
|
|
|
|
/* This is an anonymous class */ |
|
|
|
|
|
|
|
writer.closeBraceNoSpace(); |
|
|
|
|
|
|
|
} else |
|
|
|
|
|
|
|
writer.closeBrace(); |
|
|
|
|
|
|
|
writer.popScope(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public String getTypeString(Type type) { |
|
|
|
public String getTypeString(Type type) { |
|
|
|