/*
* System.Reflection-like API for access to .NET assemblies (DLL & EXE)
*/
package ch.epfl.lamp.compiler.msil;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Arrays;
/**
* Represents type declarations: class types, interface types, array types,
* value types, and enumeration types.
*
* @author Nikolay Mihaylov
* @version 1.0
*/
public abstract class Type extends MemberInfo {
private java.util.List /* GenericParamAndConstraints */ tVars = new java.util.LinkedList();
private GenericParamAndConstraints[] sortedTVars = null;
public void addTVar(GenericParamAndConstraints tvarAndConstraints) {
sortedTVars = null;
tVars.add(tvarAndConstraints);
}
public GenericParamAndConstraints[] getSortedTVars() {
if(sortedTVars == null) {
sortedTVars = new GenericParamAndConstraints[tVars.size()];
for (int i = 0; i < sortedTVars.length; i ++){
Iterator iter = tVars.iterator();
while(iter.hasNext()) {
GenericParamAndConstraints tvC = (GenericParamAndConstraints)iter.next();
if(tvC.Number == i) {
sortedTVars[i] = tvC;
}
}
}
}
return sortedTVars;
}
//##########################################################################
// public static members
/** Empty array of type Type. */
public static final Type[] EmptyTypes = new Type[0];
/** Separates names in the namespace of the Type. */
public static final char Delimiter = '.';
//##########################################################################
// public properties
/** The fully qualified name of the Type. */
public final String FullName;
/** The namespace of the Type. */
public final String Namespace;
/** The type from which the current Type directly inherits. */
public final Type BaseType() {
initBaseType();
return baseType;
}
protected Type baseType;
/** The attributes associated with the Type. */
public final int Attributes;
/** The sssembly that the type is declared in. */
public final Assembly Assembly() { return Module.Assembly; }
/** The module (the EXE/DLL) in which the current Type is defined. */
public final Module Module;
public final int MemberType() {
return DeclaringType == null
? MemberTypes.TypeInfo : MemberTypes.NestedType;
}
//##########################################################################
// internal members
// Fields declared by this class
protected FieldInfo[] fields;
// Methods declared by this class
protected MethodInfo[] methods;
// Constructors of this class
protected ConstructorInfo[] constructors;
// Properties of the class
protected PropertyInfo[] properties;
// Events of the class
protected EventInfo[] events;
// Interfaces implemented by this class
protected Type[] interfaces;
// Nested types declared by this class
protected Type[] nestedTypes;
// holds the element type of array, pointer and byref types
private final Type elemType;
// the underlying type of an enumeration. null if the type is not enum.
protected Type underlyingType;
protected int auxAttr;
//##########################################################################
// Map with all the types known so far and operations on it
private static final Map types = new HashMap();
protected static Type getType(String name) {
return (Type) types.get(name);
}
protected static Type addType(Type t) {
assert(!(t instanceof TMVarUsage));
assert(!(t instanceof ConstructedType));
Type oldType = (Type) types.put(t.FullName, t);
// if (oldType != null)
// throw new RuntimeException("The type: [" + t.Assembly + "]" + t
// + " replaces the type: [" +
// oldType.Assembly + "]" + oldType);
return t;
}
//##########################################################################
/** The main constructor. */
protected Type(Module module,
int attr,
String fullName,
Type baseType,
Type[] interfaces,
Type declType,
int auxAttr,
Type elemType)
{
super(fullName.lastIndexOf(Delimiter) < 0 ? fullName :
fullName.substring(fullName.lastIndexOf(Delimiter) + 1,
fullName.length()),
declType);
Module = module; // null only for TMVarUsage and for PrimitiveType
Attributes = attr;
this.baseType = baseType;
if (DeclaringType == null) {
FullName = fullName;
int i = FullName.lastIndexOf(Delimiter);
Namespace = (i < 0) ? "" : FullName.substring(0,i);
} else {
FullName = declType.FullName + "+" + fullName;
Namespace = DeclaringType.Namespace;
}
this.interfaces = interfaces;
this.elemType = elemType;
this.auxAttr = auxAttr;
}
public final boolean IsAbstract() {
return (Attributes & TypeAttributes.Abstract) != 0;
}
public final boolean IsPublic() {
return (Attributes & TypeAttributes.VisibilityMask)
== TypeAttributes.Public;
}
public final boolean IsNotPublic() {
return (Attributes & TypeAttributes.VisibilityMask)
== TypeAttributes.NotPublic;
}
public final boolean IsNestedPublic() {
return (Attributes & TypeAttributes.VisibilityMask)
== TypeAttributes.NestedPublic;
}
public final boolean IsNestedPrivate() {
return (Attributes & TypeAttributes.VisibilityMask)
== TypeAttributes.NestedPrivate;
}
public final boolean IsNestedFamily() {
return (Attributes & TypeAttributes.VisibilityMask)
== TypeAttributes.NestedFamily;
}
public final boolean IsNestedAssembly() {
return (Attributes & TypeAttributes.VisibilityMask)
== TypeAttributes.NestedAssembly;
}
public final boolean IsNestedFamORAssem() {
return (Attributes & TypeAttributes.VisibilityMask)
== TypeAttributes.NestedFamORAssem;
}
public final boolean IsNestedFamANDAssem() {
return (Attributes & TypeAttributes.VisibilityMask)
== TypeAttributes.NestedFamANDAssem;
}
public final boolean IsSealed() {
return (Attributes & TypeAttributes.Sealed) != 0;
}
public final boolean IsSpecialName() {
return (Attributes & TypeAttributes.SpecialName) != 0;
}
public final boolean IsClass() {
return (Attributes & TypeAttributes.ClassSemanticsMask)
== TypeAttributes.Class;
}
public final boolean IsInterface(){
return (Attributes & TypeAttributes.ClassSemanticsMask)
== TypeAttributes.Interface;
}
public final boolean IsAutoLayout() {
return (Attributes & TypeAttributes.LayoutMask)
== TypeAttributes.AutoLayout;
}
public final boolean IsExplictitLayout() {
return (Attributes & TypeAttributes.LayoutMask)
== TypeAttributes.ExplicitLayout;
}
public final boolean IsLayoutSequential() {
return (Attributes & TypeAttributes.LayoutMask)
== TypeAttributes.SequentialLayout;
}
public final boolean IsImport() {
return (Attributes & TypeAttributes.Import) != 0;
}
public final boolean IsSerializable() {
return (Attributes & TypeAttributes.Serializable) != 0;
}
public final boolean IsAnsiClass() {
return (Attributes & TypeAttributes.StringFormatMask)
== TypeAttributes.AnsiClass;
}
public final boolean IsUnicodeClass() {
return (Attributes & TypeAttributes.StringFormatMask)
== TypeAttributes.UnicodeClass;
}
public final boolean IsAutoClass() {
return (Attributes & TypeAttributes.StringFormatMask)
== TypeAttributes.AutoClass;
}
public final boolean IsArray() {
return (auxAttr & AuxAttr.Array) != 0;
}
public final boolean IsByRef() {
return (auxAttr & AuxAttr.ByRef) != 0;
}
public final boolean IsPointer() {
return (auxAttr & AuxAttr.Pointer) != 0;
}
public final boolean IsPrimitive() {
return (auxAttr & AuxAttr.Primitive) != 0;
}
public final boolean IsValueType() {
return BaseType() == VALUE_TYPE() || IsEnum();
}
public final boolean IsEnum() {
return BaseType() == ENUM();
}
public boolean CanBeTakenAddressOf() {
/* TODO should be overridden in TMVarUsage,
but there's currently no way to bind a TMVarUsage to its GenericParamAndConstraints definition. Why?
Because of the way the msil library is organized (e.g., mkArray() returns the same !0[] representation
for all !0[] usages, irrespective of the scope of the !0 type-param)
This in turn is so because without generics there's no harm in using a type-def instance
where a type-ref should go (e.g., the ParameterType of a ParameterInfo nowadays may point to a PEType).
The net effect is that this method (CanBeTakenAddressOf) is conservative, it will answer "no"
for example for !0 where !0 refers to a type-param with the isValuetype constraint set.
The whole thing is ok at this point in time, where generics are not supported at the backend. */
return IsValueType() && (this != ENUM());
/* ENUM() is a singleton, i.e. System.Enum is not generic */
}
/** IsGeneric, true for a PEType or TypeBuilder (i.e., a type definition)
* containing one or more type params. Not to be called on a reference
* to a constructed type. */
public final boolean IsGeneric() {
return tVars.size() > 0;
}
public final boolean HasElementType() {
return IsArray() || IsPointer() || IsByRef();
}
public boolean IsTMVarUsage() {
// overridden in TMVarUsage
return false;
}
public boolean IsNestedType() {
return DeclaringType != null;
}
public boolean IsDefinitelyInternal() {
if(IsNestedType()) {
return IsNestedPrivate();
} else {
return IsNotPublic();
}
}
//public final boolean IsCOMObject;
//public final boolean IsContextful;
//public final boolean IsMarshalByRef;
protected Type(Module module,
int attr,
String fullName,
Type baseType,
Type[] interfaces,
Type declType,
int auxAttr)
{
this(module, attr, fullName, baseType, interfaces,
declType, auxAttr, null);
}
//##########################################################################
public static final class TMVarUsage extends Type {
public final int Number;
public final boolean isTVar;
/** Non-defining reference to either a TVar or an MVar.
* An instance of GenericParamAndConstraints represents a TVar or an MVar definition. */
public TMVarUsage(int Number, boolean isTVar) {
super(null, 0, ((isTVar ? "!" : "!!") + Number), null, null, null, AuxAttr.None, null);
this.Number = Number;
this.isTVar = isTVar;
}
public String toString() {
return (isTVar ? "!" : "!!") + Number;
}
public final boolean IsTMVarUsage() {
return true;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TMVarUsage that = (TMVarUsage) o;
if (Number != that.Number) return false;
if (isTVar != that.isTVar) return false;
return true;
}
public int hashCode() {
int result = Number;
result = 31 * result + (isTVar ? 1 : 0);
return result;
}
}
protected static final class AuxAttr {
public static final int None = 0x0000;
public static final int Array = 0x0001;
public static final int ByRef = 0x0002;
public static final int Pointer = 0x0008;
public static final int Primitive = 0x0010;
}
/***/
public static Type mkArray(Type elemType, int rank) {
StringBuffer arrSig = new StringBuffer("[");
for (int i = 0; i < rank; i++) {
if (i > 0) arrSig.append(',');
}
arrSig.append(']');
Type array = getType(elemType.FullName + arrSig);
if (array != null)
return array;
array = new PrimitiveType(elemType.Module,
elemType.Attributes
| TypeAttributes.Sealed
| TypeAttributes.Serializable,
elemType.FullName + arrSig,
ARRAY(), EmptyTypes, null,
AuxAttr.Array, elemType);
return addType(array);
}
/***/
public static Type mkPtr(Type elemType) {
String name = elemType.FullName + "*";
Type type = getType(name);
if (type != null) return type;
type = new PrimitiveType(elemType.Module,
elemType.Attributes,
name, null, EmptyTypes, null,
AuxAttr.Pointer, elemType);
return addType(type);
}
/***/
public static Type mkByRef(Type elemType) {
String name = elemType.FullName + "&";
Type type = getType(name);
if (type != null) return type;
type = new PrimitiveType(elemType.Module,
elemType.Attributes,
name, null, EmptyTypes, null,
AuxAttr.ByRef, elemType);
return addType(type);
}
//##########################################################################
// public methods
/**
* Return the type with the specified signature parameters.
* For example, the fully qualified name for a class might look like this:
* TopNamespace.SubNameSpace.ContainingClass+NestedClass,MyAssembly
*/
public static Type GetType(String fullName) {
Type type = getType(fullName);
if (type != null) return type;
// check if it's an array type; TODO: make array type handling more robust
int i = fullName.lastIndexOf('[');
int j = fullName.lastIndexOf(']');
if (i >= 0)
if (j > i && j == (fullName.length() - 1)) {
String elementTypeName = fullName.substring(0, i);
Type elementType = GetType(elementTypeName);
if (elementType == null)
throw new RuntimeException
("Unknown element type '" + elementTypeName +
"' for the array type: " + fullName);
int rank = j - i;
for (int k = i + 1; k < j; k++) {
if (fullName.charAt(k) != ',')
throw new RuntimeException
("Malformed type name: " + fullName);
}
return mkArray(elementType, rank);
} else
throw new RuntimeException("Malformed type name: " + fullName);
// check if it's a pointer type
if (fullName.charAt(fullName.length() - 1) == '*')
return addType
(mkPtr(GetType(fullName.substring(0, fullName.length()-1))));
// check if it's a nested class
i = fullName.lastIndexOf('+');
if (i > 0) {
if (i == 0 || i == (fullName.length() - 1))
throw new RuntimeException("malformedTypeName");
Type enclosing = GetType(fullName.substring(0, i));
return enclosing == null ? null
: enclosing.GetNestedType(fullName.substring(i + 1));
}
//System.out.println("Looking for type: " + fullName + " (" + fullName.length() + ")");
// try in the assemblies
Iterator assems = ch.epfl.lamp.compiler.msil.Assembly.
assemblies.values().iterator();
while (type == null && assems.hasNext()) {
Assembly assem = ((Assembly) assems.next());
type = assem.GetType(fullName);
//System.out.println("\tin assemby " + assem + " -> " + type);
}
Type type2 = getType(fullName);
if (type == type2) return type;
return type == null ? null : addType(type);
}
/**
* @return the type of the object encompassed or referenced to
* by the current array, pointer or reference type.
*/
public Type GetElementType() {
return elemType;
}
/**
* @return the type underlying an enumeration type.
*/
public Type getUnderlyingType() {
if (!IsEnum()) return null;
// this would force the loading of the underlying type from the
// the type of the value__ field of the enumeration
initFields();
return underlyingType;
}
//##########################################################################
// GetField/s/
/** Searches for the field with the specified name. */
public FieldInfo GetField(String name) {
initFields();
for (int i = 0; i < fields.length; i++)
if (fields[i].Name.equals(name) && !fields[i].IsPrivate())
return fields[i];
return null;
}
/**
*/
public FieldInfo GetField(String name, int bindingFlags) {
FieldInfo[] fields = this.GetFields(bindingFlags);
for (int i = 0; i < fields.length; i++)
if (name.equals(fields[i].Name))
return fields[i];
return null;
}
/** Gets the fields of the current Type. */
public FieldInfo[] GetFields() {
return GetFields(BindingFlags.Instance | BindingFlags.Public);
}
/**
*/
public FieldInfo[] GetFields(int bindingFlags) {
initFields();
final FieldInfo[] fields =
getAllFields((bindingFlags & BindingFlags.DeclaredOnly) != 0);
final boolean getInstance = (bindingFlags & BindingFlags.Instance) != 0;
final boolean getStatic = (bindingFlags & BindingFlags.Static) != 0;
final boolean getPublic = (bindingFlags & BindingFlags.Public) != 0;
final boolean getNonPublic =
(bindingFlags & BindingFlags.NonPublic) != 0;
int cnt = 0;
for (int i = 0; i < fields.length; i++) {
FieldInfo field = fields[i];
boolean accessible = (getPublic && field.IsPublic())
|| (getNonPublic && !field.IsPublic());
if (accessible
// strip off the private fields up the hierarchy
&& ((field.DeclaringType == this)
|| ((field.DeclaringType != this) && !field.IsPrivate()))
&& ((getInstance && !field.IsStatic())
|| ((getStatic && field.IsStatic()) &&
(field.DeclaringType == this
|| (bindingFlags & BindingFlags.FlattenHierarchy) != 0))
)
)
fields[cnt++] = field;
}
FieldInfo [] resFields = new FieldInfo[cnt];
System.arraycopy(fields, 0, resFields, 0, cnt);
return resFields;
}
protected FieldInfo[] getAllFields(boolean declaredOnly) {
initFields();
FieldInfo [] inherited = BaseType() == null || declaredOnly
? FieldInfo.EMPTY_ARRAY
: BaseType().getAllFields(declaredOnly);
FieldInfo[] allFields =
new FieldInfo[inherited.length + this.fields.length];
System.arraycopy(inherited, 0, allFields, 0, inherited.length);
System.arraycopy(this.fields, 0,
allFields, inherited.length, this.fields.length);
return allFields;
}
//##########################################################################
// GetConstructor/s/
/** Searches for a public instance constructor whose parameters
* match the types in the specified array. */
public ConstructorInfo GetConstructor(Type[] paramTypes) {
initMethods();
for (int i = 0; i < constructors.length; i++) {
if (equalParameters(constructors[i].GetParameters(), paramTypes))
return constructors[i];
}
return null;
}
/** Returns all public instance constructors defined for the current Type.*/
public ConstructorInfo[] GetConstructors() {
return GetConstructors(BindingFlags.Instance | BindingFlags.Public);
}
/***/
public ConstructorInfo[] GetConstructors(int bindingFlags) {
initMethods();
final boolean getInstance = (bindingFlags & BindingFlags.Instance) != 0;
final boolean getStatic = (bindingFlags & BindingFlags.Static) != 0;
final boolean getPublic = (bindingFlags & BindingFlags.Public) != 0;
final boolean getNonPublic =
(bindingFlags & BindingFlags.NonPublic) != 0;
ConstructorInfo[] constrs =
new ConstructorInfo[this.constructors.length];
int cnt = 0;
for (int i = 0; i < this.constructors.length; i++) {
ConstructorInfo constr = this.constructors[i];
boolean accessible = (getPublic && constr.IsPublic())
|| (getNonPublic && !constr.IsPublic());
if (accessible
&& ((getInstance && !constr.IsStatic())
|| (getStatic && constr.IsStatic())))
constrs[cnt++] = constr;
}
ConstructorInfo [] resConstrs = new ConstructorInfo[cnt];
System.arraycopy(constrs, 0, resConstrs, 0, cnt);
return resConstrs;
}
//##########################################################################
// GetMethod/s/
/** Searches for the specified public method whose parameters
* match the specified argument types. */
public MethodInfo GetMethod(String name, Type[] paramTypes) {
return GetMethod(name, paramTypes, null);
}
public MethodInfo GetMethod(String name, Type[] paramTypes, Type retType) {
initMethods();
MethodInfo method = findMethod(methods, name, paramTypes, retType);
if (method != null)
return method;
if (BaseType() != null) {
method = BaseType().GetMethod(name, paramTypes, retType);
if (method != null)
return method;
}
// StringBuffer str = new StringBuffer(name);
// str.append('(');
// for (int i = 0; i < paramTypes.length; i++) {
// if (i > 0) str.append(", ");
// str.append(paramTypes[i]);
// }
// str.append(')');
// System.out.println("Cannot find method " + str + ":");
// System.out.println("Methods of class " + this);
// for (int i = 0; i < methods.length; i++)
// System.out.println("\t" + methods[i]);
return null;
}
/**
*/
protected static MethodInfo findMethod(MethodInfo[] methods,
String name,
Type[] paramTypes,
Type retType)
{
for (int i = 0; i < methods.length; i++)
if (name.equals(methods[i].Name)
&& equalParameters(methods[i].GetParameters(), paramTypes)
&& (retType == null || methods[i].ReturnType == retType))
return methods[i];
return null;
}
/**
*/
protected static boolean equalParameters(ParameterInfo[] params,
Type[] paramTypes)
{
if (params.length != paramTypes.length)
return false;
for (int i = 0; i < params.length; i++) {
// System.out.println(params[i].ParameterType + " == " + paramTypes[i]
// + " = " + (params[i].ParameterType == paramTypes[i]));
if (params[i].ParameterType != paramTypes[i])
return false;
}
return true;
}
/**
*/
public MethodInfo GetMethod(String name, Type[] paramTypes, int bindingFlags) {
MethodInfo[] methods = GetMethods(bindingFlags);
MethodInfo method = findMethod(methods, name, paramTypes, null);
if (method == null) {
StringBuffer str = new StringBuffer(name);
str.append('(');
for (int i = 0; i < paramTypes.length; i++) {
if (i > 0) str.append(", ");
str.append(paramTypes[i]);
}
str.append(')');
System.out.println("Cannot find method " + str + ":");
System.out.println("Methods of class " + this);
for (int i = 0; i < methods.length; i++)
System.out.println("\t" + methods[i]);
}
return method;
}
/** Returns all public methods of the current Type. */
public MethodInfo[] GetMethods() {
return GetMethods(BindingFlags.Instance | BindingFlags.Public);
}
/**
*/
public MethodInfo[] GetMethods(int bindingFlags) {
initMethods();
final MethodInfo[] methods =
getAllMethods((bindingFlags & BindingFlags.DeclaredOnly) != 0);
//System.out.println("" + this + ".GetMethods(int) -> " + methods.length);
final boolean getInstance = (bindingFlags & BindingFlags.Instance) != 0;
final boolean getStatic = (bindingFlags & BindingFlags.Static) != 0;
final boolean getPublic = (bindingFlags & BindingFlags.Public) != 0;
final boolean getNonPublic =
(bindingFlags & BindingFlags.NonPublic) != 0;
int cnt = 0;
for (int i = 0; i < methods.length; i++) {
MethodInfo method = methods[i];
boolean accessible = (getPublic && method.IsPublic())
|| (getNonPublic && !method.IsPublic());
if (accessible
// strip off the private methods up the hierarchy
&& ((method.DeclaringType == this)
|| ((method.DeclaringType != this) && !method.IsPrivate()))
&& ((getInstance && !method.IsStatic())
|| ((getStatic && method.IsStatic()) &&
(method.DeclaringType == this
|| (bindingFlags & BindingFlags.FlattenHierarchy) != 0))
)
)
methods[cnt++] = method;
}
MethodInfo [] resMethods = new MethodInfo[cnt];
System.arraycopy(methods, 0, resMethods, 0, cnt);
return resMethods;
}
protected MethodInfo[] getAllMethods(boolean declaredOnly) {
initMethods();
MethodInfo[] inherited = BaseType() == null || declaredOnly
? MethodInfo.EMPTY_ARRAY
: BaseType().getAllMethods(declaredOnly);
MethodInfo[] allMethods =
new MethodInfo[inherited.length + this.methods.length];
System.arraycopy(inherited, 0, allMethods, 0, inherited.length);
System.arraycopy(this.methods, 0,
allMethods, inherited.length, this.methods.length);
return allMethods;
}
//##########################################################################
// GetProperty/ies/
/** Returns all public properties of the current Type.
*/
public PropertyInfo[] GetProperties() {
initProperties();
return (PropertyInfo[]) properties.clone();
}
/** Returns the properties of the current class
* that satisfy the binding constrints.
*/
public PropertyInfo[] GetProperties(int bindingFlags) {
initProperties();
return (PropertyInfo[]) properties.clone();
}
/** Returns the public property with the given name.
*/
public PropertyInfo GetProperty(String name) {
initProperties();
for (int i = 0; i < properties.length; i++)
if (name.equals(properties[i].Name))
return properties[i];
return null;
}
/** Returns the property with the given name
* that satisfies the binding constraints.
*/
public PropertyInfo GetProperty(String name, int bindingFlags) {
throw new RuntimeException("Method not implemented yet");
}
//##########################################################################
// GetEvent(s)
public EventInfo[] GetEvents() {
initEvents();
return (EventInfo[]) events.clone();
}
//##########################################################################
// GetNestedType/s/
/** Searches for nested type with the specified name. */
public Type GetNestedType(String name) {
initNestedTypes();
for (int i = 0; i < nestedTypes.length; i++)
if (nestedTypes[i].Name.equals(name))
return nestedTypes[i];
return null;
}
/** Returns all types nested within the current Type. */
public Type[] GetNestedTypes() {
initNestedTypes();
return (Type[]) nestedTypes.clone();
}
//##########################################################################
// GetInterface/s/
/** Searches for an Interface with the given name implemented by this type
*/
public Type GetInterface(String name) {
return GetInterface(name, false);
}
/** Searches for the specified interface,
* specifying whether to do a case-sensitive search.
* @param name - the name of the interface to get
* @param ignoreCase <b>true</b> to perform a case-insensitive search for name
* <b>false</b> to perform a case-sensitive search for name
* @return A Type object representing the interface with the specified name,
* implemented or inherited by the current Type, if found;
* otherwise, a null reference
*/
public Type GetInterface(String name, boolean ignoreCase) {
initInterfaces();
for (int i = 0; i < interfaces.length; i++) {
Type iface = interfaces[i];
if (ignoreCase) {
if (name.equalsIgnoreCase(iface.Name)) return iface;
if (name.equalsIgnoreCase(iface.FullName)) return iface;
} else {
if (name.equals(iface.Name)) return iface;
if (name.equals(iface.FullName)) return iface;
}
}
return BaseType() == null ? null
: BaseType().GetInterface(name, ignoreCase);
}
/** Returns the interfaces implemented or inherited by the current Type. */
public Type[] GetInterfaces() {
initInterfaces();
if (BaseType() == null) return interfaces;
Type[] ifaces = interfaces;
int count = 0;
for (int i = 0; i < interfaces.length; i++) {
if (BaseType().GetInterface(interfaces[i].FullName) == null)
ifaces[count++] = ifaces[i];
}
Type[] baseTypeIfaces = BaseType().GetInterfaces();
Type[] res = new Type[baseTypeIfaces.length + count];
System.arraycopy(baseTypeIfaces, 0, res, 0, baseTypeIfaces.length);
System.arraycopy(ifaces, 0, res, baseTypeIfaces.length, count);
return res;
}
public boolean isSubtypeOf(Type that) {
if (this == that || BaseType() == that || that == OBJECT()) return true;
initInterfaces();
for (int i = 0; i < interfaces.length; i++)
if (interfaces[i].isSubtypeOf(that))
return true;
boolean res = BaseType() == null ? false : BaseType().isSubtypeOf(that);
// if (!res) {
// System.out.println(dumpType(this) + " not a subtype of " +
// dumpType(that));
// }
return res;
}
private static String formatType(Type t) {
if (t == null) return "<null>";
String cname = t.getClass().getName();
int k = cname.lastIndexOf(".");
if (k >= 0)
cname = cname.substring(k + 1);
return "[" + t.Assembly().GetName() + "]" + t +
"(" + cname + "#" + Integer.toHexString(t.hashCode()) + ")";
}
private static String dumpType(Type t) {
StringBuffer str = new StringBuffer();
str.append(formatType(t) + " : ");
str.append(formatType(t.BaseType()));
Type[] ifaces = t.GetInterfaces();
for (int i = 0; i < ifaces.length; i++)
str.append(", " + formatType(ifaces[i]));
return str.toString();
}
//##########################################################################
// GetMember/s/
protected MemberInfo[] members;
public MemberInfo[] GetMember(String name) {
aggregateMembers();
List l = new ArrayList();
for (int i = 0; i < members.length; i++) {
if (name.equals(members[i].Name))
l.add(members[i]);
}
return (MemberInfo[])l.toArray(MemberInfo.EMPTY_ARRAY);
}
protected void aggregateMembers() {
if (members != null)
return;
initFields();
initMethods();
initProperties();
initNestedTypes();
// the List returned by Arrays.asList doesn't support the addAll method
// so we have to wrap it in ArrayList
List l = new ArrayList(Arrays.asList(fields));
l.addAll(Arrays.asList(constructors));
l.addAll(Arrays.asList(methods));
l.addAll(Arrays.asList(properties));
l.addAll(Arrays.asList(nestedTypes));
members = (MemberInfo[]) l.toArray(MemberInfo.EMPTY_ARRAY);
}
//##########################################################################
// non-standard methods that return only members declared in this type
/**
* Return only the fields declared in this type.
*/
public FieldInfo[] getFields() {
initFields();
FieldInfo[] fields = new FieldInfo[this.fields.length];
System.arraycopy(this.fields, 0, fields, 0, fields.length);
return fields;
}
/**
* Return only the conrtuctors declared in this type.
*/
public ConstructorInfo[] getConstructors() {
initMethods();
ConstructorInfo[] ctors = new ConstructorInfo[constructors.length];
System.arraycopy(constructors, 0, ctors, 0, ctors.length);
return ctors;
}
/**
* Return only the methods declared in this type.
*/
public MethodInfo[] getMethods() {
initMethods();
MethodInfo[] methods = new MethodInfo[this.methods.length];
System.arraycopy(this.methods, 0, methods, 0, methods.length);
return methods;
}
/**
* Return only the properties declared in this type.
*/
public PropertyInfo[] getProperties() {
initProperties();
PropertyInfo[] props = new PropertyInfo[properties.length];
System.arraycopy(properties, 0, props, 0, props.length);
return props;
}
/**
* Return only the interfaces directly implemented by this type.
*/
public Type[] getInterfaces() {
initInterfaces();
Type[] ifaces = new Type[interfaces.length];
System.arraycopy(interfaces, 0, ifaces, 0, ifaces.length);
return ifaces;
}
/**
* Return the types declared in this type.
*/
public Type[] getNestedTypes() {
initNestedTypes();
Type[] nested = new Type[nestedTypes.length];
System.arraycopy(nestedTypes, 0, nested, 0, nested.length);
return nested;
}
//##########################################################################
public String toString() {
return FullName;
}
//##########################################################################
// lazy type construction members
private boolean initBaseType = true;
protected final void initBaseType() {
if (initBaseType) {
loadBaseType();
initBaseType = false;
}
}
protected void loadBaseType() {}
private boolean initInterfaces = true;
protected void initInterfaces() {
if (initInterfaces) {
loadInterfaces();
initInterfaces = false;
}
assert interfaces != null : "In type " + this;
}
protected void loadInterfaces() {}
private boolean initNestedTypes = true;
protected void initNestedTypes() {
if (initNestedTypes) {
loadNestedTypes();
initNestedTypes = false;
}
assert nestedTypes != null : "In type " + this;
}
protected void loadNestedTypes() {}
private boolean initFields = true;
protected void initFields() {
if (initFields) {
loadFields();
initFields = false;
}
assert fields != null : "In type " + this;
}
protected void loadFields() {}
private boolean initMethods = true;
protected void initMethods() {
if (initMethods) {
loadMethods();
initMethods = false;
}
assert constructors != null : "In type " + this;
assert methods != null : "In type " + this;
}
protected void loadMethods() {}
private boolean initProperties = true;
protected void initProperties() {
if (initProperties) {
initMethods();
loadProperties();
initProperties = false;
}
assert properties != null : "In type " + this;
}
protected void loadProperties() {}
private boolean initEvents = true;
protected void initEvents() {
if (initEvents) {
initMethods();
loadEvents();
initEvents = false;
}
assert events != null : "In type " + this;
}
protected void loadEvents() {}
//##########################################################################
//##########################################################################
// static members
private static Assembly MSCORLIB;
private static Module MSCORLIB_DLL;
public static Type OBJECT() { return __OBJECT; }
public static Type STRING() { return __STRING; }
public static Type ARRAY() { return __ARRAY; }
public static Type VOID() { return __VOID; }
public static Type ENUM() { return __ENUM; }
public static Type VALUE_TYPE() { return __VALUE_TYPE; }
private static Type __OBJECT;
private static Type __STRING;
private static Type __ARRAY;
private static Type __VOID;
private static Type __ENUM;
private static Type __VALUE_TYPE;
public static void initMSCORLIB(Assembly mscorlib) {
if (MSCORLIB != null)
throw new RuntimeException("mscorlib already initialized");
MSCORLIB = mscorlib;
MSCORLIB_DLL = MSCORLIB.GetModules()[0];
__OBJECT = mscorlib.GetType("System.Object");
__STRING = mscorlib.GetType("System.String");
__ARRAY = mscorlib.GetType("System.Array");
__VOID = mscorlib.GetType("System.Void");
__ENUM = mscorlib.GetType("System.Enum");
__VALUE_TYPE = mscorlib.GetType("System.ValueType");
}
//##########################################################################
} // class Type