2674 lines · 109.2 KB · Java
RawDownload
    /**     * Check this class and all its fields.     */    public void check(Environment env) throws ClassNotFound {        if (tracing) env.dtEnter("SourceClass.check: " + getName());        if (isInsideLocal()) {            // An inaccessible class gets checked when the surrounding            // block is checked.            // QUERY: Should this case ever occur?            // What would invoke checking of a local class aside from            // checking the surrounding method body?            if (tracing) env.dtEvent("SourceClass.check: INSIDE LOCAL " +                                     getOuterClass().getName());            getOuterClass().check(env);        } else {            if (isInnerClass()) {                if (tracing) env.dtEvent("SourceClass.check: INNER CLASS " +                                         getOuterClass().getName());                // Make sure the outer is checked first.                ((SourceClass)getOuterClass()).maybeCheck(env);            }            Vset vset = new Vset();            Context ctx = null;            if (tracing)                env.dtEvent("SourceClass.check: CHECK INTERNAL " + getName());            vset = checkInternal(setupEnv(env), ctx, vset);            // drop vset here        }        if (tracing) env.dtExit("SourceClass.check: " + getName());    }     private void maybeCheck(Environment env) throws ClassNotFound {        if (tracing) env.dtEvent("SourceClass.maybeCheck: " + getName());        // Check this class now, if it has not yet been checked.        // Cf. Main.compile().  Perhaps this code belongs there somehow.        ClassDeclaration c = getClassDeclaration();        if (c.getStatus() == CS_PARSED) {            // Set it first to avoid vicious circularity:            c.setDefinition(this, CS_CHECKED);            check(env);        }    }     private Vset checkInternal(Environment env, Context ctx, Vset vset)                throws ClassNotFound {        Identifier nm = getClassDeclaration().getName();        if (env.verbose()) {            env.output("[checking class " + nm + "]");        }         // Save context enclosing class for later access        // by 'ClassDefinition.resolveName.'        classContext = ctx;         // At present, the call to 'newEnvironment' is not needed.        // The incoming environment to 'basicCheck' is always passed to        // 'setupEnv', which discards it completely.  This is also the        // only call to 'newEnvironment', which is now apparently dead code.        basicCheck(Context.newEnvironment(env, ctx));         // Validate access for all inner-class components        // of a qualified name, not just the last one, which        // is checked below.  Yes, this is a dirty hack...        // Much of this code was cribbed from 'checkSupers'.        // Part of fix for 4094658.        ClassDeclaration sup = getSuperClass();        if (sup != null) {            long where = getWhere();            where = IdentifierToken.getWhere(superClassId, where);            env.resolveExtendsByName(where, this, sup.getName());        }        for (int i = 0 ; i < interfaces.length ; i++) {            ClassDeclaration intf = interfaces[i];            long where = getWhere();            // Error localization fails here if interfaces were            // elided during error recovery from an invalid one.            if (interfaceIds != null                && interfaceIds.length == interfaces.length) {                where = IdentifierToken.getWhere(interfaceIds[i], where);            }            env.resolveExtendsByName(where, this, intf.getName());        }         // Does the name already exist in an imported package?        // See JLS 8.1 for the precise rules.        if (!isInnerClass() && !isInsideLocal()) {            // Discard package qualification for the import checks.            Identifier simpleName = nm.getName();            try {                // We want this to throw a ClassNotFound exception                Imports imports = toplevelEnv.getImports();                Identifier ID = imports.resolve(env, simpleName);                if (ID != getName())                    env.error(where, "class.multidef.import", simpleName, ID);            } catch (AmbiguousClass e) {                // At least one of e.name1 and e.name2 must be different                Identifier ID = (e.name1 != getName()) ? e.name1 : e.name2;                env.error(where, "class.multidef.import", simpleName, ID);            }  catch (ClassNotFound e) {                // we want this to happen            }             // Make sure that no package with the same fully qualified            // name exists.  This is required by JLS 7.1.  We only need            // to perform this check for top level classes -- it isn't            // necessary for inner classes.  (bug 4101529)            //            // This change has been backed out because, on WIN32, it            // failed to distinguish between java.awt.event and            // java.awt.Event when looking for a directory.  We will            // add this back in later.            //            // try {            //  if (env.getPackage(nm).exists()) {            //      env.error(where, "class.package.conflict", nm);            //  }            // } catch (java.io.IOException ee) {            //  env.error(where, "io.exception.package", nm);            // }             // Make sure it was defined in the right file            if (isPublic()) {                checkSourceFile(env, getWhere());            }        }         vset = checkMembers(env, ctx, vset);        return vset;    }     private boolean sourceFileChecked = false;     /**     * See if the source file of this class is of the right name.     */    public void checkSourceFile(Environment env, long where) {        // one error per offending class is sufficient        if (sourceFileChecked)  return;        sourceFileChecked = true;         String fname = getName().getName() + ".java";        String src = ((ClassFile)getSource()).getName();        if (!src.equals(fname)) {            if (isPublic()) {                env.error(where, "public.class.file", this, fname);            } else {                env.error(where, "warn.package.class.file", this, src, fname);            }        }    }     // Set true if superclass (but not necessarily superinterfaces) have    // been checked.  If the superclass is still unresolved, then an error    // message should have been issued, and we assume that no further    // resolution is possible.    private boolean supersChecked = false;     /**     * Overrides 'ClassDefinition.getSuperClass'.     */     public ClassDeclaration getSuperClass(Environment env) {        if (tracing) env.dtEnter("SourceClass.getSuperClass: " + this);        // Superclass may fail to be set because of error recovery,        // so resolve types here only if 'checkSupers' has not yet        // completed its checks on the superclass.        // QUERY: Can we eliminate the need to resolve superclasses on demand?        // See comments in 'checkSupers' and in 'ClassDefinition.getInnerClass'.        if (superClass == null && superClassId != null && !supersChecked) {            resolveTypeStructure(env);            // We used to report an error here if the superclass was not            // resolved.  Having moved the call to 'checkSupers' from 'basicCheck'            // into 'resolveTypeStructure', the errors reported here should have            // already been reported.  Furthermore, error recovery can null out            // the superclass, which would cause a spurious error from the test here.        }        if (tracing) env.dtExit("SourceClass.getSuperClass: " + this);        return superClass;    }     /**     * Check that all superclasses and superinterfaces are defined and     * well formed.  Among other checks, verify that the inheritance     * graph is acyclic.  Called from 'resolveTypeStructure'.     */     private void checkSupers(Environment env) throws ClassNotFound {         // *** DEBUG ***        supersCheckStarted = true;         if (tracing) env.dtEnter("SourceClass.checkSupers: " + this);         if (isInterface()) {            if (isFinal()) {                Identifier nm = getClassDeclaration().getName();                env.error(getWhere(), "final.intf", nm);                // Interfaces have no superclass.  Superinterfaces                // are checked below, in code shared with the class case.            }        } else {            // Check superclass.            // Call to 'getSuperClass(env)' (note argument) attempts            // 'resolveTypeStructure' if superclass has not successfully            // been resolved.  Since we have just now called 'resolveSupers'            // (see our call in 'resolveTypeStructure'), it is not clear            // that this can do any good.  Why not 'getSuperClass()' here?            if (getSuperClass(env) != null) {                long where = getWhere();                where = IdentifierToken.getWhere(superClassId, where);                try {                    ClassDefinition def =                        getSuperClass().getClassDefinition(env);                    // Resolve superclass and its ancestors.                    def.resolveTypeStructure(env);                    // Access to the superclass should be checked relative                    // to the surrounding context, not as if the reference                    // appeared within the class body. Changed 'canAccess'                    // to 'extendsCanAccess' to fix 4087314.                    if (!extendsCanAccess(env, getSuperClass())) {                        env.error(where, "cant.access.class", getSuperClass());                        // Might it be a better recovery to let the access go through?                        superClass = null;                    } else if (def.isFinal()) {                        env.error(where, "super.is.final", getSuperClass());                        // Might it be a better recovery to let the access go through?                        superClass = null;                    } else if (def.isInterface()) {                        env.error(where, "super.is.intf", getSuperClass());                        superClass = null;                    } else if (superClassOf(env, getSuperClass())) {                        env.error(where, "cyclic.super");                        superClass = null;                    } else {                        def.noteUsedBy(this, where, env);                    }                    if (superClass == null) {                        def = null;                    } else {                        // If we have a valid superclass, check its                        // supers as well, and so on up to root class.                        // Call to 'enclosingClassOf' will raise                        // 'NullPointerException' if 'def' is null,                        // so omit this check as error recovery.                        ClassDefinition sup = def;                        for (;;) {                            if (enclosingClassOf(sup)) {                                // Do we need a similar test for                                // interfaces?  See bugid 4038529.                                env.error(where, "super.is.inner");                                superClass = null;                                break;                            }                            // Since we resolved the superclass and its                            // ancestors above, we should not discover                            // any unresolved classes on the superclass                            // chain.  It should thus be sufficient to                            // call 'getSuperClass()' (no argument) here.                            ClassDeclaration s = sup.getSuperClass(env);                            if (s == null) {                                // Superclass not resolved due to error.                                break;                            }                            sup = s.getClassDefinition(env);                        }                    }                } catch (ClassNotFound e) {                    // Error is detected in call to 'getClassDefinition'.                    // The class may actually exist but be ambiguous.                    // Call env.resolve(e.name) to see if it is.                    // env.resolve(name) will definitely tell us if the                    // class is ambiguous, but may not necessarily tell                    // us if the class is not found.                    // (part of solution for 4059855)                reportError: {                        try {                            env.resolve(e.name);                        } catch (AmbiguousClass ee) {                            env.error(where,                                      "ambig.class", ee.name1, ee.name2);                            superClass = null;                            break reportError;                        } catch (ClassNotFound ee) {                            // fall through                        }                        env.error(where, "super.not.found", e.name, this);                        superClass = null;                    } // The break exits this block                }             } else {                // Superclass was null on entry, after call to                // 'resolveSupers'.  This should normally not happen,                // as 'resolveSupers' sets 'superClass' to a non-null                // value for all named classes, except for one special                // case: 'java.lang.Object', which has no superclass.                if (isAnonymous()) {                    // checker should have filled it in first                    throw new CompilerError("anonymous super");                } else  if (!getName().equals(idJavaLangObject)) {                    throw new CompilerError("unresolved super");                }            }        }         // At this point, if 'superClass' is null due to an error        // in the user program, a message should have been issued.        supersChecked = true;         // Check interfaces        for (int i = 0 ; i < interfaces.length ; i++) {            ClassDeclaration intf = interfaces[i];            long where = getWhere();            if (interfaceIds != null                && interfaceIds.length == interfaces.length) {                where = IdentifierToken.getWhere(interfaceIds[i], where);            }            try {                ClassDefinition def = intf.getClassDefinition(env);                // Resolve superinterface and its ancestors.                def.resolveTypeStructure(env);                // Check superinterface access in the correct context.                // Changed 'canAccess' to 'extendsCanAccess' to fix 4087314.                if (!extendsCanAccess(env, intf)) {                    env.error(where, "cant.access.class", intf);                } else if (!intf.getClassDefinition(env).isInterface()) {                    env.error(where, "not.intf", intf);                } else if (isInterface() && implementedBy(env, intf)) {                    env.error(where, "cyclic.intf", intf);                } else {                    def.noteUsedBy(this, where, env);                    // Interface is OK, leave it in the interface list.                    continue;                }            } catch (ClassNotFound e) {                // The interface may actually exist but be ambiguous.                // Call env.resolve(e.name) to see if it is.                // env.resolve(name) will definitely tell us if the                // interface is ambiguous, but may not necessarily tell                // us if the interface is not found.                // (part of solution for 4059855)            reportError2: {                    try {                        env.resolve(e.name);                    } catch (AmbiguousClass ee) {                        env.error(where,                                  "ambig.class", ee.name1, ee.name2);                        superClass = null;                        break reportError2;                    } catch (ClassNotFound ee) {                        // fall through                    }                    env.error(where, "intf.not.found", e.name, this);                    superClass = null;                } // The break exits this block            }            // Remove this interface from the list of interfaces            // as recovery from an error.            ClassDeclaration newInterfaces[] =                new ClassDeclaration[interfaces.length - 1];            System.arraycopy(interfaces, 0, newInterfaces, 0, i);            System.arraycopy(interfaces, i + 1, newInterfaces, i,                             newInterfaces.length - i);            interfaces = newInterfaces;            --i;        }        if (tracing) env.dtExit("SourceClass.checkSupers: " + this);    }     /**     * Check all of the members of this class.     * <p>     * Inner classes are checked in the following way.  Any class which     * is immediately contained in a block (anonymous and local classes)     * is checked along with its containing method; see the     * SourceMember.check() method for more information.  Member classes     * of this class are checked immediately after this class, unless this     * class is insideLocal(), in which case, they are checked with the     * rest of the members.     */    private Vset checkMembers(Environment env, Context ctx, Vset vset)            throws ClassNotFound {         // bail out if there were any errors        if (getError()) {            return vset;        }         // Make sure that all of our member classes have been        // basicCheck'ed before we check the rest of our members.        // If our member classes haven't been basicCheck'ed, then they        // may not have <init> methods.  It is important that they        // have <init> methods so we can process NewInstanceExpressions        // correctly.  This problem didn't occur before 1.2beta1.        // This is a fix for bug 4082816.        for (MemberDefinition f = getFirstMember();                     f != null; f = f.getNextMember()) {            if (f.isInnerClass()) {                // System.out.println("Considering " + f + " in " + this);                SourceClass cdef = (SourceClass) f.getInnerClass();                if (cdef.isMember()) {                    cdef.basicCheck(env);                }            }        }         if (isFinal() && isAbstract()) {            env.error(where, "final.abstract", this.getName().getName());        }         // This class should be abstract if there are any abstract methods        // in our parent classes and interfaces which we do not override.        // There are odd cases when, even though we cannot access some        // abstract method from our superclass, that abstract method can        // still force this class to be abstract.  See the discussion in        // bug id 1240831.        if (!isInterface() && !isAbstract() && mustBeAbstract(env)) {            // Set the class abstract.            modifiers |= M_ABSTRACT;             // Tell the user which methods force this class to be abstract.             // First list all of the "unimplementable" abstract methods.            Iterator iter = getPermanentlyAbstractMethods();            while (iter.hasNext()) {                MemberDefinition method = (MemberDefinition) iter.next();                // We couldn't override this method even if we                // wanted to.  Try to make the error message                // as non-confusing as possible.                env.error(where, "abstract.class.cannot.override",                          getClassDeclaration(), method,                          method.getDefiningClassDeclaration());            }             // Now list all of the traditional abstract methods.            iter = getMethods(env);            while (iter.hasNext()) {                // For each method, check if it is abstract.  If it is,                // output an appropriate error message.                MemberDefinition method = (MemberDefinition) iter.next();                if (method.isAbstract()) {                    env.error(where, "abstract.class",                              getClassDeclaration(), method,                              method.getDefiningClassDeclaration());                }            }        }         // Check the instance variables in a pre-pass before any constructors.        // This lets constructors "in-line" any initializers directly.        // It also lets us do some definite assignment checks on variables.        Context ctxInit = new Context(ctx);        Vset vsInst = vset.copy();        Vset vsClass = vset.copy();         // Do definite assignment checking on blank finals.        // Other variables do not need such checks.  The simple textual        // ordering constraints implemented by MemberDefinition.canReach()        // are necessary and sufficient for the other variables.        // Note that within non-static code, all statics are always        // definitely assigned, and vice-versa.        for (MemberDefinition f = getFirstMember();                     f != null; f = f.getNextMember()) {            if (f.isVariable() && f.isBlankFinal()) {                // The following allocates a LocalMember object as a proxy                // to represent the field.                int number = ctxInit.declareFieldNumber(f);                if (f.isStatic()) {                    vsClass = vsClass.addVarUnassigned(number);                    vsInst = vsInst.addVar(number);                } else {                    vsInst = vsInst.addVarUnassigned(number);                    vsClass = vsClass.addVar(number);                }            }        }         // For instance variable checks, use a context with a "this" parameter.        Context ctxInst = new Context(ctxInit, this);        LocalMember thisArg = getThisArgument();        int thisNumber = ctxInst.declare(env, thisArg);        vsInst = vsInst.addVar(thisNumber);         // Do all the initializers in order, checking the definite        // assignment of blank finals.  Separate static from non-static.        for (MemberDefinition f = getFirstMember();                     f != null; f = f.getNextMember()) {            try {                if (f.isVariable() || f.isInitializer()) {                    if (f.isStatic()) {                        vsClass = f.check(env, ctxInit, vsClass);                    } else {                        vsInst = f.check(env, ctxInst, vsInst);                    }                }            } catch (ClassNotFound ee) {                env.error(f.getWhere(), "class.not.found", ee.name, this);            }        } 

Lines 501–1000 of 2674. Previous lines