0001: // Copyright (c) 1997, 1998, 1999, 2001, 2002, 2004, 2005 Per M.A. Bothner.
0002: // This is free software; for terms and warranty disclaimer see ./COPYING.
0003:
0004: package gnu.bytecode;
0005:
0006: import java.io.*;
0007: import java.util.Vector;
0008:
0009: public class ClassType extends ObjectType implements AttrContainer,
0010: Externalizable {
0011: // An old but generally valid default value.
0012: int classfileFormatVersion = 45 * 0x10000 + 3;
0013:
0014: public short getClassfileMajorVersion() {
0015: return (short) (classfileFormatVersion >> 16);
0016: }
0017:
0018: public short getClassfileMinorVersion() {
0019: return (short) (classfileFormatVersion & 0xFFFF);
0020: }
0021:
0022: public void setClassfileVersion(int major, int minor) {
0023: classfileFormatVersion = (major & 0xFFFF) * 0x10000
0024: + (minor * 0xFFFF);
0025: }
0026:
0027: public void setClassfileVersionJava5() {
0028: setClassfileVersion(49, 0);
0029: }
0030:
0031: /** Find a ClassType with the given name, or create a new one.
0032: * Use this for "library classes", where you need the field/method types,
0033: * but not one where you are about to generate code for.
0034: * @param name the name of the class (e..g. "java.lang.String").
0035: */
0036: public static ClassType make(String name) {
0037: return (ClassType) Type.getType(name);
0038: }
0039:
0040: public static ClassType make(String name, ClassType super Class) {
0041: ClassType type = make(name);
0042: if (type.super Class == null)
0043: type.setSuper(super Class);
0044: return type;
0045: }
0046:
0047: int this ClassIndex;
0048:
0049: /** The super (base) class of the current class.
0050: * X.superClass == null means the superClass has not been specified,
0051: * and defaults to java.lang.Object. */
0052: ClassType super Class;
0053: /** The constant pool index of the superClass, or -1 if unassigned. */
0054: int super ClassIndex = -1;
0055:
0056: ClassType[] interfaces;
0057: int[] interfaceIndexes;
0058: public int access_flags;
0059:
0060: Attribute attributes;
0061:
0062: public final Attribute getAttributes() {
0063: return attributes;
0064: }
0065:
0066: public final void setAttributes(Attribute attributes) {
0067: this .attributes = attributes;
0068: }
0069:
0070: public static final ClassType[] noClasses = {};
0071:
0072: boolean emitDebugInfo = true;
0073:
0074: ConstantPool constants;
0075:
0076: public final ConstantPool getConstants() {
0077: return constants;
0078: }
0079:
0080: public final CpoolEntry getConstant(int i) {
0081: if (constants == null || constants.pool == null
0082: || i > constants.count)
0083: return null;
0084: return constants.pool[i];
0085: }
0086:
0087: /** Return the modifiers (access flags) for this class. */
0088: public final int getModifiers() {
0089: if (access_flags == 0 && (flags & EXISTING_CLASS) != 0
0090: && getReflectClass() != null)
0091: access_flags = reflectClass.getModifiers();
0092: return access_flags;
0093: }
0094:
0095: /** Set the modifiers (access flags) for this class. */
0096: public final void setModifiers(int flags) {
0097: access_flags = flags;
0098: }
0099:
0100: public final boolean hasOuterLink() {
0101: getFields();
0102: return (flags & HAS_OUTER_LINK) != 0;
0103: }
0104:
0105: public ClassType getOuterLinkType() {
0106: return !hasOuterLink() ? null : (ClassType) getDeclaredField(
0107: "this$0").getType();
0108: }
0109:
0110: /** Note that this class needs an other link ("this$0") field.
0111: * This is only allowed if !isExisting().
0112: * Adjust any existing "<init>" methods to take the extra
0113: * implicit parameter.
0114: * @param outer the outer class
0115: */
0116: public final Field setOuterLink(ClassType outer) {
0117: if ((flags & EXISTING_CLASS) != 0)
0118: throw new Error("setOuterLink called for existing class "
0119: + getName());
0120: Field field = getDeclaredField("this$0");
0121: if (field == null) {
0122: field = addField("this$0", outer);
0123: flags |= HAS_OUTER_LINK;
0124: for (Method meth = methods; meth != null; meth = meth
0125: .getNext()) {
0126: if ("<init>".equals(meth.getName())) {
0127: if (meth.code != null)
0128: throw new Error("setOuterLink called when "
0129: + meth + " has code");
0130: Type[] arg_types = meth.arg_types;
0131: Type[] new_types = new Type[arg_types.length + 1];
0132: System.arraycopy(arg_types, 0, new_types, 1,
0133: arg_types.length);
0134: new_types[0] = outer;
0135: meth.arg_types = new_types;
0136: meth.signature = null;
0137: }
0138: }
0139: } else if (!outer.equals(field.getType()))
0140: throw new Error("inconsistent setOuterLink call for "
0141: + getName());
0142: return field;
0143: }
0144:
0145: /** Check if a component is accessible from this class.
0146: * @param declaring the class containing the component (a field, method,
0147: * or inner class)
0148: * @param modifiers the access flags of the component
0149: * @return true if the specified component can be accessed from this class.
0150: */
0151: public boolean isAccessible(ClassType declaring, int modifiers) {
0152: int cmods = declaring.getModifiers();
0153: if ((modifiers & Access.PUBLIC) != 0
0154: && (cmods & Access.PUBLIC) != 0)
0155: return true;
0156: String callerName = getName();
0157: String className = declaring.getName();
0158: if (callerName.equals(className))
0159: return true;
0160: if ((modifiers & Access.PRIVATE) != 0)
0161: return false;
0162: int dot = callerName.lastIndexOf('.');
0163: String callerPackage = dot >= 0 ? callerName.substring(0, dot)
0164: : "";
0165: dot = className.lastIndexOf('.');
0166: String classPackage = dot >= 0 ? className.substring(0, dot)
0167: : "";
0168: if (callerPackage.equals(classPackage))
0169: return true;
0170: if ((modifiers & Access.PROTECTED) != 0
0171: && this .isSubclass(declaring))
0172: return true;
0173: return false;
0174: }
0175:
0176: /** Sets the name of the class being defined in this classfile.
0177: * @param name the name to give to the class
0178: */
0179: public void setName(String name) {
0180: this _name = name;
0181: setSignature("L" + name.replace('.', '/') + ";");
0182: }
0183:
0184: SourceDebugExtAttr sourceDbgExt;
0185:
0186: /** Create a <code>SourceDebugExtAttr</code>, if needed, and
0187: * set the "stratum". The stratum is typically a programming language
0188: * such as "JSP", "Scheme", or "Java" (the default). */
0189: public void setStratum(String stratum) {
0190: if (sourceDbgExt == null)
0191: sourceDbgExt = new SourceDebugExtAttr(this );
0192: sourceDbgExt.addStratum(stratum);
0193: }
0194:
0195: /** Set the name of the SourceFile associated with this class. */
0196: public void setSourceFile(String name) {
0197: if (sourceDbgExt != null) {
0198: sourceDbgExt.addFile(name);
0199: if (sourceDbgExt.fileCount > 1)
0200: return;
0201: }
0202:
0203: name = SourceFileAttr.fixSourceFile(name);
0204: int slash = name.lastIndexOf('/');
0205: if (slash >= 0)
0206: name = name.substring(slash + 1);
0207: SourceFileAttr.setSourceFile(this , name);
0208: }
0209:
0210: /**
0211: * Set the superclass of the is class.
0212: * @param name name of super class, or null if this is "Object".
0213: */
0214: public void setSuper(String name) {
0215: setSuper(name == null ? Type.pointer_type : ClassType
0216: .make(name));
0217: }
0218:
0219: public void setSuper(ClassType super Class) {
0220: this .super Class = super Class;
0221: }
0222:
0223: public ClassType getSuperclass() {
0224: if (super Class == null && !isInterface()
0225: && !("java.lang.Object".equals(getName()))
0226: && (flags & EXISTING_CLASS) != 0
0227: && getReflectClass() != null) {
0228: super Class = (ClassType) make(reflectClass.getSuperclass());
0229: }
0230: return super Class;
0231: }
0232:
0233: public String getPackageName() {
0234: String name = getName();
0235: int index = name.lastIndexOf('.');
0236: return index < 0 ? "" : name.substring(0, index);
0237: }
0238:
0239: /**
0240: * @return the interfaces this class is declared to implement
0241: * (not those inherited from its superclass/superinterfaces).
0242: */
0243: public synchronized ClassType[] getInterfaces() {
0244: if (interfaces == null && (flags & EXISTING_CLASS) != 0
0245: && getReflectClass() != null) {
0246: Class[] reflectInterfaces = reflectClass.getInterfaces();
0247: int numInterfaces = reflectInterfaces.length;
0248: interfaces = numInterfaces == 0 ? noClasses
0249: : new ClassType[numInterfaces];
0250:
0251: for (int i = 0; i < numInterfaces; i++)
0252: interfaces[i] = (ClassType) Type
0253: .make(reflectInterfaces[i]);
0254: }
0255: return interfaces;
0256: }
0257:
0258: public void setInterfaces(ClassType[] interfaces) {
0259: this .interfaces = interfaces;
0260: }
0261:
0262: /** Add an interface to the list of implemented interfaces. */
0263: public void addInterface(ClassType newInterface) {
0264: int oldCount;
0265: if (interfaces == null || interfaces.length == 0) {
0266: oldCount = 0;
0267: interfaces = new ClassType[1];
0268: } else {
0269: oldCount = interfaces.length;
0270: for (int i = oldCount; --i >= 0;)
0271: if (interfaces[i] == newInterface)
0272: return;
0273: ClassType[] newInterfaces = new ClassType[oldCount + 1];
0274: System.arraycopy(interfaces, 0, newInterfaces, 0, oldCount);
0275: interfaces = newInterfaces;
0276: }
0277: interfaces[oldCount] = newInterface;
0278: }
0279:
0280: public final boolean isInterface() {
0281: return (getModifiers() & Access.INTERFACE) != 0;
0282: }
0283:
0284: public final void setInterface(boolean val) {
0285: if (val)
0286: access_flags |= Access.INTERFACE | Access.ABSTRACT;
0287: else
0288: access_flags &= ~Access.INTERFACE | Access.ABSTRACT;
0289: }
0290:
0291: public ClassType() {
0292: }
0293:
0294: public ClassType(String class_name) {
0295: super ();
0296: setName(class_name);
0297: }
0298:
0299: Field fields;
0300: int fields_count;
0301: Field last_field;
0302: /** Constant pool index of "ConstantValue". */
0303: int ConstantValue_name_index;
0304:
0305: /** Constant pool index of "Code". */
0306: int Code_name_index;
0307:
0308: /** Constant pool index of "LocalVariableTable". */
0309: int LocalVariableTable_name_index;
0310:
0311: /** Constant pool index of "LineNumberTable". */
0312: int LineNumberTable_name_index;
0313:
0314: /** Get the fields of this class. */
0315: public final synchronized Field getFields() {
0316: if ((flags & (ADD_FIELDS_DONE | EXISTING_CLASS)) == EXISTING_CLASS)
0317: addFields();
0318: return fields;
0319: }
0320:
0321: public final int getFieldCount() {
0322: return fields_count;
0323: }
0324:
0325: /** Find a field with the given name declared in this class.
0326: * @return the matching field, or null if there is no such field.
0327: */
0328: public Field getDeclaredField(String name) {
0329: for (Field field = getFields(); field != null; field = field.next) {
0330: if (name.equals(field.name))
0331: return field;
0332: }
0333: return null;
0334: }
0335:
0336: /** Find a field with the given name declared in this class or its ancestors.
0337: * @param name the name of the field.
0338: * @param mask of match a field whose modifiers has one of these bits set.
0339: * Howeve, if mask is -1, ignore the access flags.
0340: * @return the matching field, or null if there is no such field.
0341: */
0342: public Field getField(String name, int mask) {
0343: ClassType cl = this ;
0344: for (;;) {
0345: Field field = cl.getDeclaredField(name);
0346: if (field != null
0347: && (mask == -1 || (field.getModifiers() & mask) != 0))
0348: return field;
0349: ClassType[] interfaces = cl.getInterfaces();
0350: if (interfaces != null) {
0351: for (int i = 0; i < interfaces.length; i++) {
0352: field = interfaces[i].getField(name, mask);
0353: if (field != null)
0354: return field;
0355: }
0356: }
0357: cl = cl.getSuperclass();
0358: if (cl == null)
0359: return null;
0360: }
0361: }
0362:
0363: /** Find a field with the given name declared in this class or its ancestors.
0364: * @return the matching field, or null if there is no such field.
0365: */
0366: public Field getField(String name) {
0367: return getField(name, Access.PUBLIC);
0368: }
0369:
0370: /**
0371: * Add a new field to this class.
0372: */
0373: public Field addField() {
0374: return new Field(this );
0375: }
0376:
0377: /**
0378: * Add a new field to this class, and name the field.
0379: * @param name the name of the new field
0380: */
0381: public Field addField(String name) {
0382: Field field = new Field(this );
0383: field.setName(name);
0384: return field;
0385: }
0386:
0387: public final Field addField(String name, Type type) {
0388: Field field = new Field(this );
0389: field.setName(name);
0390: field.setType(type);
0391: return field;
0392: }
0393:
0394: public final Field addField(String name, Type type, int flags) {
0395: Field field = addField(name, type);
0396: field.flags = flags;
0397: return field;
0398: }
0399:
0400: /** Use reflection to add all the declared fields of this class.
0401: * Does not add private or package-private fields.
0402: * Does not check for duplicate (already-known) fields.
0403: * Is not thread-safe if another thread may access this ClassType. */
0404: public void addFields() {
0405: Class clas = getReflectClass();
0406: java.lang.reflect.Field[] fields;
0407: try {
0408: fields = clas.getDeclaredFields();
0409: } catch (SecurityException ex) {
0410: fields = clas.getFields();
0411: }
0412: int count = fields.length;
0413: for (int i = 0; i < count; i++) {
0414: java.lang.reflect.Field field = fields[i];
0415: if ("this$0".equals(field.getName()))
0416: flags |= HAS_OUTER_LINK;
0417: addField(field.getName(), Type.make(field.getType()), field
0418: .getModifiers());
0419: }
0420: flags |= ADD_FIELDS_DONE;
0421: }
0422:
0423: Method methods;
0424: int methods_count;
0425: Method last_method;
0426: public Method constructor;
0427:
0428: /** Get the methods of this class. */
0429: public final Method getMethods() {
0430: return methods;
0431: }
0432:
0433: public final int getMethodCount() {
0434: return methods_count;
0435: }
0436:
0437: Method addMethod() {
0438: return new Method(this , 0);
0439: }
0440:
0441: public Method addMethod(String name) {
0442: return addMethod(name, 0);
0443: }
0444:
0445: public Method addMethod(String name, int flags) {
0446: Method method = new Method(this , flags);
0447: method.setName(name);
0448: return method;
0449: }
0450:
0451: // deprecated:
0452: public Method addMethod(String name, Type[] arg_types,
0453: Type return_type, int flags) {
0454: return addMethod(name, flags, arg_types, return_type);
0455: }
0456:
0457: /** Add a method to this ClassType.
0458: * If an existing method matches, return that. Otherwise, create
0459: * a new one.
0460: * In contrast, the other addMethod methods always create new Methods. */
0461: public Method addMethod(String name, int flags, Type[] arg_types,
0462: Type return_type) {
0463: Method method = getDeclaredMethod(name, arg_types);
0464: if (method != null
0465: && return_type.equals(method.getReturnType())
0466: && (flags & method.access_flags) == flags)
0467: return method;
0468: method = addMethod(name, flags);
0469: method.arg_types = arg_types;
0470: method.return_type = return_type;
0471: return method;
0472: }
0473:
0474: public Method addMethod(String name, String signature, int flags) {
0475: Method meth = addMethod(name, flags);
0476: meth.setSignature(signature);
0477: return meth;
0478: }
0479:
0480: /** Add a method to this ClassType.
0481: * If an existing method matches, return that. Otherwise, create
0482: * a new one. */
0483: public Method getMethod(java.lang.reflect.Method method) {
0484: String name = method.getName();
0485: Class[] parameterClasses = method.getParameterTypes();
0486: Type[] parameterTypes = new Type[parameterClasses.length];
0487: for (int i = parameterClasses.length; --i >= 0;)
0488: parameterTypes[i] = Type.make(parameterClasses[i]);
0489: return addMethod(name, method.getModifiers(), parameterTypes,
0490: Type.make(method.getReturnType()));
0491: }
0492:
0493: public final synchronized Method getDeclaredMethods() {
0494: if ((flags & (ADD_METHODS_DONE | EXISTING_CLASS)) == EXISTING_CLASS)
0495: addMethods(getReflectClass());
0496: return methods;
0497: }
0498:
0499: /** Count methods matching a given filter.
0500: * @param filter to select methods to return
0501: * @param searchSupers 0 if only current class should be searched,
0502: * 1 if superclasses should also be searched,
0503: * 2 if super-interfaces should also be search
0504: * @return number of methods that match
0505: */
0506: public final int countMethods(Filter filter, int searchSupers) {
0507: return getMethods(filter, searchSupers, null, 0);
0508: }
0509:
0510: public Method[] getMethods(Filter filter, boolean searchSupers) {
0511: return getMethods(filter, searchSupers ? 1 : 0);
0512: }
0513:
0514: /** Get methods matching a given filter.
0515: * @param filter to select methods to return
0516: * @param searchSupers 0 if only current class should be searched,
0517: * 1 if superclasses should also be searched,
0518: * 2 if super-interfaces should also be searched
0519: * @return a fresh array containing the methods satisfying the filter
0520: */
0521: public Method[] getMethods(Filter filter, int searchSupers) {
0522: int count = getMethods(filter, searchSupers, null, 0);
0523: Method[] result = new Method[count];
0524: getMethods(filter, searchSupers, result, 0);
0525: return result;
0526: }
0527:
0528: /** Helper to get methods satisfying a filtering predicate.
0529: * @param filter to select methods to return
0530: * @param searchSupers 0 if only current class should be searched,
0531: * 1 if superclasses should also be searched,
0532: * 2 if super-interfaces should also be searched
0533: * @param result array to place selected methods in
0534: * @param offset start of where in result to place result
0535: * @return number of methods placed in result array
0536: * @deprecated
0537: */
0538: public int getMethods(Filter filter, int searchSupers,
0539: Method[] result, int offset) {
0540: int count = 0;
0541: for (ClassType ctype = this ; ctype != null; ctype = ctype
0542: .getSuperclass()) {
0543: for (Method meth = ctype.getDeclaredMethods(); meth != null; meth = meth
0544: .getNext())
0545: if (filter.select(meth)) {
0546: if (result != null)
0547: result[offset + count] = meth;
0548: count++;
0549: }
0550: if (searchSupers == 0)
0551: break;
0552:
0553: if (searchSupers > 1) {
0554: ClassType[] interfaces = ctype.getInterfaces();
0555: if (interfaces != null) {
0556: for (int i = 0; i < interfaces.length; i++)
0557: count += interfaces[i].getMethods(filter,
0558: searchSupers, result, offset + count);
0559: }
0560: }
0561: }
0562: return count;
0563: }
0564:
0565: /** Helper to get methods satisfying a filtering predicate.
0566: * @param filter to select methods to return
0567: * @param searchSupers 0 if only current class should be searched,
0568: * 1 if superclasses should also be searched,
0569: * 2 if super-interfaces should also be searched
0570: * @param result Vector to add selected methods in
0571: * @param context If non-null, skip if class not visible in named package.
0572: * @return number of methods placed in result array
0573: */
0574: public int getMethods(Filter filter, int searchSupers,
0575: Vector result, String context) {
0576: int count = 0;
0577: for (ClassType ctype = this ; ctype != null; ctype = ctype
0578: .getSuperclass()) {
0579: if (context == null
0580: || (ctype.getModifiers() & Access.PUBLIC) != 0
0581: || context.equals(ctype.getPackageName())) {
0582: for (Method meth = ctype.getDeclaredMethods(); meth != null; meth = meth
0583: .getNext())
0584: if (filter.select(meth)) {
0585: if (result != null)
0586: result.addElement(meth);
0587: count++;
0588: }
0589: }
0590: if (searchSupers == 0)
0591: break;
0592:
0593: if (searchSupers > 1) {
0594: ClassType[] interfaces = ctype.getInterfaces();
0595: if (interfaces != null) {
0596: for (int i = 0; i < interfaces.length; i++)
0597: count += interfaces[i].getMethods(filter,
0598: searchSupers, result, context);
0599: }
0600: }
0601: }
0602: return count;
0603: }
0604:
0605: /** Look for a matching method.
0606: * @param name method name
0607: * @param arg_types parameter types that must match.
0608: * Can also be null, to match any parameter type list.
0609: * Otherwise, an element of arg_types must be the same type (equals),
0610: * though a null element of arg_types is a wildcard that matches any type.
0611: */
0612: public Method getDeclaredMethod(String name, Type[] arg_types) {
0613: int needOuterLinkArg = "<init>".equals(name) && hasOuterLink() ? 1
0614: : 0;
0615: for (Method method = getDeclaredMethods(); method != null; method = method.next) {
0616: if (!name.equals(method.getName()))
0617: continue;
0618: Type[] method_args = method.getParameterTypes();
0619: if (arg_types == null
0620: || (arg_types == method_args && needOuterLinkArg == 0))
0621: return method;
0622: int i = arg_types.length;
0623: if (i != method_args.length - needOuterLinkArg)
0624: continue;
0625: while (--i >= 0) {
0626: Type meth_type = method_args[i + needOuterLinkArg];
0627: Type need_type = arg_types[i];
0628: if (meth_type == need_type || need_type == null)
0629: continue;
0630: String meth_sig = meth_type.getSignature();
0631: String need_sig = need_type.getSignature();
0632: if (!meth_sig.equals(need_sig))
0633: break;
0634: }
0635: if (i < 0)
0636: return method;
0637: }
0638: return null;
0639: }
0640:
0641: /** Get a method with matching name and number of arguments. */
0642: public Method getDeclaredMethod(String name, int argCount) {
0643: Method result = null;
0644: int needOuterLinkArg = "<init>".equals(name) && hasOuterLink() ? 1
0645: : 0;
0646: for (Method method = getDeclaredMethods(); method != null; method = method.next) {
0647: if (name.equals(method.getName())
0648: && argCount + needOuterLinkArg == method
0649: .getParameterTypes().length) {
0650: if (result != null)
0651: throw new Error(
0652: "ambiguous call to getDeclaredMethod(\""
0653: + name + "\", " + argCount
0654: + ")\n - " + result + "\n - "
0655: + method);
0656: result = method;
0657: }
0658: }
0659: return result;
0660: }
0661:
0662: public Method getMethod(String name, Type[] arg_types) {
0663: ClassType cl = this ;
0664: for (;;) {
0665: Method method = cl.getDeclaredMethod(name, arg_types);
0666: if (method != null)
0667: return method;
0668: cl = cl.getSuperclass();
0669: if (cl == null)
0670: break;
0671: }
0672: cl = this ;
0673: for (;;) {
0674: ClassType[] interfaces = cl.getInterfaces();
0675: if (interfaces != null) {
0676: for (int i = 0; i < interfaces.length; i++) {
0677: Method method = interfaces[i].getDeclaredMethod(
0678: name, arg_types);
0679: if (method != null)
0680: return method;
0681: }
0682: }
0683: cl = cl.getSuperclass();
0684: if (cl == null)
0685: break;
0686: }
0687: return null;
0688: }
0689:
0690: /** Use reflection to add all the declared methods of this class.
0691: * Does not add constructors nor private or package-private methods.
0692: * Does not check for duplicate (already-known) methods.
0693: * @param clas should be the same as getReflectClass(). */
0694: public void addMethods(Class clas) {
0695: // Set this flag BEFORE the actual addition.
0696: // This prevents this method to be called indirectly for the same class
0697: // while it is executed, which would result in methods being listed
0698: // twice in this class.
0699: flags |= ADD_METHODS_DONE;
0700:
0701: java.lang.reflect.Method[] methods;
0702: try {
0703: methods = clas.getDeclaredMethods();
0704: } catch (SecurityException ex) {
0705: methods = clas.getMethods();
0706: }
0707: int count = methods.length;
0708: for (int i = 0; i < count; i++) {
0709: java.lang.reflect.Method method = methods[i];
0710: if (!method.getDeclaringClass().equals(clas))
0711: continue;
0712: int modifiers = method.getModifiers();
0713: Class[] paramTypes = method.getParameterTypes();
0714: int j = paramTypes.length;
0715: Type[] args = new Type[j];
0716: while (--j >= 0)
0717: args[j] = Type.make(paramTypes[j]);
0718: Method meth = addMethod(method.getName(), modifiers);
0719: meth.arg_types = args;
0720: meth.return_type = Type.make(method.getReturnType());
0721: }
0722:
0723: java.lang.reflect.Constructor[] cmethods;
0724: try {
0725: cmethods = clas.getDeclaredConstructors();
0726: } catch (SecurityException ex) {
0727: cmethods = clas.getConstructors();
0728: }
0729: count = cmethods.length;
0730: for (int i = 0; i < count; i++) {
0731: java.lang.reflect.Constructor method = cmethods[i];
0732: if (!method.getDeclaringClass().equals(clas))
0733: continue;
0734: int modifiers = method.getModifiers();
0735: if ((modifiers & (Access.PUBLIC | Access.PROTECTED)) == 0)
0736: continue;
0737: Class[] paramTypes = method.getParameterTypes();
0738: int j = paramTypes.length;
0739: Type[] args = new Type[j];
0740: while (--j >= 0)
0741: args[j] = Type.make(paramTypes[j]);
0742: Method meth = addMethod("<init>", modifiers);
0743: meth.arg_types = args;
0744: meth.return_type = Type.void_type;
0745: }
0746: }
0747:
0748: public Method[] getMatchingMethods(String name, Type[] paramTypes,
0749: int flags) {
0750: int nMatches = 0;
0751: java.util.Vector matches = new java.util.Vector(10);
0752: for (Method method = methods; method != null; method = method
0753: .getNext()) {
0754: if (!name.equals(method.getName()))
0755: continue;
0756: if ((flags & Access.STATIC) != (method.access_flags & Access.STATIC))
0757: continue;
0758: if ((flags & Access.PUBLIC) > (method.access_flags & Access.PUBLIC))
0759: continue;
0760: Type[] mtypes = method.arg_types;
0761: if (mtypes.length != paramTypes.length)
0762: continue;
0763: nMatches++;
0764: matches.addElement(method);
0765: }
0766: Method[] result = new Method[nMatches];
0767: matches.copyInto(result);
0768: return result;
0769: }
0770:
0771: /** Do various fixups after generating code but before we can write it out.
0772: * This includes assigning constant pool indexes where needed,
0773: * finalizing labels, etc. */
0774: public void doFixups() {
0775: if (constants == null)
0776: constants = new ConstantPool();
0777: if (this ClassIndex == 0)
0778: this ClassIndex = constants.addClass(this ).index;
0779: if (super Class == this )
0780: setSuper((ClassType) null);
0781: if (super ClassIndex < 0)
0782: super ClassIndex = super Class == null ? 0 : constants
0783: .addClass(super Class).index;
0784: if (interfaces != null && interfaceIndexes == null) {
0785: int n = interfaces.length;
0786: interfaceIndexes = new int[n];
0787: for (int i = 0; i < n; i++)
0788: interfaceIndexes[i] = constants.addClass(interfaces[i]).index;
0789: }
0790: for (Field field = fields; field != null; field = field.next) {
0791: field.assign_constants(this );
0792: }
0793: for (Method method = methods; method != null; method = method.next)
0794: method.assignConstants();
0795: Attribute.assignConstants(this , this );
0796: }
0797:
0798: public void writeToStream(OutputStream stream)
0799: throws java.io.IOException {
0800: java.io.DataOutputStream dstr = new java.io.DataOutputStream(
0801: stream);
0802: int i;
0803:
0804: doFixups();
0805:
0806: dstr.writeInt(0xcafebabe); // magic
0807: dstr.writeShort(getClassfileMinorVersion());
0808: dstr.writeShort(getClassfileMajorVersion());
0809:
0810: // Write out the constant pool.
0811: if (constants == null)
0812: dstr.writeShort(1);
0813: else
0814: constants.write(dstr);
0815:
0816: dstr.writeShort(access_flags);
0817: dstr.writeShort(this ClassIndex);
0818: dstr.writeShort(super ClassIndex);
0819: if (interfaceIndexes == null)
0820: dstr.writeShort(0); // interfaces_count
0821: else {
0822: int interfaces_count = interfaceIndexes.length;
0823: dstr.writeShort(interfaces_count);
0824: for (i = 0; i < interfaces_count; i++)
0825: dstr.writeShort(interfaceIndexes[i]);
0826: }
0827:
0828: dstr.writeShort(fields_count);
0829: for (Field field = fields; field != null; field = field.next)
0830: field.write(dstr, this );
0831:
0832: dstr.writeShort(methods_count);
0833: for (Method method = methods; method != null; method = method.next)
0834: method.write(dstr, this );
0835:
0836: Attribute.writeAll(this , dstr);
0837:
0838: flags |= ADD_FIELDS_DONE | ADD_METHODS_DONE;
0839: }
0840:
0841: public void writeToFile(String filename) throws java.io.IOException {
0842: OutputStream stream = new BufferedOutputStream(
0843: new FileOutputStream(filename));
0844: writeToStream(stream);
0845: stream.close();
0846: }
0847:
0848: public void writeToFile() throws java.io.IOException {
0849: writeToFile(this _name.replace('.', File.separatorChar)
0850: + ".class");
0851: }
0852:
0853: public byte[] writeToArray() {
0854: ByteArrayOutputStream stream = new ByteArrayOutputStream(500);
0855: try {
0856: writeToStream(stream);
0857: } catch (java.io.IOException ex) {
0858: throw new InternalError(ex.toString());
0859: }
0860: return stream.toByteArray();
0861: }
0862:
0863: /**
0864: * Convert a String to a Utf8 byte array.
0865: * @param str the input String.
0866: * @return the input encoded as a utf8 byte array.
0867: */
0868: public static byte[] to_utf8(String str) {
0869: if (str == null)
0870: return null;
0871: int str_len = str.length();
0872: int utf_len = 0;
0873: for (int i = 0; i < str_len; i++) {
0874: int c = str.charAt(i);
0875: if ((c > 0) && (c <= 0x7F))
0876: utf_len++;
0877: else if (c <= 0x7FF)
0878: utf_len += 2;
0879: else
0880: utf_len += 3;
0881: }
0882: byte[] buffer = new byte[utf_len];
0883: int j = 0;
0884: for (int i = 0; i < str_len; i++) {
0885: int c = str.charAt(i);
0886: if ((c > 0) && (c <= 0x7F))
0887: buffer[j++] = (byte) c;
0888: else if (c <= 0x7FF) {
0889: buffer[j++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
0890: buffer[j++] = (byte) (0x80 | ((c >> 0) & 0x3F));
0891: } else {
0892: buffer[j++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
0893: buffer[j++] = (byte) (0x80 | ((c >> 6) & 0x3F));
0894: buffer[j++] = (byte) (0x80 | ((c >> 0) & 0x3F));
0895: }
0896: }
0897: return buffer;
0898: }
0899:
0900: /** True if this class/interface implements the interface iface. */
0901: public final boolean implements Interface(ClassType iface) {
0902: if (this == iface)
0903: return true;
0904: ClassType baseClass = this .getSuperclass();
0905: if (baseClass != null && baseClass.implements Interface(iface))
0906: return true;
0907: ClassType[] interfaces = getInterfaces();
0908: if (interfaces != null) {
0909: for (int i = interfaces.length; --i >= 0;) {
0910: if (interfaces[i].implements Interface(iface))
0911: return true;
0912: }
0913: }
0914: return false;
0915: }
0916:
0917: /** A more efficient version of isSubclass(ClassType.make(cname)).
0918: * Does not cause the named class be loaded if it hasn't been.
0919: * @param cname a class name - cannot be an interface name
0920: */
0921: public final boolean isSubclass(String cname) {
0922: ClassType ctype = this ;
0923: for (;;) {
0924: if (cname.equals(ctype.getName()))
0925: return true;
0926: ctype = ctype.getSuperclass();
0927: if (ctype == null)
0928: return false;
0929: }
0930: }
0931:
0932: public final boolean isSubclass(ClassType other) {
0933: if (other.isInterface())
0934: return implements Interface(other);
0935: if ((this == tostring_type && other == string_type)
0936: || (this == string_type && other == tostring_type))
0937: return true;
0938: ClassType baseClass = this ;
0939: while (baseClass != null) {
0940: if (baseClass == other)
0941: return true;
0942: baseClass = baseClass.getSuperclass();
0943: }
0944: return false;
0945: }
0946:
0947: public int compare(Type other) {
0948: if (other == nullType)
0949: return 1;
0950: if (!(other instanceof ClassType))
0951: return swappedCompareResult(other.compare(this ));
0952: String name = getName();
0953: if (name != null && name.equals(other.getName()))
0954: return 0;
0955: ClassType cother = (ClassType) other;
0956: if (isSubclass(cother))
0957: return -1;
0958: if (cother.isSubclass(this ))
0959: return 1;
0960: if (this == tostring_type)
0961: return cother == Type.pointer_type ? -1 : 1;
0962: if (cother == tostring_type)
0963: return this == Type.pointer_type ? 1 : -1;
0964: if (this .isInterface() || cother.isInterface())
0965: return -2;
0966: return -3;
0967: }
0968:
0969: public String toString() {
0970: return "ClassType " + getName();
0971: }
0972:
0973: /**
0974: * @serialData Write the class name (as given by getName()) using writeUTF.
0975: */
0976: public void writeExternal(ObjectOutput out) throws IOException {
0977: out.writeUTF(getName());
0978: }
0979:
0980: public void readExternal(ObjectInput in) throws IOException,
0981: ClassNotFoundException {
0982: setName(in.readUTF());
0983: flags |= ClassType.EXISTING_CLASS;
0984: }
0985:
0986: public Object readResolve() throws ObjectStreamException {
0987: String name = getName();
0988: /* #ifdef JAVA5 */
0989: // java.util.HashMap<String,Type> map = mapNameToType;
0990: /* #else */
0991: java.util.Hashtable map = mapNameToType;
0992: /* #endif */
0993: synchronized (map) {
0994: Type found = (Type) map.get(name);
0995: if (found != null)
0996: return found;
0997: map.put(name, this );
0998: }
0999: return this ;
1000: }
1001:
1002: /** Clear various object references, to help garbage collection. */
1003: public void cleanupAfterCompilation() {
1004: for (Method meth = methods; meth != null; meth = meth.getNext())
1005: meth.cleanupAfterCompilation();
1006:
1007: constants = null;
1008: attributes = null;
1009: sourceDbgExt = null;
1010: }
1011: }
|