001: /*
002: * Copyright 1994-2003 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.tools.tree;
027:
028: import sun.tools.java.*;
029: import sun.tools.asm.Assembler;
030: import sun.tools.asm.LocalVariable;
031: import java.io.PrintStream;
032: import java.util.Hashtable;
033:
034: /**
035: * WARNING: The contents of this source file are not part of any
036: * supported API. Code that depends on them does so at its own risk:
037: * they are subject to change or removal without notice.
038: */
039: public class IdentifierExpression extends Expression {
040: Identifier id;
041: MemberDefinition field;
042: Expression implementation;
043:
044: /**
045: * Constructor
046: */
047: public IdentifierExpression(long where, Identifier id) {
048: super (IDENT, where, Type.tError);
049: this .id = id;
050: }
051:
052: public IdentifierExpression(IdentifierToken id) {
053: this (id.getWhere(), id.getName());
054: }
055:
056: public IdentifierExpression(long where, MemberDefinition field) {
057: super (IDENT, where, field.getType());
058: this .id = field.getName();
059: this .field = field;
060: }
061:
062: public Expression getImplementation() {
063: if (implementation != null)
064: return implementation;
065: return this ;
066: }
067:
068: /**
069: * Check if the expression is equal to a value
070: */
071: public boolean equals(Identifier id) {
072: return this .id.equals(id);
073: }
074:
075: /**
076: * Assign a value to this identifier. [It must already be "bound"]
077: */
078: private Vset assign(Environment env, Context ctx, Vset vset) {
079: if (field.isLocal()) {
080: LocalMember local = (LocalMember) field;
081: if (local.scopeNumber < ctx.frameNumber) {
082: env.error(where, "assign.to.uplevel", id);
083: }
084: if (local.isFinal()) {
085: // allow definite single assignment of blank finals
086: if (!local.isBlankFinal()) {
087: env.error(where, "assign.to.final", id);
088: } else if (!vset.testVarUnassigned(local.number)) {
089: env.error(where, "assign.to.blank.final", id);
090: }
091: }
092: vset.addVar(local.number);
093: local.writecount++;
094: } else if (field.isFinal()) {
095: vset = FieldExpression.checkFinalAssign(env, ctx, vset,
096: where, field);
097: }
098: return vset;
099: }
100:
101: /**
102: * Get the value of this identifier. [ It must already be "bound"]
103: */
104: private Vset get(Environment env, Context ctx, Vset vset) {
105: if (field.isLocal()) {
106: LocalMember local = (LocalMember) field;
107: if (local.scopeNumber < ctx.frameNumber && !local.isFinal()) {
108: env.error(where, "invalid.uplevel", id);
109: }
110: if (!vset.testVar(local.number)) {
111: env.error(where, "var.not.initialized", id);
112: vset.addVar(local.number);
113: }
114: local.readcount++;
115: } else {
116: if (!field.isStatic()) {
117: if (!vset.testVar(ctx.getThisNumber())) {
118: env.error(where, "access.inst.before.super", id);
119: implementation = null;
120: }
121: }
122: if (field.isBlankFinal()) {
123: int number = ctx.getFieldNumber(field);
124: if (number >= 0 && !vset.testVar(number)) {
125: env.error(where, "var.not.initialized", id);
126: }
127: }
128: }
129: return vset;
130: }
131:
132: /**
133: * Bind to a field
134: */
135: boolean bind(Environment env, Context ctx) {
136: try {
137: field = ctx.getField(env, id);
138: if (field == null) {
139: for (ClassDefinition cdef = ctx.field
140: .getClassDefinition(); cdef != null; cdef = cdef
141: .getOuterClass()) {
142: if (cdef.findAnyMethod(env, id) != null) {
143: env.error(where, "invalid.var", id, ctx.field
144: .getClassDeclaration());
145: return false;
146: }
147: }
148: env.error(where, "undef.var", id);
149: return false;
150: }
151:
152: type = field.getType();
153:
154: // Check access permission
155: if (!ctx.field.getClassDefinition().canAccess(env, field)) {
156: env.error(where, "no.field.access", id, field
157: .getClassDeclaration(), ctx.field
158: .getClassDeclaration());
159: return false;
160: }
161:
162: // Find out how to access this variable.
163: if (field.isLocal()) {
164: LocalMember local = (LocalMember) field;
165: if (local.scopeNumber < ctx.frameNumber) {
166: // get a "val$x" copy via the current object
167: implementation = ctx.makeReference(env, local);
168: }
169: } else {
170: MemberDefinition f = field;
171:
172: if (f.reportDeprecated(env)) {
173: env.error(where, "warn.field.is.deprecated", id, f
174: .getClassDefinition());
175: }
176:
177: ClassDefinition fclass = f.getClassDefinition();
178: if (fclass != ctx.field.getClassDefinition()) {
179: // Maybe an inherited field hides an apparent variable.
180: MemberDefinition f2 = ctx.getApparentField(env, id);
181: if (f2 != null && f2 != f) {
182: ClassDefinition c = ctx.findScope(env, fclass);
183: if (c == null)
184: c = f.getClassDefinition();
185: if (f2.isLocal()) {
186: env.error(where, "inherited.hides.local",
187: id, c.getClassDeclaration());
188: } else {
189: env.error(where, "inherited.hides.field",
190: id, c.getClassDeclaration(), f2
191: .getClassDeclaration());
192: }
193: }
194: }
195:
196: // Rewrite as a FieldExpression.
197: // Access methods for private fields, if needed, will be added
198: // during subsequent processing of the FieldExpression. See
199: // method 'FieldExpression.checkCommon'. This division of labor
200: // is somewhat awkward, as most further processing of a
201: // FieldExpression during the checking phase is suppressed when
202: // the referenced field is pre-set as it is here.
203:
204: if (f.isStatic()) {
205: Expression base = new TypeExpression(where, f
206: .getClassDeclaration().getType());
207: implementation = new FieldExpression(where, null, f);
208: } else {
209: Expression base = ctx.findOuterLink(env, where, f);
210: if (base != null) {
211: implementation = new FieldExpression(where,
212: base, f);
213: }
214: }
215: }
216:
217: // Check forward reference
218: if (!ctx.canReach(env, field)) {
219: env.error(where, "forward.ref", id, field
220: .getClassDeclaration());
221: return false;
222: }
223: return true;
224: } catch (ClassNotFound e) {
225: env.error(where, "class.not.found", e.name, ctx.field);
226: } catch (AmbiguousMember e) {
227: env.error(where, "ambig.field", id, e.field1
228: .getClassDeclaration(), e.field2
229: .getClassDeclaration());
230: }
231: return false;
232: }
233:
234: /**
235: * Check expression
236: */
237: public Vset checkValue(Environment env, Context ctx, Vset vset,
238: Hashtable exp) {
239: if (field != null) {
240: // An internally pre-set field, such as an argument copying
241: // an uplevel value. Do not re-check it.
242: return vset;
243: }
244: if (bind(env, ctx)) {
245: vset = get(env, ctx, vset);
246: ctx.field.getClassDefinition().addDependency(
247: field.getClassDeclaration());
248: if (implementation != null)
249: vset = implementation.checkValue(env, ctx, vset, exp);
250: }
251: return vset;
252: }
253:
254: /**
255: * Check the expression if it appears on the LHS of an assignment
256: */
257: public Vset checkLHS(Environment env, Context ctx, Vset vset,
258: Hashtable exp) {
259: if (!bind(env, ctx))
260: return vset;
261: vset = assign(env, ctx, vset);
262: if (implementation != null)
263: vset = implementation.checkValue(env, ctx, vset, exp);
264: return vset;
265: }
266:
267: /**
268: * Check the expression if it appears on the LHS of an op= expression
269: */
270: public Vset checkAssignOp(Environment env, Context ctx, Vset vset,
271: Hashtable exp, Expression outside) {
272: if (!bind(env, ctx))
273: return vset;
274: vset = assign(env, ctx, get(env, ctx, vset));
275: if (implementation != null)
276: vset = implementation.checkValue(env, ctx, vset, exp);
277: return vset;
278: }
279:
280: /**
281: * Return an accessor if one is needed for assignments to this expression.
282: */
283: public FieldUpdater getAssigner(Environment env, Context ctx) {
284: if (implementation != null)
285: return implementation.getAssigner(env, ctx);
286: return null;
287: }
288:
289: /**
290: * Return an updater if one is needed for assignments to this expression.
291: */
292: public FieldUpdater getUpdater(Environment env, Context ctx) {
293: if (implementation != null)
294: return implementation.getUpdater(env, ctx);
295: return null;
296: }
297:
298: /**
299: * Check if the present name is part of a scoping prefix.
300: */
301: public Vset checkAmbigName(Environment env, Context ctx, Vset vset,
302: Hashtable exp, UnaryExpression loc) {
303: try {
304: if (ctx.getField(env, id) != null) {
305: // if this is a local field, there's nothing more to do.
306: return checkValue(env, ctx, vset, exp);
307: }
308: } catch (ClassNotFound ee) {
309: } catch (AmbiguousMember ee) {
310: }
311: // Can this be interpreted as a type?
312: ClassDefinition c = toResolvedType(env, ctx, true);
313: // Is it a real type??
314: if (c != null) {
315: loc.right = new TypeExpression(where, c.getType());
316: return vset;
317: }
318: // We hope it is a package prefix. Let the caller decide.
319: type = Type.tPackage;
320: return vset;
321: }
322:
323: /**
324: * Convert an identifier to a known type, or null.
325: */
326: private ClassDefinition toResolvedType(Environment env,
327: Context ctx, boolean pkgOK) {
328: Identifier rid = ctx.resolveName(env, id);
329: Type t = Type.tClass(rid);
330: if (pkgOK && !env.classExists(t)) {
331: return null;
332: }
333: if (env.resolve(where, ctx.field.getClassDefinition(), t)) {
334: try {
335: ClassDefinition c = env.getClassDefinition(t);
336:
337: // Maybe an inherited class hides an apparent class.
338: if (c.isMember()) {
339: ClassDefinition sc = ctx.findScope(env, c
340: .getOuterClass());
341: if (sc != c.getOuterClass()) {
342: Identifier rid2 = ctx.getApparentClassName(env,
343: id);
344: if (!rid2.equals(idNull) && !rid2.equals(rid)) {
345: env.error(where, "inherited.hides.type",
346: id, sc.getClassDeclaration());
347: }
348: }
349: }
350:
351: if (!c.getLocalName()
352: .equals(id.getFlatName().getName())) {
353: env.error(where, "illegal.mangled.name", id, c);
354: }
355:
356: return c;
357: } catch (ClassNotFound ee) {
358: }
359: }
360: return null;
361: }
362:
363: /**
364: * Convert an identifier to a type.
365: * If one is not known, use the current package as a qualifier.
366: */
367: Type toType(Environment env, Context ctx) {
368: ClassDefinition c = toResolvedType(env, ctx, false);
369: if (c != null) {
370: return c.getType();
371: }
372: return Type.tError;
373: }
374:
375: /**
376: * Convert an expresion to a type in a context where a qualified
377: * type name is expected, e.g., in the prefix of a qualified type
378: * name. We do not necessarily know where the package prefix ends,
379: * so we operate similarly to 'checkAmbiguousName'. This is the
380: * base case -- the first component of the qualified name.
381: */
382: /*-------------------------------------------------------*
383: Type toQualifiedType(Environment env, Context ctx) {
384: // We do not look for non-type fields. Is this correct?
385: ClassDefinition c = toResolvedType(env, ctx, true);
386: // Is it a real type?
387: if (c != null) {
388: return c.getType();
389: }
390: // We hope it is a package prefix. Let the caller decide.
391: return Type.tPackage;
392: }
393: *-------------------------------------------------------*/
394:
395: /**
396: * Check if constant: Will it inline away?
397: */
398: public boolean isConstant() {
399: if (implementation != null)
400: return implementation.isConstant();
401: if (field != null) {
402: return field.isConstant();
403: }
404: return false;
405: }
406:
407: /**
408: * Inline
409: */
410: public Expression inline(Environment env, Context ctx) {
411: return null;
412: }
413:
414: public Expression inlineValue(Environment env, Context ctx) {
415: if (implementation != null)
416: return implementation.inlineValue(env, ctx);
417: if (field == null) {
418: return this ;
419: }
420: try {
421: if (field.isLocal()) {
422: if (field.isInlineable(env, false)) {
423: Expression e = (Expression) field.getValue(env);
424: return (e == null) ? this : e.inlineValue(env, ctx);
425: }
426: return this ;
427: }
428: return this ;
429: } catch (ClassNotFound e) {
430: throw new CompilerError(e);
431: }
432: }
433:
434: public Expression inlineLHS(Environment env, Context ctx) {
435: if (implementation != null)
436: return implementation.inlineLHS(env, ctx);
437: return this ;
438: }
439:
440: public Expression copyInline(Context ctx) {
441: if (implementation != null)
442: return implementation.copyInline(ctx);
443: IdentifierExpression e = (IdentifierExpression) super
444: .copyInline(ctx);
445: if (field != null && field.isLocal()) {
446: e.field = ((LocalMember) field).getCurrentInlineCopy(ctx);
447: }
448: return e;
449: }
450:
451: public int costInline(int thresh, Environment env, Context ctx) {
452: if (implementation != null)
453: return implementation.costInline(thresh, env, ctx);
454: return super .costInline(thresh, env, ctx);
455: }
456:
457: /**
458: * Code local vars (object fields have been inlined away)
459: */
460: int codeLValue(Environment env, Context ctx, Assembler asm) {
461: return 0;
462: }
463:
464: void codeLoad(Environment env, Context ctx, Assembler asm) {
465: asm.add(where, opc_iload + type.getTypeCodeOffset(),
466: new Integer(((LocalMember) field).number));
467: }
468:
469: void codeStore(Environment env, Context ctx, Assembler asm) {
470: LocalMember local = (LocalMember) field;
471: asm.add(where, opc_istore + type.getTypeCodeOffset(),
472: new LocalVariable(local, local.number));
473: }
474:
475: public void codeValue(Environment env, Context ctx, Assembler asm) {
476: codeLValue(env, ctx, asm);
477: codeLoad(env, ctx, asm);
478: }
479:
480: /**
481: * Print
482: */
483: public void print(PrintStream out) {
484: out.print(id + "#" + ((field != null) ? field.hashCode() : 0));
485: if (implementation != null) {
486: out.print("/IMPL=");
487: implementation.print(out);
488: }
489: }
490: }
|