1/*
2 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.tools.tree;
27
28import sun.tools.java.*;
29import sun.tools.asm.*;
30import java.io.PrintStream;
31import java.util.Hashtable;
32
33/**
34 * WARNING: The contents of this source file are not part of any
35 * supported API.  Code that depends on them does so at its own risk:
36 * they are subject to change or removal without notice.
37 */
38public
39class FieldExpression extends UnaryExpression {
40    Identifier id;
41    MemberDefinition field;
42    Expression implementation;
43
44    // The class from which the field is select ed.
45    ClassDefinition clazz;
46
47    // For an expression of the form '<class>.super', then
48    // this is <class>, else null.
49    private ClassDefinition superBase;
50
51    /**
52     * constructor
53     */
54    public FieldExpression(long where, Expression right, Identifier id) {
55        super(FIELD, where, Type.tError, right);
56        this.id = id;
57    }
58    public FieldExpression(long where, Expression right, MemberDefinition field) {
59        super(FIELD, where, field.getType(), right);
60        this.id = field.getName();
61        this.field = field;
62    }
63
64    public Expression getImplementation() {
65        if (implementation != null)
66            return implementation;
67        return this;
68    }
69
70    /**
71     * Return true if the field is being selected from
72     * a qualified 'super'.
73     */
74    private boolean isQualSuper() {
75        return superBase != null;
76    }
77
78    /**
79     * Convert an '.' expression to a qualified identifier
80     */
81    static public Identifier toIdentifier(Expression e) {
82        StringBuilder sb = new StringBuilder();
83        while (e.op == FIELD) {
84            FieldExpression fe = (FieldExpression)e;
85            if (fe.id == idThis || fe.id == idClass) {
86                return null;
87            }
88            sb.insert(0, fe.id);
89            sb.insert(0, '.');
90            e = fe.right;
91        }
92        if (e.op != IDENT) {
93            return null;
94        }
95        sb.insert(0, ((IdentifierExpression) e).id);
96        return Identifier.lookup(sb.toString());
97    }
98
99    /**
100     * Convert a qualified name into a type.
101     * Performs a careful check of each inner-class component,
102     * including the JLS 6.6.1 access checks that were omitted
103     * in 'FieldExpression.toType'.
104     * <p>
105     * This code is similar to 'checkCommon', which could be cleaned
106     * up a bit long the lines we have done here.
107     */
108    /*-------------------------------------------------------*
109    Type toQualifiedType(Environment env, Context ctx) {
110        ClassDefinition ctxClass = ctx.field.getClassDefinition();
111        Type rty = right.toQualifiedType(env, ctx);
112        if (rty == Type.tPackage) {
113            // Is this field expression a non-inner type?
114            Identifier nm = toIdentifier(this);
115            if ((nm != null) && env.classExists(nm)) {
116                Type t = Type.tClass(nm);
117                if (env.resolve(where, ctxClass, t)) {
118                    return t;
119                } else {
120                    return null;
121                }
122            }
123            // Not a type.  Must be a package prefix.
124            return Type.tPackage;
125        }
126        if (rty == null) {
127            // An error was already reported, so quit.
128            return null;
129        }
130
131        // Check inner-class qualification while unwinding from recursion.
132        try {
133            ClassDefinition rightClass = env.getClassDefinition(rty);
134
135            // Local variables, which cannot be inner classes,
136            // are ignored here, and thus will not hide inner
137            // classes.  Is this correct?
138            MemberDefinition field = rightClass.getInnerClass(env, id);
139            if (field == null) {
140                env.error(where, "inner.class.expected", id, rightClass);
141                return Type.tError;
142            }
143
144            ClassDefinition innerClass = field.getInnerClass();
145            Type t = innerClass.getType();
146
147            if (!ctxClass.canAccess(env, field)) {
148                env.error(where, "no.type.access", id, rightClass, ctxClass);
149                return t;
150            }
151            if (field.isProtected()
152                && !ctxClass.protectedAccess(env, field, rty)) {
153                env.error(where, "invalid.protected.type.use", id, ctxClass, rty);
154                return t;
155            }
156
157            // These were omitted earlier in calls to 'toType', but I can't
158            // see any reason for that.  I think it was an oversight.  See
159            // 'checkCommon' and 'checkInnerClass'.
160            innerClass.noteUsedBy(ctxClass, where, env);
161            ctxClass.addDependency(field.getClassDeclaration());
162
163            return t;
164
165        } catch (ClassNotFound e) {
166            env.error(where, "class.not.found", e.name, ctx.field);
167        }
168
169        // Class not found.
170        return null;
171    }
172    *-------------------------------------------------------*/
173
174    /**
175     * Convert an '.' expression to a type
176     */
177
178    // This is a rewrite to treat qualified names in a
179    // context in which a type name is expected in the
180    // same way that they are handled for an ambiguous
181    // or expression-expected context in 'checkCommon'
182    // below.  The new code is cleaner and allows better
183    // localization of errors.  Unfortunately, most
184    // qualified names appearing in types are actually
185    // handled by 'Environment.resolve'.  There isn't
186    // much point, then, in breaking out 'toType' as a
187    // special case until the other cases can be cleaned
188    // up as well.  For the time being, we will leave this
189    // code disabled, thus reducing the testing requirements.
190    /*-------------------------------------------------------*
191    Type toType(Environment env, Context ctx) {
192        Type t = toQualifiedType(env, ctx);
193        if (t == null) {
194            return Type.tError;
195        }
196        if (t == Type.tPackage) {
197            FieldExpression.reportFailedPackagePrefix(env, right, true);
198            return Type.tError;
199        }
200        return t;
201    }
202    *-------------------------------------------------------*/
203
204    Type toType(Environment env, Context ctx) {
205        Identifier id = toIdentifier(this);
206        if (id == null) {
207            env.error(where, "invalid.type.expr");
208            return Type.tError;
209        }
210        Type t = Type.tClass(ctx.resolveName(env, id));
211        if (env.resolve(where, ctx.field.getClassDefinition(), t)) {
212            return t;
213        }
214        return Type.tError;
215    }
216
217    /**
218     * Check if the present name is part of a scoping prefix.
219     */
220
221    public Vset checkAmbigName(Environment env, Context ctx,
222                               Vset vset, Hashtable<Object, Object> exp,
223                               UnaryExpression loc) {
224        if (id == idThis || id == idClass) {
225            loc = null;         // this cannot be a type or package
226        }
227        return checkCommon(env, ctx, vset, exp, loc, false);
228    }
229
230    /**
231     * Check the expression
232     */
233
234    public Vset checkValue(Environment env, Context ctx,
235                           Vset vset, Hashtable<Object, Object> exp) {
236        vset = checkCommon(env, ctx, vset, exp, null, false);
237        if (id == idSuper && type != Type.tError) {
238            // "super" is not allowed in this context.
239            // It must always qualify another name.
240            env.error(where, "undef.var.super", idSuper);
241        }
242        return vset;
243    }
244
245    /**
246     * If 'checkAmbiguousName' returns 'Package.tPackage', then it was
247     * unable to resolve any prefix of the qualified name.  This method
248     * attempts to diagnose the problem.
249     */
250
251    static void reportFailedPackagePrefix(Environment env, Expression right) {
252        reportFailedPackagePrefix(env, right, false);
253    }
254
255    static void reportFailedPackagePrefix(Environment env,
256                                          Expression right,
257                                          boolean mustBeType) {
258        // Find the leftmost component, and put the blame on it.
259        Expression idp = right;
260        while (idp instanceof UnaryExpression)
261            idp = ((UnaryExpression)idp).right;
262        IdentifierExpression ie = (IdentifierExpression)idp;
263
264        // It may be that 'ie' refers to an ambiguous class.  Check this
265        // with a call to env.resolve(). Part of solution for 4059855.
266        try {
267            env.resolve(ie.id);
268        } catch (AmbiguousClass e) {
269            env.error(right.where, "ambig.class", e.name1, e.name2);
270            return;
271        } catch (ClassNotFound e) {
272        }
273
274        if (idp == right) {
275            if (mustBeType) {
276                env.error(ie.where, "undef.class", ie.id);
277            } else {
278                env.error(ie.where, "undef.var.or.class", ie.id);
279            }
280        } else {
281            if (mustBeType) {
282                env.error(ie.where, "undef.class.or.package", ie.id);
283            } else {
284                env.error(ie.where, "undef.var.class.or.package", ie.id);
285            }
286        }
287    }
288
289    /**
290     * Rewrite accesses to private fields of another class.
291     */
292
293    private Expression
294    implementFieldAccess(Environment env, Context ctx, Expression base, boolean isLHS) {
295        ClassDefinition abase = accessBase(env, ctx);
296        if (abase != null) {
297
298            // If the field is final and its initializer is a constant expression,
299            // then just rewrite to the constant expression. This is not just an
300            // optimization, but is required for correctness.  If an expression is
301            // rewritten to use an access method, then its status as a constant
302            // expression is lost.  This was the cause of bug 4098737.  Note that
303            // a call to 'getValue(env)' below would not be correct, as it attempts
304            // to simplify the initial value expression, which must not occur until
305            // after the checking phase, for example, after definite assignment checks.
306            if (field.isFinal()) {
307                Expression e = (Expression)field.getValue();
308                // Must not be LHS here.  Test as a precaution,
309                // as we may not be careful to avoid this when
310                // compiling an erroneous program.
311                if ((e != null) && e.isConstant() && !isLHS) {
312                    return e.copyInline(ctx);
313                }
314            }
315
316            //System.out.println("Finding access method for " + field);
317            MemberDefinition af = abase.getAccessMember(env, ctx, field, isQualSuper());
318            //System.out.println("Using access method " + af);
319
320            if (!isLHS) {
321                //System.out.println("Reading " + field +
322                //                              " via access method " + af);
323                // If referencing the value of the field, then replace
324                // with a call to the access method.  If assigning to
325                // the field, a call to the update method will be
326                // generated later. It is important that
327                // 'implementation' not be set to non-null if the
328                // expression is a valid assignment target.
329                // (See 'checkLHS'.)
330                if (field.isStatic()) {
331                    Expression args[] = { };
332                    Expression call =
333                        new MethodExpression(where, null, af, args);
334                    return new CommaExpression(where, base, call);
335                } else {
336                    Expression args[] = { base };
337                    return new MethodExpression(where, null, af, args);
338                }
339            }
340        }
341
342        return null;
343    }
344
345    /**
346     * Determine if an access method is required, and, if so, return
347     * the class in which it should appear, else return null.
348     */
349    private ClassDefinition accessBase(Environment env, Context ctx) {
350        if (field.isPrivate()) {
351            ClassDefinition cdef = field.getClassDefinition();
352            ClassDefinition ctxClass = ctx.field.getClassDefinition();
353            if (cdef == ctxClass){
354                // If access from same class as field, then no access
355                // method is needed.
356                return null;
357            }
358            // An access method is needed in the class containing the field.
359            return cdef;
360        } else if (field.isProtected()) {
361            if (superBase == null) {
362                // If access is not via qualified super, then it is either
363                // OK without an access method, or it is an illegal access
364                // for which an error message should have been issued.
365                // Legal accesses include unqualified 'super.foo'.
366                return null;
367            }
368            ClassDefinition cdef = field.getClassDefinition();
369            ClassDefinition ctxClass = ctx.field.getClassDefinition();
370            if (cdef.inSamePackage(ctxClass)) {
371                // Access to protected member in same package always allowed.
372                return null;
373            }
374            // Access via qualified super.
375            // An access method is needed in the qualifying class, an
376            // immediate subclass of the class containing the selected
377            // field.  NOTE: The fact that the returned class is 'superBase'
378            // carries the additional bit of information (that a special
379            // superclass access method is being created) which is provided
380            // to 'getAccessMember' via its 'isSuper' argument.
381            return superBase;
382        } else {
383            // No access method needed.
384            return null;
385        }
386    }
387
388    /**
389     * Determine if a type is accessible from a given class.
390     */
391    static boolean isTypeAccessible(long where,
392                                    Environment env,
393                                    Type t,
394                                    ClassDefinition c) {
395        switch (t.getTypeCode()) {
396          case TC_CLASS:
397            try {
398                Identifier nm = t.getClassName();
399                // Why not just use 'Environment.getClassDeclaration' here?
400                // But 'Environment.getClassDeclation' has special treatment
401                // for local classes that is probably necessary.  This code
402                // was adapted from 'Environment.resolve'.
403                ClassDefinition def = env.getClassDefinition(t);
404                return c.canAccess(env, def.getClassDeclaration());
405            } catch (ClassNotFound e) {}  // Ignore -- reported elsewhere.
406            return true;
407          case TC_ARRAY:
408            return isTypeAccessible(where, env, t.getElementType(), c);
409          default:
410            return true;
411        }
412    }
413
414    /**
415     * Common code for checkValue and checkAmbigName
416     */
417
418    private Vset checkCommon(Environment env, Context ctx,
419                             Vset vset, Hashtable<Object, Object> exp,
420                             UnaryExpression loc, boolean isLHS) {
421
422        // Handle class literal, e.g., 'x.class'.
423        if (id == idClass) {
424
425            // In 'x.class', 'x' must be a type name, possibly qualified.
426            Type t = right.toType(env, ctx);
427
428            if (!t.isType(TC_CLASS) && !t.isType(TC_ARRAY)) {
429                if (t.isType(TC_ERROR)) {
430                    type = Type.tClassDesc;
431                    return vset;
432                }
433                String wrc = null;
434                switch (t.getTypeCode()) {
435                  case TC_VOID: wrc = "Void"; break;
436                  case TC_BOOLEAN: wrc = "Boolean"; break;
437                  case TC_BYTE: wrc = "Byte"; break;
438                  case TC_CHAR: wrc = "Character"; break;
439                  case TC_SHORT: wrc = "Short"; break;
440                  case TC_INT: wrc = "Integer"; break;
441                  case TC_FLOAT: wrc = "Float"; break;
442                  case TC_LONG: wrc = "Long"; break;
443                  case TC_DOUBLE: wrc = "Double"; break;
444                  default:
445                      env.error(right.where, "invalid.type.expr");
446                      return vset;
447                }
448                Identifier wid = Identifier.lookup(idJavaLang+"."+wrc);
449                Expression wcls = new TypeExpression(where, Type.tClass(wid));
450                implementation = new FieldExpression(where, wcls, idTYPE);
451                vset = implementation.checkValue(env, ctx, vset, exp);
452                type = implementation.type; // java.lang.Class
453                return vset;
454            }
455
456            // Check for the bogus type `array of void'
457            if (t.isVoidArray()) {
458                type = Type.tClassDesc;
459                env.error(right.where, "void.array");
460                return vset;
461            }
462
463            // it is a class or array
464            long fwhere = ctx.field.getWhere();
465            ClassDefinition fcls = ctx.field.getClassDefinition();
466            MemberDefinition lookup = fcls.getClassLiteralLookup(fwhere);
467
468            String sig = t.getTypeSignature();
469            String className;
470            if (t.isType(TC_CLASS)) {
471                // sig is like "Lfoo/bar;", name is like "foo.bar".
472                // We assume SIG_CLASS and SIG_ENDCLASS are 1 char each.
473                className = sig.substring(1, sig.length()-1)
474                    .replace(SIGC_PACKAGE, '.');
475            } else {
476                // sig is like "[Lfoo/bar;" or "[I";
477                // name is like "[Lfoo.bar" or (again) "[I".
478                className = sig.replace(SIGC_PACKAGE, '.');
479            }
480
481            if (fcls.isInterface()) {
482                // The immediately-enclosing type is an interface.
483                // The class literal can only appear in an initialization
484                // expression, so don't bother caching it.  (This could
485                // lose if many initializations use the same class literal,
486                // but saves time and code space otherwise.)
487                implementation =
488                    makeClassLiteralInlineRef(env, ctx, lookup, className);
489            } else {
490                // Cache the call to the helper, as it may be executed
491                // many times (e.g., if the class literal is inside a loop).
492                ClassDefinition inClass = lookup.getClassDefinition();
493                MemberDefinition cfld =
494                    getClassLiteralCache(env, ctx, className, inClass);
495                implementation =
496                    makeClassLiteralCacheRef(env, ctx, lookup, cfld, className);
497            }
498
499            vset = implementation.checkValue(env, ctx, vset, exp);
500            type = implementation.type; // java.lang.Class
501            return vset;
502        }
503
504        // Arrive here if not a class literal.
505
506        if (field != null) {
507
508            // The field as been pre-set, e.g., as the result of transforming
509            // an 'IdentifierExpression'. Most error-checking has already been
510            // performed at this point.
511            // QUERY: Why don't we further unify checking of identifier
512            // expressions and field expressions that denote instance and
513            // class variables?
514
515            implementation = implementFieldAccess(env, ctx, right, isLHS);
516            return (right == null) ?
517                vset : right.checkAmbigName(env, ctx, vset, exp, this);
518        }
519
520        // Does the qualifier have a meaning of its own?
521        vset = right.checkAmbigName(env, ctx, vset, exp, this);
522        if (right.type == Type.tPackage) {
523            // Are we out of options?
524            if (loc == null) {
525                FieldExpression.reportFailedPackagePrefix(env, right);
526                return vset;
527            }
528
529            // ASSERT(loc.right == this)
530
531            // Nope.  Is this field expression a type?
532            Identifier nm = toIdentifier(this);
533            if ((nm != null) && env.classExists(nm)) {
534                loc.right = new TypeExpression(where, Type.tClass(nm));
535                // Check access. (Cf. IdentifierExpression.toResolvedType.)
536                ClassDefinition ctxClass = ctx.field.getClassDefinition();
537                env.resolve(where, ctxClass, loc.right.type);
538                return vset;
539            }
540
541            // Let the caller make sense of it, then.
542            type = Type.tPackage;
543            return vset;
544        }
545
546        // Good; we have a well-defined qualifier type.
547
548        ClassDefinition ctxClass = ctx.field.getClassDefinition();
549        boolean staticRef = (right instanceof TypeExpression);
550
551        try {
552
553            // Handle array 'length' field, e.g., 'x.length'.
554
555            if (!right.type.isType(TC_CLASS)) {
556                if (right.type.isType(TC_ARRAY) && id.equals(idLength)) {
557                    // Verify that the type of the base expression is accessible.
558                    // Required by JLS 6.6.1.  Fixes 4094658.
559                    if (!FieldExpression.isTypeAccessible(where, env, right.type, ctxClass)) {
560                        ClassDeclaration cdecl = ctxClass.getClassDeclaration();
561                        if (staticRef) {
562                            env.error(where, "no.type.access",
563                                      id, right.type.toString(), cdecl);
564                        } else {
565                            env.error(where, "cant.access.member.type",
566                                      id, right.type.toString(), cdecl);
567                        }
568                    }
569                    type = Type.tInt;
570                    implementation = new LengthExpression(where, right);
571                    return vset;
572                }
573                if (!right.type.isType(TC_ERROR)) {
574                    env.error(where, "invalid.field.reference", id, right.type);
575                }
576                return vset;
577            }
578
579            // At this point, we know that 'right.type' is a class type.
580
581            // Note that '<expr>.super(...)' and '<expr>.this(...)' cases never
582            // reach here.  Instead, '<expr>' is stored as the 'outerArg' field
583            // of a 'SuperExpression' or 'ThisExpression' node.
584
585            // If our prefix is of the form '<class>.super', then we are
586            // about to do a field selection '<class>.super.<field>'.
587            // Save the qualifying class in 'superBase', which is non-null
588            // only if the current FieldExpression is a qualified 'super' form.
589            // Also, set 'sourceClass' to the "effective accessing class" relative
590            // to which access checks will be performed.  Normally, this is the
591            // immediately enclosing class.  For '<class>.this' and '<class>.super',
592            // however, we use <class>.
593
594            ClassDefinition sourceClass = ctxClass;
595            if (right instanceof FieldExpression) {
596                Identifier id = ((FieldExpression)right).id;
597                if (id == idThis) {
598                    sourceClass = ((FieldExpression)right).clazz;
599                } else if (id == idSuper) {
600                    sourceClass = ((FieldExpression)right).clazz;
601                    superBase = sourceClass;
602                }
603            }
604
605            // Handle 'class.this' and 'class.super'.
606            //
607            // Suppose 'super.name' appears within a class C with immediate
608            // superclass S. According to JLS 15.10.2, 'super.name' in this
609            // case is equivalent to '((S)this).name'.  Analogously, we interpret
610            // 'class.super.name' as '((S)(class.this)).name', where S is the
611            // immediate superclass of (enclosing) class 'class'.
612            // Note that 'super' may not stand alone as an expression, but must
613            // occur as the qualifying expression of a field access or a method
614            // invocation.  This is enforced in 'SuperExpression.checkValue' and
615            // 'FieldExpression.checkValue', and need not concern us here.
616
617            //ClassDefinition clazz = env.getClassDefinition(right.type);
618            clazz = env.getClassDefinition(right.type);
619            if (id == idThis || id == idSuper) {
620                if (!staticRef) {
621                    env.error(right.where, "invalid.type.expr");
622                }
623
624                // We used to check that 'right.type' is accessible here,
625                // per JLS 6.6.1.  As a result of the fix for 4102393, however,
626                // the qualifying class name must exactly match an enclosing
627                // outer class, which is necessarily accessible.
628
629                /*** Temporary assertion check ***/
630                if (ctx.field.isSynthetic())
631                    throw new CompilerError("synthetic qualified this");
632                /*********************************/
633
634                // A.this means we're inside an A and we want its self ptr.
635                // C.this is always the same as this when C is innermost.
636                // Another A.this means we skip out to get a "hidden" this,
637                // just as ASuper.foo skips out to get a hidden variable.
638                // Last argument 'true' means we want an exact class match,
639                // not a subclass of the specified class ('clazz').
640                implementation = ctx.findOuterLink(env, where, clazz, null, true);
641                vset = implementation.checkValue(env, ctx, vset, exp);
642                if (id == idSuper) {
643                    type = clazz.getSuperClass().getType();
644                } else {
645                    type = clazz.getType();
646                }
647                return vset;
648            }
649
650            // Field should be an instance variable or class variable.
651            field = clazz.getVariable(env, id, sourceClass);
652
653            if (field == null && staticRef && loc != null) {
654                // Is this field expression an inner type?
655                // Search the class and its supers (but not its outers).
656                // QUERY: We may need to get the inner class from a
657                // superclass of 'clazz'.  This call is prepared to
658                // resolve the superclass if necessary.  Can we arrange
659                // to assure that it is always previously resolved?
660                // This is one of a small number of problematic calls that
661                // requires 'getSuperClass' to resolve superclasses on demand.
662                // See 'ClassDefinition.getInnerClass(env, nm)'.
663                field = clazz.getInnerClass(env, id);
664                if (field != null) {
665                    return checkInnerClass(env, ctx, vset, exp, loc);
666                }
667            }
668
669            // If not a variable reference, diagnose error if name is
670            // that of a method.
671
672            if (field == null) {
673                if ((field = clazz.findAnyMethod(env, id)) != null) {
674                    env.error(where, "invalid.field",
675                              id, field.getClassDeclaration());
676                } else {
677                    env.error(where, "no.such.field", id, clazz);
678                }
679                return vset;
680            }
681
682            // At this point, we have identified a valid field.
683
684            // Required by JLS 6.6.1.  Fixes 4094658.
685            if (!FieldExpression.isTypeAccessible(where, env, right.type, sourceClass)) {
686                ClassDeclaration cdecl = sourceClass.getClassDeclaration();
687                if (staticRef) {
688                    env.error(where, "no.type.access",
689                              id, right.type.toString(), cdecl);
690                } else {
691                    env.error(where, "cant.access.member.type",
692                              id, right.type.toString(), cdecl);
693                }
694            }
695
696            type = field.getType();
697
698            if (!sourceClass.canAccess(env, field)) {
699                env.error(where, "no.field.access",
700                          id, clazz, sourceClass.getClassDeclaration());
701                return vset;
702            }
703
704            if (staticRef && !field.isStatic()) {
705                // 'Class.field' is not legal when field is not static;
706                // see JLS 15.13.1.  This case was permitted by javac
707                // prior to 1.2; static refs were silently changed to
708                // be dynamic access of the form 'this.field'.
709                env.error(where, "no.static.field.access", id, clazz);
710                return vset;
711            } else {
712                // Rewrite access to use an access method if necessary.
713                implementation = implementFieldAccess(env, ctx, right, isLHS);
714            }
715
716            // Check for invalid access to protected field.
717            if (field.isProtected()
718                && !(right instanceof SuperExpression
719                     // Extension of JLS 6.6.2 for qualified 'super'.
720                     || (right instanceof FieldExpression &&
721                         ((FieldExpression)right).id == idSuper))
722                && !sourceClass.protectedAccess(env, field, right.type)) {
723                env.error(where, "invalid.protected.field.use",
724                          field.getName(), field.getClassDeclaration(),
725                          right.type);
726                return vset;
727            }
728
729            if ((!field.isStatic()) &&
730                (right.op == THIS) && !vset.testVar(ctx.getThisNumber())) {
731                env.error(where, "access.inst.before.super", id);
732            }
733
734            if (field.reportDeprecated(env)) {
735                env.error(where, "warn."+"field.is.deprecated",
736                          id, field.getClassDefinition());
737            }
738
739            // When a package-private class defines public or protected
740            // members, those members may sometimes be accessed from
741            // outside of the package in public subclasses.  In these
742            // cases, we need to massage the getField to refer to
743            // to an accessible subclass rather than the package-private
744            // parent class.  Part of fix for 4135692.
745
746            // Find out if the class which contains this field
747            // reference has access to the class which declares the
748            // public or protected field.
749            if (sourceClass == ctxClass) {
750                ClassDefinition declarer = field.getClassDefinition();
751                if (declarer.isPackagePrivate() &&
752                    !declarer.getName().getQualifier()
753                    .equals(sourceClass.getName().getQualifier())) {
754
755                    //System.out.println("The access of member " +
756                    //             field + " declared in class " +
757                    //             declarer +
758                    //             " is not allowed by the VM from class  " +
759                    //             ctxClass +
760                    //             ".  Replacing with an access of class " +
761                    //             clazz);
762
763                    // We cannot make this access at the VM level.
764                    // Construct a member which will stand for this
765                    // field in ctxClass and set `field' to refer to it.
766                    field =
767                        MemberDefinition.makeProxyMember(field, clazz, env);
768                }
769            }
770
771            sourceClass.addDependency(field.getClassDeclaration());
772
773        } catch (ClassNotFound e) {
774            env.error(where, "class.not.found", e.name, ctx.field);
775
776        } catch (AmbiguousMember e) {
777            env.error(where, "ambig.field",
778                      id, e.field1.getClassDeclaration(), e.field2.getClassDeclaration());
779        }
780        return vset;
781    }
782
783    /**
784     * Return a <code>FieldUpdater</code> object to be used in updating the
785     * value of the location denoted by <code>this</code>, which must be an
786     * expression suitable for the left-hand side of an assignment.
787     * This is used for implementing assignments to private fields for which
788     * an access method is required.  Returns null if no access method is
789     * needed, in which case the assignment is handled in the usual way, by
790     * direct access.  Only simple assignment expressions are handled here
791     * Assignment operators and pre/post increment/decrement operators are
792     * are handled by 'getUpdater' below.
793     * <p>
794     * Must be called after 'checkValue', else 'right' will be invalid.
795     */
796
797
798    public FieldUpdater getAssigner(Environment env, Context ctx) {
799        if (field == null) {
800            // Field can legitimately be null if the field name was
801            // undefined, in which case an error was reported, but
802            // no value for 'field' is available.
803            //   throw new CompilerError("getAssigner");
804            return null;
805        }
806        ClassDefinition abase = accessBase(env, ctx);
807        if (abase != null) {
808            MemberDefinition setter = abase.getUpdateMember(env, ctx, field, isQualSuper());
809            // It may not be necessary to copy 'right' here.
810            Expression base = (right == null) ? null : right.copyInline(ctx);
811            // Created 'FieldUpdater' has no getter method.
812            return new FieldUpdater(where, field, base, null, setter);
813        }
814        return null;
815    }
816
817    /**
818     * Return a <code>FieldUpdater</code> object to be used in updating the
819     * value of the location denoted by <code>this</code>, which must be an
820     * expression suitable for the left-hand side of an assignment.  This is
821     * used for implementing the assignment operators and the increment and
822     * decrement operators on private fields that are accessed from another
823     * class, e.g, uplevel from an inner class. Returns null if no access
824     * method is needed.
825     * <p>
826     * Must be called after 'checkValue', else 'right' will be invalid.
827     */
828
829    public FieldUpdater getUpdater(Environment env, Context ctx) {
830        if (field == null) {
831            // Field can legitimately be null if the field name was
832            // undefined, in which case an error was reported, but
833            // no value for 'field' is available.
834            //   throw new CompilerError("getUpdater");
835            return null;
836        }
837        ClassDefinition abase = accessBase(env, ctx);
838        if (abase != null) {
839            MemberDefinition getter = abase.getAccessMember(env, ctx, field, isQualSuper());
840            MemberDefinition setter = abase.getUpdateMember(env, ctx, field, isQualSuper());
841            // It may not be necessary to copy 'right' here.
842            Expression base = (right == null) ? null : right.copyInline(ctx);
843            return new FieldUpdater(where, field, base, getter, setter);
844        }
845        return null;
846    }
847
848    /**
849     * This field expression is an inner class reference.
850     * Finish checking it.
851     */
852    private Vset checkInnerClass(Environment env, Context ctx,
853                                 Vset vset, Hashtable<Object, Object> exp,
854                                 UnaryExpression loc) {
855        ClassDefinition inner = field.getInnerClass();
856        type = inner.getType();
857
858        if (!inner.isTopLevel()) {
859            env.error(where, "inner.static.ref", inner.getName());
860        }
861
862        Expression te = new TypeExpression(where, type);
863
864        // check access
865        ClassDefinition ctxClass = ctx.field.getClassDefinition();
866        try {
867            if (!ctxClass.canAccess(env, field)) {
868                ClassDefinition clazz = env.getClassDefinition(right.type);
869                //env.error(where, "no.type.access",
870                //          id, clazz, ctx.field.getClassDeclaration());
871                env.error(where, "no.type.access",
872                          id, clazz, ctxClass.getClassDeclaration());
873                return vset;
874            }
875
876            if (field.isProtected()
877                && !(right instanceof SuperExpression
878                     // Extension of JLS 6.6.2 for qualified 'super'.
879                     || (right instanceof FieldExpression &&
880                         ((FieldExpression)right).id == idSuper))
881                && !ctxClass.protectedAccess(env, field, right.type)){
882                env.error(where, "invalid.protected.field.use",
883                          field.getName(), field.getClassDeclaration(),
884                          right.type);
885                return vset;
886            }
887
888            inner.noteUsedBy(ctxClass, where, env);
889
890        } catch (ClassNotFound e) {
891            env.error(where, "class.not.found", e.name, ctx.field);
892        }
893
894        ctxClass.addDependency(field.getClassDeclaration());
895        if (loc == null)
896            // Complain about a free-floating type name.
897            return te.checkValue(env, ctx, vset, exp);
898        loc.right = te;
899        return vset;
900    }
901
902    /**
903     * Check the expression if it appears on the LHS of an assignment
904     */
905    public Vset checkLHS(Environment env, Context ctx,
906                         Vset vset, Hashtable<Object, Object> exp) {
907        boolean hadField = (field != null);
908
909        //checkValue(env, ctx, vset, exp);
910        checkCommon(env, ctx, vset, exp, null, true);
911
912        // If 'implementation' is set to a non-null value, then the
913        // field expression does not denote an assignable location,
914        // e.g., the 'length' field of an array.
915        if (implementation != null) {
916            // This just reports an error and recovers.
917            return super.checkLHS(env, ctx, vset, exp);
918        }
919
920        if (field != null && field.isFinal() && !hadField) {
921            if (field.isBlankFinal()) {
922                if (field.isStatic()) {
923                    if (right != null) {
924                        env.error(where, "qualified.static.final.assign");
925                    }
926                    // Continue with checking anyhow.
927                    // In fact, it would be easy to allow this case.
928                } else {
929                    if ((right != null) && (right.op != THIS)) {
930                        env.error(where, "bad.qualified.final.assign", field.getName());
931                        // The actual instance could be anywhere, so don't
932                        // continue with checking the definite assignment status.
933                        return vset;
934                    }
935                }
936                vset = checkFinalAssign(env, ctx, vset, where, field);
937            } else {
938                env.error(where, "assign.to.final", id);
939            }
940        }
941        return vset;
942    }
943
944    /**
945     * Check the expression if it appears on the LHS of an op= expression
946     */
947    public Vset checkAssignOp(Environment env, Context ctx,
948                              Vset vset, Hashtable<Object, Object> exp, Expression outside) {
949
950        //checkValue(env, ctx, vset, exp);
951        checkCommon(env, ctx, vset, exp, null, true);
952
953        // If 'implementation' is set to a non-null value, then the
954        // field expression does not denote an assignable location,
955        // e.g., the 'length' field of an array.
956        if (implementation != null) {
957            return super.checkLHS(env, ctx, vset, exp);
958        }
959        if (field != null && field.isFinal()) {
960            env.error(where, "assign.to.final", id);
961        }
962        return vset;
963    }
964
965    /**
966     * There is a simple assignment being made to the given final field.
967     * The field was named either by a simple name or by an almost-simple
968     * expression of the form "this.v".
969     * Check if this is a legal assignment.
970     * <p>
971     * Blank final variables can be set in initializers or constructor
972     * bodies.  In all cases there must be definite single assignment.
973     * (All instance and instance variable initializers and each
974     * constructor body are treated as if concatenated for the purposes
975     * of this check.  Assignment to "this.x" is treated as a definite
976     * assignment to the simple name "x" which names the instance variable.)
977     */
978
979    public static Vset checkFinalAssign(Environment env, Context ctx,
980                                        Vset vset, long where,
981                                        MemberDefinition field) {
982        if (field.isBlankFinal()
983            && field.getClassDefinition() == ctx.field.getClassDefinition()) {
984            int number = ctx.getFieldNumber(field);
985            if (number >= 0 && vset.testVarUnassigned(number)) {
986                // definite single assignment
987                vset = vset.addVar(number);
988            } else {
989                // it is a blank final in this class, but not assignable
990                Identifier id = field.getName();
991                env.error(where, "assign.to.blank.final", id);
992            }
993        } else {
994            // give the generic error message
995            Identifier id = field.getName();
996            env.error(where, "assign.to.final", id);
997        }
998        return vset;
999    }
1000
1001    private static MemberDefinition getClassLiteralCache(Environment env,
1002                                                         Context ctx,
1003                                                         String className,
1004                                                         ClassDefinition c) {
1005        // Given a class name, look for a static field to cache it.
1006        //      className       lname
1007        //      pkg.Foo         class$pkg$Foo
1008        //      [Lpkg.Foo;      array$Lpkg$Foo
1009        //      [[Lpkg.Foo;     array$$Lpkg$Foo
1010        //      [I              array$I
1011        //      [[I             array$$I
1012        String lname;
1013        if (!className.startsWith(SIG_ARRAY)) {
1014            lname = prefixClass + className.replace('.', '$');
1015        } else {
1016            lname = prefixArray + className.substring(1);
1017            lname = lname.replace(SIGC_ARRAY, '$'); // [[[I => array$$$I
1018            if (className.endsWith(SIG_ENDCLASS)) {
1019                // [Lpkg.Foo; => array$Lpkg$Foo
1020                lname = lname.substring(0, lname.length() - 1);
1021                lname = lname.replace('.', '$');
1022            }
1023            // else [I => array$I or some such; lname is already OK
1024        }
1025        Identifier fname = Identifier.lookup(lname);
1026
1027        // The class to put the cache in is now given as an argument.
1028        //
1029        // ClassDefinition c = ctx.field.getClassDefinition();
1030        // while (c.isInnerClass()) {
1031        //     c = c.getOuterClass();
1032
1033        MemberDefinition cfld;
1034        try {
1035            cfld = c.getVariable(env, fname, c);
1036        } catch (ClassNotFound ee) {
1037            return null;
1038        } catch (AmbiguousMember ee) {
1039            return null;
1040        }
1041
1042        // Ignore inherited field.  Each top-level class
1043        // containing a given class literal must have its own copy,
1044        // both for reasons of binary compatibility and to prevent
1045        // access violations should the superclass be in another
1046        // package.  Part of fix 4106051.
1047        if (cfld != null && cfld.getClassDefinition() == c) {
1048            return cfld;
1049        }
1050
1051        // Since each class now has its own copy, we might as well
1052        // tighten up the access to private (previously default).
1053        // Part of fix for 4106051.
1054        // ** Temporarily retract this, as it tickles 4098316.
1055        return env.makeMemberDefinition(env, c.getWhere(),
1056                                        c, null,
1057                                        M_STATIC | M_SYNTHETIC, // M_PRIVATE,
1058                                        Type.tClassDesc, fname,
1059                                        null, null, null);
1060    }
1061
1062    private Expression makeClassLiteralCacheRef(Environment env, Context ctx,
1063                                                MemberDefinition lookup,
1064                                                MemberDefinition cfld,
1065                                                String className) {
1066        Expression ccls = new TypeExpression(where,
1067                                             cfld.getClassDefinition()
1068                                             .getType());
1069        Expression cache = new FieldExpression(where, ccls, cfld);
1070        Expression cacheOK =
1071            new NotEqualExpression(where, cache.copyInline(ctx),
1072                                   new NullExpression(where));
1073        Expression lcls =
1074            new TypeExpression(where, lookup.getClassDefinition() .getType());
1075        Expression name = new StringExpression(where, className);
1076        Expression namearg[] = { name };
1077        Expression setCache = new MethodExpression(where, lcls,
1078                                                   lookup, namearg);
1079        setCache = new AssignExpression(where, cache.copyInline(ctx),
1080                                        setCache);
1081        return new ConditionalExpression(where, cacheOK, cache, setCache);
1082    }
1083
1084    private Expression makeClassLiteralInlineRef(Environment env, Context ctx,
1085                                                 MemberDefinition lookup,
1086                                                 String className) {
1087        Expression lcls =
1088            new TypeExpression(where, lookup.getClassDefinition().getType());
1089        Expression name = new StringExpression(where, className);
1090        Expression namearg[] = { name };
1091        Expression getClass = new MethodExpression(where, lcls,
1092                                                   lookup, namearg);
1093        return getClass;
1094    }
1095
1096
1097    /**
1098     * Check if constant:  Will it inline away?
1099     */
1100    public boolean isConstant() {
1101        if (implementation != null)
1102            return implementation.isConstant();
1103        if ((field != null)
1104            && (right == null || right instanceof TypeExpression
1105                || (right.op == THIS && right.where == where))) {
1106            return field.isConstant();
1107        }
1108        return false;
1109    }
1110
1111    /**
1112     * Inline
1113     */
1114    public Expression inline(Environment env, Context ctx) {
1115        if (implementation != null)
1116            return implementation.inline(env, ctx);
1117        // A field expression may have the side effect of causing
1118        // a NullPointerException, so evaluate it even though
1119        // the value is not needed.  Similarly, static field dereferences
1120        // may cause class initialization, so they mustn't be omitted
1121        // either.
1122        //
1123        // However, NullPointerException can't happen and initialization must
1124        // already have occurred if you are dotting into 'this'.  So
1125        // allow fields of 'this' to be eliminated as a special case.
1126        Expression e = inlineValue(env, ctx);
1127        if (e instanceof FieldExpression) {
1128            FieldExpression fe = (FieldExpression) e;
1129            if ((fe.right != null) && (fe.right.op==THIS))
1130                return null;
1131            // It should be possible to split this into two checks: one using
1132            // isNonNull() for non-statics and a different check for statics.
1133            // That would make the inlining slightly less conservative by
1134            // allowing, for example, dotting into String constants.
1135            }
1136        return e;
1137    }
1138    public Expression inlineValue(Environment env, Context ctx) {
1139        if (implementation != null)
1140            return implementation.inlineValue(env, ctx);
1141        try {
1142            if (field == null) {
1143                return this;
1144            }
1145
1146            if (field.isFinal()) {
1147                Expression e = (Expression)field.getValue(env);
1148                if ((e != null) && e.isConstant()) {
1149                    // remove bogus line-number info
1150                    e = e.copyInline(ctx);
1151                    e.where = where;
1152                    return new CommaExpression(where, right, e).inlineValue(env, ctx);
1153                }
1154            }
1155
1156            if (right != null) {
1157                if (field.isStatic()) {
1158                    Expression e = right.inline(env, ctx);
1159                    right = null;
1160                    if (e != null) {
1161                        return new CommaExpression(where, e, this);
1162                    }
1163                } else {
1164                    right = right.inlineValue(env, ctx);
1165                }
1166            }
1167            return this;
1168
1169        } catch (ClassNotFound e) {
1170            throw new CompilerError(e);
1171        }
1172    }
1173    public Expression inlineLHS(Environment env, Context ctx) {
1174        if (implementation != null)
1175            return implementation.inlineLHS(env, ctx);
1176        if (right != null) {
1177            if (field.isStatic()) {
1178                Expression e = right.inline(env, ctx);
1179                right = null;
1180                if (e != null) {
1181                    return new CommaExpression(where, e, this);
1182                }
1183            } else {
1184                right = right.inlineValue(env, ctx);
1185            }
1186        }
1187        return this;
1188    }
1189
1190    public Expression copyInline(Context ctx) {
1191        if (implementation != null)
1192            return implementation.copyInline(ctx);
1193        return super.copyInline(ctx);
1194    }
1195
1196    /**
1197     * The cost of inlining this expression
1198     */
1199    public int costInline(int thresh, Environment env, Context ctx) {
1200        if (implementation != null)
1201            return implementation.costInline(thresh, env, ctx);
1202        if (ctx == null) {
1203            return 3 + ((right == null) ? 0
1204                                        : right.costInline(thresh, env, ctx));
1205        }
1206        // ctxClass is the current class trying to inline this method
1207        ClassDefinition ctxClass = ctx.field.getClassDefinition();
1208        try {
1209            // We only allow the inlining if the current class can access
1210            // the field, the field's class, and right's declared type.
1211            if (    ctxClass.permitInlinedAccess(env, field.getClassDeclaration())
1212                 && ctxClass.permitInlinedAccess(env, field)) {
1213                if (right == null) {
1214                    return 3;
1215                } else {
1216                    ClassDeclaration rt = env.getClassDeclaration(right.type);
1217                    if (ctxClass.permitInlinedAccess(env, rt)) {
1218                        return 3 + right.costInline(thresh, env, ctx);
1219                    }
1220                }
1221            }
1222        } catch (ClassNotFound e) {
1223        }
1224        return thresh;
1225    }
1226
1227    /**
1228     * Code
1229     */
1230    int codeLValue(Environment env, Context ctx, Assembler asm) {
1231        if (implementation != null)
1232            throw new CompilerError("codeLValue");
1233        if (field.isStatic()) {
1234            if (right != null) {
1235                right.code(env, ctx, asm);
1236                return 1;
1237            }
1238            return 0;
1239        }
1240        right.codeValue(env, ctx, asm);
1241        return 1;
1242    }
1243    void codeLoad(Environment env, Context ctx, Assembler asm) {
1244        if (field == null) {
1245            throw new CompilerError("should not be null");
1246        }
1247        if (field.isStatic()) {
1248            asm.add(where, opc_getstatic, field);
1249        } else {
1250            asm.add(where, opc_getfield, field);
1251        }
1252    }
1253    void codeStore(Environment env, Context ctx, Assembler asm) {
1254        if (field.isStatic()) {
1255            asm.add(where, opc_putstatic, field);
1256        } else {
1257            asm.add(where, opc_putfield, field);
1258        }
1259    }
1260
1261    public void codeValue(Environment env, Context ctx, Assembler asm) {
1262        codeLValue(env, ctx, asm);
1263        codeLoad(env, ctx, asm);
1264    }
1265
1266    /**
1267     * Print
1268     */
1269    public void print(PrintStream out) {
1270        out.print("(");
1271        if (right != null) {
1272            right.print(out);
1273        } else {
1274            out.print("<empty>");
1275        }
1276        out.print("." + id + ")");
1277        if (implementation != null) {
1278            out.print("/IMPL=");
1279            implementation.print(out);
1280        }
1281    }
1282}
1283