git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@360 379699f6-c40d-0410-875b-85095c16579estable
parent
77f2fbe9d7
commit
633f044a20
@ -0,0 +1,11 @@ |
|||||||
|
\input texinfo @c -*- texinfo -*- |
||||||
|
|
||||||
|
@setfilename jode.info |
||||||
|
@settitle Jode, a Java Decompiler |
||||||
|
@direntry |
||||||
|
* Jode: (jode). A Java Decompiler |
||||||
|
@end direntry |
||||||
|
|
||||||
|
|
||||||
|
@include technical.texi |
||||||
|
@bye |
@ -0,0 +1,200 @@ |
|||||||
|
@node Technical Info, Top, Top, Top |
||||||
|
@chapter Technical Information |
||||||
|
|
||||||
|
This chapter contains information, how the decompiler works. |
||||||
|
|
||||||
|
@menu |
||||||
|
* Types:: |
||||||
|
* Expression analysis:: |
||||||
|
* Flow analysis:: |
||||||
|
* Solving unknown stack-ops:: |
||||||
|
* Highlevel analysis:: |
||||||
|
@end menu |
||||||
|
|
||||||
|
@node Types, Expression analysis, Technical Info, Technical Info |
||||||
|
@section Type checking and guessing |
||||||
|
@cindex Types, Conversions |
||||||
|
|
||||||
|
The type class has the following operators: |
||||||
|
|
||||||
|
getSubType |
||||||
|
getSuperType |
||||||
|
intersection |
||||||
|
(getCastHelper?) |
||||||
|
(getImplicitCast?) |
||||||
|
|
||||||
|
reference types (classes, interfaces, arrays and null type) often appear |
||||||
|
in ranges. They have the methods: |
||||||
|
|
||||||
|
createRangeType |
||||||
|
getSpecializedType |
||||||
|
getGeneralizedType |
||||||
|
|
||||||
|
The meaning is |
||||||
|
ref1.intersection(ref2) = |
||||||
|
ref1.getSpecializedType(ref2).createRangeType(ref1.getGeneralizedType(ref2)) |
||||||
|
|
||||||
|
<Object - NULL> |
||||||
|
<Object[] - NULL> |
||||||
|
<Object[] - Serialized[]> |
||||||
|
<tUnknown[]> |
||||||
|
<Object - tUnknown[]> |
||||||
|
{IBCS}[] intersect {CSZ}[] = {CS}[] |
||||||
|
<Object - {ICSB}[]> intersect <Serializable - {CSZ}[]> |
||||||
|
--> <Serializable - { |
||||||
|
|
||||||
|
The byte code distinguishes five different types: |
||||||
|
|
||||||
|
@enumerate |
||||||
|
@item 16 bit integral types (boolean, byte, short, char and int) |
||||||
|
@item long |
||||||
|
@item float |
||||||
|
@item double |
||||||
|
@item reference types (objects, interfaces, arrays, null type) |
||||||
|
@end enumerate |
||||||
|
|
||||||
|
It sometimes makes a difference between byte, short, char and int, but |
||||||
|
not always. |
||||||
|
|
||||||
|
|
||||||
|
16bit integral types: |
||||||
|
|
||||||
|
We differ seven different 16 bit integral types: |
||||||
|
@table @asis |
||||||
|
@item I |
||||||
|
@code{int} type |
||||||
|
@item C |
||||||
|
@code{char} type |
||||||
|
@item S |
||||||
|
@code{short} type |
||||||
|
@item B |
||||||
|
@code{byte} type |
||||||
|
@item Z |
||||||
|
@code{boolean} type |
||||||
|
@item cS |
||||||
|
An @code{int} constant whose value is in @code{short} range. |
||||||
|
@item cB |
||||||
|
An @code{int} constant whose value is in @code{byte} range. |
||||||
|
@end table |
||||||
|
|
||||||
|
Each of this types has a super range and a sub range: |
||||||
|
@multitable {type} {(I,C,S,B,Z,cS,cB)} {(I,C,S,B,Z,cS,cB)} |
||||||
|
@item type @tab sub types @tab super types |
||||||
|
@item I @tab (I,C,S,B,cS,cB) @tab (I) |
||||||
|
@item C @tab (C) @tab (I,C) |
||||||
|
@item S @tab (S,B,cS,cB) @tab (I,S) |
||||||
|
@item B @tab (B,cB) @tab (I,S,B) |
||||||
|
@item Z @tab (Z) @tab (Z) |
||||||
|
@item cS @tab (cS,cB) @tab (I,S,cS) |
||||||
|
@item cB @tab (cB) @tab (I,S,B,cS,cB) |
||||||
|
@end multitable |
||||||
|
|
||||||
|
getTop() getBottom() give the type directly. |
||||||
|
|
||||||
|
createRangeType(Type bottom) does the following: |
||||||
|
If top == tUnknown , union all supertypes |
||||||
|
If top is 16bit type, |
||||||
|
intersect (union of subtypes of top) (union of supertypes) |
||||||
|
Return tError otherwise. |
||||||
|
|
||||||
|
Type.createRangeType(Type top) does the following: |
||||||
|
if Type == tUnknown |
||||||
|
if top is IntegerType |
||||||
|
new IntegerType(union of subtypes of top) |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Hints. We distinguish strong and weak Hints: |
||||||
|
|
||||||
|
strong Hints: |
||||||
|
assignment: |
||||||
|
lhs.strongHint = mergeHint(lhs.strongHint, rhs.strongHint) |
||||||
|
lhs.weakHint = mergeHint(lhs.weakHint, rhs.weakHint) |
||||||
|
rhs.strongHint = lhs.strongHint |
||||||
|
|
||||||
|
|
||||||
|
binary op: |
||||||
|
left.weakHint = mergeHints(left.weakHint, right.strongHint?strongHint: weakHint) |
||||||
|
|
||||||
|
binary op |
||||||
|
types that may occur directly in bytecode: |
||||||
|
(I,Z) |
||||||
|
(I) |
||||||
|
(Z) |
||||||
|
(I,C,S,B,Z) |
||||||
|
(I,cS,cB) |
||||||
|
(I,cS) |
||||||
|
(I,C,cS,cB) |
||||||
|
(I,C,cS) |
||||||
|
(I,C) |
||||||
|
(C) |
||||||
|
(S) |
||||||
|
(B) |
||||||
|
(B,Z) |
||||||
|
|
||||||
|
now the sub (>) and super (<) operators |
||||||
|
|
||||||
|
>(I,Z) = (I,C,S,B,Z,cS,cB) New! |
||||||
|
>(I) = (I,C,S,B,cS,cB) New! |
||||||
|
>(Z) = (Z) |
||||||
|
>(I,C,S,B,Z) = (I,C,S,B,Z,cS,cB) |
||||||
|
>(I,cS,cB) = (I,C,S,B,cS,cB) |
||||||
|
>(I,cS) = (I,C,S,B,cS,cB) |
||||||
|
>(I,C,cS,cB) = (I,C,S,B,cS,cB) |
||||||
|
>(I,C,cS) = (I,C,S,B,cS,cB) |
||||||
|
>(I,C) = (I,C,S,B,cS,cB) |
||||||
|
>(C) = (C) |
||||||
|
>(S) = (S,B,cS,cB) New! |
||||||
|
>(B) = (B,cB) New! |
||||||
|
>(B,Z) = (B,Z,cB) New! |
||||||
|
|
||||||
|
<(I,Z) = (I,Z) |
||||||
|
<(I) = (I) |
||||||
|
<(Z) = (Z) |
||||||
|
<(I,C,S,B,Z) = (I,C,S,B,Z) |
||||||
|
<(I,cS,cB) = (I,S,B,cS,cB) New! |
||||||
|
<(I,cS) = (I,S,cS) New! |
||||||
|
<(I,C,cS,cB) = (I,C,S,B,cS,cB) |
||||||
|
<(I,C,cS) = (I,C,S,cS) New! |
||||||
|
<(I,C) = (I,C) |
||||||
|
<(C) = (I,C) |
||||||
|
<(S) = (I,S) New! |
||||||
|
<(B) = (I,S,B) New! |
||||||
|
<(B,Z) = (I,S,B,Z) New! |
||||||
|
|
||||||
|
>(I,C,S,B,Z,cS,cB) = (I,C,S,B,Z,cS,cB) |
||||||
|
>(I,C,S,B,cS,cB) = (I,C,S,B,cS,cB) |
||||||
|
>(B,Z,cB) = (B,Z,cB) |
||||||
|
>(I,C,S,cS) = (I,C,S,B,cS,cB) |
||||||
|
>(I,S,B,Z) = (I,C,S,B,Z,cS,cB) |
||||||
|
>(I,S,B,cS,cB) = (I,C,S,B,cS,cB) |
||||||
|
|
||||||
|
<(I,C,S,B,Z,cS,cB) = (I,C,S,B,Z,cS,cB) |
||||||
|
<(I,C,S,B,cS,cB) = (I,C,S,B,cS,cB) |
||||||
|
<(B,Z,cB) = (I,S,B,Z,cS,cB) |
||||||
|
<(I,C,S,cS) = (I,C,S,cS) |
||||||
|
<(I,S,B,Z) = (I,S,B,Z) |
||||||
|
<(I,S,B,cS,cB) = (I,S,B,cS,cB) |
||||||
|
|
||||||
|
|
||||||
|
Zu betrachtende 32bit Typen: |
||||||
|
|
||||||
|
(I,Z) = (I,Z) |
||||||
|
(I) = (I) |
||||||
|
(Z) = (Z) |
||||||
|
(I,C,S,B,Z) |
||||||
|
(I,cS,cB) |
||||||
|
(I,cS) |
||||||
|
(I,C,cS,cB) |
||||||
|
(I,C,cS) |
||||||
|
(I,C) |
||||||
|
(B,Z) |
||||||
|
(I,C,S,B,Z,cS,cB) |
||||||
|
(I,C,S,B,cS,cB) |
||||||
|
(B,Z,cB) |
||||||
|
(I,C,S,cS) |
||||||
|
(I,S,B,Z) |
||||||
|
(I,S,B,cS,cB) |
||||||
|
|
@ -0,0 +1,288 @@ |
|||||||
|
/* |
||||||
|
* IntegerType (c) 1998 Jochen Hoenicke |
||||||
|
* |
||||||
|
* You may distribute under the terms of the GNU General Public License. |
||||||
|
* |
||||||
|
* IN NO EVENT SHALL JOCHEN HOENICKE BE LIABLE TO ANY PARTY FOR DIRECT, |
||||||
|
* INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF |
||||||
|
* THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF JOCHEN HOENICKE |
||||||
|
* HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
* |
||||||
|
* JOCHEN HOENICKE SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT |
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
||||||
|
* PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" |
||||||
|
* BASIS, AND JOCHEN HOENICKE HAS NO OBLIGATION TO PROVIDE MAINTENANCE, |
||||||
|
* SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode; |
||||||
|
|
||||||
|
/** |
||||||
|
* This is a type class for 16 bit integral types. There are seven |
||||||
|
* different types, namely <code>int, char, short, byte, boolean, |
||||||
|
* const short, const byte</code> abbreviated <code>I, C, S, B, Z, cS, |
||||||
|
* cB</code>. <code>cB</code> and <code>cS</code> specify constant |
||||||
|
* ints whose value is in byte resp. short range. They may be |
||||||
|
* converted to B resp. S, but sometimes need an explicit cast. |
||||||
|
* |
||||||
|
* @author Jochen Hoenicke */ |
||||||
|
public class IntegerType extends Type { |
||||||
|
|
||||||
|
public static final int IT_I = 0x01; |
||||||
|
public static final int IT_C = 0x02; |
||||||
|
public static final int IT_S = 0x04; |
||||||
|
public static final int IT_B = 0x08; |
||||||
|
public static final int IT_Z = 0x10; |
||||||
|
public static final int IT_cS = 0x20; |
||||||
|
public static final int IT_cB = 0x40; |
||||||
|
private static final int NUM_TYPES = 7; |
||||||
|
|
||||||
|
private static final int[] subTypes = { |
||||||
|
/*I*/ IT_I|IT_C|IT_S|IT_B/*|IT_cS|IT_cB*/, /*C*/ IT_C, |
||||||
|
/*S*/ IT_S|IT_B/*|IT_cS|IT_cB*/, /*B*/ IT_B/*|IT_cB*/, |
||||||
|
/*Z*/ IT_Z, |
||||||
|
/*cS*/IT_cS|IT_cB, /*cB*/IT_cB |
||||||
|
}; |
||||||
|
private static final int[] superTypes = { |
||||||
|
/*I*/ IT_I, /*C*/ IT_I|IT_C, |
||||||
|
/*S*/ IT_I|IT_S, /*B*/ IT_I|IT_S|IT_B, |
||||||
|
/*Z*/ IT_Z, |
||||||
|
/*cS*/IT_I|IT_C|IT_S|IT_cS, /*cB*/IT_I|IT_C|IT_S|IT_B|IT_cS|IT_cB |
||||||
|
}; |
||||||
|
private static final Type[] simpleTypes = { |
||||||
|
new IntegerType(IT_I), new IntegerType(IT_C), |
||||||
|
new IntegerType(IT_S), new IntegerType(IT_B), |
||||||
|
new IntegerType(IT_Z), |
||||||
|
new IntegerType(IT_cS), new IntegerType(IT_cB) |
||||||
|
}; |
||||||
|
private static final String[] typeNames = { |
||||||
|
"I","C","S","B","Z","cS","cB" |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
int possTypes; |
||||||
|
int strongHint = 0; |
||||||
|
int weakHint = 0; |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new type with the given type. |
||||||
|
*/ |
||||||
|
public IntegerType(int types) { |
||||||
|
super(TC_INTEGER); |
||||||
|
possTypes = types; |
||||||
|
} |
||||||
|
|
||||||
|
public Type getHint() { |
||||||
|
int hint = ((possTypes & IT_Z) != 0 ? IT_Z |
||||||
|
: strongHint != 0 ? strongHint |
||||||
|
: weakHint != 0 ? weakHint |
||||||
|
: possTypes); |
||||||
|
int i = 0; |
||||||
|
for (int it = 0x1; (it & hint) == 0; it <<= 1) |
||||||
|
i++; |
||||||
|
return simpleTypes[i]; |
||||||
|
} |
||||||
|
|
||||||
|
private int getSubTypes() { |
||||||
|
int result = 0; |
||||||
|
for (int i=0; i < NUM_TYPES; i++) { |
||||||
|
if (((1<<i) & possTypes) != 0) |
||||||
|
result |= subTypes[i]; |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
private int getSuperTypes() { |
||||||
|
int result = 0; |
||||||
|
for (int i=0; i < NUM_TYPES; i++) { |
||||||
|
if (((1<<i) & possTypes) != 0) |
||||||
|
result |= superTypes[i]; |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
public Type getSubType() { |
||||||
|
return new IntegerType(getSubTypes()); |
||||||
|
} |
||||||
|
|
||||||
|
public Type getSuperType() { |
||||||
|
return new IntegerType(getSuperTypes()); |
||||||
|
} |
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Returns the common sub type of this and type.
|
||||||
|
// * @param type the other type.
|
||||||
|
// * @return the common sub type.
|
||||||
|
// */
|
||||||
|
// public Type getSpecializedType(Type type) {
|
||||||
|
// /* tError , x -> tError
|
||||||
|
// * x , tUnknown -> x
|
||||||
|
// * Integer , Integer -> possTypes1 & possTypes2 == 0 ? tError
|
||||||
|
// */
|
||||||
|
// if (type == tUnknown)
|
||||||
|
// return this;
|
||||||
|
// if (type.typecode != TC_INTEGER)
|
||||||
|
// return tError;
|
||||||
|
// IntegerType other = (IntegerType) type;
|
||||||
|
// int mergeTypes = possTypes & other.possTypes;
|
||||||
|
// /* HINTING XXX */
|
||||||
|
// if (mergeTypes == possTypes)
|
||||||
|
// return this;
|
||||||
|
// if (mergeTypes == other.possTypes)
|
||||||
|
// return other;
|
||||||
|
// if (mergeTypes == 0)
|
||||||
|
// return tError;
|
||||||
|
// return new IntegerType(mergeTypes);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Returns the common super type of this and type.
|
||||||
|
// * @param type the other type.
|
||||||
|
// * @return the common super type.
|
||||||
|
// */
|
||||||
|
// public Type getGeneralizedType(Type type) {
|
||||||
|
// return getSpecializedType(type);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Create the type corresponding to the range from bottomType to this.
|
||||||
|
// * @param bottomType the start point of the range
|
||||||
|
// * @return the range type, or tError if not possible.
|
||||||
|
// */
|
||||||
|
// public Type intersection(Type bottomType) {
|
||||||
|
// /* Note that this can't be tBoolByte or tBoolInt */
|
||||||
|
// /* x , tError -> tError
|
||||||
|
// * object , tUnknown -> <object, tUnknown>
|
||||||
|
// * boolean , tUnknown -> boolean
|
||||||
|
// * int , tUnknown -> <int, byte>
|
||||||
|
// * boolint , tUnknown -> boolint
|
||||||
|
// * tUnknown, x -> getSuperTypes(x)
|
||||||
|
// * tUnknown, short -> <int, short>
|
||||||
|
// * short , byte -> <short, byte>
|
||||||
|
// * byte , short -> tError
|
||||||
|
// * tUnknown, float -> float
|
||||||
|
// */
|
||||||
|
// if (bottomType == tUnknown)
|
||||||
|
// return this;
|
||||||
|
// else if (bottomType.typecode != TC_INTEGER)
|
||||||
|
// return tError;
|
||||||
|
// /*XXX HINTING*/
|
||||||
|
|
||||||
|
// int result = ((IntegerType)bottomType).possTypes & possTypes;
|
||||||
|
// return new IntegerType(result);
|
||||||
|
// }
|
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if this type represents a valid type instead of a list |
||||||
|
* of minimum types. |
||||||
|
*/ |
||||||
|
public boolean isValidType() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Check if this and <unknown -- type&rt; are not disjunct. |
||||||
|
* @param type a simple type; this mustn't be a range type. |
||||||
|
* @return true if this is the case. |
||||||
|
*/ |
||||||
|
public boolean isOfType(Type type) { |
||||||
|
return (type.typecode == TC_INTEGER |
||||||
|
&& (((IntegerType)type).possTypes & possTypes) != 0); |
||||||
|
} |
||||||
|
|
||||||
|
public String getDefaultName() { |
||||||
|
switch (((IntegerType)getHint()).possTypes) { |
||||||
|
case IT_Z: |
||||||
|
return "bool"; |
||||||
|
case IT_C: |
||||||
|
return "c"; |
||||||
|
case IT_B: |
||||||
|
case IT_S: |
||||||
|
case IT_I: |
||||||
|
return "i"; |
||||||
|
default: |
||||||
|
throw new jode.AssertError("Local can't be of constant type!"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String getTypeSignature() { |
||||||
|
switch (((IntegerType)getHint()).possTypes) { |
||||||
|
case IT_Z: |
||||||
|
return "Z"; |
||||||
|
case IT_C: |
||||||
|
return "C"; |
||||||
|
case IT_B: |
||||||
|
return "B"; |
||||||
|
case IT_S: |
||||||
|
return "S"; |
||||||
|
case IT_I: |
||||||
|
default: |
||||||
|
return "I"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
switch (possTypes) { |
||||||
|
case IT_Z: |
||||||
|
return "boolean"; |
||||||
|
case IT_C: |
||||||
|
return "char"; |
||||||
|
case IT_B: |
||||||
|
return "byte"; |
||||||
|
case IT_S: |
||||||
|
return "short"; |
||||||
|
case IT_I: |
||||||
|
return "int"; |
||||||
|
default: |
||||||
|
StringBuffer sb = new StringBuffer("{"); |
||||||
|
String comma = ""; |
||||||
|
for (int i=0; i< NUM_TYPES; i++) |
||||||
|
if (((1<<i) & possTypes) != 0) { |
||||||
|
sb.append(comma).append(typeNames[i]); |
||||||
|
comma = ","; |
||||||
|
} |
||||||
|
sb.append("}"); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Intersect this type with another type and return the new type. |
||||||
|
* @param type the other type. |
||||||
|
* @return the intersection, or tError, if a type conflict happens. |
||||||
|
*/ |
||||||
|
public Type intersection(Type type) { |
||||||
|
if (type == tError) |
||||||
|
return type; |
||||||
|
if (type == tUnknown) |
||||||
|
return this; |
||||||
|
|
||||||
|
int mergeTypes; |
||||||
|
if (type.typecode != TC_INTEGER) |
||||||
|
mergeTypes = 0; |
||||||
|
else { |
||||||
|
IntegerType other = (IntegerType) type; |
||||||
|
mergeTypes = possTypes & other.possTypes; |
||||||
|
/* HINTING XXX */ |
||||||
|
if (mergeTypes == possTypes) |
||||||
|
return this; |
||||||
|
if (mergeTypes == other.possTypes) |
||||||
|
return other; |
||||||
|
} |
||||||
|
Type result = mergeTypes == 0 ? tError : new IntegerType(mergeTypes); |
||||||
|
if (Decompiler.isTypeDebugging || result == tError) { |
||||||
|
Decompiler.err.println("intersecting "+ this +" and "+ type + |
||||||
|
" to " + result); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object o) { |
||||||
|
if (o == this) |
||||||
|
return true; |
||||||
|
if (o instanceof IntegerType) |
||||||
|
return ((IntegerType)o).possTypes == possTypes; |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
package jode; |
||||||
|
public class NullType extends ClassInterfacesType { |
||||||
|
public NullType() { |
||||||
|
super(null, null); |
||||||
|
typecode = TC_NULL; |
||||||
|
} |
||||||
|
|
||||||
|
public Type createRangeType(ClassInterfacesType bottomType) { |
||||||
|
return tRange(bottomType, this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the generalized type of this and type. We have two |
||||||
|
* classes and multiple interfaces. The result should be the |
||||||
|
* object that is the the super class of both objects and all |
||||||
|
* interfaces, that one class or interface of each type |
||||||
|
* implements. */ |
||||||
|
public Type getGeneralizedType(Type type) { |
||||||
|
if (type.typecode == TC_RANGE) |
||||||
|
type = ((RangeType) type).getTop(); |
||||||
|
return type; |
||||||
|
} |
||||||
|
/** |
||||||
|
* Returns the specialized type of this and type. |
||||||
|
* We have two classes and multiple interfaces. The result |
||||||
|
* should be the object that extends both objects |
||||||
|
* and the union of all interfaces. |
||||||
|
*/ |
||||||
|
public Type getSpecializedType(Type type) { |
||||||
|
if (type.typecode == TC_RANGE) |
||||||
|
type = ((RangeType) type).getBottom(); |
||||||
|
return type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Marks this type as used, so that the class is imported. |
||||||
|
*/ |
||||||
|
public void useType() { |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
return "/*NULL*/" + env.classString("java.lang.Object"); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object o) { |
||||||
|
return o == this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Intersect this type with another type and return the new type. |
||||||
|
* @param type the other type. |
||||||
|
* @return the intersection, or tError, if a type conflict happens. |
||||||
|
*/ |
||||||
|
public Type intersection(Type type) { |
||||||
|
throw new AssertError("NULL.intersection"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
Loading…
Reference in new issue