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
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 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}