0001: /*
0002: * Janino - An embedded Java[TM] compiler
0003: *
0004: * Copyright (c) 2001-2007, Arno Unkrig
0005: * All rights reserved.
0006: *
0007: * Redistribution and use in source and binary forms, with or without
0008: * modification, are permitted provided that the following conditions
0009: * are met:
0010: *
0011: * 1. Redistributions of source code must retain the above copyright
0012: * notice, this list of conditions and the following disclaimer.
0013: * 2. Redistributions in binary form must reproduce the above
0014: * copyright notice, this list of conditions and the following
0015: * disclaimer in the documentation and/or other materials
0016: * provided with the distribution.
0017: * 3. The name of the author may not be used to endorse or promote
0018: * products derived from this software without specific prior
0019: * written permission.
0020: *
0021: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0022: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0023: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
0025: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0026: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
0027: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
0029: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
0030: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
0031: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0032: */
0033:
0034: package org.codehaus.janino;
0035:
0036: import java.util.*;
0037:
0038: /**
0039: * A simplified equivalent to "java.lang.reflect".
0040: */
0041: public abstract class IClass {
0042: private static final boolean DEBUG = false;
0043:
0044: public static final IClass VOID = new PrimitiveIClass(
0045: Descriptor.VOID_);
0046: public static final IClass BYTE = new PrimitiveIClass(
0047: Descriptor.BYTE_);
0048: public static final IClass CHAR = new PrimitiveIClass(
0049: Descriptor.CHAR_);
0050: public static final IClass DOUBLE = new PrimitiveIClass(
0051: Descriptor.DOUBLE_);
0052: public static final IClass FLOAT = new PrimitiveIClass(
0053: Descriptor.FLOAT_);
0054: public static final IClass INT = new PrimitiveIClass(
0055: Descriptor.INT_);
0056: public static final IClass LONG = new PrimitiveIClass(
0057: Descriptor.LONG_);
0058: public static final IClass SHORT = new PrimitiveIClass(
0059: Descriptor.SHORT_);
0060: public static final IClass BOOLEAN = new PrimitiveIClass(
0061: Descriptor.BOOLEAN_);
0062:
0063: private static class PrimitiveIClass extends IClass {
0064: private final String fieldDescriptor;
0065:
0066: public PrimitiveIClass(String fieldDescriptor) {
0067: this .fieldDescriptor = fieldDescriptor;
0068: }
0069:
0070: protected IClass getComponentType2() {
0071: return null;
0072: }
0073:
0074: protected IClass[] getDeclaredIClasses2() {
0075: return new IClass[0];
0076: }
0077:
0078: protected IConstructor[] getDeclaredIConstructors2() {
0079: return new IConstructor[0];
0080: }
0081:
0082: protected IField[] getDeclaredIFields2() {
0083: return new IField[0];
0084: }
0085:
0086: protected IMethod[] getDeclaredIMethods2() {
0087: return new IMethod[0];
0088: }
0089:
0090: protected IClass getDeclaringIClass2() {
0091: return null;
0092: }
0093:
0094: protected String getDescriptor2() {
0095: return this .fieldDescriptor;
0096: }
0097:
0098: protected IClass[] getInterfaces2() {
0099: return new IClass[0];
0100: }
0101:
0102: protected IClass getOuterIClass2() {
0103: return null;
0104: }
0105:
0106: protected IClass getSuperclass2() {
0107: return null;
0108: }
0109:
0110: public boolean isAbstract() {
0111: return false;
0112: }
0113:
0114: public boolean isArray() {
0115: return false;
0116: }
0117:
0118: public boolean isFinal() {
0119: return true;
0120: }
0121:
0122: public boolean isInterface() {
0123: return false;
0124: }
0125:
0126: public boolean isPrimitive() {
0127: return true;
0128: }
0129:
0130: public boolean isPrimitiveNumeric() {
0131: return Descriptor.isPrimitiveNumeric(this .fieldDescriptor);
0132: }
0133:
0134: public Access getAccess() {
0135: return Access.PUBLIC;
0136: }
0137: }
0138:
0139: /**
0140: * Returns all the constructors declared by the class represented by the
0141: * type. If the class has a default constructor, it is included.
0142: * <p>
0143: * Returns an array with zero elements for an interface, array, primitive type or
0144: * "void".
0145: */
0146: public final IConstructor[] getDeclaredIConstructors() {
0147: if (this .declaredIConstructors == null) {
0148: this .declaredIConstructors = this
0149: .getDeclaredIConstructors2();
0150: }
0151: return this .declaredIConstructors;
0152: }
0153:
0154: private IConstructor[] declaredIConstructors = null;
0155:
0156: protected abstract IConstructor[] getDeclaredIConstructors2();
0157:
0158: /**
0159: * Returns the methods of the class or interface (but not inherited
0160: * methods).<br>
0161: * Returns an empty array for an array, primitive type or "void".
0162: */
0163: public final IMethod[] getDeclaredIMethods() {
0164: if (this .declaredIMethods == null) {
0165: this .declaredIMethods = this .getDeclaredIMethods2();
0166: }
0167: return this .declaredIMethods;
0168: }
0169:
0170: protected IMethod[] declaredIMethods = null;
0171:
0172: protected abstract IMethod[] getDeclaredIMethods2();
0173:
0174: /**
0175: * Returns all methods with the given name declared in the class or
0176: * interface (but not inherited methods).<br>
0177: * Returns an empty array if no methods with that name are declared.
0178: *
0179: * @return an array of {@link IMethod}s that must not be modified
0180: */
0181: public final IMethod[] getDeclaredIMethods(String methodName) {
0182: if (this .declaredIMethodCache == null) {
0183: Map m = new HashMap();
0184:
0185: // Fill the map with "IMethod"s and "List"s.
0186: IMethod[] dims = this .getDeclaredIMethods();
0187: for (int i = 0; i < dims.length; i++) {
0188: IMethod dim = dims[i];
0189: String mn = dim.getName();
0190: Object o = m.get(mn);
0191: if (o == null) {
0192: m.put(mn, dim);
0193: } else if (o instanceof IMethod) {
0194: List l = new ArrayList();
0195: l.add(o);
0196: l.add(dim);
0197: m.put(mn, l);
0198: } else {
0199: ((List) o).add(dim);
0200: }
0201: }
0202:
0203: // Convert "IMethod"s and "List"s to "IMethod[]"s.
0204: for (Iterator it = m.entrySet().iterator(); it.hasNext();) {
0205: Map.Entry me = (Map.Entry) it.next();
0206: Object v = me.getValue();
0207: if (v instanceof IMethod) {
0208: me.setValue(new IMethod[] { (IMethod) v });
0209: } else {
0210: List l = (List) v;
0211: me.setValue(l.toArray(new IMethod[l.size()]));
0212: }
0213: }
0214: this .declaredIMethodCache = m;
0215: }
0216:
0217: IMethod[] methods = (IMethod[]) this .declaredIMethodCache
0218: .get(methodName);
0219: return methods == null ? IClass.NO_IMETHODS : methods;
0220: }
0221:
0222: /*package*/Map declaredIMethodCache = null; // String methodName => IMethod[]
0223:
0224: /**
0225: * Returns all methods declared in the class or interface, its superclasses and its
0226: * superinterfaces.<br>
0227: * For overridden methods, only the last non-abstract implementation is returned.
0228: *
0229: * @return an array of {@link IMethod}s that must not be modified
0230: */
0231: public final IMethod[] getIMethods() throws CompileException {
0232: if (this .iMethodCache == null) {
0233: Map m = new HashMap();
0234: this .getIMethods(m);
0235: Collection iMethods = m.values();
0236: this .iMethodCache = (IMethod[]) iMethods
0237: .toArray(new IMethod[iMethods.size()]);
0238: }
0239: return this .iMethodCache;
0240: }
0241:
0242: /*package*/IMethod[] iMethodCache = null;
0243:
0244: private void getIMethods(Map result) throws CompileException {
0245: IMethod[] ms = this .getDeclaredIMethods();
0246: for (int i = 0; i < ms.length; ++i) {
0247: IMethod m = ms[i];
0248: String key = m.getName() + m.getDescriptor();
0249: IMethod m2 = (IMethod) result.get(key);
0250: if (m2 == null || m2.isAbstract())
0251: result.put(key, m);
0252: }
0253: {
0254: IClass sc = this .getSuperclass();
0255: if (sc != null)
0256: sc.getIMethods(result);
0257: }
0258: {
0259: IClass[] iis = this .getInterfaces();
0260: for (int i = 0; i < iis.length; ++i)
0261: iis[i].getIMethods(result);
0262: }
0263: }
0264:
0265: public static final IMethod[] NO_IMETHODS = new IMethod[0];
0266:
0267: public final boolean hasIMethod(String methodName,
0268: IClass[] parameterTypes) throws CompileException {
0269: IMethod[] ims = this .getDeclaredIMethods(methodName);
0270: for (int i = 0; i < ims.length; ++i) {
0271: IClass[] pts = ims[i].getParameterTypes();
0272: if (Arrays.equals(pts, parameterTypes))
0273: return true;
0274: }
0275: return false;
0276: }
0277:
0278: /**
0279: * Returns the fields of a class or interface (but not inherited
0280: * fields).<br>
0281: * Returns an empty array for an array, primitive type or "void".
0282: */
0283: public final IField[] getDeclaredIFields() {
0284: if (this .declaredIFields == null) {
0285: this .declaredIFields = this .getDeclaredIFields2();
0286: }
0287: return this .declaredIFields;
0288: }
0289:
0290: protected IField[] declaredIFields = null;
0291:
0292: protected abstract IField[] getDeclaredIFields2();
0293:
0294: /**
0295: * Returns the synthetic fields of an anonymous or local class, in
0296: * the order in which they are passed to all constructors.
0297: */
0298: public IField[] getSyntheticIFields() {
0299: return new IField[0];
0300: }
0301:
0302: /**
0303: * Returns the classes and interfaces declared as members of the class
0304: * (but not inherited classes and interfaces).<br>
0305: * Returns an empty array for an array, primitive type or "void".
0306: */
0307: public final IClass[] getDeclaredIClasses() throws CompileException {
0308: if (this .declaredIClasses == null) {
0309: this .declaredIClasses = this .getDeclaredIClasses2();
0310: }
0311: return this .declaredIClasses;
0312: }
0313:
0314: private IClass[] declaredIClasses = null;
0315:
0316: protected abstract IClass[] getDeclaredIClasses2()
0317: throws CompileException;
0318:
0319: /**
0320: * If this class is a member class, return the declaring class, otherwise return
0321: * <code>null</code>.
0322: */
0323: public final IClass getDeclaringIClass() throws CompileException {
0324: if (!this .declaringIClassIsCached) {
0325: this .declaringIClass = this .getDeclaringIClass2();
0326: this .declaringIClassIsCached = true;
0327: }
0328: return this .declaringIClass;
0329: }
0330:
0331: private boolean declaringIClassIsCached = false;
0332: private IClass declaringIClass = null;
0333:
0334: protected abstract IClass getDeclaringIClass2()
0335: throws CompileException;
0336:
0337: /**
0338: * The following types have an "outer class":
0339: * <ul>
0340: * <li>Anonymous classes declared in a non-static method of a class
0341: * <li>Local classes declared in a non-static method of a class
0342: * <li>Non-static member classes
0343: * </ul>
0344: */
0345: public final IClass getOuterIClass() throws CompileException {
0346: if (!this .outerIClassIsCached) {
0347: this .outerIClass = this .getOuterIClass2();
0348: this .outerIClassIsCached = true;
0349: }
0350: return this .outerIClass;
0351: }
0352:
0353: private boolean outerIClassIsCached = false;
0354: private IClass outerIClass = null;
0355:
0356: protected abstract IClass getOuterIClass2() throws CompileException;
0357:
0358: /**
0359: * Returns the superclass of the class.<br>
0360: * Returns "null" for class "Object", interfaces, arrays, primitive types
0361: * and "void".
0362: */
0363: public final IClass getSuperclass() throws CompileException {
0364: if (!this .super classIsCached) {
0365: this .super class = this .getSuperclass2();
0366: this .super classIsCached = true;
0367: if (this .super class != null
0368: && this .super class.isSubclassOf(this ))
0369: throw new CompileException(
0370: "Class circularity detected for \""
0371: + Descriptor.toClassName(this
0372: .getDescriptor()) + "\"", null);
0373: }
0374: return this .super class;
0375: }
0376:
0377: private boolean super classIsCached = false;
0378: private IClass super class = null;
0379:
0380: protected abstract IClass getSuperclass2() throws CompileException;
0381:
0382: public abstract Access getAccess();
0383:
0384: /**
0385: * Whether subclassing is allowed (JVMS 4.1 access_flags)
0386: * @return <code>true</code> if subclassing is prohibited
0387: */
0388: public abstract boolean isFinal();
0389:
0390: /**
0391: * Returns the interfaces implemented by the class.<br>
0392: * Returns the superinterfaces of the interface.<br>
0393: * Returns "Cloneable" and "Serializable" for arrays.<br>
0394: * Returns an empty array for primitive types and "void".
0395: */
0396: public final IClass[] getInterfaces() throws CompileException {
0397: if (this .interfaces == null) {
0398: this .interfaces = this .getInterfaces2();
0399: for (int i = 0; i < this .interfaces.length; ++i) {
0400: if (this .interfaces[i].implements Interface(this ))
0401: throw new CompileException(
0402: "Interface circularity detected for \""
0403: + Descriptor.toClassName(this
0404: .getDescriptor()) + "\"",
0405: null);
0406: }
0407: }
0408: return this .interfaces;
0409: }
0410:
0411: private IClass[] interfaces = null;
0412:
0413: protected abstract IClass[] getInterfaces2()
0414: throws CompileException;
0415:
0416: /**
0417: * Whether the class may be instantiated (JVMS 4.1 access_flags)
0418: * @return <code>true</code> if instantiation is prohibited
0419: */
0420: public abstract boolean isAbstract();
0421:
0422: /**
0423: * Returns the field descriptor for the type as defined by JVMS 4.3.2.
0424: */
0425: public final String getDescriptor() {
0426: if (this .descriptor == null) {
0427: this .descriptor = this .getDescriptor2();
0428: }
0429: return this .descriptor;
0430: }
0431:
0432: private String descriptor = null;
0433:
0434: protected abstract String getDescriptor2();
0435:
0436: /**
0437: * Convenience method that determines the field descriptors of an array of {@link IClass}es.
0438: * @see #getDescriptor()
0439: */
0440: public static String[] getDescriptors(IClass[] iClasses) {
0441: String[] descriptors = new String[iClasses.length];
0442: for (int i = 0; i < iClasses.length; ++i)
0443: descriptors[i] = iClasses[i].getDescriptor();
0444: return descriptors;
0445: }
0446:
0447: /**
0448: * Returns "true" if this type represents an interface.
0449: */
0450: public abstract boolean isInterface();
0451:
0452: /**
0453: * Returns "true" if this type represents an array.
0454: */
0455: public abstract boolean isArray();
0456:
0457: /**
0458: * Returns "true" if this type represents a primitive type or "void".
0459: */
0460: public abstract boolean isPrimitive();
0461:
0462: /**
0463: * Returns "true" if this type represents "byte", "short", "int", "long",
0464: * "char", "float" or "double".
0465: */
0466: public abstract boolean isPrimitiveNumeric();
0467:
0468: /**
0469: * Returns the component type of the array.<br>
0470: * Returns "null" for classes, interfaces, primitive types and "void".
0471: */
0472: public final IClass getComponentType() {
0473: if (!this .componentTypeIsCached) {
0474: this .componentType = this .getComponentType2();
0475: this .componentTypeIsCached = true;
0476: }
0477: return this .componentType;
0478: }
0479:
0480: private boolean componentTypeIsCached = false;
0481: private IClass componentType = null;
0482:
0483: protected abstract IClass getComponentType2();
0484:
0485: /**
0486: * Returns a string representation for this object.
0487: */
0488: public String toString() {
0489: return Descriptor.toClassName(this .getDescriptor());
0490: }
0491:
0492: /**
0493: * Determine if "this" is assignable from "that". This is true if "this"
0494: * is identical with "that" (JLS2 5.1.1), or if "that" is
0495: * widening-primitive-convertible to "this" (JLS2 5.1.2), or if "that" is
0496: * widening-reference-convertible to "this" (JLS2 5.1.4).
0497: */
0498: public boolean isAssignableFrom(IClass that)
0499: throws CompileException {
0500:
0501: // Identity conversion, JLS2 5.1.1
0502: if (this == that)
0503: return true;
0504:
0505: // Widening primitive conversion, JLS2 5.1.2
0506: {
0507: String ds = that.getDescriptor() + this .getDescriptor();
0508: if (ds.length() == 2
0509: && IClass.PRIMITIVE_WIDENING_CONVERSIONS
0510: .contains(ds))
0511: return true;
0512: }
0513:
0514: // Widening reference conversion, JLS2 5.1.4
0515: {
0516:
0517: // JLS 5.1.4.1: Target type is superclass of source class type.
0518: if (that.isSubclassOf(this ))
0519: return true;
0520:
0521: // JLS 5.1.4.2: Source class type implements target interface type.
0522: // JLS 5.1.4.4: Source interface type implements target interface type.
0523: if (that.implements Interface(this ))
0524: return true;
0525:
0526: // JLS 5.1.4.3 Convert "null" literal to any reference type.
0527: if (that == IClass.VOID && !this .isPrimitive())
0528: return true;
0529:
0530: // JLS 5.1.4.5: From any interface to type "Object".
0531: if (that.isInterface()
0532: && this .getDescriptor().equals(Descriptor.OBJECT))
0533: return true;
0534:
0535: if (that.isArray()) {
0536:
0537: // JLS 5.1.4.6: From any array type to type "Object".
0538: if (this .getDescriptor().equals(Descriptor.OBJECT))
0539: return true;
0540:
0541: // JLS 5.1.4.7: From any array type to type "Cloneable".
0542: if (this .getDescriptor().equals(Descriptor.CLONEABLE))
0543: return true;
0544:
0545: // JLS 5.1.4.8: From any array type to type "java.io.Serializable".
0546: if (this .getDescriptor()
0547: .equals(Descriptor.SERIALIZABLE))
0548: return true;
0549:
0550: // JLS 5.1.4.9: From SC[] to TC[] while SC if widening reference convertible to TC.
0551: if (this .isArray()) {
0552: IClass this CT = this .getComponentType();
0553: IClass thatCT = that.getComponentType();
0554: if (!this CT.isPrimitive()
0555: && this CT.isAssignableFrom(thatCT))
0556: return true;
0557: }
0558: }
0559: }
0560: return false;
0561: }
0562:
0563: private static final Set PRIMITIVE_WIDENING_CONVERSIONS = new HashSet();
0564: static {
0565: String[] pwcs = new String[] {
0566: Descriptor.BYTE_ + Descriptor.SHORT_,
0567:
0568: Descriptor.BYTE_ + Descriptor.INT_,
0569: Descriptor.SHORT_ + Descriptor.INT_,
0570: Descriptor.CHAR_ + Descriptor.INT_,
0571:
0572: Descriptor.BYTE_ + Descriptor.LONG_,
0573: Descriptor.SHORT_ + Descriptor.LONG_,
0574: Descriptor.CHAR_ + Descriptor.LONG_,
0575: Descriptor.INT_ + Descriptor.LONG_,
0576:
0577: Descriptor.BYTE_ + Descriptor.FLOAT_,
0578: Descriptor.SHORT_ + Descriptor.FLOAT_,
0579: Descriptor.CHAR_ + Descriptor.FLOAT_,
0580: Descriptor.INT_ + Descriptor.FLOAT_,
0581:
0582: Descriptor.LONG_ + Descriptor.FLOAT_,
0583:
0584: Descriptor.BYTE_ + Descriptor.DOUBLE_,
0585: Descriptor.SHORT_ + Descriptor.DOUBLE_,
0586: Descriptor.CHAR_ + Descriptor.DOUBLE_,
0587: Descriptor.INT_ + Descriptor.DOUBLE_,
0588:
0589: Descriptor.LONG_ + Descriptor.DOUBLE_,
0590:
0591: Descriptor.FLOAT_ + Descriptor.DOUBLE_, };
0592: for (int i = 0; i < pwcs.length; ++i)
0593: IClass.PRIMITIVE_WIDENING_CONVERSIONS.add(pwcs[i]);
0594: }
0595:
0596: /**
0597: * Returns <code>true</code> if this class is an immediate or non-immediate
0598: * subclass of <code>that</code> class.
0599: */
0600: public boolean isSubclassOf(IClass that) throws CompileException {
0601: for (IClass sc = this .getSuperclass(); sc != null; sc = sc
0602: .getSuperclass()) {
0603: if (sc == that)
0604: return true;
0605: }
0606: return false;
0607: }
0608:
0609: /**
0610: * If <code>this</code> represents a class: Return <code>true</code> if this class
0611: * directly or indirectly implements <code>that</code> interface.
0612: * <p>
0613: * If <code>this</code> represents an interface: Return <code>true</code> if this
0614: * interface directly or indirectly extends <code>that</code> interface.
0615: */
0616: public boolean implements Interface(IClass that)
0617: throws CompileException {
0618: for (IClass c = this ; c != null; c = c.getSuperclass()) {
0619: IClass[] tis = c.getInterfaces();
0620: for (int i = 0; i < tis.length; ++i) {
0621: IClass ti = tis[i];
0622: if (ti == that || ti.implements Interface(that))
0623: return true;
0624: }
0625: }
0626: return false;
0627: }
0628:
0629: /**
0630: * Get an {@link IClass} that represents an n-dimensional array of this type.
0631: *
0632: * @param n dimension count
0633: * @param objectType Required because the superclass of an array class is {@link Object} by definition
0634: */
0635: public IClass getArrayIClass(int n, IClass objectType) {
0636: IClass result = this ;
0637: for (int i = 0; i < n; ++i)
0638: result = result.getArrayIClass(objectType);
0639: return result;
0640: }
0641:
0642: /**
0643: * Get an {@link IClass} that represents an array of this type.
0644: *
0645: * @param objectType Required because the superclass of an array class is {@link Object} by definition
0646: */
0647: public IClass getArrayIClass(IClass objectType) {
0648: if (this .arrayIClass == null)
0649: this .arrayIClass = this .getArrayIClass2(objectType);
0650: return this .arrayIClass;
0651: }
0652:
0653: private IClass arrayIClass = null;
0654:
0655: private IClass getArrayIClass2(final IClass objectType) {
0656: final IClass componentType = this ;
0657: return new IClass() {
0658: public IClass.IConstructor[] getDeclaredIConstructors2() {
0659: return new IClass.IConstructor[0];
0660: }
0661:
0662: // Special trickery #17: Arrays override "Object.clone()", but without "throws
0663: // CloneNotSupportedException"!
0664: public IClass.IMethod[] getDeclaredIMethods2() {
0665: return new IClass.IMethod[] { new IMethod() {
0666: public String getName() {
0667: return "clone";
0668: }
0669:
0670: public IClass getReturnType() {
0671: return objectType /*ot*/;
0672: }
0673:
0674: public boolean isAbstract() {
0675: return false;
0676: }
0677:
0678: public boolean isStatic() {
0679: return false;
0680: }
0681:
0682: public Access getAccess() {
0683: return Access.PUBLIC;
0684: }
0685:
0686: public IClass[] getParameterTypes() {
0687: return new IClass[0];
0688: }
0689:
0690: public IClass[] getThrownExceptions() {
0691: return new IClass[0];
0692: }
0693: } };
0694: }
0695:
0696: public IClass.IField[] getDeclaredIFields2() {
0697: return new IClass.IField[0];
0698: }
0699:
0700: public IClass[] getDeclaredIClasses2() {
0701: return new IClass[0];
0702: }
0703:
0704: public IClass getDeclaringIClass2() {
0705: return null;
0706: }
0707:
0708: public IClass getOuterIClass2() {
0709: return null;
0710: }
0711:
0712: public IClass getSuperclass2() {
0713: return objectType;
0714: }
0715:
0716: public IClass[] getInterfaces2() {
0717: return new IClass[0];
0718: }
0719:
0720: public String getDescriptor2() {
0721: return '[' + componentType.getDescriptor();
0722: }
0723:
0724: public Access getAccess() {
0725: return componentType.getAccess();
0726: }
0727:
0728: public boolean isFinal() {
0729: return true;
0730: }
0731:
0732: public boolean isInterface() {
0733: return false;
0734: }
0735:
0736: public boolean isAbstract() {
0737: return false;
0738: }
0739:
0740: public boolean isArray() {
0741: return true;
0742: }
0743:
0744: public boolean isPrimitive() {
0745: return false;
0746: }
0747:
0748: public boolean isPrimitiveNumeric() {
0749: return false;
0750: }
0751:
0752: public IClass getComponentType2() {
0753: return componentType;
0754: }
0755:
0756: public String toString() {
0757: return componentType.toString() + "[]";
0758: }
0759: };
0760: }
0761:
0762: /**
0763: * If <code>optionalName</code> is <code>null</code>, find all {@link IClass}es visible in the
0764: * scope of the current class.
0765: * <p>
0766: * If <code>optionalName</code> is not <code>null</code>, find the member {@link IClass}es
0767: * that has the given name. If the name is ambiguous (i.e. if more than one superclass,
0768: * interface of enclosing type declares a type with that name), then the size of the
0769: * returned array is greater than one.
0770: * <p>
0771: * Examines superclasses, interfaces and enclosing type declarations.
0772: * @return an array of {@link IClass}es in unspecified order, possibly of length zero
0773: */
0774: IClass[] findMemberType(String optionalName)
0775: throws CompileException {
0776: IClass[] res = (IClass[]) this .memberTypeCache
0777: .get(optionalName);
0778: if (res == null) {
0779:
0780: // Notice: A type may be added multiply to the result set because we are in its scope
0781: // multiply. E.g. the type is a member of a superclass AND a member of an enclosing type.
0782: Set s = new HashSet(); // IClass
0783: this .findMemberType(optionalName, s);
0784: res = s.isEmpty() ? IClass.ZERO_ICLASSES : (IClass[]) s
0785: .toArray(new IClass[s.size()]);
0786:
0787: this .memberTypeCache.put(optionalName, res);
0788: }
0789:
0790: return res;
0791: }
0792:
0793: private final Map memberTypeCache = new HashMap(); // String name => IClass[]
0794: private static final IClass[] ZERO_ICLASSES = new IClass[0];
0795:
0796: private void findMemberType(String optionalName, Collection result)
0797: throws CompileException {
0798:
0799: // Search for a type with the given name in the current class.
0800: IClass[] memberTypes = this .getDeclaredIClasses();
0801: if (optionalName == null) {
0802: result.addAll(Arrays.asList(memberTypes));
0803: } else {
0804: String memberDescriptor = Descriptor
0805: .fromClassName(Descriptor.toClassName(this
0806: .getDescriptor())
0807: + '$' + optionalName);
0808: for (int i = 0; i < memberTypes.length; ++i) {
0809: final IClass mt = memberTypes[i];
0810: if (mt.getDescriptor().equals(memberDescriptor)) {
0811: result.add(mt);
0812: return;
0813: }
0814: }
0815: }
0816:
0817: // Examine superclass.
0818: {
0819: IClass super class = this .getSuperclass();
0820: if (super class != null)
0821: super class.findMemberType(optionalName, result);
0822: }
0823:
0824: // Examine interfaces.
0825: {
0826: IClass[] ifs = this .getInterfaces();
0827: for (int i = 0; i < ifs.length; ++i)
0828: ifs[i].findMemberType(optionalName, result);
0829: }
0830:
0831: // Examine enclosing type declarations.
0832: {
0833: IClass declaringIClass = this .getDeclaringIClass();
0834: IClass outerIClass = this .getOuterIClass();
0835: if (declaringIClass != null) {
0836: declaringIClass.findMemberType(optionalName, result);
0837: }
0838: if (outerIClass != null && outerIClass != declaringIClass) {
0839: outerIClass.findMemberType(optionalName, result);
0840: }
0841: }
0842: }
0843:
0844: public interface IMember {
0845:
0846: /**
0847: * @return One of {@link Access#PRIVATE}, {@link Access#PROTECTED},
0848: * {@link Access#DEFAULT} and {@link Access#PUBLIC}.
0849: */
0850: Access getAccess();
0851:
0852: /**
0853: * Returns the {@link IClass} that declares this {@link IClass.IMember}.
0854: */
0855: IClass getDeclaringIClass();
0856: }
0857:
0858: public abstract class IInvocable implements IMember {
0859:
0860: // Implement IMember.
0861: public abstract Access getAccess();
0862:
0863: public IClass getDeclaringIClass() {
0864: return IClass.this ;
0865: }
0866:
0867: public abstract IClass[] getParameterTypes()
0868: throws CompileException;
0869:
0870: public abstract String getDescriptor() throws CompileException;
0871:
0872: public abstract IClass[] getThrownExceptions()
0873: throws CompileException;
0874:
0875: public boolean isMoreSpecificThan(IInvocable that)
0876: throws CompileException {
0877: if (IClass.DEBUG)
0878: System.out
0879: .print("\"" + this + "\".isMoreSpecificThan(\""
0880: + that + "\") => ");
0881:
0882: // The following case is tricky: JLS2 says that the invocation is AMBIGUOUS, but only
0883: // JAVAC 1.2 issues an error; JAVAC 1.4.1, 1.5.0 and 1.6.0 obviously ignore the declaring
0884: // type and invoke "A.meth(String)".
0885: // JLS3 is not clear about this. For compatibility with JAVA 1.4.1, 1.5.0 and 1.6.0,
0886: // JANINO also ignores the declaring type.
0887: //
0888: // See also JANINO-79 and JLS2Tests / 15.12.2.2
0889: if (false) {
0890: if (!that.getDeclaringIClass().isAssignableFrom(
0891: this .getDeclaringIClass())) {
0892: if (IClass.DEBUG)
0893: System.out.println("falsE");
0894: return false;
0895: }
0896: }
0897:
0898: IClass[] this ParameterTypes = this .getParameterTypes();
0899: IClass[] thatParameterTypes = that.getParameterTypes();
0900: int i;
0901: for (i = 0; i < this ParameterTypes.length; ++i) {
0902: if (!thatParameterTypes[i]
0903: .isAssignableFrom(this ParameterTypes[i])) {
0904: if (IClass.DEBUG)
0905: System.out.println("false");
0906: return false;
0907: }
0908: }
0909: if (IClass.DEBUG)
0910: System.out.println("true");
0911: return !Arrays.equals(this ParameterTypes,
0912: thatParameterTypes);
0913: }
0914:
0915: public boolean isLessSpecificThan(IInvocable that)
0916: throws CompileException {
0917: return that.isMoreSpecificThan(this );
0918: }
0919:
0920: public abstract String toString();
0921: }
0922:
0923: public abstract class IConstructor extends IInvocable {
0924:
0925: /**
0926: * Opposed to {@link java.lang.reflect.Constructor#getParameterTypes()}, the
0927: * return value of this method does not include the optionally leading "synthetic
0928: * parameters".
0929: */
0930: public abstract IClass[] getParameterTypes()
0931: throws CompileException;
0932:
0933: /**
0934: * Opposed to {@link #getParameterTypes()}, the method descriptor returned by this
0935: * method does include the optionally leading synthetic parameters.
0936: */
0937: public String getDescriptor() throws CompileException {
0938: IClass[] parameterTypes = this .getParameterTypes();
0939:
0940: IClass outerIClass = IClass.this .getOuterIClass();
0941: if (outerIClass != null) {
0942: IClass[] tmp = new IClass[parameterTypes.length + 1];
0943: tmp[0] = outerIClass;
0944: System.arraycopy(parameterTypes, 0, tmp, 1,
0945: parameterTypes.length);
0946: parameterTypes = tmp;
0947: }
0948:
0949: return new MethodDescriptor(IClass
0950: .getDescriptors(parameterTypes), Descriptor.VOID_)
0951: .toString();
0952: }
0953:
0954: public String toString() {
0955: StringBuffer sb = new StringBuffer(this
0956: .getDeclaringIClass().toString());
0957: sb.append('(');
0958: try {
0959: IClass[] parameterTypes = this .getParameterTypes();
0960: for (int i = 0; i < parameterTypes.length; ++i) {
0961: if (i > 0)
0962: sb.append(", ");
0963: sb.append(parameterTypes[i].toString());
0964: }
0965: } catch (CompileException ex) {
0966: sb.append("<invalid type>");
0967: }
0968: sb.append(')');
0969: return sb.toString();
0970: }
0971: }
0972:
0973: public abstract class IMethod extends IInvocable {
0974: public abstract boolean isStatic();
0975:
0976: public abstract boolean isAbstract();
0977:
0978: public abstract IClass getReturnType() throws CompileException;
0979:
0980: public abstract String getName();
0981:
0982: public String getDescriptor() throws CompileException {
0983: return new MethodDescriptor(IClass.getDescriptors(this
0984: .getParameterTypes()), this .getReturnType()
0985: .getDescriptor()).toString();
0986: }
0987:
0988: public String toString() {
0989: StringBuffer sb = new StringBuffer();
0990: try {
0991: sb.append(this .getReturnType().toString());
0992: } catch (CompileException ex) {
0993: sb.append("<invalid type>");
0994: }
0995: sb.append(' ');
0996: sb.append(this .getDeclaringIClass().toString());
0997: sb.append('.');
0998: sb.append(this .getName());
0999: sb.append('(');
1000: try {
1001: IClass[] parameterTypes = this .getParameterTypes();
1002: for (int i = 0; i < parameterTypes.length; ++i) {
1003: if (i > 0)
1004: sb.append(", ");
1005: sb.append(parameterTypes[i].toString());
1006: }
1007: } catch (CompileException ex) {
1008: sb.append("<invalid type>");
1009: }
1010: sb.append(')');
1011: try {
1012: IClass[] tes = this .getThrownExceptions();
1013: if (tes.length > 0) {
1014: sb.append(" throws ").append(tes[0]);
1015: for (int i = 1; i < tes.length; ++i)
1016: sb.append(", ").append(tes[i]);
1017: }
1018: } catch (CompileException ex) {
1019: sb.append("<invalid thrown exception type>");
1020: }
1021: return sb.toString();
1022: }
1023: }
1024:
1025: public abstract class IField implements IMember {
1026:
1027: // Implement IMember.
1028: public abstract Access getAccess();
1029:
1030: public IClass getDeclaringIClass() {
1031: return IClass.this ;
1032: }
1033:
1034: public abstract boolean isStatic();
1035:
1036: public abstract IClass getType() throws CompileException;
1037:
1038: public abstract String getName();
1039:
1040: public String getDescriptor() throws CompileException {
1041: return this .getType().getDescriptor();
1042: }
1043:
1044: /**
1045: * Returns the value of the field if it is a compile-time constant
1046: * value, i.e. the field is FINAL and its initializer is a constant
1047: * expression (JLS2 15.28, bullet 12).
1048: */
1049: public abstract Object getConstantValue()
1050: throws CompileException;
1051:
1052: public String toString() {
1053: return this.getName();
1054: }
1055: }
1056: }
|