/** * 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 Load more
/** * 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); } }