comments reworked

git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@906 379699f6-c40d-0410-875b-85095c16579e
stable
jochen 25 years ago
parent e46f6c3625
commit 5e24bfce86
  1. 322
      jode/jode/type/Type.java

@ -31,55 +31,15 @@ import java.util.Hashtable;
///#endif ///#endif
/** /**
* This is my type class. It differs from java.lang.class, in * This is my type class. It differs from java.lang.class, in that it
* that it maintains a type range. This type range may be implicit or * represents a set of types. Since most times this set is infinite, it
* explicit. <br> * needs a special representation. <br>
* *
* * The main operation on a type sets are tSuperType, tSubType and
* Think of this global type hierarchie: * intersection.
* <pre>
*
* tUnknown
* / | \
* / | \
* tObject boolean int
* / \ / \
* / tArray short char
* other |
* classes byte
* </pre>
*
* int implements the "interface" tBoolInt. boolean and byte
* implement the "interface" tBoolByte which extends tBoolInt. <br>
*
* The type tBoolInt is <tBoolInt, tUnknown>, the type tBoolByte is
* <tBoolByte, tUnknown> (hard coded in <code>getTop</code>). The
* type tUInt is <int, byte>. <br>
*
* Note that tUnknown is no valid type, so we can replace
* <tUnknown, byte> with <int, byte>
* <tUnknown, tArray> with <tObject, tArray>, <br>
*
* Arrays extend Object and implement java.lang.Cloneable and
* java.io.Serializable, as defined in jls.
*
* The main operation on a type range is the intersection. To do this
* on class ranges we need three more operations: specialization,
* generalization and createRange. <p>
*
* specialization chooses the common sub type of the two types. It
* is used to find the start point of the intersected interval. <p>
*
* generalization chooses the common super type of two types. It
* is used to find the end point of the intersected interval. <p>
*
* When the new interval is created with <code>createRangeType</code>
* the start and end points are adjusted so that they only consists of
* possible types.
* *
* @author Jochen Hoenicke */ * @author Jochen Hoenicke */
public class Type { public class Type {
public static final int TC_BOOLEAN = 0; public static final int TC_BOOLEAN = 0;
public static final int TC_BYTE = 1; public static final int TC_BYTE = 1;
public static final int TC_CHAR = 2; public static final int TC_CHAR = 2;
@ -111,38 +71,114 @@ public class Type {
private static final Hashtable methodHash = new Hashtable(); private static final Hashtable methodHash = new Hashtable();
///#endif ///#endif
/**
* This type represents the singleton set containing the boolean type.
*/
public static final Type tBoolean = new IntegerType(IntegerType.IT_Z); public static final Type tBoolean = new IntegerType(IntegerType.IT_Z);
/**
* This type represents the singleton set containing the byte type.
*/
public static final Type tByte = new IntegerType(IntegerType.IT_B); public static final Type tByte = new IntegerType(IntegerType.IT_B);
/**
* This type represents the singleton set containing the char type.
*/
public static final Type tChar = new IntegerType(IntegerType.IT_C); public static final Type tChar = new IntegerType(IntegerType.IT_C);
/**
* This type represents the singleton set containing the short type.
*/
public static final Type tShort = new IntegerType(IntegerType.IT_S); public static final Type tShort = new IntegerType(IntegerType.IT_S);
/**
* This type represents the singleton set containing the int type.
*/
public static final Type tInt = new IntegerType(IntegerType.IT_I); public static final Type tInt = new IntegerType(IntegerType.IT_I);
/**
* This type represents the singleton set containing the long type.
*/
public static final Type tLong = new Type(TC_LONG); public static final Type tLong = new Type(TC_LONG);
/**
* This type represents the singleton set containing the float type.
*/
public static final Type tFloat = new Type(TC_FLOAT); public static final Type tFloat = new Type(TC_FLOAT);
/**
* This type represents the singleton set containing the double type.
*/
public static final Type tDouble = new Type(TC_DOUBLE); public static final Type tDouble = new Type(TC_DOUBLE);
/**
* This type represents the void type. It is really not a type at
* all.
*/
public static final Type tVoid = new Type(TC_VOID); public static final Type tVoid = new Type(TC_VOID);
/**
* This type represents the empty set, and probably means, that something
* has gone wrong.
*/
public static final Type tError = new Type(TC_ERROR); public static final Type tError = new Type(TC_ERROR);
/**
* This type represents the set of all possible types.
*/
public static final Type tUnknown = new Type(TC_UNKNOWN); public static final Type tUnknown = new Type(TC_UNKNOWN);
/**
* This type represents the set of all integer types, up to 32 bit.
*/
public static final Type tUInt = new IntegerType(IntegerType.IT_I public static final Type tUInt = new IntegerType(IntegerType.IT_I
| IntegerType.IT_B | IntegerType.IT_B
| IntegerType.IT_C | IntegerType.IT_C
| IntegerType.IT_S); | IntegerType.IT_S);
/**
* This type represents the set of the boolean and int type.
*/
public static final Type tBoolInt = new IntegerType(IntegerType.IT_I public static final Type tBoolInt = new IntegerType(IntegerType.IT_I
| IntegerType.IT_Z); | IntegerType.IT_Z);
/**
* This type represents the set of boolean and all integer types,
* up to 32 bit.
*/
public static final Type tBoolUInt= new IntegerType(IntegerType.IT_I public static final Type tBoolUInt= new IntegerType(IntegerType.IT_I
| IntegerType.IT_B | IntegerType.IT_B
| IntegerType.IT_C | IntegerType.IT_C
| IntegerType.IT_S | IntegerType.IT_S
| IntegerType.IT_Z); | IntegerType.IT_Z);
/**
* This type represents the set of the boolean and byte type.
*/
public static final Type tBoolByte= new IntegerType(IntegerType.IT_B public static final Type tBoolByte= new IntegerType(IntegerType.IT_B
| IntegerType.IT_Z); | IntegerType.IT_Z);
/**
* This type represents the singleton set containing
* <code>java.lang.Object</code>.
*/
public static final ClassInterfacesType tObject = public static final ClassInterfacesType tObject =
tClass("java.lang.Object"); tClass("java.lang.Object");
/**
* This type represents the singleton set containing the special
* null type (the type of null).
*/
public static final ReferenceType tNull = new NullType(); public static final ReferenceType tNull = new NullType();
/**
* This type represents the set of all reference types, including
* class types, array types, interface types and the null type.
*/
public static final Type tUObject = tRange(tObject, tNull); public static final Type tUObject = tRange(tObject, tNull);
/**
* This type represents the singleton set containing
* <code>java.lang.String</code>.
*/
public static final Type tString = tClass("java.lang.String"); public static final Type tString = tClass("java.lang.String");
/**
* This type represents the singleton set containing
* <code>java.lang.StringBuffer</code>.
*/
public static final Type tStringBuffer = tClass("java.lang.StringBuffer"); public static final Type tStringBuffer = tClass("java.lang.StringBuffer");
/**
* This type represents the singleton set containing
* <code>java.lang.Class</code>.
*/
public static final Type tJavaLangClass = tClass("java.lang.Class"); public static final Type tJavaLangClass = tClass("java.lang.Class");
/**
* This is a private method for generating the signature of a
* given type.
*/
private static final StringBuffer appendSignature(StringBuffer sb, private static final StringBuffer appendSignature(StringBuffer sb,
Class javaType) { Class javaType) {
if (javaType.isPrimitive()) { if (javaType.isPrimitive()) {
@ -175,10 +211,24 @@ public class Type {
} }
} }
/**
* Generate the signature for the given Class.
* @param clazz a java.lang.Class, this may also be a primitive or
* array type.
* @return the type signature (see section 4.3.2 Field Descriptors
* of the JVM specification)
*/
public static String getSignature(Class clazz) { public static String getSignature(Class clazz) {
return appendSignature(new StringBuffer(), clazz).toString(); return appendSignature(new StringBuffer(), clazz).toString();
} }
/**
* Generate a method signature.
* @param paramT the java.lang.Class of the parameter types of the method.
* @param returnT the java.lang.Class of the return type of the method.
* @return the method signature (see section 4.3.3 Method Descriptors
* of the JVM specification)
*/
public static String getSignature(Class paramT[], Class returnT) { public static String getSignature(Class paramT[], Class returnT) {
StringBuffer sig = new StringBuffer("("); StringBuffer sig = new StringBuffer("(");
for (int i=0; i< paramT.length; i++) for (int i=0; i< paramT.length; i++)
@ -186,6 +236,12 @@ public class Type {
return appendSignature(sig.append(')'), returnT).toString(); return appendSignature(sig.append(')'), returnT).toString();
} }
/**
* Generate the singleton set of the type represented by the given
* string.
* @param type the type signature (or method signature).
* @return a singleton set containing the given type.
*/
public static final Type tType(String type) { public static final Type tType(String type) {
if (type == null || type.length() == 0) if (type == null || type.length() == 0)
return tError; return tError;
@ -221,14 +277,33 @@ public class Type {
throw new AssertError("Unknown type signature: "+type); throw new AssertError("Unknown type signature: "+type);
} }
/**
* Generate the singleton set of the type represented by the given
* class.
* @param javaType the type class.
* @return a singleton set containing the given type.
*/
public static final Type tType(Class javaType) { public static final Type tType(Class javaType) {
return Type.tType(getSignature(javaType)); return Type.tType(getSignature(javaType));
} }
/**
* Generate the singleton set of the type represented by the given
* class name.
* @param clazzname the full qualified name of the class.
* The packages may be separated by `.' or `/'.
* @return a singleton set containing the given type.
*/
public static final ClassInterfacesType tClass(String clazzname) { public static final ClassInterfacesType tClass(String clazzname) {
return tClass(ClassInfo.forName(clazzname.replace('/','.'))); return tClass(ClassInfo.forName(clazzname.replace('/','.')));
} }
/**
* Generate the singleton set of the type represented by the given
* class info.
* @param clazzinfo the jode.bytecode.ClassInfo.
* @return a singleton set containing the given type.
*/
public static final ClassInterfacesType tClass(ClassInfo clazzinfo) { public static final ClassInterfacesType tClass(ClassInfo clazzinfo) {
///#ifdef JDK12 ///#ifdef JDK12
/// java.lang.ref.Reference died; /// java.lang.ref.Reference died;
@ -250,6 +325,12 @@ public class Type {
return (ClassInterfacesType) result; return (ClassInterfacesType) result;
} }
/**
* Generate/look up the set of the array type whose element types
* are in the given type set.
* @param type the element types (which may be the empty set tError).
* @return the set of array types (which may be the empty set tError).
*/
public static final Type tArray(Type type) { public static final Type tArray(Type type) {
if (type == tError) if (type == tError)
return type; return type;
@ -273,6 +354,11 @@ public class Type {
return result; return result;
} }
/**
* Generate/look up the method type for the given signature
* @param signature the method decriptor.
* @return a method type (a singleton set).
*/
public static MethodType tMethod(String signature) { public static MethodType tMethod(String signature) {
///#ifdef JDK12 ///#ifdef JDK12
/// java.lang.ref.Reference died; /// java.lang.ref.Reference died;
@ -293,23 +379,69 @@ public class Type {
} }
return result; return result;
} }
/**
* Generate/look up the method type for the given class
* @param paramT the parameter types of the method.
* @param returnT the return type of the method.
* @return a method type (a singleton set).
*/
public static MethodType tMethod(Class paramT[], Class returnT) { public static MethodType tMethod(Class paramT[], Class returnT) {
return tMethod(getSignature(paramT, returnT)); return tMethod(getSignature(paramT, returnT));
} }
/**
* Generate the range type from bottom to top. This should
* represent all reference types, that can be casted to bottom by
* a widening cast and where top can be casted to. You should not
* use this method directly; use tSubType, tSuperType and
* intersection instead, which is more general.
* @param bottom the bottom type.
* @param top the top type.
* @return the range type.
*/
public static final Type tRange(ReferenceType bottom, public static final Type tRange(ReferenceType bottom,
ReferenceType top) { ReferenceType top) {
return new RangeType(bottom, top); return new RangeType(bottom, top);
} }
/**
* Generate the set of types, to which one of the types in type can
* be casted to by a widening cast. The following holds:
* <ul><li>tSuperType(tObject) = tObject </li>
* <li>tSuperType(tError) = tError </li>
* <li>type.intersection(tSuperType(type)).equals(type)
* (this means type is a subset of tSuperType(type).</li>
* <li>tSuperType(tNull) = tUObject</li>
* <li>tSuperType(tChar) = {tChar, tInt } </li></ul>
* @param type a set of types.
* @return the super types of type.
*/
public static Type tSuperType(Type type) { public static Type tSuperType(Type type) {
return type.getSuperType(); return type.getSuperType();
} }
/**
* Generate the set of types, which can be casted to one of the
* types in type by a widening cast. The following holds:
* <ul><li>tSubType(tObject) = tUObject </li>
* <li>tSubType(tError) = tError </li>
* <li>type.intersection(tSubType(type)).equals(type)
* (this means type is a subset of tSubType(type).</li>
* <li>tSuperType(tSubType(type)) is a subset of type </li>
* <li>tSubType(tSuperType(type)) is a subset of type </li>
* <li>tSubType(tNull) = tNull</li>
* <li>tSubType(tBoolean, tShort) = { tBoolean, tByte, tShort }</li></ul>
* @param type a set of types.
* @return the sub types of type.
*/
public static Type tSubType(Type type) { public static Type tSubType(Type type) {
return type.getSubType(); return type.getSubType();
} }
/**
* The typecode of this type. This should be one of the TC_ constants.
*/
final int typecode; final int typecode;
/** /**
@ -319,33 +451,59 @@ public class Type {
typecode = tc; typecode = tc;
} }
/**
* The sub types of this type.
* @return tSubType(this).
*/
public Type getSubType() { public Type getSubType() {
return this; return this;
} }
/**
* The super types of this type.
* @return tSuperType(this).
*/
public Type getSuperType() { public Type getSuperType() {
return this; return this;
} }
// public Type getBottom() { /**
// return this; * Returns the hint type of this type set. This returns the singleton
// } * set containing only the `most likely' type in this set. This doesn't
* work for <code>tError</code> or <code>tUnknown</code>, and may lead
// public Type getTop() { * to errors for certain range types.
// return this; * @return the hint type.
// } */
public Type getHint() { public Type getHint() {
return getCanonic();
}
/**
* Returns the canonic type of this type set. The intention is, to
* return for each expression the type, that the java compiler would
* assign to this expression.
* @return the canonic type.
*/
public Type getCanonic() {
return this; return this;
} }
/** /**
* @return the type code of the type. * Returns the type code of this type. Don't use this; it is
* merily needed by the sub types (and the bytecode verifier, which
* has its own type merging methods).
* @return the type code of the type.
*/ */
public final int getTypeCode() { public final int getTypeCode() {
return typecode; return typecode;
} }
/**
* Returns the number of stack/local entries an object of this type
* occupies.
* @return 0 for tVoid, 2 for tDouble and tLong and
* 1 for every other type.
*/
public int stackSize() public int stackSize()
{ {
switch(typecode) { switch(typecode) {
@ -361,9 +519,10 @@ public class Type {
} }
/** /**
* Intersect this type with another type and return the new type. * Intersect this set of types with another type set and return the
* @param type the other type. * intersection.
* @return the intersection, or tError, if a type conflict happens. * @param type the other type set.
* @return the intersection, tError, if the intersection is empty.
*/ */
public Type intersection(Type type) { public Type intersection(Type type) {
if (this == tError || type == tError) if (this == tError || type == tError)
@ -372,6 +531,8 @@ public class Type {
return type; return type;
if (type == tUnknown || this == type) if (type == tUnknown || this == type)
return this; return this;
/* We have two different singleton sets now.
*/
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0) if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_TYPES) != 0)
GlobalOptions.err.println("intersecting "+ this +" and "+ type GlobalOptions.err.println("intersecting "+ this +" and "+ type
+ " to <error>"); + " to <error>");
@ -380,7 +541,9 @@ public class Type {
/** /**
* Checks if we need to cast to a middle type, before we can cast from * Checks if we need to cast to a middle type, before we can cast from
* fromType to this type. * fromType to this type. For example it is impossible to cast a
* String to a StringBuffer, but if we cast to Object in between this
* is allowed (it doesn't make much sense though).
* @return the middle type, or null if it is not necessary. * @return the middle type, or null if it is not necessary.
*/ */
public Type getCastHelper(Type fromType) { public Type getCastHelper(Type fromType) {
@ -388,29 +551,35 @@ public class Type {
} }
/** /**
* Checks if this type represents a valid type instead of a list * Checks if this type represents a valid singleton type.
* of minimum types.
*/ */
public boolean isValidType() { public boolean isValidType() {
return typecode <= TC_DOUBLE; return typecode <= TC_DOUBLE;
} }
/** /**
* Checks if this type represents a class or an array of a class * Checks if this is a class or array type (but not a null type).
* @XXX remove this?
* @return true if this is a class or array type.
*/ */
public boolean isClassType() { public boolean isClassType() {
return false; return false;
} }
/** /**
* Check if this and &lt;unknown -- type&rt; are not disjunct. * Check if this type set and the other type set are not disjunct.
* @param type a simple type; this mustn't be a range type. * @param type the other type set.
* @return true if this is the case. * @return true if this they aren't disjunct.
*/ */
public boolean isOfType(Type type) { public boolean isOfType(Type type) {
return this.intersection(type) != Type.tError; return this.intersection(type) != Type.tError;
} }
/**
* Generates the default name, that is the `natural' choice for
* local of this type.
* @return the default name of a local of this type.
*/
public String getDefaultName() { public String getDefaultName() {
switch (typecode) { switch (typecode) {
case TC_LONG: case TC_LONG:
@ -424,6 +593,11 @@ public class Type {
} }
} }
/**
* Generates the default value, that is the initial value of a field
* of this type.
* @return the default value of a field of this type.
*/
public Object getDefaultValue() { public Object getDefaultValue() {
switch (typecode) { switch (typecode) {
case TC_LONG: case TC_LONG:
@ -437,6 +611,11 @@ public class Type {
} }
} }
/**
* Returns the type signature of this type. You should only call
* this on singleton types.
* @return the type (or method) signature of this type.
*/
public String getTypeSignature() { public String getTypeSignature() {
switch (typecode) { switch (typecode) {
case TC_LONG: case TC_LONG:
@ -450,6 +629,11 @@ public class Type {
} }
} }
/**
* Returns the java.lang.Class representing this type. You should
* only call this on singleton types.
* @return the Class object representing this type.
*/
public Class getTypeClass() throws ClassNotFoundException { public Class getTypeClass() throws ClassNotFoundException {
switch (typecode) { switch (typecode) {
case TC_LONG: case TC_LONG:
@ -463,6 +647,10 @@ public class Type {
} }
} }
/**
* Returns a string representation describing this type set.
* @return a string representation describing this type set.
*/
public String toString() { public String toString() {
switch (typecode) { switch (typecode) {
case TC_LONG: case TC_LONG:

Loading…
Cancel
Save