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) {