diff --git a/jode/.classpath b/jode/.classpath
index fbc5703..226766d 100644
--- a/jode/.classpath
+++ b/jode/.classpath
@@ -4,13 +4,9 @@
-
-
-
-
-
-
+
+
diff --git a/jode/src/net/sf/jode/bytecode/ClassInfo.java b/jode/src/net/sf/jode/bytecode/ClassInfo.java
index f36ed38..1ae1626 100644
--- a/jode/src/net/sf/jode/bytecode/ClassInfo.java
+++ b/jode/src/net/sf/jode/bytecode/ClassInfo.java
@@ -1210,8 +1210,10 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
public String getSignature() {
if (status < HIERARCHY)
throw new IllegalStateException("status is "+status);
- if (signature != null)
+ if (signature != null) {
+ System.err.println("Sig(attrib) of "+this+": "+signature);/*XXX REMOVE*/
return signature;
+ }
if (superclass == null)
return "";
StringBuffer sb = new StringBuffer();
@@ -1221,6 +1223,7 @@ public final class ClassInfo extends BinaryInfo implements Comparable {
sb.append('L').append(interfaces[i].getName().replace('.','/'))
.append(";");
}
+ System.err.println("Sig of "+this+": "+sb.toString());/*XXX REMOVE*/
return sb.toString();
}
diff --git a/jode/src/net/sf/jode/bytecode/TypeSignature.java b/jode/src/net/sf/jode/bytecode/TypeSignature.java
index 0bd9322..6d7ae0c 100644
--- a/jode/src/net/sf/jode/bytecode/TypeSignature.java
+++ b/jode/src/net/sf/jode/bytecode/TypeSignature.java
@@ -19,6 +19,7 @@
package net.sf.jode.bytecode;
///#def COLLECTIONS java.util
+import java.util.ArrayList;
import java.util.Map;
///#enddef
@@ -429,6 +430,65 @@ public class TypeSignature {
return params;
}
+ /**
+ * Gets the signature of the super class from a class signature.
+ * @param typeSig the class's signature.
+ * @return the signature of the super class.
+ */
+ public static String getSuperSignature(String typeSig) {
+ int pos = 0;
+ if (typeSig.charAt(0) == '<') {
+ /* Skip generic info */
+ pos++;
+ while (typeSig.charAt(pos) != '>') {
+ while (typeSig.charAt(pos) != ':')
+ pos++;
+ /* check for empty entry */
+ if (typeSig.charAt(pos+1) == ':')
+ pos++;
+ while (typeSig.charAt(pos) == ':') {
+ /* skip colon and type */
+ pos = skipType(typeSig, pos + 1);
+ }
+ }
+ pos++;
+ }
+ return typeSig.substring(pos, skipType(typeSig, pos));
+ }
+
+ /**
+ * Gets the signatures of the super interfaces from a class signature.
+ * @param typeSig the class's signature.
+ * @return an array containing the signatures of the interfaces.
+ */
+ public static String[] getIfaceSignatures(String typeSig) {
+ int pos = 0;
+ if (typeSig.charAt(0) == '<') {
+ /* Skip generic info */
+ pos++;
+ while (typeSig.charAt(pos) != '>') {
+ while (typeSig.charAt(pos) != ':')
+ pos++;
+ /* check for empty entry */
+ if (typeSig.charAt(pos+1) == ':')
+ pos++;
+ while (typeSig.charAt(pos) == ':') {
+ /* skip colon and type */
+ pos = skipType(typeSig, pos + 1);
+ }
+ }
+ pos++;
+ }
+ pos = skipType(typeSig, pos);
+ ArrayList list = new ArrayList();
+ while (pos < typeSig.length()) {
+ int epos = skipType(typeSig, pos);
+ list.add(typeSig.substring(pos, epos));
+ pos = epos;
+ }
+ return (String[]) list.toArray(new String[list.size()]);
+ }
+
private static int mapGenericsInType(String typeSig, Map generics,
StringBuffer mapped, int spos) {
int pos = spos;
@@ -551,34 +611,36 @@ public class TypeSignature {
private static int checkClassName(String clName, int i)
throws IllegalArgumentException, StringIndexOutOfBoundsException
{
- while (true) {
- char c = clName.charAt(i++);
- if (c == '<') {
- c = clName.charAt(i++);
- do {
- if (c == '*')
- i++;
- else {
- if (c == '+' || c == '-')
- c = clName.charAt(i++);
- if (c != 'L' && c != 'T' && c != '[')
- throw new IllegalArgumentException
- ("Wrong class instantiation: "+clName);
- i = checkTypeSig(clName, i - 1);
- }
- c = clName.charAt(i++);
- } while (c != '>');
- c = clName.charAt(i++);
- if (c != ';')
- throw new IllegalArgumentException
- ("no ; after > in "+clName);
- }
- if (c == ';')
- return i;
+ char c = clName.charAt(i++);
+ while (c != ';' && c != '.' && c != '<') {
if (c != '/' && !Character.isJavaIdentifierPart(c))
throw new IllegalArgumentException("Illegal java class name: "
+ clName);
+ c = clName.charAt(i++);
}
+ if (c == '<') {
+ c = clName.charAt(i++);
+ do {
+ if (c == '*')
+ i++;
+ else {
+ if (c == '+' || c == '-')
+ c = clName.charAt(i++);
+ if (c != 'L' && c != 'T' && c != '[')
+ throw new IllegalArgumentException
+ ("Wrong class instantiation: "+clName);
+ i = checkTypeSig(clName, i - 1);
+ }
+ c = clName.charAt(i++);
+ } while (c != '>');
+ c = clName.charAt(i++);
+ }
+ if (c == '.')
+ return checkClassName(clName, i);
+ if (c != ';')
+ throw new IllegalArgumentException
+ ("no ; after > in "+clName);
+ return i;
}
/**
diff --git a/jode/src/net/sf/jode/decompiler/ClassAnalyzer.java b/jode/src/net/sf/jode/decompiler/ClassAnalyzer.java
index b80ddb1..194ddd1 100644
--- a/jode/src/net/sf/jode/decompiler/ClassAnalyzer.java
+++ b/jode/src/net/sf/jode/decompiler/ClassAnalyzer.java
@@ -178,7 +178,7 @@ public class ClassAnalyzer
*/
if ((Options.options & Options.OPTION_INNER) != 0
&& parent instanceof ClassAnalyzer && !isStatic())
- outerInstance = new ThisOperator(((ClassAnalyzer) parent).clazz);
+ outerInstance = new ThisOperator((ClassAnalyzer) parent);
if (outerValues != null)
this.outerValues = new OuterValues(this, outerValues);
}
@@ -569,7 +569,7 @@ public class ClassAnalyzer
}
String signature = clazz.getSignature();
System.err.println("Class Signature: "+signature+ " (class "+name+")");
- writer.printExtendsImplements(Type.tClass(clazz));
+ writer.printExtendsImplements(myType);
writer.println();
writer.openBraceClass();
@@ -799,6 +799,18 @@ public class ClassAnalyzer
return getParent().getClassAnalyzer(cinfo);
}
+ public GenericParameterType getGenericType(String name) {
+ if (genericTypes != null) {
+ for (int i = 0; i < genericTypes.length; i++) {
+ if (genericTypes[i].getClassName().equals(name))
+ return genericTypes[i];
+ }
+ }
+ if (parent != null)
+ return parent.getGenericType(name);
+ return null;
+ }
+
/**
* Get the class analyzer for the given inner class.
* @param name the short name of the inner class
diff --git a/jode/src/net/sf/jode/decompiler/ClassDeclarer.java b/jode/src/net/sf/jode/decompiler/ClassDeclarer.java
index cd996d5..e0f682f 100644
--- a/jode/src/net/sf/jode/decompiler/ClassDeclarer.java
+++ b/jode/src/net/sf/jode/decompiler/ClassDeclarer.java
@@ -19,6 +19,8 @@
package net.sf.jode.decompiler;
import net.sf.jode.bytecode.ClassInfo;
+import net.sf.jode.bytecode.ClassPath;
+import net.sf.jode.type.GenericParameterType;
/**
* This is the interface for objects, that a method can declare
@@ -29,6 +31,12 @@ public interface ClassDeclarer {
* @return null if this is the outermost instance.
*/
public ClassDeclarer getParent();
+
+ /**
+ * Get the current class path.
+ * @return the current class path.
+ */
+ public ClassPath getClassPath();
/**
* Get the class analyzer for the given anonymous class info. It
@@ -38,5 +46,13 @@ public interface ClassDeclarer {
*/
public ClassAnalyzer getClassAnalyzer(ClassInfo ci);
+
+ /**
+ * Gets the generic type for the given named generic.
+ * @param name the name of the generic, e.g. K.
+ * @return the generic type for the named generic.
+ */
+ public GenericParameterType getGenericType(String name);
+
public void addClassAnalyzer(ClassAnalyzer classAna);
}
diff --git a/jode/src/net/sf/jode/decompiler/FieldAnalyzer.java b/jode/src/net/sf/jode/decompiler/FieldAnalyzer.java
index 8077173..907659e 100644
--- a/jode/src/net/sf/jode/decompiler/FieldAnalyzer.java
+++ b/jode/src/net/sf/jode/decompiler/FieldAnalyzer.java
@@ -51,7 +51,7 @@ public class FieldAnalyzer implements Analyzer {
imports = i;
modifiers = fd.getModifiers();
- type = Type.tType(cla.getClassPath(), fd.getType());
+ type = Type.tType(cla.getClassPath(), cla.getType(), fd.getSignature());
fieldName = fd.getName();
constant = null;
this.isSynthetic = fd.isSynthetic();
diff --git a/jode/src/net/sf/jode/decompiler/ImportHandler.java b/jode/src/net/sf/jode/decompiler/ImportHandler.java
index f1a2d4d..85e2590 100644
--- a/jode/src/net/sf/jode/decompiler/ImportHandler.java
+++ b/jode/src/net/sf/jode/decompiler/ImportHandler.java
@@ -21,6 +21,7 @@ package net.sf.jode.decompiler;
import net.sf.jode.GlobalOptions;
import net.sf.jode.bytecode.ClassInfo;
import net.sf.jode.bytecode.ClassPath;
+import net.sf.jode.type.SystemClassType;
import net.sf.jode.type.Type;
import net.sf.jode.type.ArrayType;
import net.sf.jode.type.ClassInfoType;
@@ -321,7 +322,7 @@ public class ImportHandler {
useType(((ArrayType) type).getElementType());
else if (type instanceof ClassInfoType)
useClass(((ClassInfoType) type).getClassInfo());
- else if (type instanceof ClassType)
+ else if (type instanceof SystemClassType)
useClass(((ClassType) type).getClassName());
}
diff --git a/jode/src/net/sf/jode/decompiler/MethodAnalyzer.java b/jode/src/net/sf/jode/decompiler/MethodAnalyzer.java
index c59e687..b41d72d 100644
--- a/jode/src/net/sf/jode/decompiler/MethodAnalyzer.java
+++ b/jode/src/net/sf/jode/decompiler/MethodAnalyzer.java
@@ -22,10 +22,12 @@ import net.sf.jode.GlobalOptions;
import net.sf.jode.bytecode.BasicBlocks;
import net.sf.jode.bytecode.Block;
import net.sf.jode.bytecode.ClassInfo;
+import net.sf.jode.bytecode.ClassPath;
import net.sf.jode.bytecode.Handler;
import net.sf.jode.bytecode.Instruction;
import net.sf.jode.bytecode.LocalVariableInfo;
import net.sf.jode.bytecode.MethodInfo;
+import net.sf.jode.bytecode.TypeSignature;
import net.sf.jode.jvm.SyntheticAnalyzer;
import net.sf.jode.type.*;
import net.sf.jode.expr.Expression;
@@ -53,6 +55,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
///#def COLLECTIONS java.util
+import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.ArrayList;
@@ -186,6 +189,11 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
* classes that are used in this method.
*/
Collection usedAnalyzers;
+ /**
+ * This array contains the generic types this method declares if
+ * it is generic.
+ */
+ GenericParameterType[] genericTypes;
/**
* This is the default constructor.
@@ -199,7 +207,47 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
this.imports = imports;
this.minfo = minfo;
this.methodName = minfo.getName();
- this.methodType = Type.tMethod(cla.getClassPath(), minfo.getSignature());
+ String signature = minfo.getSignature();
+ if (signature.charAt(0) == '<') {
+ String[] genericSignatures =
+ TypeSignature.getGenericSignatures(signature);
+ genericTypes = new GenericParameterType[genericSignatures.length];
+ for (int i = 0; i < genericTypes.length; i++) {
+ int colon = genericSignatures[i].indexOf(':');
+ String genName;
+ if (colon == -1) {
+ genericTypes[i] =
+ new GenericParameterType(genericSignatures[i],
+ Type.tObject,
+ new ClassType[0]);
+ } else {
+ String genname = genericSignatures[i].substring(0, colon);
+ String remainder = genericSignatures[i].substring(colon+1);
+ int nextIndex = TypeSignature.skipType(remainder, 0);
+ List superClazzes = new ArrayList();
+ for (;;) {
+ String clazzSig = remainder.substring(0, nextIndex);
+ superClazzes.add(Type.tType(classAnalyzer.getClassPath(),
+ classAnalyzer.getType(), clazzSig));
+ if (nextIndex >= remainder.length())
+ break;
+ remainder = remainder.substring(nextIndex+1);
+ }
+ ClassType genSupClass = (ClassType) superClazzes.get(0);
+ if (!genSupClass.isInterface())
+ superClazzes.remove(0);
+ else
+ genSupClass = Type.tObject;
+ ClassType[] genSupIfaces = (ClassType[])
+ superClazzes.toArray(new ClassType[0]);
+ genericTypes[i] = new GenericParameterType(genname,
+ genSupClass,
+ genSupIfaces);
+ }
+ }
+ }
+
+ this.methodType = Type.tMethod(cla.getClassPath(), cla.getType(), signature);
this.isConstructor =
methodName.equals("") || methodName.equals("");
@@ -423,8 +471,10 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
LocalInfo li = new LocalInfo(this, lvi.getSlot());
if ((Options.options & Options.OPTION_LVT) != 0
&& lvi.getName() != null)
- li.addHint(lvi.getName(), Type.tType(classAnalyzer.getClassPath(),
- lvi.getType()));
+ li.addHint(lvi.getName(),
+ Type.tType(classAnalyzer.getClassPath(),
+ classAnalyzer.getType(),
+ lvi.getType()));
allLocals.addElement(li);
return li;
}
@@ -582,11 +632,10 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
int offset = 0;
int slot = 0;
if (!isStatic()) {
- ClassInfo classInfo = classAnalyzer.getClazz();
param[offset] = getLocalInfo(bb != null
? bb.getParamInfo(slot)
: LocalVariableInfo.getInfo(slot));
- param[offset].setExpression(new ThisOperator(classInfo, true));
+ param[offset].setExpression(new ThisOperator(classAnalyzer, true));
slot++;
offset++;
}
@@ -1011,7 +1060,7 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
expr).getSubExpressions()[0];
if (expr instanceof ThisOperator) {
outerValueArray[j] =
- new ThisOperator(((ThisOperator) expr).getClassInfo());
+ new ThisOperator(((ThisOperator) expr).getClassAnalyzer());
continue;
}
LocalInfo li = null;
@@ -1109,6 +1158,23 @@ public class MethodAnalyzer implements Scope, ClassDeclarer {
return getParent().getClassAnalyzer(cinfo);
}
+ public GenericParameterType getGenericType(String name) {
+ if (genericTypes != null) {
+ for (int i = 0; i < genericTypes.length; i++) {
+ if (genericTypes[i].getClassName().equals(name))
+ return genericTypes[i];
+ }
+ }
+ return getParent().getGenericType(name);
+ }
+
+ /**
+ * Gets the current class path.
+ */
+ public ClassPath getClassPath() {
+ return classAnalyzer.getClassPath();
+ }
+
public void addClassAnalyzer(ClassAnalyzer clazzAna) {
if (innerAnalyzers == null)
innerAnalyzers = new Vector();
diff --git a/jode/src/net/sf/jode/decompiler/Opcodes.java b/jode/src/net/sf/jode/decompiler/Opcodes.java
index f4287f5..4e833ab 100644
--- a/jode/src/net/sf/jode/decompiler/Opcodes.java
+++ b/jode/src/net/sf/jode/decompiler/Opcodes.java
@@ -152,8 +152,8 @@ public abstract class Opcodes implements net.sf.jode.bytecode.Opcodes {
if (instr.getConstant() instanceof Reference) {
Reference ref = (Reference) instr.getConstant();
expr = new ClassFieldOperator
- (Type.tType(cp, ref.getType()),
- Type.tType(cp, ref.getClazz()));
+ (Type.tType(ma.getClassPath(), null, ref.getType()),
+ Type.tType(ma.getClassPath(), null, ref.getClazz()));
} else if (instr.getConstant() instanceof String) {
expr = new ConstOperator(cp, (String) instr.getConstant());
} else {
diff --git a/jode/src/net/sf/jode/expr/FieldOperator.java b/jode/src/net/sf/jode/expr/FieldOperator.java
index 189c137..47c10ca 100644
--- a/jode/src/net/sf/jode/expr/FieldOperator.java
+++ b/jode/src/net/sf/jode/expr/FieldOperator.java
@@ -62,8 +62,8 @@ public abstract class FieldOperator extends Operator {
this.methodAnalyzer = methodAnalyzer;
this.staticFlag = staticFlag;
- this.type = Type.tType(classPath, ref.getType());
- this.classType = Type.tType(classPath, ref.getClazz());
+ this.type = Type.tType(methodAnalyzer, ref.getType());
+ this.classType = Type.tType(methodAnalyzer, ref.getClazz());
this.ref = ref;
if (staticFlag)
methodAnalyzer.useType(classType);
@@ -119,7 +119,7 @@ public abstract class FieldOperator extends Operator {
while (true) {
if (clazz == ana.getClazz()) {
int field = ana.getFieldIndex
- (ref.getName(), Type.tType(classPath, ref.getType()));
+ (ref.getName(), Type.tType(methodAnalyzer, ref.getType()));
if (field >= 0)
return ana.getField(field);
return null;
@@ -143,7 +143,7 @@ public abstract class FieldOperator extends Operator {
}
public Type getFieldType() {
- return Type.tType(classPath, ref.getType());
+ return Type.tType(methodAnalyzer, ref.getType());
}
private void loadFields(ClassInfo clazz) {
diff --git a/jode/src/net/sf/jode/expr/IfThenElseOperator.java b/jode/src/net/sf/jode/expr/IfThenElseOperator.java
index e183779..b402d16 100644
--- a/jode/src/net/sf/jode/expr/IfThenElseOperator.java
+++ b/jode/src/net/sf/jode/expr/IfThenElseOperator.java
@@ -100,7 +100,7 @@ public class IfThenElseOperator extends Operator {
return new ClassFieldOperator
(invoke.getType(),
clazz.charAt(0) == '['
- ? Type.tType(cp, clazz)
+ ? Type.tType(field.getClassAnalyzer(), clazz)
: Type.tClass(cp, clazz));
}
}
diff --git a/jode/src/net/sf/jode/expr/InvokeOperator.java b/jode/src/net/sf/jode/expr/InvokeOperator.java
index f799b50..44b181e 100644
--- a/jode/src/net/sf/jode/expr/InvokeOperator.java
+++ b/jode/src/net/sf/jode/expr/InvokeOperator.java
@@ -155,10 +155,11 @@ public final class InvokeOperator extends Operator
super(Type.tUnknown, 0);
this.classPath = methodAnalyzer.getClassAnalyzer().getClassPath();
this.ref = reference;
- this.methodType = Type.tMethod(classPath, reference.getType());
+ this.methodType = Type.tMethod(methodAnalyzer.getClassPath(),
+ null, reference.getType());
this.methodName = reference.getName();
this.classType = (ClassType)
- Type.tType(classPath, reference.getClazz());
+ Type.tType(methodAnalyzer.getClassPath(), null, reference.getClazz());
this.hints = null;
Map allHints = (Map) hintTypes.get(methodName+"."+methodType);
if (allHints != null) {
@@ -774,7 +775,7 @@ public final class InvokeOperator extends Operator
continue next_method;
Type[] otherParamTypes
- = Type.tMethod(classPath, methods[i].getType())
+ = Type.tMethod(methodAnalyzer.getClassPath(), null, methods[i].getSignature())
.getParameterTypes();
if (otherParamTypes.length != myParamTypes.length) {
/* parameter count doesn't match*/
@@ -1120,7 +1121,7 @@ public final class InvokeOperator extends Operator
/* XXX check if this is a private method. */
if (needsCast(0, paramTypes)){
writer.print("(");
- writer.startOp(writer.EXPL_PAREN, 1);
+ writer.startOp(TabbedPrintWriter.EXPL_PAREN, 1);
writer.print("(");
writer.printType(classType);
writer.print(") ");
@@ -1135,7 +1136,7 @@ public final class InvokeOperator extends Operator
writer.print(".");
} else {
writer.print("(");
- writer.startOp(writer.EXPL_PAREN, 0);
+ writer.startOp(TabbedPrintWriter.EXPL_PAREN, 0);
writer.print("(NON VIRTUAL ");
writer.printType(classType);
writer.print(") ");
diff --git a/jode/src/net/sf/jode/expr/ThisOperator.java b/jode/src/net/sf/jode/expr/ThisOperator.java
index 5b758dc..093e660 100644
--- a/jode/src/net/sf/jode/expr/ThisOperator.java
+++ b/jode/src/net/sf/jode/expr/ThisOperator.java
@@ -20,25 +20,30 @@
package net.sf.jode.expr;
import net.sf.jode.type.Type;
import net.sf.jode.bytecode.ClassInfo;
+import net.sf.jode.decompiler.ClassAnalyzer;
import net.sf.jode.decompiler.Scope;
import net.sf.jode.decompiler.TabbedPrintWriter;
public class ThisOperator extends NoArgOperator {
boolean isInnerMost;
- ClassInfo classInfo;
+ ClassAnalyzer classAna;
- public ThisOperator(ClassInfo classInfo, boolean isInnerMost) {
- super(Type.tClass(classInfo));
- this.classInfo = classInfo;
+ public ThisOperator(ClassAnalyzer classAna, boolean isInnerMost) {
+ super(classAna.getType());
+ this.classAna = classAna;
this.isInnerMost = isInnerMost;
}
- public ThisOperator(ClassInfo classInfo) {
- this(classInfo, false);
+ public ThisOperator(ClassAnalyzer classAna) {
+ this(classAna, false);
}
public ClassInfo getClassInfo() {
- return classInfo;
+ return classAna.getClazz();
+ }
+
+ public ClassAnalyzer getClassAnalyzer() {
+ return classAna;
}
public int getPriority() {
@@ -46,18 +51,18 @@ public class ThisOperator extends NoArgOperator {
}
public String toString() {
- return classInfo+".this";
+ return classAna+".this";
}
public boolean opEquals(Operator o) {
return (o instanceof ThisOperator &&
- ((ThisOperator) o).classInfo.equals(classInfo));
+ ((ThisOperator) o).classAna == classAna);
}
public void dumpExpression(TabbedPrintWriter writer)
throws java.io.IOException {
if (!isInnerMost) {
- writer.print(writer.getClassString(classInfo,
+ writer.print(writer.getClassString(getClassInfo(),
Scope.AMBIGUOUSNAME));
writer.print(".");
}
diff --git a/jode/src/net/sf/jode/flow/CreateClassField.java b/jode/src/net/sf/jode/flow/CreateClassField.java
index 35a2825..ab37287 100644
--- a/jode/src/net/sf/jode/flow/CreateClassField.java
+++ b/jode/src/net/sf/jode/flow/CreateClassField.java
@@ -76,7 +76,7 @@ public class CreateClassField {
cmp.setSubExpressions
(0, new ClassFieldOperator(put.getType(),
clazz.charAt(0) == '['
- ? Type.tType(cp, clazz)
+ ? Type.tType(invoke.getClassAnalyzer(), clazz)
: Type.tClass(cp, clazz)));
EmptyBlock empty = new EmptyBlock();
empty.moveJump(ifBlock.thenBlock.jump);
diff --git a/jode/src/net/sf/jode/jvm/SyntheticAnalyzer.java b/jode/src/net/sf/jode/jvm/SyntheticAnalyzer.java
index 5ac72e4..86d22c0 100644
--- a/jode/src/net/sf/jode/jvm/SyntheticAnalyzer.java
+++ b/jode/src/net/sf/jode/jvm/SyntheticAnalyzer.java
@@ -311,12 +311,12 @@ public class SyntheticAnalyzer implements Opcodes {
}
MethodInfo refMethod
= refClazz.findMethod(ref.getName(), ref.getType());
- MethodType refType = Type.tMethod(classInfo.getClassPath(),
- ref.getType());
+ String[] refParams = TypeSignature.getParameterTypes(ref.getType());
+ String retType = TypeSignature.getReturnType(ref.getType());
if ((refMethod.getModifiers() & modifierMask) != 0
- || refType.getParameterTypes().length != params)
+ || refParams.length != params)
return false;
- if (refType.getReturnType() == Type.tVoid) {
+ if (retType.equals("V")) {
if (iter.hasNext())
return false;
} else {
@@ -390,12 +390,11 @@ public class SyntheticAnalyzer implements Opcodes {
return false;
MethodInfo refMethod
= refClazz.findMethod(ref.getName(), ref.getType());
- MethodType refType = Type.tMethod(classInfo.getClassPath(),
- ref.getType());
+ String[] refParams = TypeSignature.getParameterTypes(ref.getType());
if ((refMethod.getModifiers() & modifierMask) != 0
|| !refMethod.getName().equals("")
|| unifyParam == -1
- || refType.getParameterTypes().length != params - 2)
+ || refParams.length != params - 2)
return false;
if (iter.hasNext())
return false;
diff --git a/jode/src/net/sf/jode/type/ArrayType.java b/jode/src/net/sf/jode/type/ArrayType.java
index 1324700..ef3afd6 100644
--- a/jode/src/net/sf/jode/type/ArrayType.java
+++ b/jode/src/net/sf/jode/type/ArrayType.java
@@ -31,7 +31,7 @@ public class ArrayType extends ClassType {
Type elementType;
ArrayType(Type elementType) {
- super(TC_ARRAY, elementType + "[]");
+ super(TC_ARRAY, elementType + "[]", null);
this.elementType = elementType;
}
diff --git a/jode/src/net/sf/jode/type/ClassInfoType.java b/jode/src/net/sf/jode/type/ClassInfoType.java
index 97b7c9f..710018b 100644
--- a/jode/src/net/sf/jode/type/ClassInfoType.java
+++ b/jode/src/net/sf/jode/type/ClassInfoType.java
@@ -43,8 +43,9 @@ public class ClassInfoType extends ClassType {
return clazz;
}
- public ClassInfoType(ClassInfo clazz, Type[] generics) {
- super(TC_CLASS, clazz.getName());
+ public ClassInfoType(ClassInfo clazz, Type[] generics,
+ ClassType outerClass) {
+ super(TC_CLASS, clazz.getName(), outerClass);
this.clazz = clazz;
try {
@@ -70,20 +71,15 @@ public class ClassInfoType extends ClassType {
Map genericMap = new SimpleMap();
if (generics != null) {
/* parse generic names */
- String[] genNames;
- if (signature.charAt(0) != '<')
- throw new IllegalArgumentException
- ("Generic parameters for non-generic class");
-
- genNames = TypeSignature.getGenericNames(signature);
- if (generics.length != genNames.length)
+ genericNames = TypeSignature.getGenericNames(signature);
+ if (generics.length != genericNames.length)
throw new IllegalArgumentException
("Wrong number of generic parameters");
- for (int i = 0; i < generics.length; i++)
- genericMap.put(genNames[i], generics[i].getTypeSignature());
}
-
- signature = TypeSignature.mapGenerics(signature, genericMap);
+ }
+
+ public ClassInfoType(ClassInfo clazz, Type[] generics) {
+ this(clazz, generics, null);
}
public boolean isUnknown() {
@@ -99,26 +95,30 @@ public class ClassInfoType extends ClassType {
}
public ClassType getSuperClass() {
- if (clazz.isInterface())
+ String signature = clazz.getSignature();
+ if (clazz.isInterface() || signature.length() == 0)
return null;
if (superClass == null) {
- ClassInfo superInfo = clazz.getSuperclass();
- if (superInfo == null)
- return null;
- superClass = Type.tClass(superInfo);
+ String superSig = TypeSignature.getSuperSignature(signature);
+ superClass = (ClassType) tType(clazz.getClassPath(), this, superSig);
}
return superClass;
}
public ClassType[] getInterfaces() {
if (interfaces == null) {
- ClassInfo[] ifaceInfos = clazz.getInterfaces();
- if (ifaceInfos.length == 0)
+ String sig = clazz.getSignature();
+ if (sig.length() == 0)
+ return EMPTY_IFACES;
+ String[] ifaceSigs =
+ TypeSignature.getIfaceSignatures(sig);
+ if (ifaceSigs.length == 0)
interfaces = EMPTY_IFACES;
else {
- interfaces = new ClassType[ifaceInfos.length];
+ interfaces = new ClassType[ifaceSigs.length];
for (int i=0; i < interfaces.length; i++)
- interfaces[i] = Type.tClass(ifaceInfos[i]);
+ interfaces[i] = (ClassType)
+ Type.tType(clazz.getClassPath(), this, ifaceSigs[i]);
}
}
return interfaces;
diff --git a/jode/src/net/sf/jode/type/ClassType.java b/jode/src/net/sf/jode/type/ClassType.java
index ba31149..d6f0c52 100644
--- a/jode/src/net/sf/jode/type/ClassType.java
+++ b/jode/src/net/sf/jode/type/ClassType.java
@@ -33,6 +33,7 @@ public abstract class ClassType extends ReferenceType {
protected String className;
protected String[] genericNames;
protected Type[] genericInstances;
+ protected ClassType outerClass;
/*
* @invariant (genericNames == null) == (genericInstances == null)
@@ -50,12 +51,15 @@ public abstract class ClassType extends ReferenceType {
if (genericNames[i].equals(name))
return genericInstances[i];
}
+ if (outerClass != null)
+ return outerClass.getGeneric(name);
return null;
}
- public ClassType(int typecode, String clazzName) {
+ public ClassType(int typecode, String clazzName, ClassType outerClass) {
super(typecode);
className = clazzName;
+ this.outerClass = outerClass;
}
public ClassType(int typecode, String clazzName,
diff --git a/jode/src/net/sf/jode/type/GenericParameterType.java b/jode/src/net/sf/jode/type/GenericParameterType.java
index 139d447..71b302e 100644
--- a/jode/src/net/sf/jode/type/GenericParameterType.java
+++ b/jode/src/net/sf/jode/type/GenericParameterType.java
@@ -18,16 +18,13 @@
*/
package net.sf.jode.type;
-import net.sf.jode.bytecode.ClassInfo;
-import java.util.Vector;
-import java.util.Stack;
-import java.util.Hashtable;
-import java.io.IOException;
/**
- * This class represents the type of a system class, i.e. the classes
- * from package java.lang, that need special handling, like
- * Object, String, StringBuffer, etc.
+ * This class represents the singleton set containing one parameter type. For
+ * example in the context of the class Enum<E extends
+ * Enum<E>>
the identifier E
denotes such a
+ * parameter type. It has the super class Enum<E>
and
+ * implements no interfaces.
*
* @author Jochen Hoenicke
*/
@@ -41,7 +38,7 @@ public class GenericParameterType extends ClassType {
public GenericParameterType(String className,
ClassType superType,
ClassType[] ifacesTypes) {
- super(TC_SYSCLASS, className);
+ super(TC_SYSCLASS, className, null);
this.superType = superType;
this.ifacesTypes = ifacesTypes;
}
diff --git a/jode/src/net/sf/jode/type/MethodType.java b/jode/src/net/sf/jode/type/MethodType.java
index 03fbf7b..9e6e7af 100644
--- a/jode/src/net/sf/jode/type/MethodType.java
+++ b/jode/src/net/sf/jode/type/MethodType.java
@@ -20,6 +20,7 @@
package net.sf.jode.type;
import net.sf.jode.bytecode.ClassPath;
import net.sf.jode.bytecode.TypeSignature;
+import net.sf.jode.decompiler.ClassDeclarer;
/**
* This type represents an method type.
@@ -32,21 +33,29 @@ public class MethodType extends Type {
final Type returnType;
final ClassPath cp;
- public MethodType(ClassPath cp, String signature) {
+ public MethodType(ClassPath cp, ClassType declarer, String signature) {
+ /* TODO:
+ * We need TypeVariable: e.g. iff we have
+ * E getElm(Vector v);
+ * then E is a TypeVariable and if we now, that input type is a
+ * vector of Integer, then return value is Integer...
+ *
+ * A problem is that casts of v omit the value for E.
+ */
super(TC_METHOD);
this.cp = cp;
this.signature = signature;
if (signature.charAt(0) == '<') {
- /*FIXME */
+ /* handled by MethodAnalyzer */
signature = signature.substring(signature.indexOf('('));
}
String[] params = TypeSignature.getParameterTypes(signature);
parameterTypes = new Type[params.length];
for (int i = 0; i < params.length; i++) {
- parameterTypes[i] = Type.tType(cp, params[i]);
+ parameterTypes[i] = Type.tType(cp, declarer, params[i]);
}
- returnType = Type.tType(cp,
- signature.substring(signature.indexOf(')')+1));
+ returnType = Type.tType(cp, declarer,
+ TypeSignature.getReturnType(signature));
}
public final int stackSize() {
diff --git a/jode/src/net/sf/jode/type/ParameterType.java b/jode/src/net/sf/jode/type/ParameterType.java
index 3639175..e69de29 100644
--- a/jode/src/net/sf/jode/type/ParameterType.java
+++ b/jode/src/net/sf/jode/type/ParameterType.java
@@ -1,88 +0,0 @@
-/* ParameterType Copyright (C) 2005 Jochen Hoenicke.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; see the file COPYING.LESSER. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: ParameterType.java,v 1.3 2004/06/01 08:46:10 hoenicke Exp $
- */
-
-package net.sf.jode.type;
-import net.sf.jode.bytecode.ClassInfo;
-import net.sf.jode.GlobalOptions;
-
-import java.lang.reflect.Modifier;
-import java.io.IOException;
-import java.util.Vector;
-import java.util.Stack;
-import java.util.Hashtable;
-
-///#def COLLECTIONS java.util
-import java.util.Map;
-///#enddef
-
-/**
- * This class represents the singleton set containing one parameter type. For
- * example in the context of the class Enum<E extends
- * Enum<E>>
the identifier E
denotes such a
- * parameter type. It has the super class Enum<E>
and
- * implements no interfaces.
- *
- * @author Jochen Hoenicke
- */
-public class ParameterType extends ClassType {
- ClassType superClass;
- ClassType[] interfaces;
-
- public ParameterType(String name,
- ClassInfo superInfo, ClassInfo[] ifaceInfos) {
- super(TC_PARAMETER, name);
-
- superClass = Type.tClass(superInfo);
- if (ifaceInfos.length == 0) {
- interfaces = EMPTY_IFACES;
- } else {
- interfaces = new ClassType[ifaceInfos.length];
- for (int i=0; i < interfaces.length; i++)
- interfaces[i] = Type.tClass(ifaceInfos[i]);
- }
- }
-
- public boolean isUnknown() {
- return false;
- }
- public boolean isFinal() {
- return false;
- }
- public boolean isInterface() {
- return false;
- }
-
- public ClassType getSuperClass() {
- return superClass;
- }
-
- public ClassType[] getInterfaces() {
- return interfaces;
- }
-
- public boolean equals(Object o) {
- if (o instanceof ParameterType)
- return ((ParameterType) o).className == className;
- return false;
- }
-}
-
-
-
-
diff --git a/jode/src/net/sf/jode/type/SystemClassType.java b/jode/src/net/sf/jode/type/SystemClassType.java
index d259adb..09e90ca 100644
--- a/jode/src/net/sf/jode/type/SystemClassType.java
+++ b/jode/src/net/sf/jode/type/SystemClassType.java
@@ -43,7 +43,7 @@ public class SystemClassType extends ClassType {
ClassType superType,
ClassType[] ifacesTypes,
boolean isFinal, boolean isInterface) {
- super(TC_SYSCLASS, className);
+ super(TC_SYSCLASS, className, null);
this.superType = superType;
this.ifacesTypes = ifacesTypes;
this.isFinal = isFinal;
diff --git a/jode/src/net/sf/jode/type/Type.java b/jode/src/net/sf/jode/type/Type.java
index ad0ac70..d523543 100644
--- a/jode/src/net/sf/jode/type/Type.java
+++ b/jode/src/net/sf/jode/type/Type.java
@@ -22,11 +22,10 @@ import net.sf.jode.GlobalOptions;
import net.sf.jode.bytecode.ClassPath;
import net.sf.jode.bytecode.ClassInfo;
import net.sf.jode.bytecode.TypeSignature;
+import net.sf.jode.decompiler.ClassDeclarer;
import net.sf.jode.util.UnifyHash;
///#def COLLECTIONS java.util
-import java.util.Collections;
-import java.util.Map;
import java.util.Iterator;
import java.util.Arrays;
///#enddef
@@ -64,7 +63,6 @@ public class Type {
private static final UnifyHash classHash = new UnifyHash();
private static final UnifyHash arrayHash = new UnifyHash();
- private static final UnifyHash methodHash = new UnifyHash();
/**
* This type represents the singleton set containing the boolean type.
@@ -193,23 +191,83 @@ public class Type {
* Generate the singleton set of the type represented by the given
* string.
* @param classpath the current classpath.
- * @param type the type signature (or method signature).
+ * @param type the type signature (or method signature).
+ * @deprecated give a classdeclarer instead.
* @return a singleton set containing the given type.
*/
public static final Type tType(ClassPath cp, String type) {
- return tType(cp, type, Collections.EMPTY_MAP);
+ return tType(cp, null, type);
}
/**
* Generate the singleton set of the type represented by the given
* string.
- * @param classpath the current classpath.
- * @param signature the type signature (or method signature).
- * @param parameterMap the map from type variables to real types.
+ * @param declarer a class declarer for the current context.
+ * @param type the type signature (or method signature).
+ * @return a singleton set containing the given type.
+ */
+ public static final Type tType(ClassDeclarer declarer,
+ String signature) {
+ return tType(declarer.getClassPath(), null, signature);
+ }
+
+ public static final ClassInfoType tClassSig(ClassPath cp, ClassType declarer,
+ String signature)
+ {
+ Type[] generics = null;
+ ClassInfoType outer = null;
+ int index = signature.indexOf('.');
+ if (index >= 0) {
+ outer = tClassSig(cp, declarer, signature.substring(0, index));
+ signature = signature.substring(index+1);
+ if (outer == null)
+ return null;
+ }
+ index = signature.indexOf('<');
+ if (index >= 0) {
+ /* parse parameter types */
+ String[] genericNames = TypeSignature
+ .getArgumentTypes(signature.substring(index));
+ signature = signature.substring(0, index);
+ generics = new Type[genericNames.length];
+ for (int i = 0; i < generics.length; i++) {
+ String name = genericNames[i];
+ char c = name.charAt(0);
+ if (c == '*')
+ generics[i] = Type.tUObject;
+ else if (c == '+')
+ generics[i] = Type.tType(cp, declarer, name.substring(1))
+ .getSubType();
+ else if (c == '-')
+ generics[i] = Type.tType(cp, declarer, name.substring(1))
+ .getSuperType();
+ else
+ generics[i] = Type.tType(cp, declarer, name);
+ }
+ }
+ if (outer != null) {
+ ClassInfo[] inner = outer.getClassInfo().getClasses();
+ for (int i = 0; i < inner.length; i++) {
+ if (inner[i].getClassName().equals(signature))
+ return tClass(inner[i], generics, outer);
+ }
+ System.err.println("Inner class "+signature+" in class "+outer
+ +" not found.");
+ return null;
+ }
+ return tClass(cp, signature, generics);
+ }
+
+ /**
+ * Generate the singleton set of the type represented by the given
+ * string.
+ * @param cp current classpath.
+ * @param genericType the class containing generics of current context.
+ * @param type the type signature (or method signature).
* @return a singleton set containing the given type.
*/
- public static final Type tType(ClassPath cp, String signature,
- Map parameterMap) {
+ public static final Type tType(ClassPath cp, ClassType declarer,
+ String signature) {
if (signature == null || signature.length() == 0)
return tError;
switch(signature.charAt(0)) {
@@ -232,41 +290,24 @@ public class Type {
case 'V':
return tVoid;
case '[':
- return tArray(tType(cp, signature.substring(1)));
+ return tArray(tType(cp, declarer, signature.substring(1)));
case 'L': {
int endIndex = signature.length()-1;
- Type[] generics = null;
if (signature.charAt(endIndex) != ';')
return tError;
- if (signature.charAt(endIndex-1) == '>') {
- /* parse parameter types */
- int index = signature.indexOf('<');
- String[] genericNames = TypeSignature
- .getArgumentTypes(signature.substring(index, endIndex));
- endIndex = index;
- generics = new Type[genericNames.length];
- for (int i = 0; i < generics.length; i++) {
- String name = genericNames[i];
- char c = name.charAt(0);
- if (c == '*')
- generics[i] = Type.tUObject;
- else if (c == '+')
- generics[i] = Type.tType(cp, name.substring(1))
- .getSubType();
- else if (c == '-')
- generics[i] = Type.tType(cp, name.substring(1))
- .getSuperType();
- else
- generics[i] = Type.tType(cp, name);
- }
- }
- return tClass(cp, signature.substring(1, endIndex), generics);
+ Type type = tClassSig(cp, declarer,
+ signature.substring(1, endIndex));
+ if (type == null)
+ return tError;
+ return type;
}
case 'T': {
int index = signature.indexOf(';');
if (index != signature.length()-1)
return tError;
- Type type = (Type) parameterMap.get(signature.substring(1, index));
+ if (declarer == null)
+ return tUnknown; /* XXX: Should be a type variable */
+ Type type = declarer.getGeneric(signature.substring(1, index));
if (type == null)
return tError;
return type;
@@ -282,7 +323,7 @@ public class Type {
* The packages may be separated by `.' or `/'.
* @return a singleton set containing the given type.
*/
- public static final ClassType tClass(ClassPath classPath,
+ public static final ClassInfoType tClass(ClassPath classPath,
String className,
Type[] generics) {
return tClass(classPath.getClassInfo(className.replace('/','.')),
@@ -316,9 +357,12 @@ public class Type {
* @param clazzinfo the net.sf.jode.bytecode.ClassInfo.
* @return a singleton set containing the given type.
*/
- public static final ClassType tClass(ClassInfo clazzinfo,
- Type[] generics) {
+ public static final ClassInfoType tClass(ClassInfo clazzinfo,
+ Type[] generics,
+ ClassInfoType outer) {
int hash = clazzinfo.hashCode();
+ if (outer != null)
+ hash = hash * 11 + outer.hashCode();
if (generics != null) {
for (int i = 0; i < generics.length; i++)
hash = hash * 11 + generics[i].hashCode();
@@ -327,14 +371,26 @@ public class Type {
while (iter.hasNext()) {
ClassInfoType type = (ClassInfoType) iter.next();
if (type.getClassInfo() == clazzinfo
+ && type.outerClass == outer
&& Arrays.equals(generics, type.genericInstances))
return type;
}
- ClassInfoType type = new ClassInfoType(clazzinfo, generics);
+ ClassInfoType type = new ClassInfoType(clazzinfo, generics, outer);
classHash.put(hash, type);
return type;
}
+ /**
+ * Generate the singleton set of the type represented by the given
+ * class info.
+ * @param clazzinfo the net.sf.jode.bytecode.ClassInfo.
+ * @return a singleton set containing the given type.
+ */
+ public static final ClassInfoType tClass(ClassInfo clazzinfo,
+ Type[] generics) {
+ return tClass(clazzinfo, generics, null);
+ }
+
/**
* Generate the singleton set of the type represented by the given
* class info.
@@ -342,7 +398,7 @@ public class Type {
* @return a singleton set containing the given type.
* deprecated This should be removed if generics work.
*/
- public static final ClassType tClass(ClassInfo clazzinfo) {
+ public static final ClassInfoType tClass(ClassInfo clazzinfo) {
return tClass(clazzinfo, null);
}
@@ -370,21 +426,11 @@ public class Type {
/**
* Generate/look up the method type for the given signature
- * @param signature the method decriptor.
+ * @param signature the method descriptor.
* @return a method type (a singleton set).
*/
- public static MethodType tMethod(ClassPath cp, String signature) {
- int hash = signature.hashCode() + cp.hashCode();
- Iterator iter = methodHash.iterateHashCode(hash);
- while (iter.hasNext()) {
- MethodType methodType = (MethodType) iter.next();
- if (methodType.getTypeSignature().equals(signature)
- && methodType.getClassPath().equals(cp))
- return methodType;
- }
- MethodType methodType = new MethodType(cp, signature);
- methodHash.put(hash, methodType);
- return methodType;
+ public static MethodType tMethod(ClassPath cp, ClassType declarer, String signature) {
+ return new MethodType(cp, declarer, signature);
}
/**
diff --git a/jode/test/TryCatch.java b/jode/test/TryCatch.java
index 8f95c89..f597e74 100644
--- a/jode/test/TryCatch.java
+++ b/jode/test/TryCatch.java
@@ -63,6 +63,7 @@ class TryCatch {
}
}
+ @SuppressWarnings("finally")
int finallyBreaks() {
try {
simple();
@@ -75,6 +76,7 @@ class TryCatch {
}
}
+ @SuppressWarnings("finally")
int whileInTry() {
int a=1;
try {
@@ -95,6 +97,7 @@ class TryCatch {
}
}
+ @SuppressWarnings("finally")
void foo() {
TryCatch local = null;
while (true) {