0001: /*
0002: * Copyright 1994-2006 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package sun.tools.java;
0027:
0028: import sun.tools.tree.Node;
0029: import sun.tools.tree.Vset;
0030: import sun.tools.tree.Expression;
0031: import sun.tools.tree.Statement;
0032: import sun.tools.tree.Context;
0033: import sun.tools.asm.Assembler;
0034: import java.io.PrintStream;
0035: import java.util.Vector;
0036: import java.util.Map;
0037: import java.util.HashMap;
0038:
0039: /**
0040: * This class defines a member of a Java class:
0041: * a variable, a method, or an inner class.
0042: *
0043: * WARNING: The contents of this source file are not part of any
0044: * supported API. Code that depends on them does so at its own risk:
0045: * they are subject to change or removal without notice.
0046: */
0047: public class MemberDefinition implements Constants {
0048: protected long where;
0049: protected int modifiers;
0050: protected Type type;
0051: protected String documentation;
0052: protected IdentifierToken expIds[];
0053: protected ClassDeclaration exp[];
0054: protected Node value;
0055: protected ClassDefinition clazz;
0056: protected Identifier name;
0057: protected ClassDefinition innerClass;
0058: protected MemberDefinition nextMember;
0059: protected MemberDefinition nextMatch;
0060: protected MemberDefinition accessPeer;
0061: protected boolean super AccessMethod;
0062:
0063: /**
0064: * Constructor
0065: */
0066: public MemberDefinition(long where, ClassDefinition clazz,
0067: int modifiers, Type type, Identifier name,
0068: IdentifierToken expIds[], Node value) {
0069: if (expIds == null) {
0070: expIds = new IdentifierToken[0];
0071: }
0072: this .where = where;
0073: this .clazz = clazz;
0074: this .modifiers = modifiers;
0075: this .type = type;
0076: this .name = name;
0077: this .expIds = expIds;
0078: this .value = value;
0079: }
0080:
0081: /**
0082: * Constructor for an inner class.
0083: * Inner classes are represented as fields right along with
0084: * variables and methods for simplicity of data structure,
0085: * and to reflect properly the textual declaration order.
0086: * <p>
0087: * This constructor calls the generic constructor for this
0088: * class, extracting all necessary values from the innerClass.
0089: */
0090: public MemberDefinition(ClassDefinition innerClass) {
0091: this (innerClass.getWhere(), innerClass.getOuterClass(),
0092: innerClass.getModifiers(), innerClass.getType(),
0093: innerClass.getName().getFlatName().getName(), null,
0094: null);
0095: this .innerClass = innerClass;
0096: }
0097:
0098: /**
0099: * A cache of previously created proxy members. Used to ensure
0100: * uniqueness of proxy objects. See the makeProxyMember method
0101: * defined below.
0102: */
0103: static private Map proxyCache;
0104:
0105: /**
0106: * Create a member which is externally the same as `field' but
0107: * is defined in class `classDef'. This is used by code
0108: * in sun.tools.tree.(MethodExpression,FieldExpression) as
0109: * part of the fix for bug 4135692.
0110: *
0111: * Proxy members should not be added, ala addMember(), to classes.
0112: * They are merely "stand-ins" to produce modified MethodRef
0113: * constant pool entries during code generation.
0114: *
0115: * We keep a cache of previously created proxy members not to
0116: * save time or space, but to ensure uniqueness of the proxy
0117: * member for any (field,classDef) pair. If these are not made
0118: * unique then we can end up generating duplicate MethodRef
0119: * constant pool entries during code generation.
0120: */
0121: public static MemberDefinition makeProxyMember(
0122: MemberDefinition field, ClassDefinition classDef,
0123: Environment env) {
0124:
0125: if (proxyCache == null) {
0126: proxyCache = new HashMap();
0127: }
0128:
0129: String key = field.toString() + "@" + classDef.toString();
0130: // System.out.println("Key is : " + key);
0131: MemberDefinition proxy = (MemberDefinition) proxyCache.get(key);
0132:
0133: if (proxy != null)
0134: return proxy;
0135:
0136: proxy = new MemberDefinition(field.getWhere(), classDef, field
0137: .getModifiers(), field.getType(), field.getName(),
0138: field.getExceptionIds(), null);
0139: proxy.exp = field.getExceptions(env);
0140: proxyCache.put(key, proxy);
0141:
0142: return proxy;
0143: }
0144:
0145: /**
0146: * Get the position in the input
0147: */
0148: public final long getWhere() {
0149: return where;
0150: }
0151:
0152: /**
0153: * Get the class declaration
0154: */
0155: public final ClassDeclaration getClassDeclaration() {
0156: return clazz.getClassDeclaration();
0157: }
0158:
0159: /**
0160: * A stub. Subclasses can do more checking.
0161: */
0162: public void resolveTypeStructure(Environment env) {
0163: }
0164:
0165: /**
0166: * Get the class declaration in which the field is actually defined
0167: */
0168: public ClassDeclaration getDefiningClassDeclaration() {
0169: return getClassDeclaration();
0170: }
0171:
0172: /**
0173: * Get the class definition
0174: */
0175: public final ClassDefinition getClassDefinition() {
0176: return clazz;
0177: }
0178:
0179: /**
0180: * Get the field's top-level enclosing class
0181: */
0182: public final ClassDefinition getTopClass() {
0183: return clazz.getTopClass();
0184: }
0185:
0186: /**
0187: * Get the field's modifiers
0188: */
0189: public final int getModifiers() {
0190: return modifiers;
0191: }
0192:
0193: public final void subModifiers(int mod) {
0194: modifiers &= ~mod;
0195: }
0196:
0197: public final void addModifiers(int mod) {
0198: modifiers |= mod;
0199: }
0200:
0201: /**
0202: * Get the field's type
0203: */
0204: public final Type getType() {
0205: return type;
0206: }
0207:
0208: /**
0209: * Get the field's name
0210: */
0211: public final Identifier getName() {
0212: return name;
0213: }
0214:
0215: /**
0216: * Get arguments (a vector of LocalMember)
0217: */
0218: public Vector getArguments() {
0219: return isMethod() ? new Vector() : null;
0220: }
0221:
0222: /**
0223: * Get the exceptions that are thrown by this method.
0224: */
0225: public ClassDeclaration[] getExceptions(Environment env) {
0226: if (expIds != null && exp == null) {
0227: if (expIds.length == 0)
0228: exp = new ClassDeclaration[0];
0229: else
0230: // we should have translated this already!
0231: throw new CompilerError("getExceptions " + this );
0232: }
0233: return exp;
0234: }
0235:
0236: public final IdentifierToken[] getExceptionIds() {
0237: return expIds;
0238: }
0239:
0240: /**
0241: * Get an inner class.
0242: */
0243: public ClassDefinition getInnerClass() {
0244: return innerClass;
0245: }
0246:
0247: /**
0248: * Is this a synthetic field which holds a copy of,
0249: * or reference to, a local variable or enclosing instance?
0250: */
0251: public boolean isUplevelValue() {
0252: if (!isSynthetic() || !isVariable() || isStatic()) {
0253: return false;
0254: }
0255: String name = this .name.toString();
0256: return name.startsWith(prefixVal)
0257: || name.toString().startsWith(prefixLoc)
0258: || name.toString().startsWith(prefixThis);
0259: }
0260:
0261: public boolean isAccessMethod() {
0262: // This no longer works, because access methods
0263: // for constructors do not use the standard naming
0264: // scheme.
0265: // return isSynthetic() && isMethod()
0266: // && name.toString().startsWith(prefixAccess);
0267: // Assume that a method is an access method if it has
0268: // an access peer. NOTE: An access method will not be
0269: // recognized as such until 'setAccessMethodTarget' has
0270: // been called on it.
0271: return isSynthetic() && isMethod() && (accessPeer != null);
0272: }
0273:
0274: /**
0275: * Is this a synthetic method which provides access to a
0276: * visible private member?
0277: */
0278: public MemberDefinition getAccessMethodTarget() {
0279: if (isAccessMethod()) {
0280: for (MemberDefinition f = accessPeer; f != null; f = f.accessPeer) {
0281: // perhaps skip over another access for the same field
0282: if (!f.isAccessMethod()) {
0283: return f;
0284: }
0285: }
0286: }
0287: return null;
0288: }
0289:
0290: public void setAccessMethodTarget(MemberDefinition target) {
0291: if (getAccessMethodTarget() != target) {
0292: /*-------------------*
0293: if (!isAccessMethod() || accessPeer != null ||
0294: target.accessPeer != null) {
0295: throw new CompilerError("accessPeer");
0296: }
0297: *-------------------*/
0298: if (accessPeer != null || target.accessPeer != null) {
0299: throw new CompilerError("accessPeer");
0300: }
0301: accessPeer = target;
0302: }
0303: }
0304:
0305: /**
0306: * If this method is a getter for a private field, return the setter.
0307: */
0308: public MemberDefinition getAccessUpdateMember() {
0309: if (isAccessMethod()) {
0310: for (MemberDefinition f = accessPeer; f != null; f = f.accessPeer) {
0311: if (f.isAccessMethod()) {
0312: return f;
0313: }
0314: }
0315: }
0316: return null;
0317: }
0318:
0319: public void setAccessUpdateMember(MemberDefinition updater) {
0320: if (getAccessUpdateMember() != updater) {
0321: if (!isAccessMethod()
0322: || updater.getAccessMethodTarget() != getAccessMethodTarget()) {
0323: throw new CompilerError("accessPeer");
0324: }
0325: updater.accessPeer = accessPeer;
0326: accessPeer = updater;
0327: }
0328: }
0329:
0330: /**
0331: * Is this an access method for a field selection or method call
0332: * of the form '...super.foo' or '...super.foo()'?
0333: */
0334: public final boolean isSuperAccessMethod() {
0335: return super AccessMethod;
0336: }
0337:
0338: /**
0339: * Mark this member as an access method for a field selection
0340: * or method call via the 'super' keyword.
0341: */
0342: public final void setIsSuperAccessMethod(boolean b) {
0343: super AccessMethod = b;
0344: }
0345:
0346: /**
0347: * Tell if this is a final variable without an initializer.
0348: * Such variables are subject to definite single assignment.
0349: */
0350: public final boolean isBlankFinal() {
0351: return isFinal() && !isSynthetic() && getValue() == null;
0352: }
0353:
0354: public boolean isNeverNull() {
0355: if (isUplevelValue()) {
0356: // loc$x and this$C are never null
0357: return !name.toString().startsWith(prefixVal);
0358: }
0359: return false;
0360: }
0361:
0362: /**
0363: * Get the field's final value (may return null)
0364: */
0365: public Node getValue(Environment env) throws ClassNotFound {
0366: return value;
0367: }
0368:
0369: public final Node getValue() {
0370: return value;
0371: }
0372:
0373: public final void setValue(Node value) {
0374: this .value = value;
0375: }
0376:
0377: public Object getInitialValue() {
0378: return null;
0379: }
0380:
0381: /**
0382: * Get the next field or the next match
0383: */
0384: public final MemberDefinition getNextMember() {
0385: return nextMember;
0386: }
0387:
0388: public final MemberDefinition getNextMatch() {
0389: return nextMatch;
0390: }
0391:
0392: /**
0393: * Get the field's documentation
0394: */
0395: public String getDocumentation() {
0396: return documentation;
0397: }
0398:
0399: /**
0400: * Request a check of the field definition.
0401: */
0402: public void check(Environment env) throws ClassNotFound {
0403: }
0404:
0405: /**
0406: * Really check the field definition.
0407: */
0408: public Vset check(Environment env, Context ctx, Vset vset)
0409: throws ClassNotFound {
0410: return vset;
0411: }
0412:
0413: /**
0414: * Generate code
0415: */
0416: public void code(Environment env, Assembler asm)
0417: throws ClassNotFound {
0418: throw new CompilerError("code");
0419: }
0420:
0421: public void codeInit(Environment env, Context ctx, Assembler asm)
0422: throws ClassNotFound {
0423: throw new CompilerError("codeInit");
0424: }
0425:
0426: /**
0427: * Tells whether to report a deprecation error for this field.
0428: */
0429: public boolean reportDeprecated(Environment env) {
0430: return (isDeprecated() || clazz.reportDeprecated(env));
0431: }
0432:
0433: /**
0434: * Check if a field can reach another field (only considers
0435: * forward references, not the access modifiers).
0436: */
0437: public final boolean canReach(Environment env, MemberDefinition f) {
0438: if (f.isLocal() || !f.isVariable()
0439: || !(isVariable() || isInitializer()))
0440: return true;
0441: if ((getClassDeclaration().equals(f.getClassDeclaration()))
0442: && (isStatic() == f.isStatic())) {
0443: // They are located in the same class, and are either both
0444: // static or both non-static. Check the initialization order.
0445: while (((f = f.getNextMember()) != null) && (f != this ))
0446: ;
0447: return f != null;
0448: }
0449: return true;
0450: }
0451:
0452: //-----------------------------------------------------------------
0453: // The code in this section is intended to test certain kinds of
0454: // compatibility between methods. There are two kinds of compatibility
0455: // that the compiler may need to test. The first is whether one
0456: // method can legally override another. The second is whether two
0457: // method definitions can legally coexist. We use the word `meet'
0458: // to mean the intersection of two legally coexisting methods.
0459: // For more information on these kinds of compatibility, see the
0460: // comments/code for checkOverride() and checkMeet() below.
0461:
0462: /**
0463: * Constants used by getAccessLevel() to represent the access
0464: * modifiers as numbers.
0465: */
0466: static final int PUBLIC_ACCESS = 1;
0467: static final int PROTECTED_ACCESS = 2;
0468: static final int PACKAGE_ACCESS = 3;
0469: static final int PRIVATE_ACCESS = 4;
0470:
0471: /**
0472: * Return the access modifier of this member as a number. The idea
0473: * is that this number may be used to check properties like "the
0474: * access modifier of x is more restrictive than the access
0475: * modifier of y" with a simple inequality test:
0476: * "x.getAccessLevel() > y.getAccessLevel.
0477: *
0478: * This is an internal utility method.
0479: */
0480: private int getAccessLevel() {
0481: // Could just compute this once instead of recomputing.
0482: // Check to see if this is worth it.
0483: if (isPublic()) {
0484: return PUBLIC_ACCESS;
0485: } else if (isProtected()) {
0486: return PROTECTED_ACCESS;
0487: } else if (isPackagePrivate()) {
0488: return PACKAGE_ACCESS;
0489: } else if (isPrivate()) {
0490: return PRIVATE_ACCESS;
0491: } else {
0492: throw new CompilerError("getAccessLevel()");
0493: }
0494: }
0495:
0496: /**
0497: * Munge our error message to report whether the override conflict
0498: * came from an inherited method or a declared method.
0499: */
0500: private void reportError(Environment env, String errorString,
0501: ClassDeclaration clazz, MemberDefinition method) {
0502:
0503: if (clazz == null) {
0504: // For example:
0505: // "Instance method BLAH inherited from CLASSBLAH1 cannot be
0506: // overridden by the static method declared in CLASSBLAH2."
0507: env
0508: .error(getWhere(), errorString, this ,
0509: getClassDeclaration(), method
0510: .getClassDeclaration());
0511: } else {
0512: // For example:
0513: // "In CLASSBLAH1, instance method BLAH inherited from CLASSBLAH2
0514: // cannot be overridden by the static method inherited from
0515: // CLASSBLAH3."
0516: env.error(clazz.getClassDefinition().getWhere(),
0517: //"inherit." + errorString,
0518: errorString,
0519: //clazz,
0520: this , getClassDeclaration(), method
0521: .getClassDeclaration());
0522: }
0523: }
0524:
0525: /**
0526: * Convenience method to see if two methods return the same type
0527: */
0528: public boolean sameReturnType(MemberDefinition method) {
0529: // Make sure both are methods.
0530: if (!isMethod() || !method.isMethod()) {
0531: throw new CompilerError("sameReturnType: not method");
0532: }
0533:
0534: Type myReturnType = getType().getReturnType();
0535: Type yourReturnType = method.getType().getReturnType();
0536:
0537: return (myReturnType == yourReturnType);
0538: }
0539:
0540: /**
0541: * Check to see if `this' can override/hide `method'. Caller is
0542: * responsible for verifying that `method' has the same signature
0543: * as `this'. Caller is also responsible for verifying that
0544: * `method' is visible to the class where this override is occurring.
0545: * This method is called for the case when class B extends A and both
0546: * A and B define some method.
0547: * <pre>
0548: * A - void foo() throws e1
0549: * |
0550: * |
0551: * B - void foo() throws e2
0552: * </pre>
0553: */
0554: public boolean checkOverride(Environment env,
0555: MemberDefinition method) {
0556: return checkOverride(env, method, null);
0557: }
0558:
0559: /**
0560: * Checks whether `this' can override `method'. It `clazz' is
0561: * null, it reports the errors in the class where `this' is
0562: * declared. If `clazz' is not null, it reports the error in `clazz'.
0563: */
0564: private boolean checkOverride(Environment env,
0565: MemberDefinition method, ClassDeclaration clazz) {
0566: // This section of code is largely based on section 8.4.6.3
0567: // of the JLS.
0568:
0569: boolean success = true;
0570:
0571: // Sanity
0572: if (!isMethod()) {
0573: throw new CompilerError("checkOverride(), expected method");
0574: }
0575:
0576: // Suppress checks for synthetic methods, as the compiler presumably
0577: // knows what it is doing, e.g., access methods.
0578: if (isSynthetic()) {
0579: // Sanity check: We generally do not intend for one synthetic
0580: // method to override another, though hiding of static members
0581: // is expected. This check may need to be changed if new uses
0582: // of synthetic methods are devised.
0583: //
0584: // Query: this code was copied from elsewhere. What
0585: // exactly is the role of the !isStatic() in the test?
0586: if (method.isFinal()
0587: || (!method.isConstructor() && !method.isStatic() && !isStatic())) {
0588: ////////////////////////////////////////////////////////////
0589: // NMG 2003-01-28 removed the following test because it is
0590: // invalidated by bridge methods inserted by the "generic"
0591: // (1.5) Java compiler. In 1.5, this code is used,
0592: // indirectly, by rmic
0593: ////////////////////////////////////////////////////////////
0594: // throw new CompilerError("checkOverride() synthetic");
0595: ////////////////////////////////////////////////////////////
0596: }
0597:
0598: // We trust the compiler. (Ha!) We're done checking.
0599: return true;
0600: }
0601:
0602: // Our caller should have verified that the method had the
0603: // same signature.
0604: if (getName() != method.getName()
0605: || !getType().equalArguments(method.getType())) {
0606:
0607: throw new CompilerError(
0608: "checkOverride(), signature mismatch");
0609: }
0610:
0611: // It is forbidden to `override' a static method with an instance
0612: // method.
0613: if (method.isStatic() && !isStatic()) {
0614: reportError(env, "override.static.with.instance", clazz,
0615: method);
0616: success = false;
0617: }
0618:
0619: // It is forbidden to `hide' an instance method with a static
0620: // method.
0621: if (!method.isStatic() && isStatic()) {
0622: reportError(env, "hide.instance.with.static", clazz, method);
0623: success = false;
0624: }
0625:
0626: // We cannot override a final method.
0627: if (method.isFinal()) {
0628: reportError(env, "override.final.method", clazz, method);
0629: success = false;
0630: }
0631:
0632: // Give a warning when we override a deprecated method with
0633: // a non-deprecated one.
0634: //
0635: // We bend over backwards to suppress this warning if
0636: // the `method' has not been already compiled or
0637: // `this' has been already compiled.
0638: if (method.reportDeprecated(env) && !isDeprecated()
0639: && this instanceof sun.tools.javac.SourceMember) {
0640: reportError(env, "warn.override.is.deprecated", clazz,
0641: method);
0642: }
0643:
0644: // Visibility may not be more restrictive
0645: if (getAccessLevel() > method.getAccessLevel()) {
0646: reportError(env, "override.more.restrictive", clazz, method);
0647: success = false;
0648: }
0649:
0650: // Return type equality
0651: if (!sameReturnType(method)) {
0652: ////////////////////////////////////////////////////////////
0653: // PCJ 2003-07-30 removed the following error because it is
0654: // invalidated by the covariant return type feature of the
0655: // 1.5 compiler. The resulting check is now much looser
0656: // than the actual 1.5 language spec, but that should be OK
0657: // because this code is only still used by rmic. See 4892308.
0658: ////////////////////////////////////////////////////////////
0659: // reportError(env, "override.different.return", clazz, method);
0660: // success = false;
0661: ////////////////////////////////////////////////////////////
0662: }
0663:
0664: // Exception agreeement
0665: if (!exceptionsFit(env, method)) {
0666: reportError(env, "override.incompatible.exceptions", clazz,
0667: method);
0668: success = false;
0669: }
0670:
0671: return success;
0672: }
0673:
0674: /**
0675: * Check to see if two method definitions are compatible, that is
0676: * do they have a `meet'. The meet of two methods is essentially
0677: * and `intersection' of
0678: * two methods. This method is called when some class C inherits
0679: * declarations for some method foo from two parents (superclass,
0680: * interfaces) but it does not, itself, have a declaration of foo.
0681: * Caller is responsible for making sure that both methods are
0682: * indeed visible in clazz.
0683: * <pre>
0684: * A - void foo() throws e1
0685: * \
0686: * \ B void foo() throws e2
0687: * \ /
0688: * \ /
0689: * C
0690: * </pre>
0691: */
0692: public boolean checkMeet(Environment env, MemberDefinition method,
0693: ClassDeclaration clazz) {
0694: // This section of code is largely based on Section 8.4.6
0695: // and 9.4.1 of the JLS.
0696:
0697: // Sanity
0698: if (!isMethod()) {
0699: throw new CompilerError("checkMeet(), expected method");
0700: }
0701:
0702: // Check for both non-abstract.
0703: if (!isAbstract() && !method.isAbstract()) {
0704: throw new CompilerError("checkMeet(), no abstract method");
0705: }
0706:
0707: // If either method is non-abstract, then we need to check that
0708: // the abstract method can be properly overridden. We call
0709: // the checkOverride method to check this and generate any errors.
0710: // This test must follow the previous test.
0711: else if (!isAbstract()) {
0712: return checkOverride(env, method, clazz);
0713: } else if (!method.isAbstract()) {
0714: return method.checkOverride(env, this , clazz);
0715: }
0716:
0717: // Both methods are abstract.
0718:
0719: // Our caller should have verified that the method has the
0720: // same signature.
0721: if (getName() != method.getName()
0722: || !getType().equalArguments(method.getType())) {
0723:
0724: throw new CompilerError("checkMeet(), signature mismatch");
0725: }
0726:
0727: // Check for return type equality
0728: if (!sameReturnType(method)) {
0729: // More args?
0730: env.error(clazz.getClassDefinition().getWhere(),
0731: "meet.different.return", this , this
0732: .getClassDeclaration(), method
0733: .getClassDeclaration());
0734: return false;
0735: }
0736:
0737: // We don't have to check visibility -- there always
0738: // potentially exists a meet. Similarly with exceptions.
0739:
0740: // There does exist a meet.
0741: return true;
0742: }
0743:
0744: /**
0745: * This method is meant to be used to determine if one of two inherited
0746: * methods could override the other. Unlike checkOverride(), failure
0747: * is not an error. This method is only meant to be called after
0748: * checkMeet() has succeeded on the two methods.
0749: *
0750: * If you call couldOverride() without doing a checkMeet() first, then
0751: * you are on your own.
0752: */
0753: public boolean couldOverride(Environment env,
0754: MemberDefinition method) {
0755:
0756: // Sanity
0757: if (!isMethod()) {
0758: throw new CompilerError("coulcOverride(), expected method");
0759: }
0760:
0761: // couldOverride() is only called with `this' and `method' both
0762: // being inherited methods. Neither of them is defined in the
0763: // class which we are currently working on. Even though an
0764: // abstract method defined *in* a class can override a non-abstract
0765: // method defined in a superclass, an abstract method inherited
0766: // from an interface *never* can override a non-abstract method.
0767: // This comment may sound odd, but that's the way inheritance is.
0768: // The following check makes sure we aren't trying to override
0769: // an inherited non-abstract definition with an abstract definition
0770: // from an interface.
0771: if (!method.isAbstract()) {
0772: return false;
0773: }
0774:
0775: // Visibility should be less restrictive
0776: if (getAccessLevel() > method.getAccessLevel()) {
0777: return false;
0778: }
0779:
0780: // Exceptions
0781: if (!exceptionsFit(env, method)) {
0782: return false;
0783: }
0784:
0785: // Potentially some deprecation warnings could be given here
0786: // when we merge two abstract methods, one of which is deprecated.
0787: // This is not currently reported.
0788:
0789: return true;
0790: }
0791:
0792: /**
0793: * Check to see if the exceptions of `this' fit within the
0794: * exceptions of `method'.
0795: */
0796: private boolean exceptionsFit(Environment env,
0797: MemberDefinition method) {
0798: ClassDeclaration e1[] = getExceptions(env); // my exceptions
0799: ClassDeclaration e2[] = method.getExceptions(env); // parent's
0800:
0801: // This code is taken nearly verbatim from the old implementation
0802: // of checkOverride() in SourceClass.
0803: outer: for (int i = 0; i < e1.length; i++) {
0804: try {
0805: ClassDefinition c1 = e1[i].getClassDefinition(env);
0806: for (int j = 0; j < e2.length; j++) {
0807: if (c1.subClassOf(env, e2[j])) {
0808: continue outer;
0809: }
0810: }
0811: if (c1.subClassOf(env, env
0812: .getClassDeclaration(idJavaLangError)))
0813: continue outer;
0814: if (c1
0815: .subClassOf(
0816: env,
0817: env
0818: .getClassDeclaration(idJavaLangRuntimeException)))
0819: continue outer;
0820:
0821: // the throws was neither something declared by a parent,
0822: // nor one of the ignorables.
0823: return false;
0824:
0825: } catch (ClassNotFound ee) {
0826: // We were unable to find one of the exceptions.
0827: env.error(getWhere(), "class.not.found", ee.name,
0828: method.getClassDeclaration());
0829: }
0830: }
0831:
0832: // All of the exceptions `fit'.
0833: return true;
0834: }
0835:
0836: //-----------------------------------------------------------------
0837:
0838: /**
0839: * Checks
0840: */
0841: public final boolean isPublic() {
0842: return (modifiers & M_PUBLIC) != 0;
0843: }
0844:
0845: public final boolean isPrivate() {
0846: return (modifiers & M_PRIVATE) != 0;
0847: }
0848:
0849: public final boolean isProtected() {
0850: return (modifiers & M_PROTECTED) != 0;
0851: }
0852:
0853: public final boolean isPackagePrivate() {
0854: return (modifiers & (M_PUBLIC | M_PRIVATE | M_PROTECTED)) == 0;
0855: }
0856:
0857: public final boolean isFinal() {
0858: return (modifiers & M_FINAL) != 0;
0859: }
0860:
0861: public final boolean isStatic() {
0862: return (modifiers & M_STATIC) != 0;
0863: }
0864:
0865: public final boolean isSynchronized() {
0866: return (modifiers & M_SYNCHRONIZED) != 0;
0867: }
0868:
0869: public final boolean isAbstract() {
0870: return (modifiers & M_ABSTRACT) != 0;
0871: }
0872:
0873: public final boolean isNative() {
0874: return (modifiers & M_NATIVE) != 0;
0875: }
0876:
0877: public final boolean isVolatile() {
0878: return (modifiers & M_VOLATILE) != 0;
0879: }
0880:
0881: public final boolean isTransient() {
0882: return (modifiers & M_TRANSIENT) != 0;
0883: }
0884:
0885: public final boolean isMethod() {
0886: return type.isType(TC_METHOD);
0887: }
0888:
0889: public final boolean isVariable() {
0890: return !type.isType(TC_METHOD) && innerClass == null;
0891: }
0892:
0893: public final boolean isSynthetic() {
0894: return (modifiers & M_SYNTHETIC) != 0;
0895: }
0896:
0897: public final boolean isDeprecated() {
0898: return (modifiers & M_DEPRECATED) != 0;
0899: }
0900:
0901: public final boolean isStrict() {
0902: return (modifiers & M_STRICTFP) != 0;
0903: }
0904:
0905: public final boolean isInnerClass() {
0906: return innerClass != null;
0907: }
0908:
0909: public final boolean isInitializer() {
0910: return getName().equals(idClassInit);
0911: }
0912:
0913: public final boolean isConstructor() {
0914: return getName().equals(idInit);
0915: }
0916:
0917: public boolean isLocal() {
0918: return false;
0919: }
0920:
0921: public boolean isInlineable(Environment env, boolean fromFinal)
0922: throws ClassNotFound {
0923: return (isStatic() || isPrivate() || isFinal()
0924: || isConstructor() || fromFinal)
0925: && !(isSynchronized() || isNative());
0926: }
0927:
0928: /**
0929: * Check if constant: Will it inline away to a constant?
0930: */
0931: public boolean isConstant() {
0932: if (isFinal() && isVariable() && value != null) {
0933: try {
0934: // If an infinite regress requeries this name,
0935: // deny that it is a constant.
0936: modifiers &= ~M_FINAL;
0937: return ((Expression) value).isConstant();
0938: } finally {
0939: modifiers |= M_FINAL;
0940: }
0941: }
0942: return false;
0943: }
0944:
0945: /**
0946: * toString
0947: */
0948: public String toString() {
0949: Identifier name = getClassDefinition().getName();
0950: if (isInitializer()) {
0951: return isStatic() ? "static {}" : "instance {}";
0952: } else if (isConstructor()) {
0953: StringBuffer buf = new StringBuffer();
0954: buf.append(name);
0955: buf.append('(');
0956: Type argTypes[] = getType().getArgumentTypes();
0957: for (int i = 0; i < argTypes.length; i++) {
0958: if (i > 0) {
0959: buf.append(',');
0960: }
0961: buf.append(argTypes[i].toString());
0962: }
0963: buf.append(')');
0964: return buf.toString();
0965: } else if (isInnerClass()) {
0966: return getInnerClass().toString();
0967: }
0968: return type.typeString(getName().toString());
0969: }
0970:
0971: /**
0972: * Print for debugging
0973: */
0974: public void print(PrintStream out) {
0975: if (isPublic()) {
0976: out.print("public ");
0977: }
0978: if (isPrivate()) {
0979: out.print("private ");
0980: }
0981: if (isProtected()) {
0982: out.print("protected ");
0983: }
0984: if (isFinal()) {
0985: out.print("final ");
0986: }
0987: if (isStatic()) {
0988: out.print("static ");
0989: }
0990: if (isSynchronized()) {
0991: out.print("synchronized ");
0992: }
0993: if (isAbstract()) {
0994: out.print("abstract ");
0995: }
0996: if (isNative()) {
0997: out.print("native ");
0998: }
0999: if (isVolatile()) {
1000: out.print("volatile ");
1001: }
1002: if (isTransient()) {
1003: out.print("transient ");
1004: }
1005: out.println(toString() + ";");
1006: }
1007:
1008: public void cleanup(Environment env) {
1009: documentation = null;
1010: if (isMethod() && value != null) {
1011: int cost = 0;
1012: if (isPrivate() || isInitializer()) {
1013: value = Statement.empty;
1014: } else if ((cost = ((Statement) value).costInline(
1015: Statement.MAXINLINECOST, null, null)) >= Statement.MAXINLINECOST) {
1016: // will never be inlined
1017: value = Statement.empty;
1018: } else {
1019: try {
1020: if (!isInlineable(null, true)) {
1021: value = Statement.empty;
1022: }
1023: } catch (ClassNotFound ee) {
1024: }
1025: }
1026: if (value != Statement.empty && env.dump()) {
1027: env.output("[after cleanup of " + getName() + ", "
1028: + cost + " expression cost units remain]");
1029: }
1030: } else if (isVariable()) {
1031: if (isPrivate() || !isFinal() || type.isType(TC_ARRAY)) {
1032: value = null;
1033: }
1034: }
1035: }
1036: }
|