option parsing a bit reworked. git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1267 379699f6-c40d-0410-875b-85095c16579emaster
parent
5e6af53990
commit
4a63627c87
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,108 @@ |
|||||||
|
/* ClassInfoType Copyright (C) 1998-1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU 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 General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.type; |
||||||
|
import jode.bytecode.ClassInfo; |
||||||
|
import jode.GlobalOptions; |
||||||
|
|
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.Vector; |
||||||
|
import java.util.Stack; |
||||||
|
import java.util.Hashtable; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class is the type representing a class loaded from a ClassPath.<p> |
||||||
|
* |
||||||
|
* @author Jochen Hoenicke */ |
||||||
|
public class ClassInfoType extends ClassType { |
||||||
|
ClassInfo clazz; |
||||||
|
ClassType superClass = null; |
||||||
|
ClassType[] interfaces = null; |
||||||
|
|
||||||
|
public ClassInfo getClazz() { |
||||||
|
return clazz; |
||||||
|
} |
||||||
|
|
||||||
|
public ClassInfoType(ClassInfo clazz) { |
||||||
|
super(TC_CLASS, clazz.getName()); |
||||||
|
this.clazz = clazz; |
||||||
|
try { |
||||||
|
clazz.load(ClassInfo.HIERARCHY); |
||||||
|
} catch (IOException ex) { |
||||||
|
clazz.guess(ClassInfo.HIERARCHY); |
||||||
|
GlobalOptions.err.println |
||||||
|
("Can't get full class hierarchy for "+clazz+ |
||||||
|
" types may be incorrect."); |
||||||
|
GlobalOptions.err.println(ex.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isUnknown() { |
||||||
|
return clazz.isGuessed(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isFinal() { |
||||||
|
return Modifier.isFinal(clazz.getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isInterface() { |
||||||
|
return clazz.isInterface(); |
||||||
|
} |
||||||
|
|
||||||
|
public ClassType getSuperClass() { |
||||||
|
if (clazz.isInterface()) |
||||||
|
return null; |
||||||
|
if (superClass == null) { |
||||||
|
ClassInfo superInfo = clazz.getSuperclass(); |
||||||
|
if (superInfo == null) |
||||||
|
return null; |
||||||
|
superClass = Type.tClass(superInfo); |
||||||
|
} |
||||||
|
return superClass; |
||||||
|
} |
||||||
|
|
||||||
|
public ClassType[] getInterfaces() { |
||||||
|
if (interfaces == null) { |
||||||
|
ClassInfo[] ifaceInfos = clazz.getInterfaces(); |
||||||
|
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]); |
||||||
|
} |
||||||
|
} |
||||||
|
return interfaces; |
||||||
|
} |
||||||
|
|
||||||
|
public ClassInfo getClassInfo() { |
||||||
|
return clazz; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object o) { |
||||||
|
if (o instanceof ClassInfoType) |
||||||
|
return ((ClassInfoType) o).clazz == clazz; |
||||||
|
return super.equals(o); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,624 +0,0 @@ |
|||||||
/* ClassInterfacesType Copyright (C) 1998-1999 Jochen Hoenicke. |
|
||||||
* |
|
||||||
* This program is free software; you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU 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 General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU General Public License |
|
||||||
* along with this program; see the file COPYING. If not, write to |
|
||||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
|
||||||
* |
|
||||||
* $Id$ |
|
||||||
*/ |
|
||||||
|
|
||||||
package jode.type; |
|
||||||
import jode.bytecode.ClassInfo; |
|
||||||
import java.util.Vector; |
|
||||||
import java.util.Stack; |
|
||||||
import java.util.Hashtable; |
|
||||||
import java.io.IOException; |
|
||||||
|
|
||||||
/** |
|
||||||
* This class represents a type aproximation, consisting of multiple |
|
||||||
* interfaces and a class type.<p> |
|
||||||
* |
|
||||||
* If this is the bottom boundary, this specifies, which class our |
|
||||||
* type must extend and which interfaces it must implement. |
|
||||||
* |
|
||||||
* If this is the top boundary, this gives all interfaces and classes |
|
||||||
* that may extend the type. I.e. at least one interface or class extends |
|
||||||
* the searched type. |
|
||||||
* |
|
||||||
* @author Jochen Hoenicke */ |
|
||||||
public class ClassInterfacesType extends ReferenceType { |
|
||||||
|
|
||||||
ClassInfo clazz; |
|
||||||
ClassInfo ifaces[]; |
|
||||||
|
|
||||||
public ClassInfo getClazz() { |
|
||||||
return clazz != null ? clazz |
|
||||||
: ClassInfo.forName("java.lang.Object"); |
|
||||||
} |
|
||||||
|
|
||||||
public ClassInterfacesType(String clazzName) { |
|
||||||
this(ClassInfo.forName(clazzName)); |
|
||||||
} |
|
||||||
|
|
||||||
public ClassInterfacesType(ClassInfo clazz) { |
|
||||||
super(TC_CLASS); |
|
||||||
try { |
|
||||||
clazz.load(ClassInfo.HIERARCHY); |
|
||||||
} catch (IOException ex) { |
|
||||||
clazz.guess(ClassInfo.HIERARCHY); |
|
||||||
} |
|
||||||
if (clazz.isInterface()) { |
|
||||||
this.clazz = null; |
|
||||||
ifaces = new ClassInfo[] { clazz }; |
|
||||||
} else { |
|
||||||
this.clazz = |
|
||||||
(clazz.getName() == "java.lang.Object") ? null : clazz; |
|
||||||
ifaces = new ClassInfo[0]; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public ClassInterfacesType(ClassInfo clazz, ClassInfo[] ifaces) { |
|
||||||
super(TC_CLASS); |
|
||||||
this.clazz = clazz; |
|
||||||
this.ifaces = ifaces; |
|
||||||
} |
|
||||||
|
|
||||||
static ClassInterfacesType create(ClassInfo clazz, ClassInfo[] ifaces) { |
|
||||||
/* Make sure that every {java.lang.Object} equals tObject */ |
|
||||||
if (ifaces.length == 0 && clazz == null) |
|
||||||
return tObject; |
|
||||||
if (ifaces.length == 0) |
|
||||||
return tClass(clazz); |
|
||||||
if (ifaces.length == 1 && clazz == null) |
|
||||||
return tClass(ifaces[0]); |
|
||||||
return new ClassInterfacesType(clazz, ifaces); |
|
||||||
} |
|
||||||
|
|
||||||
public Type getSubType() { |
|
||||||
if ((clazz == null && ifaces.length == 1) |
|
||||||
|| ifaces.length == 0) |
|
||||||
return tRange(this, tNull); |
|
||||||
|
|
||||||
/* We don't implement the set of types, that are castable to some |
|
||||||
* of the given classes or interfaces. |
|
||||||
*/ |
|
||||||
throw new jode.AssertError |
|
||||||
("getSubType called on set of classes and interfaces!"); |
|
||||||
} |
|
||||||
|
|
||||||
public Type getHint() { |
|
||||||
if (ifaces.length == 0 |
|
||||||
|| (clazz == null && ifaces.length == 1)) |
|
||||||
return this; |
|
||||||
if (clazz != null) |
|
||||||
return Type.tClass(clazz); |
|
||||||
else |
|
||||||
return Type.tClass(ifaces[0]); |
|
||||||
} |
|
||||||
|
|
||||||
public Type getCanonic() { |
|
||||||
if (ifaces.length == 0 |
|
||||||
|| (clazz == null && ifaces.length == 1)) |
|
||||||
return this; |
|
||||||
if (clazz != null) |
|
||||||
return Type.tClass(clazz); |
|
||||||
else |
|
||||||
return Type.tClass(ifaces[0]); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Create the type corresponding to the range from bottomType to |
|
||||||
* this. Checks if the given type range may be not empty. This |
|
||||||
* means, that bottom.clazz is extended by this.clazz and that all |
|
||||||
* interfaces in bottom are implemented by an interface or by |
|
||||||
* clazz. |
|
||||||
* @param bottom the start point of the range |
|
||||||
* @return the range type, or tError if range is empty. |
|
||||||
*/ |
|
||||||
public Type createRangeType(ReferenceType bottomType) { |
|
||||||
if (bottomType.typecode != TC_CLASS) |
|
||||||
return tError; |
|
||||||
|
|
||||||
ClassInterfacesType bottom = (ClassInterfacesType) bottomType; |
|
||||||
|
|
||||||
if (bottomType == tObject) |
|
||||||
return (this == tObject) ? tObject : tRange(tObject, this); |
|
||||||
|
|
||||||
try { |
|
||||||
if (bottom.clazz != null) { |
|
||||||
/* The searched type must be a class type. |
|
||||||
*/ |
|
||||||
if (!bottom.clazz.superClassOf(this.clazz)) |
|
||||||
return tError; |
|
||||||
|
|
||||||
/* All interfaces must be implemented by this.clazz |
|
||||||
*/ |
|
||||||
for (int i=0; i < bottom.ifaces.length; i++) { |
|
||||||
if (!bottom.ifaces[i].implementedBy(this.clazz)) |
|
||||||
return tError; |
|
||||||
} |
|
||||||
|
|
||||||
if (bottom.clazz == this.clazz |
|
||||||
&& bottom.ifaces.length == 0) |
|
||||||
return bottom; |
|
||||||
|
|
||||||
if (this.ifaces.length != 0) |
|
||||||
return tRange(bottom, create(this.clazz, new ClassInfo[0])); |
|
||||||
return tRange(bottom, this); |
|
||||||
|
|
||||||
} else { |
|
||||||
|
|
||||||
/* Now bottom.clazz is null (or tObject), find all |
|
||||||
* classes/interfaces that implement all bottom.ifaces. |
|
||||||
*/ |
|
||||||
|
|
||||||
ClassInfo clazz = this.clazz; |
|
||||||
if (clazz != null) { |
|
||||||
for (int i=0; i < bottom.ifaces.length; i++) { |
|
||||||
if (!bottom.ifaces[i].implementedBy(clazz)) { |
|
||||||
clazz = null; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* If bottom is a single interface and equals some top |
|
||||||
* interface, then bottom is the only possible type. |
|
||||||
*/ |
|
||||||
if (clazz == null && bottom.ifaces.length == 1) { |
|
||||||
for (int i=0; i< this.ifaces.length; i++) { |
|
||||||
if (this.ifaces[i] == bottom.ifaces[0]) |
|
||||||
return bottom; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ClassInfo[] ifaces = new ClassInfo[this.ifaces.length]; |
|
||||||
int count = 0; |
|
||||||
big_loop: |
|
||||||
for (int j=0; j < this.ifaces.length; j++) { |
|
||||||
for (int i=0; i < bottom.ifaces.length; i++) { |
|
||||||
if (!bottom.ifaces[i].implementedBy(this.ifaces[j])) |
|
||||||
continue big_loop; |
|
||||||
} |
|
||||||
ifaces[count++] = (this.ifaces[j]); |
|
||||||
} |
|
||||||
|
|
||||||
if (clazz == null && count == 0) { |
|
||||||
/* There are no more possible interfaces or classes left. |
|
||||||
* This is a type error. |
|
||||||
*/ |
|
||||||
return tError; |
|
||||||
} else if (count < ifaces.length) { |
|
||||||
ClassInfo[] shortIfaces = new ClassInfo[count]; |
|
||||||
System.arraycopy(ifaces, 0, shortIfaces, 0, count); |
|
||||||
ifaces = shortIfaces; |
|
||||||
} else if (clazz == this.clazz) |
|
||||||
return tRange(bottom, this); |
|
||||||
return tRange(bottom, create(clazz, ifaces)); |
|
||||||
} |
|
||||||
} catch (IOException ex) { |
|
||||||
/*XXX : There is something better than tError*/ |
|
||||||
return tError; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 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) { |
|
||||||
int code = type.typecode; |
|
||||||
if (code == TC_RANGE) { |
|
||||||
type = ((RangeType) type).getBottom(); |
|
||||||
code = type.typecode; |
|
||||||
} |
|
||||||
if (code == TC_NULL) |
|
||||||
return this; |
|
||||||
if (code == TC_ARRAY) |
|
||||||
return ((ArrayType) type).getSpecializedType(this); |
|
||||||
if (code != TC_CLASS) |
|
||||||
return tError; |
|
||||||
|
|
||||||
ClassInterfacesType other = (ClassInterfacesType) type; |
|
||||||
ClassInfo clazz; |
|
||||||
|
|
||||||
/* First determine the clazz, one of the two classes must be a sub |
|
||||||
* class of the other or null. |
|
||||||
*/ |
|
||||||
|
|
||||||
try { |
|
||||||
if (this.clazz == null) |
|
||||||
clazz = other.clazz; |
|
||||||
else if (other.clazz == null) |
|
||||||
clazz = this.clazz; |
|
||||||
else if (this.clazz.superClassOf(other.clazz)) |
|
||||||
clazz = other.clazz; |
|
||||||
else if (other.clazz.superClassOf(this.clazz)) |
|
||||||
clazz = this.clazz; |
|
||||||
else |
|
||||||
return tError; |
|
||||||
} catch (IOException ex) { |
|
||||||
/*XXX : There is something better than tError*/ |
|
||||||
return tError; |
|
||||||
} |
|
||||||
|
|
||||||
/* Most times (99.9999999 %) one of the two classes is already |
|
||||||
* more specialized. Optimize for this case. (I know of one |
|
||||||
* class where at one intersection this doesn't succeed) |
|
||||||
*/ |
|
||||||
if (clazz == this.clazz |
|
||||||
&& implementsAllIfaces(this.clazz, this.ifaces, other.ifaces)) |
|
||||||
return this; |
|
||||||
else if (clazz == other.clazz |
|
||||||
&& implementsAllIfaces(other.clazz, other.ifaces, |
|
||||||
this.ifaces)) |
|
||||||
return other; |
|
||||||
|
|
||||||
try { |
|
||||||
/* The interfaces are simply the union of both interfaces set. |
|
||||||
* But we can simplify this, if an interface is implemented by |
|
||||||
* another or by the class, we can omit it. |
|
||||||
*/ |
|
||||||
Vector ifaces = new Vector(); |
|
||||||
big_loop_this: |
|
||||||
for (int i=0; i< this.ifaces.length; i++) { |
|
||||||
ClassInfo iface = this.ifaces[i]; |
|
||||||
if (clazz != null && iface.implementedBy(clazz)) { |
|
||||||
continue big_loop_this; |
|
||||||
} |
|
||||||
for (int j=0; j<other.ifaces.length; j++) { |
|
||||||
if (iface.implementedBy(other.ifaces[j])) { |
|
||||||
continue big_loop_this; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* This interface is not implemented by any of the other |
|
||||||
* ifaces. Add it to the interfaces vector. |
|
||||||
*/ |
|
||||||
ifaces.addElement(iface); |
|
||||||
} |
|
||||||
big_loop_other: |
|
||||||
for (int i=0; i< other.ifaces.length; i++) { |
|
||||||
ClassInfo iface = other.ifaces[i]; |
|
||||||
if (clazz != null && iface.implementedBy(clazz)) { |
|
||||||
continue big_loop_other; |
|
||||||
} |
|
||||||
for (int j=0; j<ifaces.size(); j++) { |
|
||||||
if (iface.implementedBy((ClassInfo) |
|
||||||
ifaces.elementAt(j))) { |
|
||||||
continue big_loop_other; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* This interface is not implemented by any of the other |
|
||||||
* ifaces. Add it to the interfaces vector. |
|
||||||
*/ |
|
||||||
ifaces.addElement(iface); |
|
||||||
} |
|
||||||
|
|
||||||
ClassInfo[] ifaceArray = new ClassInfo[ifaces.size()]; |
|
||||||
ifaces.copyInto(ifaceArray); |
|
||||||
return create(clazz, ifaceArray); |
|
||||||
} catch (IOException ex) { |
|
||||||
/*XXX : There is something better than tError*/ |
|
||||||
return tError; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 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) { |
|
||||||
try{ |
|
||||||
int code = type.typecode; |
|
||||||
if (code == TC_RANGE) { |
|
||||||
type = ((RangeType) type).getTop(); |
|
||||||
code = type.typecode; |
|
||||||
} |
|
||||||
if (code == TC_NULL) |
|
||||||
return this; |
|
||||||
if (code == TC_ARRAY) |
|
||||||
return ((ArrayType) type).getGeneralizedType(this); |
|
||||||
if (code != TC_CLASS) |
|
||||||
return tError; |
|
||||||
ClassInterfacesType other = (ClassInterfacesType) type; |
|
||||||
ClassInfo clazz; |
|
||||||
|
|
||||||
/* First the easy part, determine the clazz */ |
|
||||||
if (this.clazz == null || other.clazz == null) |
|
||||||
clazz = null; |
|
||||||
else { |
|
||||||
clazz = this.clazz; |
|
||||||
|
|
||||||
try { |
|
||||||
while(clazz != null) { |
|
||||||
if (clazz.superClassOf(other.clazz)) |
|
||||||
break; |
|
||||||
clazz = clazz.getSuperclass(); |
|
||||||
} |
|
||||||
if (clazz.getName() == "java.lang.Object") |
|
||||||
clazz = null; |
|
||||||
} catch (IOException ex) { |
|
||||||
/*XXX : There is something better than tObject*/ |
|
||||||
clazz = null; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (clazz == this.clazz |
|
||||||
&& implementsAllIfaces(other.clazz, other.ifaces, this.ifaces)) |
|
||||||
return this; |
|
||||||
else if (clazz == other.clazz |
|
||||||
&& implementsAllIfaces(this.clazz, this.ifaces, other.ifaces)) |
|
||||||
return other; |
|
||||||
|
|
||||||
/* Now the more complicated part: find all interfaces, that are |
|
||||||
* implemented by one interface or class in each group. |
|
||||||
* |
|
||||||
* First get all interfaces of this.clazz and this.ifaces. |
|
||||||
*/ |
|
||||||
|
|
||||||
Stack allIfaces = new Stack(); |
|
||||||
if (this.clazz != null) { |
|
||||||
ClassInfo c = this.clazz; |
|
||||||
while (clazz != c) { |
|
||||||
ClassInfo clazzIfaces[] = c.getInterfaces(); |
|
||||||
for (int i=0; i<clazzIfaces.length; i++) |
|
||||||
allIfaces.push(clazzIfaces[i]); |
|
||||||
c = c.getSuperclass(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Vector ifaces = new Vector(); |
|
||||||
|
|
||||||
for (int i=0; i<this.ifaces.length; i++) |
|
||||||
allIfaces.push(this.ifaces[i]); |
|
||||||
|
|
||||||
/* Now consider each interface. If any clazz or interface
|
|
||||||
* in other implements it, add it to the ifaces vector. |
|
||||||
* Otherwise consider all sub interfaces. |
|
||||||
*/ |
|
||||||
iface_loop: |
|
||||||
while (!allIfaces.isEmpty()) { |
|
||||||
ClassInfo iface = (ClassInfo) allIfaces.pop(); |
|
||||||
if ((clazz != null && iface.implementedBy(clazz)) |
|
||||||
|| ifaces.contains(iface)) |
|
||||||
/* We can skip this, as clazz or ifaces already imply it. |
|
||||||
*/ |
|
||||||
continue iface_loop; |
|
||||||
|
|
||||||
if (other.clazz != null && iface.implementedBy(other.clazz)) { |
|
||||||
ifaces.addElement(iface); |
|
||||||
continue iface_loop; |
|
||||||
} |
|
||||||
for (int i=0; i<other.ifaces.length; i++) { |
|
||||||
if (iface.implementedBy(other.ifaces[i])) { |
|
||||||
ifaces.addElement(iface); |
|
||||||
continue iface_loop; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/* This interface is not implemented by any of the other |
|
||||||
* ifaces. Try its parent interfaces now. |
|
||||||
*/ |
|
||||||
ClassInfo clazzIfaces[] = iface.getInterfaces(); |
|
||||||
for (int i=0; i<clazzIfaces.length; i++) |
|
||||||
allIfaces.push(clazzIfaces[i]); |
|
||||||
} |
|
||||||
|
|
||||||
ClassInfo[] ifaceArray = new ClassInfo[ifaces.size()]; |
|
||||||
ifaces.copyInto(ifaceArray); |
|
||||||
return create(clazz, ifaceArray); |
|
||||||
} catch (IOException ex) { |
|
||||||
/*XXX : There is something better than tError*/ |
|
||||||
return tError; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public String getTypeSignature() { |
|
||||||
if (clazz != null) |
|
||||||
return "L" + clazz.getName().replace('.','/') + ";"; |
|
||||||
else if (ifaces.length > 0) |
|
||||||
return "L" + ifaces[0].getName().replace('.','/') + ";"; |
|
||||||
else |
|
||||||
return "Ljava/lang/Object;"; |
|
||||||
} |
|
||||||
|
|
||||||
public Class getTypeClass() throws ClassNotFoundException { |
|
||||||
if (clazz != null) |
|
||||||
return Class.forName(clazz.getName()); |
|
||||||
else if (ifaces.length > 0) |
|
||||||
return Class.forName(ifaces[0].getName()); |
|
||||||
else |
|
||||||
return Class.forName("java.lang.Object"); |
|
||||||
} |
|
||||||
|
|
||||||
public ClassInfo getClassInfo() { |
|
||||||
if (clazz != null) |
|
||||||
return clazz; |
|
||||||
else if (ifaces.length > 0) |
|
||||||
return ifaces[0]; |
|
||||||
else |
|
||||||
return ClassInfo.forName("java.lang.Object"); |
|
||||||
} |
|
||||||
|
|
||||||
public String toString() |
|
||||||
{ |
|
||||||
if (this == tObject) |
|
||||||
return "java.lang.Object"; |
|
||||||
|
|
||||||
if (ifaces.length == 0) |
|
||||||
return clazz.getName(); |
|
||||||
if (clazz == null && ifaces.length == 1) |
|
||||||
return ifaces[0].getName(); |
|
||||||
|
|
||||||
StringBuffer sb = new StringBuffer("{"); |
|
||||||
String comma = ""; |
|
||||||
if (clazz != null) { |
|
||||||
sb = sb.append(clazz.getName()); |
|
||||||
comma = ", "; |
|
||||||
} |
|
||||||
for (int i=0; i< ifaces.length; i++) { |
|
||||||
sb.append(comma).append(ifaces[i].getName()); |
|
||||||
comma = ", "; |
|
||||||
} |
|
||||||
return sb.append("}").toString(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Checks if we need to cast to a middle type, before we can cast from |
|
||||||
* fromType to this type. |
|
||||||
* @return the middle type, or null if it is not necessary. |
|
||||||
*/ |
|
||||||
public Type getCastHelper(Type fromType) { |
|
||||||
Type hintType = fromType.getHint(); |
|
||||||
switch (hintType.getTypeCode()) { |
|
||||||
case TC_ARRAY: |
|
||||||
if (clazz == null |
|
||||||
&& implementsAllIfaces(null, ArrayType.arrayIfaces, |
|
||||||
this.ifaces)) |
|
||||||
return null; |
|
||||||
else |
|
||||||
return tObject; |
|
||||||
case TC_CLASS: |
|
||||||
try { |
|
||||||
ClassInterfacesType hint = (ClassInterfacesType) hintType; |
|
||||||
if (hint.clazz == null || clazz == null |
|
||||||
|| clazz.superClassOf(hint.clazz) |
|
||||||
|| hint.clazz.superClassOf(clazz)) |
|
||||||
return null; |
|
||||||
ClassInfo superClazz = clazz.getSuperclass(); |
|
||||||
while (superClazz != null |
|
||||||
&& !superClazz.superClassOf(hint.clazz)) { |
|
||||||
superClazz = superClazz.getSuperclass(); |
|
||||||
} |
|
||||||
return tClass(superClazz.getName()); |
|
||||||
} catch (IOException ex) { |
|
||||||
/*XXX : There is something better than tObject*/ |
|
||||||
return tObject; |
|
||||||
} |
|
||||||
case TC_UNKNOWN: |
|
||||||
return null; |
|
||||||
} |
|
||||||
return tObject; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Checks if this type represents a valid type instead of a list |
|
||||||
* of minimum types. |
|
||||||
*/ |
|
||||||
public boolean isValidType() { |
|
||||||
return ifaces.length == 0 |
|
||||||
|| (clazz == null && ifaces.length == 1); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 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() { |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
private final static Hashtable keywords = new Hashtable(); |
|
||||||
static { |
|
||||||
keywords.put("if", Boolean.TRUE); |
|
||||||
keywords.put("else", Boolean.TRUE); |
|
||||||
keywords.put("for", Boolean.TRUE); |
|
||||||
keywords.put("while", Boolean.TRUE); |
|
||||||
keywords.put("throw", Boolean.TRUE); |
|
||||||
keywords.put("return", Boolean.TRUE); |
|
||||||
keywords.put("class", Boolean.TRUE); |
|
||||||
keywords.put("interface", Boolean.TRUE); |
|
||||||
keywords.put("implements", Boolean.TRUE); |
|
||||||
keywords.put("extends", Boolean.TRUE); |
|
||||||
keywords.put("instanceof", Boolean.TRUE); |
|
||||||
keywords.put("new", Boolean.TRUE); |
|
||||||
keywords.put("int", Boolean.TRUE); |
|
||||||
keywords.put("boolean", Boolean.TRUE); |
|
||||||
keywords.put("long", Boolean.TRUE); |
|
||||||
keywords.put("float", Boolean.TRUE); |
|
||||||
keywords.put("double", Boolean.TRUE); |
|
||||||
keywords.put("short", Boolean.TRUE); |
|
||||||
keywords.put("public", Boolean.TRUE); |
|
||||||
keywords.put("protected", Boolean.TRUE); |
|
||||||
keywords.put("private", Boolean.TRUE); |
|
||||||
keywords.put("static", Boolean.TRUE); |
|
||||||
keywords.put("synchronized", Boolean.TRUE); |
|
||||||
keywords.put("strict", Boolean.TRUE); |
|
||||||
keywords.put("transient", Boolean.TRUE); |
|
||||||
keywords.put("abstract", Boolean.TRUE); |
|
||||||
keywords.put("volatile", Boolean.TRUE); |
|
||||||
keywords.put("final", Boolean.TRUE); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 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() { |
|
||||||
ClassInfo type; |
|
||||||
if (clazz != null) |
|
||||||
type = clazz; |
|
||||||
else if (ifaces.length > 0) |
|
||||||
type = ifaces[0]; |
|
||||||
else |
|
||||||
type = ClassInfo.forName("java.lang.Object"); |
|
||||||
String name = type.getName(); |
|
||||||
int dot = Math.max(name.lastIndexOf('.'), name.lastIndexOf('$')); |
|
||||||
if (dot >= 0) |
|
||||||
name = name.substring(dot+1); |
|
||||||
if (Character.isUpperCase(name.charAt(0))) { |
|
||||||
name = name.toLowerCase(); |
|
||||||
if (keywords.get(name) != null) |
|
||||||
return "var_" + name; |
|
||||||
return name; |
|
||||||
} else |
|
||||||
return "var_" + name; |
|
||||||
} |
|
||||||
|
|
||||||
public int hashCode() { |
|
||||||
int hash = clazz == null ? 0 : clazz.hashCode(); |
|
||||||
for (int i=0; i < ifaces.length; i++) { |
|
||||||
hash ^= ifaces[i].hashCode(); |
|
||||||
} |
|
||||||
return hash; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean equals(Object o) { |
|
||||||
if (o == this) |
|
||||||
return true; |
|
||||||
if (o instanceof Type && ((Type)o).typecode == TC_CLASS) { |
|
||||||
ClassInterfacesType type = (ClassInterfacesType) o; |
|
||||||
if (type.clazz == clazz |
|
||||||
&& type.ifaces.length == ifaces.length) { |
|
||||||
big_loop: |
|
||||||
for (int i=0; i< type.ifaces.length; i++) { |
|
||||||
for (int j=0; j<ifaces.length; j++) { |
|
||||||
if (type.ifaces[i] == ifaces[j]) |
|
||||||
continue big_loop; |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,332 @@ |
|||||||
|
/* ClassType Copyright (C) 2000 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU 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 General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.type; |
||||||
|
import java.util.Stack; |
||||||
|
import java.util.Hashtable; |
||||||
|
import java.util.Enumeration; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class is the base class of all types representing a class type.<p> |
||||||
|
* |
||||||
|
* @author Jochen Hoenicke |
||||||
|
*/ |
||||||
|
public abstract class ClassType extends ReferenceType { |
||||||
|
protected String className; |
||||||
|
|
||||||
|
public String getClassName() { |
||||||
|
return className; |
||||||
|
} |
||||||
|
|
||||||
|
public ClassType(int typecode, String clazzName) { |
||||||
|
super(typecode); |
||||||
|
className = clazzName; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if this type represents an interface. |
||||||
|
* @return true if this is an interface, false if this is a class or |
||||||
|
* if unsure. |
||||||
|
*/ |
||||||
|
public abstract boolean isUnknown(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if this type represents an interface. |
||||||
|
* @return true if this is an interface, false if this is a class or |
||||||
|
* if unsure. |
||||||
|
*/ |
||||||
|
public abstract boolean isInterface(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if this type represents an interface. |
||||||
|
* @return true if this is an interface, false if this is a class or |
||||||
|
* if unsure. |
||||||
|
*/ |
||||||
|
public abstract boolean isFinal(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the reference type representing the super class, or null |
||||||
|
* if this reference type represents java.lang.Object, or for interfaces. |
||||||
|
* @return the super class' type. |
||||||
|
*/ |
||||||
|
public abstract ClassType getSuperClass(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the reference type representing the interfaces this class
|
||||||
|
* implements. This may of course be an empty array. |
||||||
|
* @return the interfaces' types. |
||||||
|
*/ |
||||||
|
public abstract ClassType[] getInterfaces(); |
||||||
|
|
||||||
|
public boolean isSubTypeOf(Type type) { |
||||||
|
if (type == tNull) |
||||||
|
return true; |
||||||
|
if (type instanceof MultiClassType) |
||||||
|
return ((MultiClassType)type).containsSuperTypeOf(this); |
||||||
|
if (!(type instanceof ClassType)) |
||||||
|
return false; |
||||||
|
if (this.equals(tObject)) |
||||||
|
return true; |
||||||
|
|
||||||
|
ClassType ctype = (ClassType) type; |
||||||
|
|
||||||
|
if (isFinal()) |
||||||
|
return ctype.equals(this); |
||||||
|
|
||||||
|
while (ctype != null) { |
||||||
|
if (ctype.equals(this)) |
||||||
|
return true; |
||||||
|
|
||||||
|
if (isInterface()) { |
||||||
|
ClassType[] typeIfaces = ctype.getInterfaces(); |
||||||
|
for (int i = 0; i < typeIfaces.length; i++) |
||||||
|
if (isSubTypeOf(typeIfaces[i])) |
||||||
|
return true; |
||||||
|
} |
||||||
|
ctype = ctype.getSuperClass(); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean maybeSubTypeOf(Type type) { |
||||||
|
if (type == tNull) |
||||||
|
return true; |
||||||
|
if (!(type instanceof ClassType)) |
||||||
|
return false; |
||||||
|
if (this.equals(tObject)) |
||||||
|
return true; |
||||||
|
|
||||||
|
ClassType ctype = (ClassType) type; |
||||||
|
|
||||||
|
if (isFinal()) |
||||||
|
return ctype.equals(this); |
||||||
|
|
||||||
|
while (ctype != null) { |
||||||
|
if (ctype.equals(this)) |
||||||
|
return true; |
||||||
|
|
||||||
|
if (ctype.isUnknown()) |
||||||
|
return true; |
||||||
|
|
||||||
|
if (isInterface()) { |
||||||
|
ClassType[] typeIfaces = ctype.getInterfaces(); |
||||||
|
for (int i = 0; i < typeIfaces.length; i++) |
||||||
|
if (isSubTypeOf(typeIfaces[i])) |
||||||
|
return true; |
||||||
|
} |
||||||
|
ctype = ctype.getSuperClass(); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public Type getSubType() { |
||||||
|
return tRange(this, tNull); |
||||||
|
} |
||||||
|
|
||||||
|
public Type getHint() { |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public Type getCanonic() { |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create the type corresponding to the range from bottomType to |
||||||
|
* this. Checks if the given type range may be not empty. This |
||||||
|
* means, that bottom.clazz is extended by this.clazz and that all |
||||||
|
* interfaces in bottom are implemented by an interface or by |
||||||
|
* clazz. |
||||||
|
* @param bottom the start point of the range |
||||||
|
* @return the range type, or tError if range is empty. |
||||||
|
*/ |
||||||
|
public Type createRangeType(ReferenceType bottomType) { |
||||||
|
if (!bottomType.maybeSubTypeOf(this)) |
||||||
|
return tError; |
||||||
|
|
||||||
|
if (this.isSubTypeOf(bottomType)) |
||||||
|
/* bottomType contains a class equal to this. |
||||||
|
*/ |
||||||
|
return this; |
||||||
|
return tRange(bottomType, this); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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 instanceof RangeType) { |
||||||
|
type = ((RangeType) type).getBottom(); |
||||||
|
} |
||||||
|
|
||||||
|
/* Most times (almost always) one of the two classes is |
||||||
|
* already more specialized. Optimize for this case. |
||||||
|
*/ |
||||||
|
if (type.isSubTypeOf(this)) |
||||||
|
return this; |
||||||
|
if (this.isSubTypeOf(type)) |
||||||
|
return type; |
||||||
|
|
||||||
|
if (type instanceof MultiClassType) |
||||||
|
return ((MultiClassType) type).getSpecializedType(this); |
||||||
|
|
||||||
|
if (!(type instanceof ClassType)) |
||||||
|
return tError; |
||||||
|
ClassType other = (ClassType) type; |
||||||
|
return MultiClassType.create(new ClassType[] {this, other}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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) { |
||||||
|
int code = type.typecode; |
||||||
|
if (code == TC_RANGE) { |
||||||
|
type = ((RangeType) type).getTop(); |
||||||
|
code = type.typecode; |
||||||
|
} |
||||||
|
if (code == TC_NULL) |
||||||
|
return this; |
||||||
|
|
||||||
|
/* Often one of the two classes is already more generalized. |
||||||
|
* Optimize for this case. |
||||||
|
*/ |
||||||
|
if (type.isSubTypeOf(this)) |
||||||
|
return type; |
||||||
|
if (this.isSubTypeOf(type)) |
||||||
|
return this; |
||||||
|
|
||||||
|
if (!(type instanceof ReferenceType)) |
||||||
|
return tError; |
||||||
|
|
||||||
|
Stack classTypes = new Stack(); |
||||||
|
classTypes.push(this); |
||||||
|
return ((ReferenceType) type).findCommonClassTypes(classTypes); |
||||||
|
} |
||||||
|
|
||||||
|
public String getTypeSignature() { |
||||||
|
return "L" + className + ";"; |
||||||
|
} |
||||||
|
|
||||||
|
public Class getTypeClass() throws ClassNotFoundException { |
||||||
|
return Class.forName(className); |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() |
||||||
|
{ |
||||||
|
return className; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if we need to cast to a middle type, before we can cast from |
||||||
|
* fromType to this type. |
||||||
|
* @return the middle type, or null if it is not necessary. |
||||||
|
*/ |
||||||
|
public Type getCastHelper(Type fromType) { |
||||||
|
if (fromType.getHint().isSubTypeOf(this)) |
||||||
|
return null; |
||||||
|
return tObject; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if this type represents a valid type instead of a list |
||||||
|
* of minimum types. |
||||||
|
*/ |
||||||
|
public boolean isValidType() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
private final static Hashtable keywords = new Hashtable(); |
||||||
|
static { |
||||||
|
keywords.put("if", Boolean.TRUE); |
||||||
|
keywords.put("else", Boolean.TRUE); |
||||||
|
keywords.put("for", Boolean.TRUE); |
||||||
|
keywords.put("while", Boolean.TRUE); |
||||||
|
keywords.put("throw", Boolean.TRUE); |
||||||
|
keywords.put("return", Boolean.TRUE); |
||||||
|
keywords.put("class", Boolean.TRUE); |
||||||
|
keywords.put("interface", Boolean.TRUE); |
||||||
|
keywords.put("implements", Boolean.TRUE); |
||||||
|
keywords.put("extends", Boolean.TRUE); |
||||||
|
keywords.put("instanceof", Boolean.TRUE); |
||||||
|
keywords.put("new", Boolean.TRUE); |
||||||
|
keywords.put("int", Boolean.TRUE); |
||||||
|
keywords.put("boolean", Boolean.TRUE); |
||||||
|
keywords.put("long", Boolean.TRUE); |
||||||
|
keywords.put("float", Boolean.TRUE); |
||||||
|
keywords.put("double", Boolean.TRUE); |
||||||
|
keywords.put("short", Boolean.TRUE); |
||||||
|
keywords.put("public", Boolean.TRUE); |
||||||
|
keywords.put("protected", Boolean.TRUE); |
||||||
|
keywords.put("private", Boolean.TRUE); |
||||||
|
keywords.put("static", Boolean.TRUE); |
||||||
|
keywords.put("synchronized", Boolean.TRUE); |
||||||
|
keywords.put("strict", Boolean.TRUE); |
||||||
|
keywords.put("transient", Boolean.TRUE); |
||||||
|
keywords.put("abstract", Boolean.TRUE); |
||||||
|
keywords.put("volatile", Boolean.TRUE); |
||||||
|
keywords.put("final", Boolean.TRUE); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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() { |
||||||
|
String name = className; |
||||||
|
int dot = Math.max(name.lastIndexOf('.'), name.lastIndexOf('$')); |
||||||
|
if (dot >= 0) |
||||||
|
name = name.substring(dot+1); |
||||||
|
if (Character.isUpperCase(name.charAt(0))) { |
||||||
|
name = name.toLowerCase(); |
||||||
|
if (keywords.get(name) != null) |
||||||
|
return "var_" + name; |
||||||
|
return name; |
||||||
|
} else |
||||||
|
return "var_" + name; |
||||||
|
} |
||||||
|
|
||||||
|
public int hashCode() { |
||||||
|
return className.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object o) { |
||||||
|
if (o instanceof ClassType) |
||||||
|
return ((ClassType) o).className.equals(className); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,315 @@ |
|||||||
|
/* MultiClassType Copyright (C) 1998-1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU 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 General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.type; |
||||||
|
import jode.bytecode.ClassInfo; |
||||||
|
import java.util.Stack; |
||||||
|
import java.util.Vector; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class represents a type aproximation, consisting of multiple |
||||||
|
* interfaces and a class type.<p> |
||||||
|
* |
||||||
|
* If this is the bottom boundary, this specifies, which class our |
||||||
|
* type must extend and which interfaces it must implement. |
||||||
|
* |
||||||
|
* If this is the top boundary, this gives all interfaces and classes |
||||||
|
* that may extend the type. I.e. at least one interface or class extends |
||||||
|
* the searched type. |
||||||
|
* |
||||||
|
* @author Jochen Hoenicke */ |
||||||
|
public class MultiClassType extends ReferenceType { |
||||||
|
|
||||||
|
ClassType classes[]; |
||||||
|
|
||||||
|
private MultiClassType(ClassType[] classes) { |
||||||
|
super(TC_CLASSIFACE); |
||||||
|
this.classes = classes; |
||||||
|
} |
||||||
|
|
||||||
|
public static ReferenceType create(ClassType[] classes) { |
||||||
|
if (classes.length == 0) |
||||||
|
return tObject; |
||||||
|
if (classes.length == 1) |
||||||
|
return classes[0]; |
||||||
|
return new MultiClassType(classes); |
||||||
|
} |
||||||
|
|
||||||
|
public Type getSubType() { |
||||||
|
/* We don't implement the set of types, that are castable to some |
||||||
|
* of the given classes or interfaces. |
||||||
|
*/ |
||||||
|
throw new jode.AssertError |
||||||
|
("getSubType called on set of classes and interfaces!"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns true, iff this type implements all interfaces in type |
||||||
|
* and extends all objects in type. |
||||||
|
*/ |
||||||
|
public boolean isSubTypeOf(Type type) { |
||||||
|
for (int i = 0; i < classes.length; i++) |
||||||
|
if (!classes[i].isSubTypeOf(type)) |
||||||
|
return false; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns true, iff this type implements all interfaces in type |
||||||
|
* and extends all objects in type. |
||||||
|
*/ |
||||||
|
public boolean maybeSubTypeOf(Type type) { |
||||||
|
for (int i = 0; i < classes.length; i++) |
||||||
|
if (!classes[i].maybeSubTypeOf(type)) |
||||||
|
return false; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public Type getHint() { |
||||||
|
return getCanonic(); |
||||||
|
} |
||||||
|
|
||||||
|
public Type getCanonic() { |
||||||
|
return classes[0]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create the type corresponding to the range from bottomType to |
||||||
|
* this. This removes all classes that doesn't extend all classes |
||||||
|
* in bottom. If no class remains, this is a type error. |
||||||
|
* @param bottom the start point of the range |
||||||
|
* @return the range type, or tError if range is empty. |
||||||
|
*/ |
||||||
|
public Type createRangeType(ReferenceType bottomType) { |
||||||
|
ReferenceType topType; |
||||||
|
/** |
||||||
|
* Check if we fully implement the bottom type. |
||||||
|
*/ |
||||||
|
int j; |
||||||
|
for (j=0; j < classes.length; j++) { |
||||||
|
if (!bottomType.maybeSubTypeOf(classes[j])) |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
if (j == classes.length) |
||||||
|
topType = this; |
||||||
|
else { |
||||||
|
/* Now we have at least one class, that doesn't implement |
||||||
|
* bottomType, remove all such classes. |
||||||
|
*/ |
||||||
|
ClassType[] topClasses = new ClassType[classes.length - 1]; |
||||||
|
System.arraycopy(classes, 0, topClasses, 0, j); |
||||||
|
int count = j; |
||||||
|
for (j++; j < classes.length; j++) { |
||||||
|
if (bottomType.isSubTypeOf(classes[j])) |
||||||
|
topClasses[count++] = classes[j]; |
||||||
|
} |
||||||
|
|
||||||
|
if (count == 0) |
||||||
|
return tError; |
||||||
|
if (count < topClasses.length - 1) { |
||||||
|
ClassType[] shortClasses = new ClassType[count]; |
||||||
|
System.arraycopy(topClasses, 0, shortClasses, 0, count); |
||||||
|
topClasses = shortClasses; |
||||||
|
} |
||||||
|
topType = create(topClasses); |
||||||
|
} |
||||||
|
if (topType.isSubTypeOf(bottomType)) |
||||||
|
/* This means that topType contains only classes that are also |
||||||
|
* in bottomType. So topType is the whole range. |
||||||
|
*/ |
||||||
|
return topType; |
||||||
|
return tRange(bottomType, topType); |
||||||
|
} |
||||||
|
|
||||||
|
boolean containsSuperTypeOf(Type type) { |
||||||
|
for (int i = 0; i < classes.length; i++) |
||||||
|
if (type.isSubTypeOf(classes[i])) |
||||||
|
return true; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the specialized type of this and type. |
||||||
|
* We simple unify the lists of classes, but simplify them, to remove |
||||||
|
* all classes that are already subtypes of some other class in the |
||||||
|
* other list. |
||||||
|
*/ |
||||||
|
public Type getSpecializedType(Type type) { |
||||||
|
if (type instanceof RangeType) |
||||||
|
type = ((RangeType) type).getBottom(); |
||||||
|
|
||||||
|
/* Most times (almost always) one of the two types is |
||||||
|
* already more specialized. Optimize for this case. |
||||||
|
*/ |
||||||
|
if (type.isSubTypeOf(this)) |
||||||
|
return this; |
||||||
|
if (this.isSubTypeOf(type)) |
||||||
|
return type; |
||||||
|
|
||||||
|
ClassType[] otherClasses; |
||||||
|
if (type instanceof MultiClassType) { |
||||||
|
otherClasses = ((MultiClassType) type).classes; |
||||||
|
} else if (type instanceof ClassType) { |
||||||
|
otherClasses = new ClassType[] { (ClassType) type }; |
||||||
|
} else |
||||||
|
return tError; |
||||||
|
|
||||||
|
/* The classes are simply the union of both classes set. But |
||||||
|
* we can simplify this, if a class is implemented by another |
||||||
|
* class in the other list, we can omit it. |
||||||
|
*/ |
||||||
|
Vector destClasses = new Vector(); |
||||||
|
big_loop_this: |
||||||
|
for (int i=0; i< classes.length; i++) { |
||||||
|
ClassType clazz = classes[i]; |
||||||
|
if (!clazz.isSubTypeOf(type)) { |
||||||
|
/* This interface is not implemented by any of the other |
||||||
|
* classes. Add it to the destClasses. |
||||||
|
*/ |
||||||
|
destClasses.addElement(clazz); |
||||||
|
} |
||||||
|
} |
||||||
|
big_loop_other: |
||||||
|
for (int i=0; i< otherClasses.length; i++) { |
||||||
|
ClassType clazz = otherClasses[i]; |
||||||
|
if (!clazz.isSubTypeOf(this)) { |
||||||
|
/* This interface is not implemented by any of the other |
||||||
|
* classes. Add it to the destClasses. |
||||||
|
*/ |
||||||
|
destClasses.addElement(clazz); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ClassType[] classArray = new ClassType[destClasses.size()]; |
||||||
|
destClasses.copyInto(classArray); |
||||||
|
return create(classArray); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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 instanceof RangeType) |
||||||
|
type = ((RangeType) type).getTop(); |
||||||
|
|
||||||
|
/* Often one of the two classes is already more generalized. |
||||||
|
* Optimize for this case. |
||||||
|
*/ |
||||||
|
if (type.isSubTypeOf(this)) |
||||||
|
return type; |
||||||
|
if (this.isSubTypeOf(type)) |
||||||
|
return this; |
||||||
|
|
||||||
|
if (!(type instanceof ReferenceType)) |
||||||
|
return tError; |
||||||
|
|
||||||
|
Stack classTypes = new Stack(); |
||||||
|
for (int i = 0; i < classes.length; i++) |
||||||
|
classTypes.push(classes[i]); |
||||||
|
return ((ReferenceType)type).findCommonClassTypes(classTypes); |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() |
||||||
|
{ |
||||||
|
StringBuffer sb = new StringBuffer("{"); |
||||||
|
String comma = ""; |
||||||
|
for (int i=0; i< classes.length; i++) { |
||||||
|
sb.append(comma).append(classes[i]); |
||||||
|
comma = ", "; |
||||||
|
} |
||||||
|
return sb.append("}").toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public String getTypeSignature() { |
||||||
|
return getCanonic().getTypeSignature(); |
||||||
|
} |
||||||
|
|
||||||
|
public Class getTypeClass() throws ClassNotFoundException { |
||||||
|
return getCanonic().getTypeClass(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if we need to cast to a middle type, before we can cast from |
||||||
|
* fromType to this type. |
||||||
|
* @return the middle type, or null if it is not necessary. |
||||||
|
*/ |
||||||
|
public Type getCastHelper(Type fromType) { |
||||||
|
return getCanonic().getCastHelper(fromType); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Checks if this type represents a valid type instead of a list |
||||||
|
* of minimum types. |
||||||
|
*/ |
||||||
|
public boolean isValidType() { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 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() { |
||||||
|
return getCanonic().getDefaultName(); |
||||||
|
} |
||||||
|
|
||||||
|
public int hashCode() { |
||||||
|
int hash = 0; |
||||||
|
for (int i=0; i < classes.length; i++) { |
||||||
|
hash ^= classes[i].hashCode(); |
||||||
|
} |
||||||
|
return hash; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object o) { |
||||||
|
if (o == this) |
||||||
|
return true; |
||||||
|
if (o instanceof MultiClassType) { |
||||||
|
MultiClassType type = (MultiClassType) o; |
||||||
|
if (type.classes.length == classes.length) { |
||||||
|
big_loop: |
||||||
|
for (int i=0; i< type.classes.length; i++) { |
||||||
|
for (int j=0; j<classes.length; j++) { |
||||||
|
if (type.classes[i] == classes[j]) |
||||||
|
continue big_loop; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
/* SystemClassType Copyright (C) 1998-1999 Jochen Hoenicke. |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU 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 General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program; see the file COPYING. If not, write to |
||||||
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
||||||
|
* |
||||||
|
* $Id$ |
||||||
|
*/ |
||||||
|
|
||||||
|
package jode.type; |
||||||
|
import 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. |
||||||
|
* |
||||||
|
* @author Jochen Hoenicke |
||||||
|
*/ |
||||||
|
public class SystemClassType extends ClassType { |
||||||
|
ClassType superType; |
||||||
|
ClassType[] ifacesTypes; |
||||||
|
boolean isFinal, isInterface; |
||||||
|
|
||||||
|
/** |
||||||
|
* @param className The name of this system class, must be interned. |
||||||
|
*/ |
||||||
|
public SystemClassType(String className, |
||||||
|
ClassType superType, |
||||||
|
ClassType[] ifacesTypes, |
||||||
|
boolean isFinal, boolean isInterface) { |
||||||
|
super(TC_SYSCLASS, className); |
||||||
|
this.superType = superType; |
||||||
|
this.ifacesTypes = ifacesTypes; |
||||||
|
this.isFinal = isFinal; |
||||||
|
this.isInterface = isInterface; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isInterface() { |
||||||
|
return isInterface; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isFinal() { |
||||||
|
return isFinal; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isUnknown() { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public ClassType getSuperClass() { |
||||||
|
return superType; |
||||||
|
} |
||||||
|
|
||||||
|
public ClassType[] getInterfaces() { |
||||||
|
return ifacesTypes; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue