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 java.util.*;
0029: import java.io.OutputStream;
0030: import java.io.PrintStream;
0031: import sun.tools.tree.Context;
0032: import sun.tools.tree.Vset;
0033: import sun.tools.tree.Expression;
0034: import sun.tools.tree.LocalMember;
0035: import sun.tools.tree.UplevelReference;
0036:
0037: /**
0038: * This class is a Java class definition
0039: *
0040: * WARNING: The contents of this source file are not part of any
0041: * supported API. Code that depends on them does so at its own risk:
0042: * they are subject to change or removal without notice.
0043: */
0044: public class ClassDefinition implements Constants {
0045:
0046: protected Object source;
0047: protected long where;
0048: protected int modifiers;
0049: protected Identifier localName; // for local classes
0050: protected ClassDeclaration declaration;
0051: protected IdentifierToken super ClassId;
0052: protected IdentifierToken interfaceIds[];
0053: protected ClassDeclaration super Class;
0054: protected ClassDeclaration interfaces[];
0055: protected ClassDefinition outerClass;
0056: protected MemberDefinition outerMember;
0057: protected MemberDefinition innerClassMember; // field for me in outerClass
0058: protected MemberDefinition firstMember;
0059: protected MemberDefinition lastMember;
0060: protected boolean resolved;
0061: protected String documentation;
0062: protected boolean error;
0063: protected boolean nestError;
0064: protected UplevelReference references;
0065: protected boolean referencesFrozen;
0066: private Hashtable fieldHash = new Hashtable(31);
0067: private int abstr;
0068:
0069: // Table of local and anonymous classes whose internal names are constructed
0070: // using the current class as a prefix. This is part of a fix for
0071: // bugid 4054523 and 4030421. See also 'Environment.getClassDefinition'
0072: // and 'BatchEnvironment.makeClassDefinition'. Allocated on demand.
0073: private Hashtable localClasses = null;
0074: private final int LOCAL_CLASSES_SIZE = 31;
0075:
0076: // The immediately surrounding context in which the class appears.
0077: // Set at the beginning of checking, upon entry to 'SourceClass.checkInternal'.
0078: // Null for classes that are not local or inside a local class.
0079: // At present, this field exists only for the benefit of 'resolveName' as part
0080: // of the fix for 4095716.
0081: protected Context classContext;
0082:
0083: // The saved class context is now also used in 'SourceClass.getAccessMember'.
0084: // Provide read-only access via this method. Part of fix for 4098093.
0085: public Context getClassContext() {
0086: return classContext;
0087: }
0088:
0089: /**
0090: * Constructor
0091: */
0092: protected ClassDefinition(Object source, long where,
0093: ClassDeclaration declaration, int modifiers,
0094: IdentifierToken super Class, IdentifierToken interfaces[]) {
0095: this .source = source;
0096: this .where = where;
0097: this .declaration = declaration;
0098: this .modifiers = modifiers;
0099: this .super ClassId = super Class;
0100: this .interfaceIds = interfaces;
0101: }
0102:
0103: /**
0104: * Get the source of the class
0105: */
0106: public final Object getSource() {
0107: return source;
0108: }
0109:
0110: /**
0111: * Check if there were any errors in this class.
0112: */
0113: public final boolean getError() {
0114: return error;
0115: }
0116:
0117: /**
0118: * Mark this class to be erroneous.
0119: */
0120: public final void setError() {
0121: this .error = true;
0122: setNestError();
0123: }
0124:
0125: /**
0126: * Check if there were any errors in our class nest.
0127: */
0128: public final boolean getNestError() {
0129: // Check to see if our error value is set, or if any of our
0130: // outer classes' error values are set. This will work in
0131: // conjunction with setError(), which sets the error value
0132: // of its outer class, to yield true is any of our nest
0133: // siblings has an error. This addresses bug 4111488: either
0134: // code should be generated for all classes in a nest, or
0135: // none of them.
0136: return nestError
0137: || ((outerClass != null) ? outerClass.getNestError()
0138: : false);
0139: }
0140:
0141: /**
0142: * Mark this class, and all siblings in its class nest, to be
0143: * erroneous.
0144: */
0145: public final void setNestError() {
0146: this .nestError = true;
0147: if (outerClass != null) {
0148: // If we have an outer class, set it to be erroneous as well.
0149: // This will work in conjunction with getError(), which checks
0150: // the error value of its outer class, to set the whole class
0151: // nest to be erroneous. This address bug 4111488: either
0152: // code should be generated for all classes in a nest, or
0153: // none of them.
0154: outerClass.setNestError();
0155: }
0156: }
0157:
0158: /**
0159: * Get the position in the input
0160: */
0161: public final long getWhere() {
0162: return where;
0163: }
0164:
0165: /**
0166: * Get the class declaration
0167: */
0168: public final ClassDeclaration getClassDeclaration() {
0169: return declaration;
0170: }
0171:
0172: /**
0173: * Get the class' modifiers
0174: */
0175: public final int getModifiers() {
0176: return modifiers;
0177: }
0178:
0179: public final void subModifiers(int mod) {
0180: modifiers &= ~mod;
0181: }
0182:
0183: public final void addModifiers(int mod) {
0184: modifiers |= mod;
0185: }
0186:
0187: // *** DEBUG ***
0188: protected boolean super sCheckStarted = !(this instanceof sun.tools.javac.SourceClass);
0189:
0190: /**
0191: * Get the class' super class
0192: */
0193: public final ClassDeclaration getSuperClass() {
0194: /*---
0195: if (superClass == null && superClassId != null)
0196: throw new CompilerError("getSuperClass "+superClassId);
0197: // There are obscure cases where null is the right answer,
0198: // in order to enable some error reporting later on.
0199: // For example: class T extends T.N { class N { } }
0200: ---*/
0201:
0202: // *** DEBUG ***
0203: // This method should not be called if the superclass has not been resolved.
0204: if (!super sCheckStarted)
0205: throw new CompilerError("unresolved super");
0206:
0207: return super Class;
0208: }
0209:
0210: /**
0211: * Get the super class, and resolve names now if necessary.
0212: *
0213: * It is only possible to resolve names at this point if we are
0214: * a source class. The provision of this method at this level
0215: * in the class hierarchy is dubious, but see 'getInnerClass' below.
0216: * All other calls to 'getSuperClass(env)' appear in 'SourceClass'.
0217: * NOTE: An older definition of this method has been moved to
0218: * 'SourceClass', where it overrides this one.
0219: *
0220: * @see #resolveTypeStructure
0221: */
0222:
0223: public ClassDeclaration getSuperClass(Environment env) {
0224: return getSuperClass();
0225: }
0226:
0227: /**
0228: * Get the class' interfaces
0229: */
0230: public final ClassDeclaration getInterfaces()[] {
0231: if (interfaces == null)
0232: throw new CompilerError("getInterfaces");
0233: return interfaces;
0234: }
0235:
0236: /**
0237: * Get the class' enclosing class (or null if not inner)
0238: */
0239: public final ClassDefinition getOuterClass() {
0240: return outerClass;
0241: }
0242:
0243: /**
0244: * Set the class' enclosing class. Must be done at most once.
0245: */
0246: protected final void setOuterClass(ClassDefinition outerClass) {
0247: if (this .outerClass != null)
0248: throw new CompilerError("setOuterClass");
0249: this .outerClass = outerClass;
0250: }
0251:
0252: /**
0253: * Set the class' enclosing current instance pointer.
0254: * Must be done at most once.
0255: */
0256: protected final void setOuterMember(MemberDefinition outerMember) {
0257:
0258: if (isStatic() || !isInnerClass())
0259: throw new CompilerError("setOuterField");
0260: if (this .outerMember != null)
0261: throw new CompilerError("setOuterField");
0262: this .outerMember = outerMember;
0263: }
0264:
0265: /**
0266: * Tell if the class is inner.
0267: * This predicate also returns true for top-level nested types.
0268: * To test for a true inner class as seen by the programmer,
0269: * use <tt>!isTopLevel()</tt>.
0270: */
0271: public final boolean isInnerClass() {
0272: return outerClass != null;
0273: }
0274:
0275: /**
0276: * Tell if the class is a member of another class.
0277: * This is false for package members and for block-local classes.
0278: */
0279: public final boolean isMember() {
0280: return outerClass != null && !isLocal();
0281: }
0282:
0283: /**
0284: * Tell if the class is "top-level", which is either a package member,
0285: * or a static member of another top-level class.
0286: */
0287: public final boolean isTopLevel() {
0288: return outerClass == null || isStatic() || isInterface();
0289: }
0290:
0291: /**
0292: * Tell if the class is local or inside a local class,
0293: * which means it cannot be mentioned outside of its file.
0294: */
0295:
0296: // The comment above is true only because M_LOCAL is set
0297: // whenever M_ANONYMOUS is. I think it is risky to assume that
0298: // isAnonymous(x) => isLocal(x).
0299: public final boolean isInsideLocal() {
0300: return isLocal()
0301: || (outerClass != null && outerClass.isInsideLocal());
0302: }
0303:
0304: /**
0305: * Tell if the class is local or or anonymous class, or inside
0306: * such a class, which means it cannot be mentioned outside of
0307: * its file.
0308: */
0309: public final boolean isInsideLocalOrAnonymous() {
0310: return isLocal()
0311: || isAnonymous()
0312: || (outerClass != null && outerClass
0313: .isInsideLocalOrAnonymous());
0314: }
0315:
0316: /**
0317: * Return a simple identifier for this class (idNull if anonymous).
0318: */
0319: public Identifier getLocalName() {
0320: if (localName != null) {
0321: return localName;
0322: }
0323: // This is also the name of the innerClassMember, if any:
0324: return getName().getFlatName().getName();
0325: }
0326:
0327: /**
0328: * Set the local name of a class. Must be a local class.
0329: */
0330: public void setLocalName(Identifier name) {
0331: if (isLocal()) {
0332: localName = name;
0333: }
0334: }
0335:
0336: /**
0337: * If inner, get the field for this class in the enclosing class
0338: */
0339: public final MemberDefinition getInnerClassMember() {
0340: if (outerClass == null)
0341: return null;
0342: if (innerClassMember == null) {
0343: // We must find the field in the outer class.
0344: Identifier nm = getName().getFlatName().getName();
0345: for (MemberDefinition field = outerClass.getFirstMatch(nm); field != null; field = field
0346: .getNextMatch()) {
0347: if (field.isInnerClass()) {
0348: innerClassMember = field;
0349: break;
0350: }
0351: }
0352: if (innerClassMember == null)
0353: throw new CompilerError("getInnerClassField");
0354: }
0355: return innerClassMember;
0356: }
0357:
0358: /**
0359: * If inner, return an innermost uplevel self pointer, if any exists.
0360: * Otherwise, return null.
0361: */
0362: public final MemberDefinition findOuterMember() {
0363: return outerMember;
0364: }
0365:
0366: /**
0367: * See if this is a (nested) static class.
0368: */
0369: public final boolean isStatic() {
0370: return (modifiers & ACC_STATIC) != 0;
0371: }
0372:
0373: /**
0374: * Get the class' top-level enclosing class
0375: */
0376: public final ClassDefinition getTopClass() {
0377: ClassDefinition p, q;
0378: for (p = this ; (q = p.outerClass) != null; p = q)
0379: ;
0380: return p;
0381: }
0382:
0383: /**
0384: * Get the class' first field or first match
0385: */
0386: public final MemberDefinition getFirstMember() {
0387: return firstMember;
0388: }
0389:
0390: public final MemberDefinition getFirstMatch(Identifier name) {
0391: return (MemberDefinition) fieldHash.get(name);
0392: }
0393:
0394: /**
0395: * Get the class' name
0396: */
0397: public final Identifier getName() {
0398: return declaration.getName();
0399: }
0400:
0401: /**
0402: * Get the class' type
0403: */
0404: public final Type getType() {
0405: return declaration.getType();
0406: }
0407:
0408: /**
0409: * Get the class' documentation
0410: */
0411: public String getDocumentation() {
0412: return documentation;
0413: }
0414:
0415: /**
0416: * Return true if the given documentation string contains a deprecation
0417: * paragraph. This is true if the string contains the tag @deprecated
0418: * is the first word in a line.
0419: */
0420: public static boolean containsDeprecated(String documentation) {
0421: if (documentation == null) {
0422: return false;
0423: }
0424: doScan: for (int scan = 0; (scan = documentation.indexOf(
0425: paraDeprecated, scan)) >= 0; scan += paraDeprecated
0426: .length()) {
0427: // make sure there is only whitespace between this word
0428: // and the beginning of the line
0429: for (int beg = scan - 1; beg >= 0; beg--) {
0430: char ch = documentation.charAt(beg);
0431: if (ch == '\n' || ch == '\r') {
0432: break; // OK
0433: }
0434: if (!Character.isSpace(ch)) {
0435: continue doScan;
0436: }
0437: }
0438: // make sure the char after the word is space or end of line
0439: int end = scan + paraDeprecated.length();
0440: if (end < documentation.length()) {
0441: char ch = documentation.charAt(end);
0442: if (!(ch == '\n' || ch == '\r')
0443: && !Character.isSpace(ch)) {
0444: continue doScan;
0445: }
0446: }
0447: return true;
0448: }
0449: return false;
0450: }
0451:
0452: public final boolean inSamePackage(ClassDeclaration c) {
0453: // find out if the class stored in c is defined in the same
0454: // package as the current class.
0455: return inSamePackage(c.getName().getQualifier());
0456: }
0457:
0458: public final boolean inSamePackage(ClassDefinition c) {
0459: // find out if the class stored in c is defined in the same
0460: // package as the current class.
0461: return inSamePackage(c.getName().getQualifier());
0462: }
0463:
0464: public final boolean inSamePackage(Identifier packageName) {
0465: return (getName().getQualifier().equals(packageName));
0466: }
0467:
0468: /**
0469: * Checks
0470: */
0471: public final boolean isInterface() {
0472: return (getModifiers() & M_INTERFACE) != 0;
0473: }
0474:
0475: public final boolean isClass() {
0476: return (getModifiers() & M_INTERFACE) == 0;
0477: }
0478:
0479: public final boolean isPublic() {
0480: return (getModifiers() & M_PUBLIC) != 0;
0481: }
0482:
0483: public final boolean isPrivate() {
0484: return (getModifiers() & M_PRIVATE) != 0;
0485: }
0486:
0487: public final boolean isProtected() {
0488: return (getModifiers() & M_PROTECTED) != 0;
0489: }
0490:
0491: public final boolean isPackagePrivate() {
0492: return (modifiers & (M_PUBLIC | M_PRIVATE | M_PROTECTED)) == 0;
0493: }
0494:
0495: public final boolean isFinal() {
0496: return (getModifiers() & M_FINAL) != 0;
0497: }
0498:
0499: public final boolean isAbstract() {
0500: return (getModifiers() & M_ABSTRACT) != 0;
0501: }
0502:
0503: public final boolean isSynthetic() {
0504: return (getModifiers() & M_SYNTHETIC) != 0;
0505: }
0506:
0507: public final boolean isDeprecated() {
0508: return (getModifiers() & M_DEPRECATED) != 0;
0509: }
0510:
0511: public final boolean isAnonymous() {
0512: return (getModifiers() & M_ANONYMOUS) != 0;
0513: }
0514:
0515: public final boolean isLocal() {
0516: return (getModifiers() & M_LOCAL) != 0;
0517: }
0518:
0519: public final boolean hasConstructor() {
0520: return getFirstMatch(idInit) != null;
0521: }
0522:
0523: /**
0524: * Check to see if a class must be abstract. This method replaces
0525: * isAbstract(env)
0526: */
0527: public final boolean mustBeAbstract(Environment env) {
0528: // If it is declared abstract, return true.
0529: // (Fix for 4110534.)
0530: if (isAbstract()) {
0531: return true;
0532: }
0533:
0534: // Check to see if the class should have been declared to be
0535: // abstract.
0536:
0537: // We make sure that the inherited method collection has been
0538: // performed.
0539: collectInheritedMethods(env);
0540:
0541: // We check for any abstract methods inherited or declared
0542: // by this class.
0543: Iterator methods = getMethods();
0544: while (methods.hasNext()) {
0545: MemberDefinition method = (MemberDefinition) methods.next();
0546:
0547: if (method.isAbstract()) {
0548: return true;
0549: }
0550: }
0551:
0552: // We check for hidden "permanently abstract" methods in
0553: // our superclasses.
0554: return getPermanentlyAbstractMethods().hasNext();
0555: }
0556:
0557: /**
0558: * Check if this is a super class of another class
0559: */
0560: public boolean super ClassOf(Environment env,
0561: ClassDeclaration otherClass) throws ClassNotFound {
0562: while (otherClass != null) {
0563: if (getClassDeclaration().equals(otherClass)) {
0564: return true;
0565: }
0566: otherClass = otherClass.getClassDefinition(env)
0567: .getSuperClass();
0568: }
0569: return false;
0570: }
0571:
0572: /**
0573: * Check if this is an enclosing class of another class
0574: */
0575: public boolean enclosingClassOf(ClassDefinition otherClass) {
0576: while ((otherClass = otherClass.getOuterClass()) != null) {
0577: if (this == otherClass) {
0578: return true;
0579: }
0580: }
0581: return false;
0582: }
0583:
0584: /**
0585: * Check if this is a sub class of another class
0586: */
0587: public boolean subClassOf(Environment env,
0588: ClassDeclaration otherClass) throws ClassNotFound {
0589: ClassDeclaration c = getClassDeclaration();
0590: while (c != null) {
0591: if (c.equals(otherClass)) {
0592: return true;
0593: }
0594: c = c.getClassDefinition(env).getSuperClass();
0595: }
0596: return false;
0597: }
0598:
0599: /**
0600: * Check if this class is implemented by another class
0601: */
0602: public boolean implementedBy(Environment env, ClassDeclaration c)
0603: throws ClassNotFound {
0604: for (; c != null; c = c.getClassDefinition(env).getSuperClass()) {
0605: if (getClassDeclaration().equals(c)) {
0606: return true;
0607: }
0608: ClassDeclaration intf[] = c.getClassDefinition(env)
0609: .getInterfaces();
0610: for (int i = 0; i < intf.length; i++) {
0611: if (implementedBy(env, intf[i])) {
0612: return true;
0613: }
0614: }
0615: }
0616: return false;
0617: }
0618:
0619: /**
0620: * Check to see if a class which implements interface `this' could
0621: * possibly implement the interface `intDef'. Note that the only
0622: * way that this can fail is if `this' and `intDef' have methods
0623: * which are of the same signature and different return types. This
0624: * method is used by Environment.explicitCast() to determine if a
0625: * cast between two interfaces is legal.
0626: *
0627: * This method should only be called on a class after it has been
0628: * basicCheck()'ed.
0629: */
0630: public boolean couldImplement(ClassDefinition intDef) {
0631: // Check to see if we could have done the necessary checks.
0632: if (!doInheritanceChecks) {
0633: throw new CompilerError("couldImplement: no checks");
0634: }
0635:
0636: // This method should only be called for interfaces.
0637: if (!isInterface() || !intDef.isInterface()) {
0638: throw new CompilerError("couldImplement: not interface");
0639: }
0640:
0641: // Make sure we are not called before we have collected our
0642: // inheritance information.
0643: if (allMethods == null) {
0644: throw new CompilerError("couldImplement: called early");
0645: }
0646:
0647: // Get the other classes' methods. getMethods() in
0648: // general can return methods which are not visible to the
0649: // current package. We need to make sure that these do not
0650: // prevent this class from being implemented.
0651: Iterator otherMethods = intDef.getMethods();
0652:
0653: while (otherMethods.hasNext()) {
0654: // Get one of the methods from intDef...
0655: MemberDefinition method = (MemberDefinition) otherMethods
0656: .next();
0657:
0658: Identifier name = method.getName();
0659: Type type = method.getType();
0660:
0661: // See if we implement a method of the same signature...
0662: MemberDefinition myMethod = allMethods
0663: .lookupSig(name, type);
0664:
0665: //System.out.println("Comparing\n\t" + myMethod +
0666: // "\nand\n\t" + method);
0667:
0668: if (myMethod != null) {
0669: // We do. Make sure the methods have the same return type.
0670: if (!myMethod.sameReturnType(method)) {
0671: return false;
0672: }
0673: }
0674: }
0675:
0676: return true;
0677: }
0678:
0679: /**
0680: * Check if another class can be accessed from the 'extends' or 'implements'
0681: * clause of this class.
0682: */
0683: public boolean extendsCanAccess(Environment env, ClassDeclaration c)
0684: throws ClassNotFound {
0685:
0686: // Names in the 'extends' or 'implements' clause of an inner class
0687: // are checked as if they appeared in the body of the surrounding class.
0688: if (outerClass != null) {
0689: return outerClass.canAccess(env, c);
0690: }
0691:
0692: // We are a package member.
0693:
0694: ClassDefinition cdef = c.getClassDefinition(env);
0695:
0696: if (cdef.isLocal()) {
0697: // No locals should be in scope in the 'extends' or
0698: // 'implements' clause of a package member.
0699: throw new CompilerError("top local");
0700: }
0701:
0702: if (cdef.isInnerClass()) {
0703: MemberDefinition f = cdef.getInnerClassMember();
0704:
0705: // Access to public member is always allowed.
0706: if (f.isPublic()) {
0707: return true;
0708: }
0709:
0710: // Private access is ok only from the same class nest. This can
0711: // happen only if the class represented by 'this' encloses the inner
0712: // class represented by 'f'.
0713: if (f.isPrivate()) {
0714: return getClassDeclaration().equals(
0715: f.getTopClass().getClassDeclaration());
0716: }
0717:
0718: // Protected or default access -- allow access if in same package.
0719: return getName().getQualifier().equals(
0720: f.getClassDeclaration().getName().getQualifier());
0721: }
0722:
0723: // Access to public member is always allowed.
0724: if (cdef.isPublic()) {
0725: return true;
0726: }
0727:
0728: // Default access -- allow access if in same package.
0729: return getName().getQualifier().equals(
0730: c.getName().getQualifier());
0731: }
0732:
0733: /**
0734: * Check if another class can be accessed from within the body of this class.
0735: */
0736: public boolean canAccess(Environment env, ClassDeclaration c)
0737: throws ClassNotFound {
0738: ClassDefinition cdef = c.getClassDefinition(env);
0739:
0740: if (cdef.isLocal()) {
0741: // if it's in scope, it's accessible
0742: return true;
0743: }
0744:
0745: if (cdef.isInnerClass()) {
0746: return canAccess(env, cdef.getInnerClassMember());
0747: }
0748:
0749: // Public access is always ok
0750: if (cdef.isPublic()) {
0751: return true;
0752: }
0753:
0754: // It must be in the same package
0755: return getName().getQualifier().equals(
0756: c.getName().getQualifier());
0757: }
0758:
0759: /**
0760: * Check if a field can be accessed from a class
0761: */
0762:
0763: public boolean canAccess(Environment env, MemberDefinition f)
0764: throws ClassNotFound {
0765:
0766: // Public access is always ok
0767: if (f.isPublic()) {
0768: return true;
0769: }
0770: // Protected access is ok from a subclass
0771: if (f.isProtected() && subClassOf(env, f.getClassDeclaration())) {
0772: return true;
0773: }
0774: // Private access is ok only from the same class nest
0775: if (f.isPrivate()) {
0776: return getTopClass().getClassDeclaration().equals(
0777: f.getTopClass().getClassDeclaration());
0778: }
0779: // It must be in the same package
0780: return getName().getQualifier().equals(
0781: f.getClassDeclaration().getName().getQualifier());
0782: }
0783:
0784: /**
0785: * Check if a class is entitled to inline access to a class from
0786: * another class.
0787: */
0788: public boolean permitInlinedAccess(Environment env,
0789: ClassDeclaration c) throws ClassNotFound {
0790:
0791: return (env.opt() && c.equals(declaration))
0792: || (env.opt_interclass() && canAccess(env, c));
0793: }
0794:
0795: /**
0796: * Check if a class is entitled to inline access to a method from
0797: * another class.
0798: */
0799: public boolean permitInlinedAccess(Environment env,
0800: MemberDefinition f) throws ClassNotFound {
0801: return (env.opt() && (f.clazz.getClassDeclaration()
0802: .equals(declaration)))
0803: || (env.opt_interclass() && canAccess(env, f));
0804: }
0805:
0806: /**
0807: * We know the the field is marked protected (and not public) and that
0808: * the field is visible (as per canAccess). Can we access the field as
0809: * <accessor>.<field>, where <accessor> has the type <accessorType>?
0810: *
0811: * Protected fields can only be accessed when the accessorType is a
0812: * subclass of the current class
0813: */
0814: public boolean protectedAccess(Environment env, MemberDefinition f,
0815: Type accessorType) throws ClassNotFound {
0816:
0817: return
0818: // static protected fields are accessible
0819: f.isStatic() || // allow array.clone()
0820: (accessorType.isType(TC_ARRAY)
0821: && (f.getName() == idClone) && (f.getType()
0822: .getArgumentTypes().length == 0)) || // <accessorType> is a subtype of the current class
0823: (accessorType.isType(TC_CLASS) && env
0824: .getClassDefinition(accessorType.getClassName())
0825: .subClassOf(env, getClassDeclaration())) || // we are accessing the field from a friendly class (same package)
0826: (getName().getQualifier()
0827: .equals(f.getClassDeclaration().getName()
0828: .getQualifier()));
0829: }
0830:
0831: /**
0832: * Find or create an access method for a private member,
0833: * or return null if this is not possible.
0834: */
0835: public MemberDefinition getAccessMember(Environment env,
0836: Context ctx, MemberDefinition field, boolean isSuper) {
0837: throw new CompilerError("binary getAccessMember");
0838: }
0839:
0840: /**
0841: * Find or create an update method for a private member,
0842: * or return null if this is not possible.
0843: */
0844: public MemberDefinition getUpdateMember(Environment env,
0845: Context ctx, MemberDefinition field, boolean isSuper) {
0846: throw new CompilerError("binary getUpdateMember");
0847: }
0848:
0849: /**
0850: * Get a field from this class. Report ambiguous fields.
0851: * If no accessible field is found, this method may return an
0852: * inaccessible field to allow a useful error message.
0853: *
0854: * getVariable now takes the source class `source' as an argument.
0855: * This allows getVariable to check whether a field is inaccessible
0856: * before it signals that a field is ambiguous. The compiler used to
0857: * signal an ambiguity even when one of the fields involved was not
0858: * accessible. (bug 4053724)
0859: */
0860: public MemberDefinition getVariable(Environment env, Identifier nm,
0861: ClassDefinition source) throws AmbiguousMember,
0862: ClassNotFound {
0863:
0864: return getVariable0(env, nm, source, true, true);
0865: }
0866:
0867: /*
0868: * private fields are never inherited. package-private fields are
0869: * not inherited across package boundaries. To capture this, we
0870: * take two booleans as parameters: showPrivate indicates whether
0871: * we have passed a class boundary, and showPackage indicates whether
0872: * we have crossed a package boundary.
0873: */
0874: private MemberDefinition getVariable0(Environment env,
0875: Identifier nm, ClassDefinition source, boolean showPrivate,
0876: boolean showPackage) throws AmbiguousMember, ClassNotFound {
0877:
0878: // Check to see if this field is defined in the current class
0879: for (MemberDefinition member = getFirstMatch(nm); member != null; member = member
0880: .getNextMatch()) {
0881: if (member.isVariable()) {
0882: if ((showPrivate || !member.isPrivate())
0883: && (showPackage || !member.isPackagePrivate())) {
0884: // It is defined in this class.
0885: return member;
0886: } else {
0887: // Even though this definition is not inherited,
0888: // it hides all definitions in supertypes.
0889: return null;
0890: }
0891: }
0892: }
0893:
0894: // Find the field in our superclass.
0895: ClassDeclaration sup = getSuperClass();
0896: MemberDefinition field = null;
0897: if (sup != null) {
0898: field = sup.getClassDefinition(env).getVariable0(env, nm,
0899: source, false, showPackage && inSamePackage(sup));
0900: }
0901:
0902: // Find the field in our superinterfaces.
0903: for (int i = 0; i < interfaces.length; i++) {
0904: // Try to look up the field in an interface. Since interfaces
0905: // only have public fields, the values of the two boolean
0906: // arguments are not important.
0907: MemberDefinition field2 = interfaces[i].getClassDefinition(
0908: env).getVariable0(env, nm, source, true, true);
0909:
0910: if (field2 != null) {
0911: // If we have two different, accessible fields, then
0912: // we've found an ambiguity.
0913: if (field != null && source.canAccess(env, field)
0914: && field2 != field) {
0915:
0916: throw new AmbiguousMember(field2, field);
0917: }
0918: field = field2;
0919: }
0920: }
0921: return field;
0922: }
0923:
0924: /**
0925: * Tells whether to report a deprecation error for this class.
0926: */
0927: public boolean reportDeprecated(Environment env) {
0928: return (isDeprecated() || (outerClass != null && outerClass
0929: .reportDeprecated(env)));
0930: }
0931:
0932: /**
0933: * Note that this class is being used somehow by <tt>ref</tt>.
0934: * Report deprecation errors, etc.
0935: */
0936: public void noteUsedBy(ClassDefinition ref, long where,
0937: Environment env) {
0938: // (Have this deal with canAccess() checks, too?)
0939: if (reportDeprecated(env)) {
0940: env.error(where, "warn.class.is.deprecated", this );
0941: }
0942: }
0943:
0944: /**
0945: * Get an inner class.
0946: * Look in supers but not outers.
0947: * (This is used directly to resolve expressions like "site.K", and
0948: * inside a loop to resolve lone names like "K" or the "K" in "K.L".)
0949: *
0950: * Called from 'Context' and 'FieldExpression' as well as this class.
0951: *
0952: * @see FieldExpression.checkCommon
0953: * @see resolveName
0954: */
0955: public MemberDefinition getInnerClass(Environment env, Identifier nm)
0956: throws ClassNotFound {
0957: // Note: AmbiguousClass will not be thrown unless and until
0958: // inner classes can be defined inside interfaces.
0959:
0960: // Check if it is defined in the current class
0961: for (MemberDefinition field = getFirstMatch(nm); field != null; field = field
0962: .getNextMatch()) {
0963: if (field.isInnerClass()) {
0964: if (field.getInnerClass().isLocal()) {
0965: continue; // ignore this name; it is internally generated
0966: }
0967: return field;
0968: }
0969: }
0970:
0971: // Get it from the super class
0972: // It is likely that 'getSuperClass()' could be made to work here
0973: // but we would have to assure somehow that 'resolveTypeStructure'
0974: // has been called on the current class nest. Since we can get
0975: // here from 'resolveName', which is called from 'resolveSupers',
0976: // it is possible that the first attempt to resolve the superclass
0977: // will originate here, instead of in the call to 'getSuperClass'
0978: // in 'checkSupers'. See 'resolveTypeStructure', in which a call
0979: // to 'resolveSupers' precedes the call to 'checkSupers'. Why is
0980: // name resolution done twice, first in 'resolveName'?
0981: // NOTE: 'SourceMember.resolveTypeStructure' may initiate type
0982: // structure resolution for an inner class. Normally, this
0983: // occurs during the resolution of the outer class, but fields
0984: // added after the resolution of their containing class will
0985: // be resolved late -- see 'addMember(env,field)' below.
0986: // This should only happen for synthetic members, which should
0987: // never be an inner class.
0988: ClassDeclaration sup = getSuperClass(env);
0989: if (sup != null)
0990: return sup.getClassDefinition(env).getInnerClass(env, nm);
0991:
0992: return null;
0993: }
0994:
0995: /**
0996: * Lookup a method. This code implements the method lookup
0997: * mechanism specified in JLS 15.11.2.
0998: *
0999: * This mechanism cannot be used to lookup synthetic methods.
1000: */
1001: private MemberDefinition matchMethod(Environment env,
1002: ClassDefinition accessor, Identifier methodName,
1003: Type[] argumentTypes, boolean isAnonConstCall,
1004: Identifier accessPackage) throws AmbiguousMember,
1005: ClassNotFound {
1006:
1007: if (allMethods == null || !allMethods.isFrozen()) {
1008: // This may be too restrictive.
1009: throw new CompilerError("matchMethod called early");
1010: // collectInheritedMethods(env);
1011: }
1012:
1013: // A tentative maximally specific method.
1014: MemberDefinition tentative = null;
1015:
1016: // A list of other methods which may be maximally specific too.
1017: List candidateList = null;
1018:
1019: // Get all the methods inherited by this class which
1020: // have the name `methodName'.
1021: Iterator methods = allMethods.lookupName(methodName);
1022:
1023: while (methods.hasNext()) {
1024: MemberDefinition method = (MemberDefinition) methods.next();
1025:
1026: // See if this method is applicable.
1027: if (!env.isApplicable(method, argumentTypes)) {
1028: continue;
1029: }
1030:
1031: // See if this method is accessible.
1032: if (accessor != null) {
1033: if (!accessor.canAccess(env, method)) {
1034: continue;
1035: }
1036: } else if (isAnonConstCall) {
1037: if (method.isPrivate()
1038: || (method.isPackagePrivate()
1039: && accessPackage != null && !inSamePackage(accessPackage))) {
1040: // For anonymous constructor accesses, we
1041: // haven't yet built an accessing class.
1042: // We disallow anonymous classes from seeing
1043: // private/package-private inaccessible
1044: // constructors in their superclass.
1045: continue;
1046: }
1047: } else {
1048: // If accessor is null, we assume that the access
1049: // is allowed. Query: is this option used?
1050: }
1051:
1052: if (tentative == null) {
1053: // `method' becomes our tentative maximally specific match.
1054: tentative = method;
1055: } else {
1056: if (env.isMoreSpecific(method, tentative)) {
1057: // We have found a method which is a strictly better
1058: // match than `tentative'. Replace it.
1059: tentative = method;
1060: } else {
1061: // If this method could possibly be another
1062: // maximally specific method, add it to our
1063: // list of other candidates.
1064: if (!env.isMoreSpecific(tentative, method)) {
1065: if (candidateList == null) {
1066: candidateList = new ArrayList();
1067: }
1068: candidateList.add(method);
1069: }
1070: }
1071: }
1072: }
1073:
1074: if (tentative != null && candidateList != null) {
1075: // Find out if our `tentative' match is a uniquely
1076: // maximally specific.
1077: Iterator candidates = candidateList.iterator();
1078: while (candidates.hasNext()) {
1079: MemberDefinition method = (MemberDefinition) candidates
1080: .next();
1081: if (!env.isMoreSpecific(tentative, method)) {
1082: throw new AmbiguousMember(tentative, method);
1083: }
1084: }
1085: }
1086:
1087: return tentative;
1088: }
1089:
1090: /**
1091: * Lookup a method. This code implements the method lookup
1092: * mechanism specified in JLS 15.11.2.
1093: *
1094: * This mechanism cannot be used to lookup synthetic methods.
1095: */
1096: public MemberDefinition matchMethod(Environment env,
1097: ClassDefinition accessor, Identifier methodName,
1098: Type[] argumentTypes) throws AmbiguousMember, ClassNotFound {
1099:
1100: return matchMethod(env, accessor, methodName, argumentTypes,
1101: false, null);
1102: }
1103:
1104: /**
1105: * Lookup a method. This code implements the method lookup
1106: * mechanism specified in JLS 15.11.2.
1107: *
1108: * This mechanism cannot be used to lookup synthetic methods.
1109: */
1110: public MemberDefinition matchMethod(Environment env,
1111: ClassDefinition accessor, Identifier methodName)
1112: throws AmbiguousMember, ClassNotFound {
1113:
1114: return matchMethod(env, accessor, methodName, Type.noArgs,
1115: false, null);
1116: }
1117:
1118: /**
1119: * A version of matchMethod to be used only for constructors
1120: * when we cannot pass in a sourceClass argument. We just assert
1121: * our package name.
1122: *
1123: * This is used only for anonymous classes, where we have to look up
1124: * a (potentially) protected constructor with no valid sourceClass
1125: * parameter available.
1126: */
1127: public MemberDefinition matchAnonConstructor(Environment env,
1128: Identifier accessPackage, Type argumentTypes[])
1129: throws AmbiguousMember, ClassNotFound {
1130:
1131: return matchMethod(env, null, idInit, argumentTypes, true,
1132: accessPackage);
1133: }
1134:
1135: /**
1136: * Find a method, ie: exact match in this class or any of the super
1137: * classes.
1138: *
1139: * Only called by javadoc. For now I am holding off rewriting this
1140: * code to rely on collectInheritedMethods(), as that code has
1141: * not gotten along with javadoc in the past.
1142: */
1143: public MemberDefinition findMethod(Environment env, Identifier nm,
1144: Type t) throws ClassNotFound {
1145: // look in the current class
1146: MemberDefinition f;
1147: for (f = getFirstMatch(nm); f != null; f = f.getNextMatch()) {
1148: // Note that non-method types return false for equalArguments().
1149: if (f.getType().equalArguments(t)) {
1150: return f;
1151: }
1152: }
1153:
1154: // constructors are not inherited
1155: if (nm.equals(idInit)) {
1156: return null;
1157: }
1158:
1159: // look in the super class
1160: ClassDeclaration sup = getSuperClass();
1161: if (sup == null)
1162: return null;
1163:
1164: return sup.getClassDefinition(env).findMethod(env, nm, t);
1165: }
1166:
1167: // We create a stub for this. Source classes do more work.
1168: protected void basicCheck(Environment env) throws ClassNotFound {
1169: // Do the outer class first.
1170: if (outerClass != null)
1171: outerClass.basicCheck(env);
1172: }
1173:
1174: /**
1175: * Check this class.
1176: */
1177: public void check(Environment env) throws ClassNotFound {
1178: }
1179:
1180: public Vset checkLocalClass(Environment env, Context ctx,
1181: Vset vset, ClassDefinition sup, Expression args[],
1182: Type argTypes[]) throws ClassNotFound {
1183: throw new CompilerError("checkLocalClass");
1184: }
1185:
1186: //---------------------------------------------------------------
1187: // The non-synthetic methods defined in this class or in any
1188: // of its parents (class or interface). This member is used
1189: // to cache work done in collectInheritedMethods for use by
1190: // getMethods() and matchMethod(). It should be accessed by
1191: // no other method without forethought.
1192: MethodSet allMethods = null;
1193:
1194: // One of our superclasses may contain an abstract method which
1195: // we are unable to ever implement. This happens when there is
1196: // a package-private abstract method in our parent and we are in
1197: // a different package than our parent. In these cases, we
1198: // keep a list of the "permanently abstract" or "unimplementable"
1199: // methods so that we can correctly detect that this class is
1200: // indeed abstract and so that we can give somewhat comprehensible
1201: // error messages.
1202: private List permanentlyAbstractMethods = new ArrayList();
1203:
1204: /**
1205: * This method returns an Iterator of all abstract methods
1206: * in our superclasses which we are unable to implement.
1207: */
1208: protected Iterator getPermanentlyAbstractMethods() {
1209: // This method can only be called after collectInheritedMethods.
1210: if (allMethods == null) {
1211: throw new CompilerError(
1212: "isPermanentlyAbstract() called early");
1213: }
1214:
1215: return permanentlyAbstractMethods.iterator();
1216: }
1217:
1218: /**
1219: * A flag used by turnOffInheritanceChecks() to indicate if
1220: * inheritance checks are on or off.
1221: */
1222: protected static boolean doInheritanceChecks = true;
1223:
1224: /**
1225: * This is a workaround to allow javadoc to turn off certain
1226: * inheritance/override checks which interfere with javadoc
1227: * badly. In the future it might be good to eliminate the
1228: * shared sources of javadoc and javac to avoid the need for this
1229: * sort of workaround.
1230: */
1231: public static void turnOffInheritanceChecks() {
1232: doInheritanceChecks = false;
1233: }
1234:
1235: /**
1236: * Add all of the methods declared in or above `parent' to
1237: * `allMethods', the set of methods in the current class.
1238: * `myMethods' is the set of all methods declared in this
1239: * class, and `mirandaMethods' is a repository for Miranda methods.
1240: * If mirandaMethods is null, no mirandaMethods will be
1241: * generated.
1242: *
1243: * For a definition of Miranda methods, see the comment above the
1244: * method addMirandaMethods() which occurs later in this file.
1245: */
1246: private void collectOneClass(Environment env,
1247: ClassDeclaration parent, MethodSet myMethods,
1248: MethodSet allMethods, MethodSet mirandaMethods) {
1249:
1250: // System.out.println("Inheriting methods from " + parent);
1251:
1252: try {
1253: ClassDefinition pClass = parent.getClassDefinition(env);
1254: Iterator methods = pClass.getMethods(env);
1255: while (methods.hasNext()) {
1256: MemberDefinition method = (MemberDefinition) methods
1257: .next();
1258:
1259: // Private methods are not inherited.
1260: //
1261: // Constructors are not inherited.
1262: //
1263: // Any non-abstract methods in an interface come
1264: // from java.lang.Object. This means that they
1265: // should have already been added to allMethods
1266: // when we walked our superclass lineage.
1267: if (method.isPrivate()
1268: || method.isConstructor()
1269: || (pClass.isInterface() && !method
1270: .isAbstract())) {
1271:
1272: continue;
1273: }
1274:
1275: // Get the components of the methods' signature.
1276: Identifier name = method.getName();
1277: Type type = method.getType();
1278:
1279: // Check for a method of the same signature which
1280: // was locally declared.
1281: MemberDefinition override = myMethods.lookupSig(name,
1282: type);
1283:
1284: // Is this method inaccessible due to package-private
1285: // visibility?
1286: if (method.isPackagePrivate()
1287: && !inSamePackage(method.getClassDeclaration())) {
1288:
1289: if (override != null
1290: && this instanceof sun.tools.javac.SourceClass) {
1291: // We give a warning when a class shadows an
1292: // inaccessible package-private method from
1293: // its superclass. This warning is meant
1294: // to prevent people from relying on overriding
1295: // when it does not happen. This warning should
1296: // probably be removed to be consistent with the
1297: // general "no warnings" policy of this
1298: // compiler.
1299: //
1300: // The `instanceof' above is a hack so that only
1301: // SourceClass generates this warning, not a
1302: // BinaryClass, for example.
1303: env.error(method.getWhere(),
1304: "warn.no.override.access", override,
1305: override.getClassDeclaration(), method
1306: .getClassDeclaration());
1307: }
1308:
1309: // If our superclass has a package-private abstract
1310: // method that we have no access to, then we add
1311: // this method to our list of permanently abstract
1312: // methods. The idea is, since we cannot override
1313: // the method, we can never make this class
1314: // non-abstract.
1315: if (method.isAbstract()) {
1316: permanentlyAbstractMethods.add(method);
1317: }
1318:
1319: // `method' is inaccessible. We do not inherit it.
1320: continue;
1321: }
1322:
1323: if (override != null) {
1324: // `method' and `override' have the same signature.
1325: // We are required to check that `override' is a
1326: // legal override of `method'
1327:
1328: //System.out.println ("About to check override of " +
1329: // method);
1330:
1331: override.checkOverride(env, method);
1332: } else {
1333: // In the absence of a definition in the class
1334: // itself, we check to see if this definition
1335: // can be successfully merged with any other
1336: // inherited definitions.
1337:
1338: // Have we added a member of the same signature
1339: // to `allMethods' already?
1340: MemberDefinition formerMethod = allMethods
1341: .lookupSig(name, type);
1342:
1343: // If the previous definition is nonexistent or
1344: // ignorable, replace it.
1345: if (formerMethod == null) {
1346: //System.out.println("Added " + method + " to " +
1347: // this);
1348:
1349: if (mirandaMethods != null
1350: && pClass.isInterface()
1351: && !isInterface()) {
1352: // Whenever a class inherits a method
1353: // from an interface, that method is
1354: // one of our "miranda" methods. Early
1355: // VMs require that these methods be
1356: // added as true members to the class
1357: // to enable method lookup to work in the
1358: // VM.
1359: method = new sun.tools.javac.SourceMember(
1360: method, this , env);
1361: mirandaMethods.add(method);
1362:
1363: //System.out.println("Added " + method +
1364: // " to " + this + " as a Miranda");
1365: }
1366:
1367: // There is no previous inherited definition.
1368: // Add `method' to `allMethods'.
1369: allMethods.add(method);
1370: } else if (isInterface()
1371: && !formerMethod.isAbstract()
1372: && method.isAbstract()) {
1373: // If we are in an interface and we have inherited
1374: // both an abstract method and a non-abstract method
1375: // then we know that the non-abstract method is
1376: // a placeholder from Object put in for type checking
1377: // and the abstract method was already checked to
1378: // be proper by our superinterface.
1379: allMethods.replace(method);
1380:
1381: } else {
1382: // Okay, `formerMethod' and `method' both have the
1383: // same signature. See if they are compatible.
1384:
1385: //System.out.println ("About to check meet of " +
1386: // method);
1387:
1388: if (!formerMethod.checkMeet(env, method, this
1389: .getClassDeclaration())) {
1390: // The methods are incompatible. Skip to
1391: // next method.
1392: continue;
1393: }
1394:
1395: if (formerMethod.couldOverride(env, method)) {
1396: // Do nothing. The current definition
1397: // is specific enough.
1398:
1399: //System.out.println("trivial meet of " +
1400: // method);
1401: continue;
1402: }
1403:
1404: if (method.couldOverride(env, formerMethod)) {
1405: // `method' is more specific than
1406: // `formerMethod'. replace `formerMethod'.
1407:
1408: //System.out.println("new def of " + method);
1409: if (mirandaMethods != null
1410: && pClass.isInterface()
1411: && !isInterface()) {
1412: // Whenever a class inherits a method
1413: // from an interface, that method is
1414: // one of our "miranda" methods. Early
1415: // VMs require that these methods be
1416: // added as true members to the class
1417: // to enable method lookup to work in the
1418: // VM.
1419: method = new sun.tools.javac.SourceMember(
1420: method, this , env);
1421:
1422: mirandaMethods.replace(method);
1423:
1424: //System.out.println("Added " + method +
1425: // " to " + this + " as a Miranda");
1426: }
1427:
1428: allMethods.replace(method);
1429:
1430: continue;
1431: }
1432:
1433: // Neither method is more specific than the other.
1434: // Oh well. We need to construct a nontrivial
1435: // meet of the two methods.
1436: //
1437: // This is not yet implemented, so we give
1438: // a message with a helpful workaround.
1439: env.error(this .where, "nontrivial.meet",
1440: method, formerMethod
1441: .getClassDefinition(), method
1442: .getClassDeclaration());
1443: }
1444: }
1445: }
1446: } catch (ClassNotFound ee) {
1447: env.error(getWhere(), "class.not.found", ee.name, this );
1448: }
1449: }
1450:
1451: /**
1452: * <p>Collect all methods defined in this class or inherited from
1453: * any of our superclasses or interfaces. Look for any
1454: * incompatible definitions.
1455: *
1456: * <p>This function is also responsible for collecting the
1457: * <em>Miranda</em> methods for a class. For a definition of
1458: * Miranda methods, see the comment in addMirandaMethods()
1459: * below.
1460: */
1461: protected void collectInheritedMethods(Environment env) {
1462: // The methods defined in this class.
1463: MethodSet myMethods;
1464: MethodSet mirandaMethods;
1465:
1466: //System.out.println("Called collectInheritedMethods() for " +
1467: // this);
1468:
1469: if (allMethods != null) {
1470: if (allMethods.isFrozen()) {
1471: // We have already done the collection. No need to
1472: // do it again.
1473: return;
1474: } else {
1475: // We have run into a circular need to collect our methods.
1476: // This should not happen at this stage.
1477: throw new CompilerError("collectInheritedMethods()");
1478: }
1479: }
1480:
1481: myMethods = new MethodSet();
1482: allMethods = new MethodSet();
1483:
1484: // For testing, do not generate miranda methods.
1485: if (env.version12()) {
1486: mirandaMethods = null;
1487: } else {
1488: mirandaMethods = new MethodSet();
1489: }
1490:
1491: // Any methods defined in the current class get added
1492: // to both the myMethods and the allMethods MethodSets.
1493:
1494: for (MemberDefinition member = getFirstMember(); member != null; member = member.nextMember) {
1495:
1496: // We only collect methods. Initializers are not relevant.
1497: if (member.isMethod() && !member.isInitializer()) {
1498:
1499: //System.out.println("Declared in " + this + ", " + member);
1500:
1501: ////////////////////////////////////////////////////////////
1502: // PCJ 2003-07-30 modified the following code because with
1503: // the covariant return type feature of the 1.5 compiler,
1504: // there might be multiple methods with the same signature
1505: // but different return types, and MethodSet doesn't
1506: // support that. We use a new utility method that attempts
1507: // to ensure that the appropriate method winds up in the
1508: // MethodSet. See 4892308.
1509: ////////////////////////////////////////////////////////////
1510: // myMethods.add(member);
1511: // allMethods.add(member);
1512: ////////////////////////////////////////////////////////////
1513: methodSetAdd(env, myMethods, member);
1514: methodSetAdd(env, allMethods, member);
1515: ////////////////////////////////////////////////////////////
1516: }
1517: }
1518:
1519: // We're ready to start adding inherited methods. First add
1520: // the methods from our superclass.
1521:
1522: //System.out.println("About to start superclasses for " + this);
1523:
1524: ClassDeclaration scDecl = getSuperClass(env);
1525: if (scDecl != null) {
1526: collectOneClass(env, scDecl, myMethods, allMethods,
1527: mirandaMethods);
1528:
1529: // Make sure that we add all unimplementable methods from our
1530: // superclass to our list of unimplementable methods.
1531: ClassDefinition sc = scDecl.getClassDefinition();
1532: Iterator supIter = sc.getPermanentlyAbstractMethods();
1533: while (supIter.hasNext()) {
1534: permanentlyAbstractMethods.add(supIter.next());
1535: }
1536: }
1537:
1538: // Now we inherit all of the methods from our interfaces.
1539:
1540: //System.out.println("About to start interfaces for " + this);
1541:
1542: for (int i = 0; i < interfaces.length; i++) {
1543: collectOneClass(env, interfaces[i], myMethods, allMethods,
1544: mirandaMethods);
1545: }
1546: allMethods.freeze();
1547:
1548: // Now we have collected all of our methods from our superclasses
1549: // and interfaces into our `allMethods' member. Good. As a last
1550: // task, we add our collected miranda methods to this class.
1551: //
1552: // If we do not add the mirandas to the class explicitly, there
1553: // will be no code generated for them.
1554: if (mirandaMethods != null && mirandaMethods.size() > 0) {
1555: addMirandaMethods(env, mirandaMethods.iterator());
1556: }
1557: }
1558:
1559: ////////////////////////////////////////////////////////////
1560: // PCJ 2003-07-30 added this utility method to insulate
1561: // MethodSet additions from the covariant return type
1562: // feature of the 1.5 compiler. When there are multiple
1563: // methods with the same signature and different return
1564: // types to be added, we try to ensure that the one with
1565: // the most specific return type winds up in the MethodSet.
1566: // This logic was not put into MethodSet itself because it
1567: // requires access to an Environment for type relationship
1568: // checking. No error checking is performed here, but that
1569: // should be OK because this code is only still used by
1570: // rmic. See 4892308.
1571: ////////////////////////////////////////////////////////////
1572: private static void methodSetAdd(Environment env,
1573: MethodSet methodSet, MemberDefinition newMethod) {
1574: MemberDefinition oldMethod = methodSet.lookupSig(newMethod
1575: .getName(), newMethod.getType());
1576: if (oldMethod != null) {
1577: Type oldReturnType = oldMethod.getType().getReturnType();
1578: Type newReturnType = newMethod.getType().getReturnType();
1579: try {
1580: if (env.isMoreSpecific(newReturnType, oldReturnType)) {
1581: methodSet.replace(newMethod);
1582: }
1583: } catch (ClassNotFound ignore) {
1584: }
1585: } else {
1586: methodSet.add(newMethod);
1587: }
1588: }
1589:
1590: ////////////////////////////////////////////////////////////
1591:
1592: /**
1593: * Get an Iterator of all methods which could be accessed in an
1594: * instance of this class.
1595: */
1596: public Iterator getMethods(Environment env) {
1597: if (allMethods == null) {
1598: collectInheritedMethods(env);
1599: }
1600: return getMethods();
1601: }
1602:
1603: /**
1604: * Get an Iterator of all methods which could be accessed in an
1605: * instance of this class. Throw a compiler error if we haven't
1606: * generated this information yet.
1607: */
1608: public Iterator getMethods() {
1609: if (allMethods == null) {
1610: throw new CompilerError("getMethods: too early");
1611: }
1612: return allMethods.iterator();
1613: }
1614:
1615: // In early VM's there was a bug -- the VM didn't walk the interfaces
1616: // of a class looking for a method, they only walked the superclass
1617: // chain. This meant that abstract methods defined only in interfaces
1618: // were not being found. To fix this bug, a counter-bug was introduced
1619: // in the compiler -- the so-called Miranda methods. If a class
1620: // does not provide a definition for an abstract method in one of
1621: // its interfaces then the compiler inserts one in the class artificially.
1622: // That way the VM didn't have to bother looking at the interfaces.
1623: //
1624: // This is a problem. Miranda methods are not part of the specification.
1625: // But they continue to be inserted so that old VM's can run new code.
1626: // Someday, when the old VM's are gone, perhaps classes can be compiled
1627: // without Miranda methods. Towards this end, the compiler has a
1628: // flag, -nomiranda, which can turn off the creation of these methods.
1629: // Eventually that behavior should become the default.
1630: //
1631: // Why are they called Miranda methods? Well the sentence "If the
1632: // class is not able to provide a method, then one will be provided
1633: // by the compiler" is very similar to the sentence "If you cannot
1634: // afford an attorney, one will be provided by the court," -- one
1635: // of the so-called "Miranda" rights in the United States.
1636:
1637: /**
1638: * Add a list of methods to this class as miranda methods. This
1639: * gets overridden with a meaningful implementation in SourceClass.
1640: * BinaryClass should not need to do anything -- it should already
1641: * have its miranda methods and, if it doesn't, then that doesn't
1642: * affect our compilation.
1643: */
1644: protected void addMirandaMethods(Environment env, Iterator mirandas) {
1645: // do nothing.
1646: }
1647:
1648: //---------------------------------------------------------------
1649:
1650: public void inlineLocalClass(Environment env) {
1651: }
1652:
1653: /**
1654: * We create a stub for this. Source classes do more work.
1655: * Some calls from 'SourceClass.checkSupers' execute this method.
1656: * @see sun.tools.javac.SourceClass#resolveTypeStructure
1657: */
1658:
1659: public void resolveTypeStructure(Environment env) {
1660: }
1661:
1662: /**
1663: * Look up an inner class name, from somewhere inside this class.
1664: * Since supers and outers are in scope, search them too.
1665: * <p>
1666: * If no inner class is found, env.resolveName() is then called,
1667: * to interpret the ambient package and import directives.
1668: * <p>
1669: * This routine operates on a "best-efforts" basis. If
1670: * at some point a class is not found, the partially-resolved
1671: * identifier is returned. Eventually, someone else has to
1672: * try to get the ClassDefinition and diagnose the ClassNotFound.
1673: * <p>
1674: * resolveName() looks at surrounding scopes, and hence
1675: * pulling in both inherited and uplevel types. By contrast,
1676: * resolveInnerClass() is intended only for interpreting
1677: * explicitly qualified names, and so look only at inherited
1678: * types. Also, resolveName() looks for package prefixes,
1679: * which appear similar to "very uplevel" outer classes.
1680: * <p>
1681: * A similar (but more complex) name-lookup process happens
1682: * when field and identifier expressions denoting qualified names
1683: * are type-checked. The added complexity comes from the fact
1684: * that variables may occur in such names, and take precedence
1685: * over class and package names.
1686: * <p>
1687: * In the expression type-checker, resolveInnerClass() is paralleled
1688: * by code in FieldExpression.checkAmbigName(), which also calls
1689: * ClassDefinition.getInnerClass() to interpret names of the form
1690: * "OuterClass.Inner" (and also outerObject.Inner). The checking
1691: * of an identifier expression that fails to be a variable is referred
1692: * directly to resolveName().
1693: */
1694: public Identifier resolveName(Environment env, Identifier name) {
1695: if (tracing)
1696: env.dtEvent("ClassDefinition.resolveName: " + name);
1697: // This logic is pretty much exactly parallel to that of
1698: // Environment.resolveName().
1699: if (name.isQualified()) {
1700: // Try to resolve the first identifier component,
1701: // because inner class names take precedence over
1702: // package prefixes. (Cf. Environment.resolveName.)
1703: Identifier rhead = resolveName(env, name.getHead());
1704:
1705: if (rhead.hasAmbigPrefix()) {
1706: // The first identifier component refers to an
1707: // ambiguous class. Limp on. We throw away the
1708: // rest of the classname as it is irrelevant.
1709: // (part of solution for 4059855).
1710: return rhead;
1711: }
1712:
1713: if (!env.classExists(rhead)) {
1714: return env.resolvePackageQualifiedName(name);
1715: }
1716: try {
1717: return env.getClassDefinition(rhead).resolveInnerClass(
1718: env, name.getTail());
1719: } catch (ClassNotFound ee) {
1720: // return partially-resolved name someone else can fail on
1721: return Identifier.lookupInner(rhead, name.getTail());
1722: }
1723: }
1724:
1725: // This method used to fail to look for local classes, thus a
1726: // reference to a local class within, e.g., the type of a member
1727: // declaration, would fail to resolve if the immediately enclosing
1728: // context was an inner class. The code added below is ugly, but
1729: // it works, and is lifted from existing code in 'Context.resolveName'
1730: // and 'Context.getClassCommon'. See the comments there about the design.
1731: // Fixes 4095716.
1732:
1733: int ls = -2;
1734: LocalMember lf = null;
1735: if (classContext != null) {
1736: lf = classContext.getLocalClass(name);
1737: if (lf != null) {
1738: ls = lf.getScopeNumber();
1739: }
1740: }
1741:
1742: // Look for an unqualified name in enclosing scopes.
1743: for (ClassDefinition c = this ; c != null; c = c.outerClass) {
1744: try {
1745: MemberDefinition f = c.getInnerClass(env, name);
1746: if (f != null
1747: && (lf == null || classContext
1748: .getScopeNumber(c) > ls)) {
1749: // An uplevel member was found, and was nested more deeply than
1750: // any enclosing local of the same name.
1751: return f.getInnerClass().getName();
1752: }
1753: } catch (ClassNotFound ee) {
1754: // a missing superclass, or something catastrophic
1755: }
1756: }
1757:
1758: // No uplevel member found, so use the enclosing local if one was found.
1759: if (lf != null) {
1760: return lf.getInnerClass().getName();
1761: }
1762:
1763: // look in imports, etc.
1764: return env.resolveName(name);
1765: }
1766:
1767: /**
1768: * Interpret a qualified class name, which may have further subcomponents..
1769: * Follow inheritance links, as in:
1770: * class C { class N { } } class D extends C { } ... new D.N() ...
1771: * Ignore outer scopes and packages.
1772: * @see resolveName
1773: */
1774: public Identifier resolveInnerClass(Environment env, Identifier nm) {
1775: if (nm.isInner())
1776: throw new CompilerError("inner");
1777: if (nm.isQualified()) {
1778: Identifier rhead = resolveInnerClass(env, nm.getHead());
1779: try {
1780: return env.getClassDefinition(rhead).resolveInnerClass(
1781: env, nm.getTail());
1782: } catch (ClassNotFound ee) {
1783: // return partially-resolved name someone else can fail on
1784: return Identifier.lookupInner(rhead, nm.getTail());
1785: }
1786: } else {
1787: try {
1788: MemberDefinition f = getInnerClass(env, nm);
1789: if (f != null) {
1790: return f.getInnerClass().getName();
1791: }
1792: } catch (ClassNotFound ee) {
1793: // a missing superclass, or something catastrophic
1794: }
1795: // Fake a good name for a diagnostic.
1796: return Identifier.lookupInner(this .getName(), nm);
1797: }
1798: }
1799:
1800: /**
1801: * While resolving import directives, the question has arisen:
1802: * does a given inner class exist? If the top-level class exists,
1803: * we ask it about an inner class via this method.
1804: * This method looks only at the literal name of the class,
1805: * and does not attempt to follow inheritance links.
1806: * This is necessary, since at the time imports are being
1807: * processed, inheritance links have not been resolved yet.
1808: * (Thus, an import directive must always spell a class
1809: * name exactly.)
1810: */
1811: public boolean innerClassExists(Identifier nm) {
1812: for (MemberDefinition field = getFirstMatch(nm.getHead()); field != null; field = field
1813: .getNextMatch()) {
1814: if (field.isInnerClass()) {
1815: if (field.getInnerClass().isLocal()) {
1816: continue; // ignore this name; it is internally generated
1817: }
1818: return !nm.isQualified()
1819: || field.getInnerClass().innerClassExists(
1820: nm.getTail());
1821: }
1822: }
1823: return false;
1824: }
1825:
1826: /**
1827: * Find any method with a given name.
1828: */
1829: public MemberDefinition findAnyMethod(Environment env, Identifier nm)
1830: throws ClassNotFound {
1831: MemberDefinition f;
1832: for (f = getFirstMatch(nm); f != null; f = f.getNextMatch()) {
1833: if (f.isMethod()) {
1834: return f;
1835: }
1836: }
1837:
1838: // look in the super class
1839: ClassDeclaration sup = getSuperClass();
1840: if (sup == null)
1841: return null;
1842: return sup.getClassDefinition(env).findAnyMethod(env, nm);
1843: }
1844:
1845: /**
1846: * Given the fact that this class has no method "nm" matching "argTypes",
1847: * find out if the mismatch can be blamed on a particular actual argument
1848: * which disagrees with all of the overloadings.
1849: * If so, return the code (i<<2)+(castOK<<1)+ambig, where
1850: * "i" is the number of the offending argument, and
1851: * "castOK" is 1 if a cast could fix the problem.
1852: * The target type for the argument is returned in margTypeResult[0].
1853: * If not all methods agree on this type, "ambig" is 1.
1854: * If there is more than one method, the choice of target type is
1855: * arbitrary.<p>
1856: * Return -1 if every argument is acceptable to at least one method.
1857: * Return -2 if there are no methods of the required arity.
1858: * The value "start" gives the index of the first argument to begin
1859: * checking.
1860: */
1861: public int diagnoseMismatch(Environment env, Identifier nm,
1862: Type argTypes[], int start, Type margTypeResult[])
1863: throws ClassNotFound {
1864: int haveMatch[] = new int[argTypes.length];
1865: Type margType[] = new Type[argTypes.length];
1866: if (!diagnoseMismatch(env, nm, argTypes, start, haveMatch,
1867: margType))
1868: return -2;
1869: for (int i = start; i < argTypes.length; i++) {
1870: if (haveMatch[i] < 4) {
1871: margTypeResult[0] = margType[i];
1872: return (i << 2) | haveMatch[i];
1873: }
1874: }
1875: return -1;
1876: }
1877:
1878: private boolean diagnoseMismatch(Environment env, Identifier nm,
1879: Type argTypes[], int start, int haveMatch[],
1880: Type margType[]) throws ClassNotFound {
1881: // look in the current class
1882: boolean haveOne = false;
1883: MemberDefinition f;
1884: for (f = getFirstMatch(nm); f != null; f = f.getNextMatch()) {
1885: if (!f.isMethod()) {
1886: continue;
1887: }
1888: Type fArgTypes[] = f.getType().getArgumentTypes();
1889: if (fArgTypes.length == argTypes.length) {
1890: haveOne = true;
1891: for (int i = start; i < argTypes.length; i++) {
1892: Type at = argTypes[i];
1893: Type ft = fArgTypes[i];
1894: if (env.implicitCast(at, ft)) {
1895: haveMatch[i] = 4;
1896: continue;
1897: } else if (haveMatch[i] <= 2
1898: && env.explicitCast(at, ft)) {
1899: if (haveMatch[i] < 2)
1900: margType[i] = null;
1901: haveMatch[i] = 2;
1902: } else if (haveMatch[i] > 0) {
1903: continue;
1904: }
1905: if (margType[i] == null)
1906: margType[i] = ft;
1907: else if (margType[i] != ft)
1908: haveMatch[i] |= 1;
1909: }
1910: }
1911: }
1912:
1913: // constructors are not inherited
1914: if (nm.equals(idInit)) {
1915: return haveOne;
1916: }
1917:
1918: // look in the super class
1919: ClassDeclaration sup = getSuperClass();
1920: if (sup != null) {
1921: if (sup.getClassDefinition(env).diagnoseMismatch(env, nm,
1922: argTypes, start, haveMatch, margType))
1923: haveOne = true;
1924: }
1925: return haveOne;
1926: }
1927:
1928: /**
1929: * Add a field (no checks)
1930: */
1931: public void addMember(MemberDefinition field) {
1932: //System.out.println("ADD = " + field);
1933: if (firstMember == null) {
1934: firstMember = lastMember = field;
1935: } else if (field.isSynthetic() && field.isFinal()
1936: && field.isVariable()) {
1937: // insert this at the front, because of initialization order
1938: field.nextMember = firstMember;
1939: firstMember = field;
1940: field.nextMatch = (MemberDefinition) fieldHash
1941: .get(field.name);
1942: } else {
1943: lastMember.nextMember = field;
1944: lastMember = field;
1945: field.nextMatch = (MemberDefinition) fieldHash
1946: .get(field.name);
1947: }
1948: fieldHash.put(field.name, field);
1949: }
1950:
1951: /**
1952: * Add a field (subclasses make checks)
1953: */
1954: public void addMember(Environment env, MemberDefinition field) {
1955: addMember(field);
1956: if (resolved) {
1957: // a late addition
1958: field.resolveTypeStructure(env);
1959: }
1960: }
1961:
1962: /**
1963: * Find or create an uplevel reference for the given target.
1964: */
1965: public UplevelReference getReference(LocalMember target) {
1966: for (UplevelReference r = references; r != null; r = r
1967: .getNext()) {
1968: if (r.getTarget() == target) {
1969: return r;
1970: }
1971: }
1972: return addReference(target);
1973: }
1974:
1975: protected UplevelReference addReference(LocalMember target) {
1976: if (target.getClassDefinition() == this ) {
1977: throw new CompilerError("addReference " + target);
1978: }
1979: referencesMustNotBeFrozen();
1980: UplevelReference r = new UplevelReference(this , target);
1981: references = r.insertInto(references);
1982: return r;
1983: }
1984:
1985: /**
1986: * Return the list of all uplevel references.
1987: */
1988: public UplevelReference getReferences() {
1989: return references;
1990: }
1991:
1992: /**
1993: * Return the same value as getReferences.
1994: * Also, mark the set of references frozen.
1995: * After that, it is an error to add new references.
1996: */
1997: public UplevelReference getReferencesFrozen() {
1998: referencesFrozen = true;
1999: return references;
2000: }
2001:
2002: /**
2003: * assertion check
2004: */
2005: public final void referencesMustNotBeFrozen() {
2006: if (referencesFrozen) {
2007: throw new CompilerError("referencesMustNotBeFrozen " + this );
2008: }
2009: }
2010:
2011: /**
2012: * Get helper method for class literal lookup.
2013: */
2014: public MemberDefinition getClassLiteralLookup(long fwhere) {
2015: throw new CompilerError("binary class");
2016: }
2017:
2018: /**
2019: * Add a dependency
2020: */
2021: public void addDependency(ClassDeclaration c) {
2022: throw new CompilerError("addDependency");
2023: }
2024:
2025: /**
2026: * Maintain a hash table of local and anonymous classes
2027: * whose internal names are prefixed by the current class.
2028: * The key is the simple internal name, less the prefix.
2029: */
2030:
2031: public ClassDefinition getLocalClass(String name) {
2032: if (localClasses == null) {
2033: return null;
2034: } else {
2035: return (ClassDefinition) localClasses.get(name);
2036: }
2037: }
2038:
2039: public void addLocalClass(ClassDefinition c, String name) {
2040: if (localClasses == null) {
2041: localClasses = new Hashtable(LOCAL_CLASSES_SIZE);
2042: }
2043: localClasses.put(name, c);
2044: }
2045:
2046: /**
2047: * Print for debugging
2048: */
2049: public void print(PrintStream out) {
2050: if (isPublic()) {
2051: out.print("public ");
2052: }
2053: if (isInterface()) {
2054: out.print("interface ");
2055: } else {
2056: out.print("class ");
2057: }
2058: out.print(getName() + " ");
2059: if (getSuperClass() != null) {
2060: out.print("extends " + getSuperClass().getName() + " ");
2061: }
2062: if (interfaces.length > 0) {
2063: out.print("implements ");
2064: for (int i = 0; i < interfaces.length; i++) {
2065: if (i > 0) {
2066: out.print(", ");
2067: }
2068: out.print(interfaces[i].getName());
2069: out.print(" ");
2070: }
2071: }
2072: out.println("{");
2073:
2074: for (MemberDefinition f = getFirstMember(); f != null; f = f
2075: .getNextMember()) {
2076: out.print(" ");
2077: f.print(out);
2078: }
2079:
2080: out.println("}");
2081: }
2082:
2083: /**
2084: * Convert to String
2085: */
2086: public String toString() {
2087: return getClassDeclaration().toString();
2088: }
2089:
2090: /**
2091: * After the class has been written to disk, try to free up
2092: * some storage.
2093: */
2094: public void cleanup(Environment env) {
2095: if (env.dump()) {
2096: env.output("[cleanup " + getName() + "]");
2097: }
2098: for (MemberDefinition f = getFirstMember(); f != null; f = f
2099: .getNextMember()) {
2100: f.cleanup(env);
2101: }
2102: // keep "references" around, for the sake of local subclasses
2103: documentation = null;
2104: }
2105: }
|