History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/tools/tree/FieldExpression.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/tools/tree/FieldExpression.java+1282−0
@@ -0,0 +1,1282 @@
1+/*
2+ * Copyright (c) 1994, 2003, 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+
26+package sun.tools.tree;
27+
28+import sun.tools.java.*;
29+import sun.tools.asm.*;
30+import java.io.PrintStream;
31+import 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+ */
38+public
39+class 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+ StringBuffer buf = new StringBuffer();
83+ while (e.op == FIELD) {
84+ FieldExpression fe = (FieldExpression)e;
85+ if (fe.id == idThis || fe.id == idClass) {
86+ return null;
87+ }
88+ buf.insert(0, fe.id);
89+ buf.insert(0, '.');
90+ e = fe.right;
91+ }
92+ if (e.op != IDENT) {
93+ return null;
94+ }
95+ buf.insert(0, ((IdentifierExpression)e).id);
96+ return Identifier.lookup(buf.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 ommitted 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 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 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 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 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 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 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 occured 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+}