861 lines · 29.2 KB · Java
RawDownload
            thisc = prevc.getOuterClass();             if (prevc == conCls) {                // Must pick up "this$C" from the constructor argument,                // not from "this.this$C", since the latter may not be                // initialized properly.  (This way is cheaper too.)                Identifier nm = outerMember.getName();                IdentifierExpression arg = new IdentifierExpression(where, nm);                arg.bind(env, this);                thise = arg;            } else {                thise = new FieldExpression(where, thise, outerMember);            }        }        if (thise != null) {            // mark crossed scopes            // ?????            //ensureAvailable(root);            return thise;        }         if (f == null) {            // say something like: undefined variable A.this            Identifier nm = reqc.getName().getFlatName().getName();            env.error(where, "undef.var", Identifier.lookup(nm,idThis));        } else if (f.isConstructor()) {            env.error(where, "no.outer.arg", reqc, f.getClassDefinition());        } else {            env.error(where, "no.static.field.access", f, field);        }         // avoid floodgating:        Expression e = new ThisExpression(where, this);        e.type = reqc.getType();        return e;    }     /**     * Is there a "this" of type reqc in scope?     */    public static boolean outerLinkExists(Environment env,                                          ClassDefinition reqc,                                          ClassDefinition thisc) {        while (!match(env, thisc, reqc)) {            if (thisc.isTopLevel()) {                return false;            }            thisc = thisc.getOuterClass();        }        return true;    }     /**     * From which enclosing class do members of this type come?     */    public ClassDefinition findScope(Environment env, ClassDefinition reqc) {        ClassDefinition thisc = field.getClassDefinition();        while (thisc != null && !match(env, thisc, reqc)) {            thisc = thisc.getOuterClass();        }        return thisc;    }     /**     * Resolve a type name from within a local scope.     * @see Environment#resolveName     */    Identifier resolveName(Environment env, Identifier name) {        // This logic is pretty much exactly parallel to that of        // Environment.resolveName().        if (name.isQualified()) {            // Try to resolve the first identifier component,            // because inner class names take precedence over            // package prefixes.  (Cf. Environment.resolveName.)            Identifier rhead = resolveName(env, name.getHead());             if (rhead.hasAmbigPrefix()) {                // The first identifier component refers to an                // ambiguous class.  Limp on.  We throw away the                // rest of the classname as it is irrelevant.                // (part of solution for 4059855).                return rhead;            }             if (!env.classExists(rhead)) {                return env.resolvePackageQualifiedName(name);            }            try {                return env.getClassDefinition(rhead).                    resolveInnerClass(env, name.getTail());            } catch (ClassNotFound ee) {                // return partially-resolved name someone else can fail on                return Identifier.lookupInner(rhead, name.getTail());            }        }         // Look for an unqualified name in enclosing scopes.        try {            MemberDefinition f = getClassCommon(env, name, false);            if (f != null) {                return f.getInnerClass().getName();            }        } catch (ClassNotFound ee) {            // a missing superclass, or something catastrophic        }         // look in imports, etc.        return env.resolveName(name);    }     /**     * Return the name of a lexically apparent type,     * skipping inherited members, and ignoring     * the current pacakge and imports.     * This is used for error checking.     */    public    Identifier getApparentClassName(Environment env, Identifier name) {        if (name.isQualified()) {            // Try to resolve the first identifier component,            // because inner class names take precedence over            // package prefixes.  (Cf. Environment.resolveName.)            Identifier rhead = getApparentClassName(env, name.getHead());            return (rhead == null) ? idNull                : Identifier.lookup(rhead,                                    name.getTail());        }         // Look for an unqualified name in enclosing scopes.        try {            MemberDefinition f = getClassCommon(env, name, true);            if (f != null) {                return f.getInnerClass().getName();            }        } catch (ClassNotFound ee) {            // a missing superclass, or something catastrophic        }         // the enclosing class name is the only apparent package member:        Identifier topnm = field.getClassDefinition().getTopClass().getName();        if (topnm.getName().equals(name)) {            return topnm;        }        return idNull;    }     /**     * Raise an error if a blank final was definitely unassigned     * on entry to a loop, but has possibly been assigned on the     * back-branch.  If this is the case, the loop may be assigning     * it multiple times.     */    public void checkBackBranch(Environment env, Statement loop,                                Vset vsEntry, Vset vsBack) {        for (LocalMember f = locals ; f != null ; f = f.prev) {            if (f.isBlankFinal()                && vsEntry.testVarUnassigned(f.number)                && !vsBack.testVarUnassigned(f.number)) {                env.error(loop.where, "assign.to.blank.final.in.loop",                          f.getName());            }        }    }     /**     * Check if a field can reach another field (only considers     * forward references, not the access modifiers).     */    public boolean canReach(Environment env, MemberDefinition f) {        return field.canReach(env, f);    }     /**     * Get the context that corresponds to a label, return null if     * not found.     */    public    Context getLabelContext(Identifier lbl) {        for (Context ctx = this ; ctx != null ; ctx = ctx.prev) {            if ((ctx.node != null) && (ctx.node instanceof Statement)) {                if (((Statement)(ctx.node)).hasLabel(lbl))                    return ctx;            }        }        return null;    }     /**     * Get the destination context of a break     */    public    Context getBreakContext(Identifier lbl) {        if (lbl != null) {            return getLabelContext(lbl);        }        for (Context ctx = this ; ctx != null ; ctx = ctx.prev) {            if (ctx.node != null) {                switch (ctx.node.op) {                  case SWITCH:                  case FOR:                  case DO:                  case WHILE:                    return ctx;                }            }        }        return null;    }     /**     * Get the destination context of a continue     */    public    Context getContinueContext(Identifier lbl) {        if (lbl != null) {            return getLabelContext(lbl);        }        for (Context ctx = this ; ctx != null ; ctx = ctx.prev) {            if (ctx.node != null) {                switch (ctx.node.op) {                  case FOR:                  case DO:                  case WHILE:                    return ctx;                }            }        }        return null;    }     /**     * Get the destination context of a return (the method body)     */    public    CheckContext getReturnContext() {        for (Context ctx = this ; ctx != null ; ctx = ctx.prev) {            // The METHOD node is set up by Statement.checkMethod().            if (ctx.node != null && ctx.node.op == METHOD) {                return (CheckContext)ctx;            }        }        return null;    }     /**     * Get the context of the innermost surrounding try-block.     * Consider only try-blocks contained within the same method.     * (There could be others when searching from within a method     * of a local class, but they are irrelevant to our purpose.)     * This is used for recording DA/DU information preceding     * all abnormal transfers of control: break, continue, return,     * and throw.     */    public    CheckContext getTryExitContext() {        for (Context ctx = this;             ctx != null && ctx.node != null && ctx.node.op != METHOD;             ctx = ctx.prev) {            if (ctx.node.op == TRY) {                return (CheckContext)ctx;            }        }        return null;    }     /**     * Get the nearest inlined context     */    Context getInlineContext() {        for (Context ctx = this ; ctx != null ; ctx = ctx.prev) {            if (ctx.node != null) {                switch (ctx.node.op) {                  case INLINEMETHOD:                  case INLINENEWINSTANCE:                    return ctx;                }            }        }        return null;    }     /**     * Get the context of a field that is being inlined     */    Context getInlineMemberContext(MemberDefinition field) {        for (Context ctx = this ; ctx != null ; ctx = ctx.prev) {            if (ctx.node != null) {                switch (ctx.node.op) {                  case INLINEMETHOD:                    if (((InlineMethodExpression)ctx.node).field.equals(field)) {                        return ctx;                    }                    break;                  case INLINENEWINSTANCE:                    if (((InlineNewInstanceExpression)ctx.node).field.equals(field)) {                        return ctx;                    }                }            }        }        return null;    }     /**     * Remove variables from the vset set  that are no longer part of     * this context.     */    public final Vset removeAdditionalVars(Vset vset) {        return vset.removeAdditionalVars(varNumber);    }     public final int getVarNumber() {        return varNumber;    }     /**     * Return the number of the innermost current instance reference.     */    public int getThisNumber() {        LocalMember thisf = getLocalField(idThis);        if (thisf != null            && thisf.getClassDefinition() == field.getClassDefinition()) {            return thisf.number;        }        // this is a variable; there is no "this" (should not happen)        return varNumber;    }     /**     * Return the field containing the present context.     */    public final MemberDefinition getField() {        return field;    }     /**     * Extend an environment with the given context.     * The resulting environment behaves the same as     * the given one, except that resolveName() takes     * into account local class names in this context.     */    public static Environment newEnvironment(Environment env, Context ctx) {        return new ContextEnvironment(env, ctx);    }} finalclass ContextEnvironment extends Environment {    Context ctx;    Environment innerEnv;     ContextEnvironment(Environment env, Context ctx) {        super(env, env.getSource());        this.ctx = ctx;        this.innerEnv = env;    }     public Identifier resolveName(Identifier name) {        return ctx.resolveName(innerEnv, name);    }}

Lines 501–861 of 861. Previous lines