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