| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.tools.tree;  | 
 | 
 | 
 | 
import sun.tools.java.*;  | 
 | 
import sun.tools.asm.Assembler;  | 
 | 
import sun.tools.asm.LocalVariable;  | 
 | 
import java.io.PrintStream;  | 
 | 
import java.util.Hashtable;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public  | 
 | 
class IdentifierExpression extends Expression { | 
 | 
    Identifier id;  | 
 | 
    MemberDefinition field;  | 
 | 
    Expression implementation;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public IdentifierExpression(long where, Identifier id) { | 
 | 
        super(IDENT, where, Type.tError);  | 
 | 
        this.id = id;  | 
 | 
    }  | 
 | 
    public IdentifierExpression(IdentifierToken id) { | 
 | 
        this(id.getWhere(), id.getName());  | 
 | 
    }  | 
 | 
    public IdentifierExpression(long where, MemberDefinition field) { | 
 | 
        super(IDENT, where, field.getType());  | 
 | 
        this.id = field.getName();  | 
 | 
        this.field = field;  | 
 | 
    }  | 
 | 
 | 
 | 
    public Expression getImplementation() { | 
 | 
        if (implementation != null)  | 
 | 
            return implementation;  | 
 | 
        return this;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean equals(Identifier id) { | 
 | 
        return this.id.equals(id);  | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private Vset assign(Environment env, Context ctx, Vset vset) { | 
 | 
        if (field.isLocal()) { | 
 | 
            LocalMember local = (LocalMember)field;  | 
 | 
            if (local.scopeNumber < ctx.frameNumber) { | 
 | 
                env.error(where, "assign.to.uplevel", id);  | 
 | 
            }  | 
 | 
            if (local.isFinal()) { | 
 | 
                  | 
 | 
                if (!local.isBlankFinal()) { | 
 | 
                    env.error(where, "assign.to.final", id);  | 
 | 
                } else if (!vset.testVarUnassigned(local.number)) { | 
 | 
                    env.error(where, "assign.to.blank.final", id);  | 
 | 
                }  | 
 | 
            }  | 
 | 
            vset.addVar(local.number);  | 
 | 
            local.writecount++;  | 
 | 
        } else if (field.isFinal()) { | 
 | 
            vset = FieldExpression.checkFinalAssign(env, ctx, vset,  | 
 | 
                                                    where, field);  | 
 | 
        }  | 
 | 
        return vset;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private Vset get(Environment env, Context ctx, Vset vset) { | 
 | 
        if (field.isLocal()) { | 
 | 
            LocalMember local = (LocalMember)field;  | 
 | 
            if (local.scopeNumber < ctx.frameNumber && !local.isFinal()) { | 
 | 
                env.error(where, "invalid.uplevel", id);  | 
 | 
            }  | 
 | 
            if (!vset.testVar(local.number)) { | 
 | 
                env.error(where, "var.not.initialized", id);  | 
 | 
                vset.addVar(local.number);  | 
 | 
            }  | 
 | 
            local.readcount++;  | 
 | 
        } else { | 
 | 
            if (!field.isStatic()) { | 
 | 
                if (!vset.testVar(ctx.getThisNumber())) { | 
 | 
                    env.error(where, "access.inst.before.super", id);  | 
 | 
                    implementation = null;  | 
 | 
                }  | 
 | 
            }  | 
 | 
            if (field.isBlankFinal()) { | 
 | 
                int number = ctx.getFieldNumber(field);  | 
 | 
                if (number >= 0 && !vset.testVar(number)) { | 
 | 
                    env.error(where, "var.not.initialized", id);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return vset;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    boolean bind(Environment env, Context ctx) { | 
 | 
        try { | 
 | 
            field = ctx.getField(env, id);  | 
 | 
            if (field == null) { | 
 | 
                for (ClassDefinition cdef = ctx.field.getClassDefinition();  | 
 | 
                     cdef != null; cdef = cdef.getOuterClass()) { | 
 | 
                    if (cdef.findAnyMethod(env, id) != null) { | 
 | 
                        env.error(where, "invalid.var", id,  | 
 | 
                                  ctx.field.getClassDeclaration());  | 
 | 
                        return false;  | 
 | 
                    }  | 
 | 
                }  | 
 | 
                env.error(where, "undef.var", id);  | 
 | 
                return false;  | 
 | 
            }  | 
 | 
 | 
 | 
            type = field.getType();  | 
 | 
 | 
 | 
              | 
 | 
            if (!ctx.field.getClassDefinition().canAccess(env, field)) { | 
 | 
                env.error(where, "no.field.access",  | 
 | 
                          id, field.getClassDeclaration(),  | 
 | 
                          ctx.field.getClassDeclaration());  | 
 | 
                return false;  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            if (field.isLocal()) { | 
 | 
                LocalMember local = (LocalMember)field;  | 
 | 
                if (local.scopeNumber < ctx.frameNumber) { | 
 | 
                      | 
 | 
                    implementation = ctx.makeReference(env, local);  | 
 | 
                }  | 
 | 
            } else { | 
 | 
                MemberDefinition f = field;  | 
 | 
 | 
 | 
                if (f.reportDeprecated(env)) { | 
 | 
                    env.error(where, "warn.field.is.deprecated",  | 
 | 
                              id, f.getClassDefinition());  | 
 | 
                }  | 
 | 
 | 
 | 
                ClassDefinition fclass = f.getClassDefinition();  | 
 | 
                if (fclass != ctx.field.getClassDefinition()) { | 
 | 
                      | 
 | 
                    MemberDefinition f2 = ctx.getApparentField(env, id);  | 
 | 
                    if (f2 != null && f2 != f) { | 
 | 
                        ClassDefinition c = ctx.findScope(env, fclass);  | 
 | 
                        if (c == null)  c = f.getClassDefinition();  | 
 | 
                        if (f2.isLocal()) { | 
 | 
                            env.error(where, "inherited.hides.local",  | 
 | 
                                      id, c.getClassDeclaration());  | 
 | 
                        } else { | 
 | 
                            env.error(where, "inherited.hides.field",  | 
 | 
                                      id, c.getClassDeclaration(),  | 
 | 
                                      f2.getClassDeclaration());  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                }  | 
 | 
 | 
 | 
                // Rewrite as a FieldExpression.  | 
 | 
                // Access methods for private fields, if needed, will be added  | 
 | 
                // during subsequent processing of the FieldExpression.  See  | 
 | 
                // method 'FieldExpression.checkCommon'. This division of labor  | 
 | 
                // is somewhat awkward, as most further processing of a  | 
 | 
                // FieldExpression during the checking phase is suppressed when  | 
 | 
                // the referenced field is pre-set as it is here.  | 
 | 
 | 
 | 
                if (f.isStatic()) { | 
 | 
                    Expression base = new TypeExpression(where,  | 
 | 
                                        f.getClassDeclaration().getType());  | 
 | 
                    implementation = new FieldExpression(where, null, f);  | 
 | 
                } else { | 
 | 
                    Expression base = ctx.findOuterLink(env, where, f);  | 
 | 
                    if (base != null) { | 
 | 
                        implementation = new FieldExpression(where, base, f);  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            if (!ctx.canReach(env, field)) { | 
 | 
                env.error(where, "forward.ref",  | 
 | 
                          id, field.getClassDeclaration());  | 
 | 
                return false;  | 
 | 
            }  | 
 | 
            return true;  | 
 | 
        } catch (ClassNotFound e) { | 
 | 
            env.error(where, "class.not.found", e.name, ctx.field);  | 
 | 
        } catch (AmbiguousMember e) { | 
 | 
            env.error(where, "ambig.field", id,  | 
 | 
                      e.field1.getClassDeclaration(),  | 
 | 
                      e.field2.getClassDeclaration());  | 
 | 
        }  | 
 | 
        return false;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public Vset checkValue(Environment env, Context ctx, Vset vset, Hashtable exp) { | 
 | 
        if (field != null) { | 
 | 
            // An internally pre-set field, such as an argument copying  | 
 | 
              | 
 | 
            return vset;  | 
 | 
        }  | 
 | 
        if (bind(env, ctx)) { | 
 | 
            vset = get(env, ctx, vset);  | 
 | 
            ctx.field.getClassDefinition().addDependency(field.getClassDeclaration());  | 
 | 
            if (implementation != null)  | 
 | 
                vset = implementation.checkValue(env, ctx, vset, exp);  | 
 | 
        }  | 
 | 
        return vset;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public Vset checkLHS(Environment env, Context ctx,  | 
 | 
                         Vset vset, Hashtable exp) { | 
 | 
        if (!bind(env, ctx))  | 
 | 
            return vset;  | 
 | 
        vset = assign(env, ctx, vset);  | 
 | 
        if (implementation != null)  | 
 | 
            vset = implementation.checkValue(env, ctx, vset, exp);  | 
 | 
        return vset;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public Vset checkAssignOp(Environment env, Context ctx,  | 
 | 
                              Vset vset, Hashtable exp, Expression outside) { | 
 | 
        if (!bind(env, ctx))  | 
 | 
            return vset;  | 
 | 
        vset = assign(env, ctx, get(env, ctx, vset));  | 
 | 
        if (implementation != null)  | 
 | 
            vset = implementation.checkValue(env, ctx, vset, exp);  | 
 | 
        return vset;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public FieldUpdater getAssigner(Environment env, Context ctx) { | 
 | 
        if (implementation != null)  | 
 | 
            return implementation.getAssigner(env, ctx);  | 
 | 
        return null;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public FieldUpdater getUpdater(Environment env, Context ctx) { | 
 | 
        if (implementation != null)  | 
 | 
            return implementation.getUpdater(env, ctx);  | 
 | 
        return null;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public Vset checkAmbigName(Environment env, Context ctx, Vset vset, Hashtable exp,  | 
 | 
                               UnaryExpression loc) { | 
 | 
        try { | 
 | 
            if (ctx.getField(env, id) != null) { | 
 | 
                  | 
 | 
                return checkValue(env, ctx, vset, exp);  | 
 | 
            }  | 
 | 
        } catch (ClassNotFound ee) { | 
 | 
        } catch (AmbiguousMember ee) { | 
 | 
        }  | 
 | 
          | 
 | 
        ClassDefinition c = toResolvedType(env, ctx, true);  | 
 | 
          | 
 | 
        if (c != null) { | 
 | 
            loc.right = new TypeExpression(where, c.getType());  | 
 | 
            return vset;  | 
 | 
        }  | 
 | 
          | 
 | 
        type = Type.tPackage;  | 
 | 
        return vset;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private ClassDefinition toResolvedType(Environment env, Context ctx,  | 
 | 
                                           boolean pkgOK) { | 
 | 
        Identifier rid = ctx.resolveName(env, id);  | 
 | 
        Type t = Type.tClass(rid);  | 
 | 
        if (pkgOK && !env.classExists(t)) { | 
 | 
            return null;  | 
 | 
        }  | 
 | 
        if (env.resolve(where, ctx.field.getClassDefinition(), t)) { | 
 | 
            try { | 
 | 
                ClassDefinition c = env.getClassDefinition(t);  | 
 | 
 | 
 | 
                  | 
 | 
                if (c.isMember()) { | 
 | 
                    ClassDefinition sc = ctx.findScope(env, c.getOuterClass());  | 
 | 
                    if (sc != c.getOuterClass()) { | 
 | 
                        Identifier rid2 = ctx.getApparentClassName(env, id);  | 
 | 
                        if (!rid2.equals(idNull) && !rid2.equals(rid)) { | 
 | 
                            env.error(where, "inherited.hides.type",  | 
 | 
                                      id, sc.getClassDeclaration());  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                }  | 
 | 
 | 
 | 
                if (!c.getLocalName().equals(id.getFlatName().getName())) { | 
 | 
                    env.error(where, "illegal.mangled.name", id, c);  | 
 | 
                }  | 
 | 
 | 
 | 
                return c;  | 
 | 
            } catch (ClassNotFound ee) { | 
 | 
            }  | 
 | 
        }  | 
 | 
        return null;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    Type toType(Environment env, Context ctx) { | 
 | 
        ClassDefinition c = toResolvedType(env, ctx, false);  | 
 | 
        if (c != null) { | 
 | 
            return c.getType();  | 
 | 
        }  | 
 | 
        return Type.tError;  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * Convert an expresion to a type in a context where a qualified  | 
 | 
     * type name is expected, e.g., in the prefix of a qualified type  | 
 | 
     * name. We do not necessarily know where the package prefix ends,  | 
 | 
     * so we operate similarly to 'checkAmbiguousName'.  This is the  | 
 | 
     * base case -- the first component of the qualified name.  | 
 | 
     */  | 
 | 
    /*-------------------------------------------------------*  | 
 | 
    Type toQualifiedType(Environment env, Context ctx) { | 
 | 
        // We do not look for non-type fields.  Is this correct?  | 
 | 
        ClassDefinition c = toResolvedType(env, ctx, true);  | 
 | 
        // Is it a real type?  | 
 | 
        if (c != null) { | 
 | 
            return c.getType();  | 
 | 
        }  | 
 | 
        // We hope it is a package prefix.  Let the caller decide.  | 
 | 
        return Type.tPackage;  | 
 | 
    }  | 
 | 
    *-------------------------------------------------------*/  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean isConstant() { | 
 | 
        if (implementation != null)  | 
 | 
            return implementation.isConstant();  | 
 | 
        if (field != null) { | 
 | 
            return field.isConstant();  | 
 | 
        }  | 
 | 
        return false;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public Expression inline(Environment env, Context ctx) { | 
 | 
        return null;  | 
 | 
    }  | 
 | 
    public Expression inlineValue(Environment env, Context ctx) { | 
 | 
        if (implementation != null)  | 
 | 
            return implementation.inlineValue(env, ctx);  | 
 | 
        if (field == null) { | 
 | 
            return this;  | 
 | 
        }  | 
 | 
        try { | 
 | 
            if (field.isLocal()) { | 
 | 
                if (field.isInlineable(env, false)) { | 
 | 
                    Expression e = (Expression)field.getValue(env);  | 
 | 
                    return (e == null) ? this : e.inlineValue(env, ctx);  | 
 | 
                }  | 
 | 
                return this;  | 
 | 
            }  | 
 | 
            return this;  | 
 | 
        } catch (ClassNotFound e) { | 
 | 
            throw new CompilerError(e);  | 
 | 
        }  | 
 | 
    }  | 
 | 
    public Expression inlineLHS(Environment env, Context ctx) { | 
 | 
        if (implementation != null)  | 
 | 
            return implementation.inlineLHS(env, ctx);  | 
 | 
        return this;  | 
 | 
    }  | 
 | 
 | 
 | 
    public Expression copyInline(Context ctx) { | 
 | 
        if (implementation != null)  | 
 | 
            return implementation.copyInline(ctx);  | 
 | 
        IdentifierExpression e =  | 
 | 
            (IdentifierExpression)super.copyInline(ctx);  | 
 | 
        if (field != null && field.isLocal()) { | 
 | 
            e.field = ((LocalMember)field).getCurrentInlineCopy(ctx);  | 
 | 
        }  | 
 | 
        return e;  | 
 | 
    }  | 
 | 
 | 
 | 
    public int costInline(int thresh, Environment env, Context ctx) { | 
 | 
        if (implementation != null)  | 
 | 
            return implementation.costInline(thresh, env, ctx);  | 
 | 
        return super.costInline(thresh, env, ctx);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    int codeLValue(Environment env, Context ctx, Assembler asm) { | 
 | 
        return 0;  | 
 | 
    }  | 
 | 
    void codeLoad(Environment env, Context ctx, Assembler asm) { | 
 | 
        asm.add(where, opc_iload + type.getTypeCodeOffset(),  | 
 | 
                new Integer(((LocalMember)field).number));  | 
 | 
    }  | 
 | 
    void codeStore(Environment env, Context ctx, Assembler asm) { | 
 | 
        LocalMember local = (LocalMember)field;  | 
 | 
        asm.add(where, opc_istore + type.getTypeCodeOffset(),  | 
 | 
                new LocalVariable(local, local.number));  | 
 | 
    }  | 
 | 
    public void codeValue(Environment env, Context ctx, Assembler asm) { | 
 | 
        codeLValue(env, ctx, asm);  | 
 | 
        codeLoad(env, ctx, asm);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public void print(PrintStream out) { | 
 | 
        out.print(id + "#" + ((field != null) ? field.hashCode() : 0));  | 
 | 
        if (implementation != null) { | 
 | 
            out.print("/IMPL="); | 
 | 
            implementation.print(out);  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |