Mirror of the JODE repository
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
jode/jode/src/net/sf/jode/type/ClassType.java

360 lines
10 KiB

/* ClassType Copyright (C) 2000-2002 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; see the file COPYING.LESSER. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package net.sf.jode.type;
import java.util.Stack;
import java.util.Hashtable;
/**
* 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 (isInterface() || fromType == tNull
|| (fromType instanceof RangeType
&& ((RangeType)fromType).getBottom() == tNull))
return null;
Type hint = fromType.getHint();
if (hint.isSubTypeOf(this)
|| (hint instanceof ClassType
&& ((ClassType) hint).isInterface()))
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("abstract", Boolean.TRUE);
keywords.put("default", Boolean.TRUE);
keywords.put("if", Boolean.TRUE);
keywords.put("private", Boolean.TRUE);
keywords.put("throw", Boolean.TRUE);
keywords.put("boolean", Boolean.TRUE);
keywords.put("do", Boolean.TRUE);
keywords.put("implements", Boolean.TRUE);
keywords.put("protected", Boolean.TRUE);
keywords.put("throws", Boolean.TRUE);
keywords.put("break", Boolean.TRUE);
keywords.put("double", Boolean.TRUE);
keywords.put("import", Boolean.TRUE);
keywords.put("public", Boolean.TRUE);
keywords.put("transient", Boolean.TRUE);
keywords.put("byte", Boolean.TRUE);
keywords.put("else", Boolean.TRUE);
keywords.put("instanceof", Boolean.TRUE);
keywords.put("return", Boolean.TRUE);
keywords.put("try", Boolean.TRUE);
keywords.put("case", Boolean.TRUE);
keywords.put("extends", Boolean.TRUE);
keywords.put("int", Boolean.TRUE);
keywords.put("short", Boolean.TRUE);
keywords.put("void", Boolean.TRUE);
keywords.put("catch", Boolean.TRUE);
keywords.put("final", Boolean.TRUE);
keywords.put("interface", Boolean.TRUE);
keywords.put("static", Boolean.TRUE);
keywords.put("volatile", Boolean.TRUE);
keywords.put("char", Boolean.TRUE);
keywords.put("finally", Boolean.TRUE);
keywords.put("long", Boolean.TRUE);
keywords.put("super", Boolean.TRUE);
keywords.put("while", Boolean.TRUE);
keywords.put("class", Boolean.TRUE);
keywords.put("float", Boolean.TRUE);
keywords.put("native", Boolean.TRUE);
keywords.put("switch", Boolean.TRUE);
keywords.put("const", Boolean.TRUE);
keywords.put("for", Boolean.TRUE);
keywords.put("new", Boolean.TRUE);
keywords.put("synchronized", Boolean.TRUE);
keywords.put("continue", Boolean.TRUE);
keywords.put("goto", Boolean.TRUE);
keywords.put("package", Boolean.TRUE);
keywords.put("this", Boolean.TRUE);
keywords.put("strictfp", Boolean.TRUE);
keywords.put("null", Boolean.TRUE);
keywords.put("true", Boolean.TRUE);
keywords.put("false", 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;
}
}