2085 lines · 77.0 KB · Java
RawDownload
     /**     * Check to see if a class must be abstract.  This method replaces     * isAbstract(env)     */    public final boolean mustBeAbstract(Environment env) {        // If it is declared abstract, return true.        // (Fix for 4110534.)        if (isAbstract()) {            return true;        }         // Check to see if the class should have been declared to be        // abstract.         // We make sure that the inherited method collection has been        // performed.        collectInheritedMethods(env);         // We check for any abstract methods inherited or declared        // by this class.        Iterator methods = getMethods();        while (methods.hasNext()) {            MemberDefinition method = (MemberDefinition) methods.next();             if (method.isAbstract()) {                return true;            }        }         // We check for hidden "permanently abstract" methods in        // our superclasses.        return getPermanentlyAbstractMethods().hasNext();    }     /**     * Check if this is a super class of another class     */    public boolean superClassOf(Environment env, ClassDeclaration otherClass)                                                                throws ClassNotFound {        while (otherClass != null) {            if (getClassDeclaration().equals(otherClass)) {                return true;            }            otherClass = otherClass.getClassDefinition(env).getSuperClass();        }        return false;    }     /**     * Check if this is an enclosing class of another class     */    public boolean enclosingClassOf(ClassDefinition otherClass) {        while ((otherClass = otherClass.getOuterClass()) != null) {            if (this == otherClass) {                return true;            }        }        return false;    }     /**     * Check if this is a sub class of another class     */    public boolean subClassOf(Environment env, ClassDeclaration otherClass) throws ClassNotFound {        ClassDeclaration c = getClassDeclaration();        while (c != null) {            if (c.equals(otherClass)) {                return true;            }            c = c.getClassDefinition(env).getSuperClass();        }        return false;    }     /**     * Check if this class is implemented by another class     */    public boolean implementedBy(Environment env, ClassDeclaration c) throws ClassNotFound {        for (; c != null ; c = c.getClassDefinition(env).getSuperClass()) {            if (getClassDeclaration().equals(c)) {                return true;            }            ClassDeclaration intf[] = c.getClassDefinition(env).getInterfaces();            for (int i = 0 ; i < intf.length ; i++) {                if (implementedBy(env, intf[i])) {                    return true;                }            }        }        return false;    }     /**     * Check to see if a class which implements interface `this' could     * possibly implement the interface `intDef'.  Note that the only     * way that this can fail is if `this' and `intDef' have methods     * which are of the same signature and different return types.  This     * method is used by Environment.explicitCast() to determine if a     * cast between two interfaces is legal.     *     * This method should only be called on a class after it has been     * basicCheck()'ed.     */    public boolean couldImplement(ClassDefinition intDef) {        // Check to see if we could have done the necessary checks.        if (!doInheritanceChecks) {            throw new CompilerError("couldImplement: no checks");        }         // This method should only be called for interfaces.        if (!isInterface() || !intDef.isInterface()) {            throw new CompilerError("couldImplement: not interface");        }         // Make sure we are not called before we have collected our        // inheritance information.        if (allMethods == null) {            throw new CompilerError("couldImplement: called early");        }         // Get the other classes' methods.  getMethods() in        // general can return methods which are not visible to the        // current package.  We need to make sure that these do not        // prevent this class from being implemented.        Iterator otherMethods = intDef.getMethods();         while (otherMethods.hasNext()) {            // Get one of the methods from intDef...            MemberDefinition method =                (MemberDefinition) otherMethods.next();             Identifier name = method.getName();            Type type = method.getType();             // See if we implement a method of the same signature...            MemberDefinition myMethod = allMethods.lookupSig(name, type);             //System.out.println("Comparing\n\t" + myMethod +            //                   "\nand\n\t" + method);             if (myMethod != null) {                // We do.  Make sure the methods have the same return type.                if (!myMethod.sameReturnType(method)) {                    return false;                }            }        }         return true;    }     /**     * Check if another class can be accessed from the 'extends' or 'implements'     * clause of this class.     */    public boolean extendsCanAccess(Environment env, ClassDeclaration c) throws ClassNotFound {         // Names in the 'extends' or 'implements' clause of an inner class        // are checked as if they appeared in the body of the surrounding class.        if (outerClass != null) {            return outerClass.canAccess(env, c);        }         // We are a package member.         ClassDefinition cdef = c.getClassDefinition(env);         if (cdef.isLocal()) {            // No locals should be in scope in the 'extends' or            // 'implements' clause of a package member.            throw new CompilerError("top local");        }         if (cdef.isInnerClass()) {            MemberDefinition f = cdef.getInnerClassMember();             // Access to public member is always allowed.            if (f.isPublic()) {                return true;            }             // Private access is ok only from the same class nest.  This can            // happen only if the class represented by 'this' encloses the inner            // class represented by 'f'.            if (f.isPrivate()) {                return getClassDeclaration().equals(f.getTopClass().getClassDeclaration());            }             // Protected or default access -- allow access if in same package.            return getName().getQualifier().equals(f.getClassDeclaration().getName().getQualifier());        }         // Access to public member is always allowed.        if (cdef.isPublic()) {            return true;        }         // Default access -- allow access if in same package.        return getName().getQualifier().equals(c.getName().getQualifier());    }     /**     * Check if another class can be accessed from within the body of this class.     */    public boolean canAccess(Environment env, ClassDeclaration c) throws ClassNotFound {        ClassDefinition cdef = c.getClassDefinition(env);         if (cdef.isLocal()) {            // if it's in scope, it's accessible            return true;        }         if (cdef.isInnerClass()) {            return canAccess(env, cdef.getInnerClassMember());        }         // Public access is always ok        if (cdef.isPublic()) {            return true;        }         // It must be in the same package        return getName().getQualifier().equals(c.getName().getQualifier());    }     /**     * Check if a field can be accessed from a class     */     public boolean canAccess(Environment env, MemberDefinition f)                throws ClassNotFound {         // Public access is always ok        if (f.isPublic()) {            return true;        }        // Protected access is ok from a subclass        if (f.isProtected() && subClassOf(env, f.getClassDeclaration())) {            return true;        }        // Private access is ok only from the same class nest        if (f.isPrivate()) {            return getTopClass().getClassDeclaration()                .equals(f.getTopClass().getClassDeclaration());        }        // It must be in the same package        return getName().getQualifier().equals(f.getClassDeclaration().getName().getQualifier());    }     /**     * Check if a class is entitled to inline access to a class from     * another class.     */    public boolean permitInlinedAccess(Environment env, ClassDeclaration c)                       throws ClassNotFound {         return (env.opt() && c.equals(declaration)) ||               (env.opt_interclass() && canAccess(env, c));    }     /**     * Check if a class is entitled to inline access to a method from     * another class.     */    public boolean permitInlinedAccess(Environment env, MemberDefinition f)                       throws ClassNotFound {        return (env.opt()                    && (f.clazz.getClassDeclaration().equals(declaration))) ||               (env.opt_interclass() && canAccess(env, f));    }     /**     * We know the the field is marked protected (and not public) and that     * the field is visible (as per canAccess).  Can we access the field as     * <accessor>.<field>, where <accessor> has the type <accessorType>?     *     * Protected fields can only be accessed when the accessorType is a     * subclass of the current class     */    public boolean protectedAccess(Environment env, MemberDefinition f,                                   Type accessorType)        throws ClassNotFound    {         return               // static protected fields are accessible               f.isStatic()            || // allow array.clone()               (accessorType.isType(TC_ARRAY) && (f.getName() == idClone)                 && (f.getType().getArgumentTypes().length == 0))            || // <accessorType> is a subtype of the current class               (accessorType.isType(TC_CLASS)                 && env.getClassDefinition(accessorType.getClassName())                         .subClassOf(env, getClassDeclaration()))            || // we are accessing the field from a friendly class (same package)               (getName().getQualifier()                   .equals(f.getClassDeclaration().getName().getQualifier()));    }      /**     * Find or create an access method for a private member,     * or return null if this is not possible.     */    public MemberDefinition getAccessMember(Environment env, Context ctx,                                          MemberDefinition field, boolean isSuper) {        throw new CompilerError("binary getAccessMember");    }     /**     * Find or create an update method for a private member,     * or return null if this is not possible.     */    public MemberDefinition getUpdateMember(Environment env, Context ctx,                                            MemberDefinition field, boolean isSuper) {        throw new CompilerError("binary getUpdateMember");    }     /**     * Get a field from this class.  Report ambiguous fields.     * If no accessible field is found, this method may return an     * inaccessible field to allow a useful error message.     *     * getVariable now takes the source class `source' as an argument.     * This allows getVariable to check whether a field is inaccessible     * before it signals that a field is ambiguous.  The compiler used to     * signal an ambiguity even when one of the fields involved was not     * accessible.  (bug 4053724)     */    public MemberDefinition getVariable(Environment env,                                        Identifier nm,                                        ClassDefinition source)        throws AmbiguousMember, ClassNotFound {         return getVariable0(env, nm, source, true, true);    }     /*     * private fields are never inherited.  package-private fields are     * not inherited across package boundaries.  To capture this, we     * take two booleans as parameters: showPrivate indicates whether     * we have passed a class boundary, and showPackage indicates whether     * we have crossed a package boundary.     */    private MemberDefinition getVariable0(Environment env,                                          Identifier nm,                                          ClassDefinition source,                                          boolean showPrivate,                                          boolean showPackage)        throws AmbiguousMember, ClassNotFound {         // Check to see if this field is defined in the current class        for (MemberDefinition member = getFirstMatch(nm);             member != null;             member = member.getNextMatch()) {            if (member.isVariable()) {                if ((showPrivate || !member.isPrivate()) &&                    (showPackage || !member.isPackagePrivate())) {                    // It is defined in this class.                    return member;                } else {                    // Even though this definition is not inherited,                    // it hides all definitions in supertypes.                    return null;                }            }        }         // Find the field in our superclass.        ClassDeclaration sup = getSuperClass();        MemberDefinition field = null;        if (sup != null) {            field =                sup.getClassDefinition(env)                  .getVariable0(env, nm, source,                                false,                                showPackage && inSamePackage(sup));        }         // Find the field in our superinterfaces.        for (int i = 0 ; i < interfaces.length ; i++) {            // Try to look up the field in an interface.  Since interfaces            // only have public fields, the values of the two boolean            // arguments are not important.            MemberDefinition field2 =                interfaces[i].getClassDefinition(env)                  .getVariable0(env, nm, source, true, true);             if (field2 != null) {                // If we have two different, accessible fields, then                // we've found an ambiguity.                if (field != null &&                    source.canAccess(env, field) &&                    field2 != field) {                     throw new AmbiguousMember(field2, field);                }                field = field2;            }        }        return field;    }     /**     * Tells whether to report a deprecation error for this class.     */    public boolean reportDeprecated(Environment env) {        return (isDeprecated()                || (outerClass != null && outerClass.reportDeprecated(env)));    }     /**     * Note that this class is being used somehow by <tt>ref</tt>.     * Report deprecation errors, etc.     */    public void noteUsedBy(ClassDefinition ref, long where, Environment env) {        // (Have this deal with canAccess() checks, too?)        if (reportDeprecated(env)) {            env.error(where, "warn.class.is.deprecated", this);        }    }    /**     * Get an inner class.     * Look in supers but not outers.     * (This is used directly to resolve expressions like "site.K", and     * inside a loop to resolve lone names like "K" or the "K" in "K.L".)     *     * Called from 'Context' and 'FieldExpression' as well as this class.     *     * @see FieldExpression.checkCommon     * @see resolveName     */    public MemberDefinition getInnerClass(Environment env, Identifier nm)                                                        throws ClassNotFound {        // Note:  AmbiguousClass will not be thrown unless and until        // inner classes can be defined inside interfaces.         // Check if it is defined in the current class        for (MemberDefinition field = getFirstMatch(nm);                field != null ; field = field.getNextMatch()) {            if (field.isInnerClass()) {                if (field.getInnerClass().isLocal()) {                    continue;   // ignore this name; it is internally generated                }                return field;            }        }         // Get it from the super class        // It is likely that 'getSuperClass()' could be made to work here        // but we would have to assure somehow that 'resolveTypeStructure'        // has been called on the current class nest.  Since we can get        // here from 'resolveName', which is called from 'resolveSupers',        // it is possible that the first attempt to resolve the superclass        // will originate here, instead of in the call to 'getSuperClass'        // in 'checkSupers'.  See 'resolveTypeStructure', in which a call        // to 'resolveSupers' precedes the call to 'checkSupers'.  Why is        // name resolution done twice, first in 'resolveName'?        // NOTE: 'SourceMember.resolveTypeStructure' may initiate type        // structure resolution for an inner class.  Normally, this        // occurs during the resolution of the outer class, but fields        // added after the resolution of their containing class will        // be resolved late -- see 'addMember(env,field)' below.        // This should only happen for synthetic members, which should        // never be an inner class.        ClassDeclaration sup = getSuperClass(env);        if (sup != null)            return sup.getClassDefinition(env).getInnerClass(env, nm);         return null;    }     /**     * Lookup a method.  This code implements the method lookup     * mechanism specified in JLS 15.11.2.     *     * This mechanism cannot be used to lookup synthetic methods.     */    private MemberDefinition matchMethod(Environment env,                                         ClassDefinition accessor,                                         Identifier methodName,                                         Type[] argumentTypes,                                         boolean isAnonConstCall,                                         Identifier accessPackage)        throws AmbiguousMember, ClassNotFound {         if (allMethods == null || !allMethods.isFrozen()) {            // This may be too restrictive.            throw new CompilerError("matchMethod called early");            // collectInheritedMethods(env);        }         // A tentative maximally specific method.        MemberDefinition tentative = null;         // A list of other methods which may be maximally specific too.        List candidateList = null; 

Lines 501–1000 of 2085. Previous lines