1282 lines · 51.6 KB · Java
RawDownload
            return vset;        }         // Arrive here if not a class literal.         if (field != null) {             // The field as been pre-set, e.g., as the result of transforming            // an 'IdentifierExpression'. Most error-checking has already been            // performed at this point.            // QUERY: Why don't we further unify checking of identifier            // expressions and field expressions that denote instance and            // class variables?             implementation = implementFieldAccess(env, ctx, right, isLHS);            return (right == null) ?                vset : right.checkAmbigName(env, ctx, vset, exp, this);        }         // Does the qualifier have a meaning of its own?        vset = right.checkAmbigName(env, ctx, vset, exp, this);        if (right.type == Type.tPackage) {            // Are we out of options?            if (loc == null) {                FieldExpression.reportFailedPackagePrefix(env, right);                return vset;            }             // ASSERT(loc.right == this)             // Nope.  Is this field expression a type?            Identifier nm = toIdentifier(this);            if ((nm != null) && env.classExists(nm)) {                loc.right = new TypeExpression(where, Type.tClass(nm));                // Check access. (Cf. IdentifierExpression.toResolvedType.)                ClassDefinition ctxClass = ctx.field.getClassDefinition();                env.resolve(where, ctxClass, loc.right.type);                return vset;            }             // Let the caller make sense of it, then.            type = Type.tPackage;            return vset;        }         // Good; we have a well-defined qualifier type.         ClassDefinition ctxClass = ctx.field.getClassDefinition();        boolean staticRef = (right instanceof TypeExpression);         try {             // Handle array 'length' field, e.g., 'x.length'.             if (!right.type.isType(TC_CLASS)) {                if (right.type.isType(TC_ARRAY) && id.equals(idLength)) {                    // Verify that the type of the base expression is accessible.                    // Required by JLS 6.6.1.  Fixes 4094658.                    if (!FieldExpression.isTypeAccessible(where, env, right.type, ctxClass)) {                        ClassDeclaration cdecl = ctxClass.getClassDeclaration();                        if (staticRef) {                            env.error(where, "no.type.access",                                      id, right.type.toString(), cdecl);                        } else {                            env.error(where, "cant.access.member.type",                                      id, right.type.toString(), cdecl);                        }                    }                    type = Type.tInt;                    implementation = new LengthExpression(where, right);                    return vset;                }                if (!right.type.isType(TC_ERROR)) {                    env.error(where, "invalid.field.reference", id, right.type);                }                return vset;            }             // At this point, we know that 'right.type' is a class type.             // Note that '<expr>.super(...)' and '<expr>.this(...)' cases never            // reach here.  Instead, '<expr>' is stored as the 'outerArg' field            // of a 'SuperExpression' or 'ThisExpression' node.             // If our prefix is of the form '<class>.super', then we are            // about to do a field selection '<class>.super.<field>'.            // Save the qualifying class in 'superBase', which is non-null            // only if the current FieldExpression is a qualified 'super' form.            // Also, set 'sourceClass' to the "effective accessing class" relative            // to which access checks will be performed.  Normally, this is the            // immediately enclosing class.  For '<class>.this' and '<class>.super',            // however, we use <class>.             ClassDefinition sourceClass = ctxClass;            if (right instanceof FieldExpression) {                Identifier id = ((FieldExpression)right).id;                if (id == idThis) {                    sourceClass = ((FieldExpression)right).clazz;                } else if (id == idSuper) {                    sourceClass = ((FieldExpression)right).clazz;                    superBase = sourceClass;                }            }             // Handle 'class.this' and 'class.super'.            //            // Suppose 'super.name' appears within a class C with immediate            // superclass S. According to JLS 15.10.2, 'super.name' in this            // case is equivalent to '((S)this).name'.  Analogously, we interpret            // 'class.super.name' as '((S)(class.this)).name', where S is the            // immediate superclass of (enclosing) class 'class'.            // Note that 'super' may not stand alone as an expression, but must            // occur as the qualifying expression of a field access or a method            // invocation.  This is enforced in 'SuperExpression.checkValue' and            // 'FieldExpression.checkValue', and need not concern us here.             //ClassDefinition clazz = env.getClassDefinition(right.type);            clazz = env.getClassDefinition(right.type);            if (id == idThis || id == idSuper) {                if (!staticRef) {                    env.error(right.where, "invalid.type.expr");                }                 // We used to check that 'right.type' is accessible here,                // per JLS 6.6.1.  As a result of the fix for 4102393, however,                // the qualifying class name must exactly match an enclosing                // outer class, which is necessarily accessible.                 /*** Temporary assertion check ***/                if (ctx.field.isSynthetic())                    throw new CompilerError("synthetic qualified this");                /*********************************/                 // A.this means we're inside an A and we want its self ptr.                // C.this is always the same as this when C is innermost.                // Another A.this means we skip out to get a "hidden" this,                // just as ASuper.foo skips out to get a hidden variable.                // Last argument 'true' means we want an exact class match,                // not a subclass of the specified class ('clazz').                implementation = ctx.findOuterLink(env, where, clazz, null, true);                vset = implementation.checkValue(env, ctx, vset, exp);                if (id == idSuper) {                    type = clazz.getSuperClass().getType();                } else {                    type = clazz.getType();                }                return vset;            }             // Field should be an instance variable or class variable.            field = clazz.getVariable(env, id, sourceClass);             if (field == null && staticRef && loc != null) {                // Is this field expression an inner type?                // Search the class and its supers (but not its outers).                // QUERY: We may need to get the inner class from a                // superclass of 'clazz'.  This call is prepared to                // resolve the superclass if necessary.  Can we arrange                // to assure that it is always previously resolved?                // This is one of a small number of problematic calls that                // requires 'getSuperClass' to resolve superclasses on demand.                // See 'ClassDefinition.getInnerClass(env, nm)'.                field = clazz.getInnerClass(env, id);                if (field != null) {                    return checkInnerClass(env, ctx, vset, exp, loc);                }            }             // If not a variable reference, diagnose error if name is            // that of a method.             if (field == null) {                if ((field = clazz.findAnyMethod(env, id)) != null) {                    env.error(where, "invalid.field",                              id, field.getClassDeclaration());                } else {                    env.error(where, "no.such.field", id, clazz);                }                return vset;            }             // At this point, we have identified a valid field.             // Required by JLS 6.6.1.  Fixes 4094658.            if (!FieldExpression.isTypeAccessible(where, env, right.type, sourceClass)) {                ClassDeclaration cdecl = sourceClass.getClassDeclaration();                if (staticRef) {                    env.error(where, "no.type.access",                              id, right.type.toString(), cdecl);                } else {                    env.error(where, "cant.access.member.type",                              id, right.type.toString(), cdecl);                }            }             type = field.getType();             if (!sourceClass.canAccess(env, field)) {                env.error(where, "no.field.access",                          id, clazz, sourceClass.getClassDeclaration());                return vset;            }             if (staticRef && !field.isStatic()) {                // 'Class.field' is not legal when field is not static;                // see JLS 15.13.1.  This case was permitted by javac                // prior to 1.2; static refs were silently changed to                // be dynamic access of the form 'this.field'.                env.error(where, "no.static.field.access", id, clazz);                return vset;            } else {                // Rewrite access to use an access method if necessary.                implementation = implementFieldAccess(env, ctx, right, isLHS);            }             // Check for invalid access to protected field.            if (field.isProtected()                && !(right instanceof SuperExpression                     // Extension of JLS 6.6.2 for qualified 'super'.                     || (right instanceof FieldExpression &&                         ((FieldExpression)right).id == idSuper))                && !sourceClass.protectedAccess(env, field, right.type)) {                env.error(where, "invalid.protected.field.use",                          field.getName(), field.getClassDeclaration(),                          right.type);                return vset;            }             if ((!field.isStatic()) &&                (right.op == THIS) && !vset.testVar(ctx.getThisNumber())) {                env.error(where, "access.inst.before.super", id);            }             if (field.reportDeprecated(env)) {                env.error(where, "warn."+"field.is.deprecated",                          id, field.getClassDefinition());            }             // When a package-private class defines public or protected            // members, those members may sometimes be accessed from            // outside of the package in public subclasses.  In these            // cases, we need to massage the getField to refer to            // to an accessible subclass rather than the package-private            // parent class.  Part of fix for 4135692.             // Find out if the class which contains this field            // reference has access to the class which declares the            // public or protected field.            if (sourceClass == ctxClass) {                ClassDefinition declarer = field.getClassDefinition();                if (declarer.isPackagePrivate() &&                    !declarer.getName().getQualifier()                    .equals(sourceClass.getName().getQualifier())) {                     //System.out.println("The access of member " +                    //             field + " declared in class " +                    //             declarer +                    //             " is not allowed by the VM from class  " +                    //             ctxClass +                    //             ".  Replacing with an access of class " +                    //             clazz);                     // We cannot make this access at the VM level.                    // Construct a member which will stand for this                    // field in ctxClass and set `field' to refer to it.                    field =                        MemberDefinition.makeProxyMember(field, clazz, env);                }            }             sourceClass.addDependency(field.getClassDeclaration());         } 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 vset;    }     /**     * Return a <code>FieldUpdater</code> object to be used in updating the     * value of the location denoted by <code>this</code>, which must be an     * expression suitable for the left-hand side of an assignment.     * This is used for implementing assignments to private fields for which     * an access method is required.  Returns null if no access method is     * needed, in which case the assignment is handled in the usual way, by     * direct access.  Only simple assignment expressions are handled here     * Assignment operators and pre/post increment/decrement operators are     * are handled by 'getUpdater' below.     * <p>     * Must be called after 'checkValue', else 'right' will be invalid.     */      public FieldUpdater getAssigner(Environment env, Context ctx) {        if (field == null) {            // Field can legitimately be null if the field name was            // undefined, in which case an error was reported, but            // no value for 'field' is available.            //   throw new CompilerError("getAssigner");            return null;        }        ClassDefinition abase = accessBase(env, ctx);        if (abase != null) {            MemberDefinition setter = abase.getUpdateMember(env, ctx, field, isQualSuper());            // It may not be necessary to copy 'right' here.            Expression base = (right == null) ? null : right.copyInline(ctx);            // Created 'FieldUpdater' has no getter method.            return new FieldUpdater(where, field, base, null, setter);        }        return null;    }     /**     * Return a <code>FieldUpdater</code> object to be used in updating the     * value of the location denoted by <code>this</code>, which must be an     * expression suitable for the left-hand side of an assignment.  This is     * used for implementing the assignment operators and the increment and     * decrement operators on private fields that are accessed from another     * class, e.g, uplevel from an inner class. Returns null if no access     * method is needed.     * <p>     * Must be called after 'checkValue', else 'right' will be invalid.     */     public FieldUpdater getUpdater(Environment env, Context ctx) {        if (field == null) {            // Field can legitimately be null if the field name was            // undefined, in which case an error was reported, but            // no value for 'field' is available.            //   throw new CompilerError("getUpdater");            return null;        }        ClassDefinition abase = accessBase(env, ctx);        if (abase != null) {            MemberDefinition getter = abase.getAccessMember(env, ctx, field, isQualSuper());            MemberDefinition setter = abase.getUpdateMember(env, ctx, field, isQualSuper());            // It may not be necessary to copy 'right' here.            Expression base = (right == null) ? null : right.copyInline(ctx);            return new FieldUpdater(where, field, base, getter, setter);        }        return null;    }     /**     * This field expression is an inner class reference.     * Finish checking it.     */    private Vset checkInnerClass(Environment env, Context ctx,                                 Vset vset, Hashtable exp,                                 UnaryExpression loc) {        ClassDefinition inner = field.getInnerClass();        type = inner.getType();         if (!inner.isTopLevel()) {            env.error(where, "inner.static.ref", inner.getName());        }         Expression te = new TypeExpression(where, type);         // check access        ClassDefinition ctxClass = ctx.field.getClassDefinition();        try {            if (!ctxClass.canAccess(env, field)) {                ClassDefinition clazz = env.getClassDefinition(right.type);                //env.error(where, "no.type.access",                //          id, clazz, ctx.field.getClassDeclaration());                env.error(where, "no.type.access",                          id, clazz, ctxClass.getClassDeclaration());                return vset;            }             if (field.isProtected()                && !(right instanceof SuperExpression                     // Extension of JLS 6.6.2 for qualified 'super'.                     || (right instanceof FieldExpression &&                         ((FieldExpression)right).id == idSuper))                && !ctxClass.protectedAccess(env, field, right.type)){                env.error(where, "invalid.protected.field.use",                          field.getName(), field.getClassDeclaration(),                          right.type);                return vset;            }             inner.noteUsedBy(ctxClass, where, env);         } catch (ClassNotFound e) {            env.error(where, "class.not.found", e.name, ctx.field);        }         ctxClass.addDependency(field.getClassDeclaration());        if (loc == null)            // Complain about a free-floating type name.            return te.checkValue(env, ctx, vset, exp);        loc.right = te;        return vset;    }     /**     * Check the expression if it appears on the LHS of an assignment     */    public Vset checkLHS(Environment env, Context ctx,                         Vset vset, Hashtable exp) {        boolean hadField = (field != null);         //checkValue(env, ctx, vset, exp);        checkCommon(env, ctx, vset, exp, null, true);         // If 'implementation' is set to a non-null value, then the        // field expression does not denote an assignable location,        // e.g., the 'length' field of an array.        if (implementation != null) {            // This just reports an error and recovers.            return super.checkLHS(env, ctx, vset, exp);        }         if (field != null && field.isFinal() && !hadField) {            if (field.isBlankFinal()) {                if (field.isStatic()) {                    if (right != null) {                        env.error(where, "qualified.static.final.assign");                    }                    // Continue with checking anyhow.                    // In fact, it would be easy to allow this case.                } else {                    if ((right != null) && (right.op != THIS)) {                        env.error(where, "bad.qualified.final.assign", field.getName());                        // The actual instance could be anywhere, so don't                        // continue with checking the definite assignment status.                        return vset;                    }                }                vset = checkFinalAssign(env, ctx, vset, where, field);            } else {                env.error(where, "assign.to.final", id);            }        }        return vset;    }     /**     * Check the expression if it appears on the LHS of an op= expression     */    public Vset checkAssignOp(Environment env, Context ctx,                              Vset vset, Hashtable exp, Expression outside) {         //checkValue(env, ctx, vset, exp);        checkCommon(env, ctx, vset, exp, null, true);         // If 'implementation' is set to a non-null value, then the        // field expression does not denote an assignable location,        // e.g., the 'length' field of an array.        if (implementation != null) {            return super.checkLHS(env, ctx, vset, exp);        }        if (field != null && field.isFinal()) {            env.error(where, "assign.to.final", id);        }        return vset;    }     /**     * There is a simple assignment being made to the given final field.     * The field was named either by a simple name or by an almost-simple     * expression of the form "this.v".     * Check if this is a legal assignment.     * <p>     * Blank final variables can be set in initializers or constructor     * bodies.  In all cases there must be definite single assignment.     * (All instance and instance variable initializers and each     * constructor body are treated as if concatenated for the purposes     * of this check.  Assignment to "this.x" is treated as a definite     * assignment to the simple name "x" which names the instance variable.)     */     public static Vset checkFinalAssign(Environment env, Context ctx,                                        Vset vset, long where,                                        MemberDefinition field) {        if (field.isBlankFinal()            && field.getClassDefinition() == ctx.field.getClassDefinition()) {            int number = ctx.getFieldNumber(field);            if (number >= 0 && vset.testVarUnassigned(number)) {                // definite single assignment                vset = vset.addVar(number);            } else {                // it is a blank final in this class, but not assignable                Identifier id = field.getName();                env.error(where, "assign.to.blank.final", id);            }        } else {            // give the generic error message            Identifier id = field.getName();            env.error(where, "assign.to.final", id);        }        return vset;    } 

Lines 501–1000 of 1282. Previous lines