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:
031: /**
032: * WARNING: The contents of this source file are not part of any
033: * supported API. Code that depends on them does so at its own risk:
034: * they are subject to change or removal without notice.
035: */
036: public class Context implements Constants {
037: Context prev;
038: Node node;
039: int varNumber;
040: LocalMember locals;
041: LocalMember classes;
042: MemberDefinition field;
043: int scopeNumber;
044: int frameNumber;
045:
046: /**
047: * Create the initial context for a method
048: * The incoming context is inherited from
049: */
050: public Context(Context ctx, MemberDefinition field) {
051: this .field = field;
052: if (ctx == null) {
053: this .frameNumber = 1;
054: this .scopeNumber = 2;
055: this .varNumber = 0;
056: } else {
057: this .prev = ctx;
058: this .locals = ctx.locals;
059: this .classes = ctx.classes;
060: if (field != null
061: && (field.isVariable() || field.isInitializer())) {
062: // Variables and initializers are inlined into a constructor.
063: // Model this by inheriting the frame number of the parent,
064: // which will contain a "this" parameter.
065: this .frameNumber = ctx.frameNumber;
066: this .scopeNumber = ctx.scopeNumber + 1;
067: } else {
068: this .frameNumber = ctx.scopeNumber + 1;
069: this .scopeNumber = this .frameNumber + 1;
070: }
071: this .varNumber = ctx.varNumber;
072: }
073: }
074:
075: /**
076: * Create a new context, for initializing a class.
077: */
078: public Context(Context ctx, ClassDefinition c) {
079: this (ctx, (MemberDefinition) null);
080: }
081:
082: /**
083: * Create a new nested context, for a block statement
084: */
085: Context(Context ctx, Node node) {
086: if (ctx == null) {
087: this .frameNumber = 1;
088: this .scopeNumber = 2;
089: this .varNumber = 0;
090: } else {
091: this .prev = ctx;
092: this .locals = ctx.locals;
093: // Inherit local classes from surrounding block,
094: // just as for local variables. Fixes 4074421.
095: this .classes = ctx.classes;
096: this .varNumber = ctx.varNumber;
097: this .field = ctx.field;
098: this .frameNumber = ctx.frameNumber;
099: this .scopeNumber = ctx.scopeNumber + 1;
100: this .node = node;
101: }
102: }
103:
104: public Context(Context ctx) {
105: this (ctx, (Node) null);
106: }
107:
108: /**
109: * Declare local
110: */
111: public int declare(Environment env, LocalMember local) {
112: //System.out.println( "DECLARE= " + local.getName() + "=" + varNumber + ", read=" + local.readcount + ", write=" + local.writecount + ", hash=" + local.hashCode());
113: local.scopeNumber = scopeNumber;
114: if (this .field == null && idThis.equals(local.getName())) {
115: local.scopeNumber += 1; // Anticipate variable or initializer.
116: }
117: if (local.isInnerClass()) {
118: local.prev = classes;
119: classes = local;
120: return 0;
121: }
122:
123: // Originally the statement:
124: //
125: // local.subModifiers(M_INLINEABLE);
126: //
127: // was here with the comment:
128: //
129: // // prevent inlining across call sites
130: //
131: // This statement prevented constant local variables from
132: // inlining. It didn't seem to do anything useful.
133: //
134: // The statement has been removed and an assertion has been
135: // added which mandates that the only members which are marked
136: // with M_INLINEABLE are the ones for which isConstant() is true.
137: // (Fix for 4106244.)
138: //
139: // Addition to the above comment: they might also be
140: // final variables initialized with 'this', 'super', or other
141: // final identifiers. See VarDeclarationStatement.inline().
142: // So I've removed the assertion. The original subModifiers
143: // call appears to have been there to fix nested class translation
144: // breakage, which has been fixed in VarDeclarationStatement
145: // now instead. (Fix for 4073244.)
146:
147: local.prev = locals;
148: locals = local;
149: local.number = varNumber;
150: varNumber += local.getType().stackSize();
151: return local.number;
152: }
153:
154: /**
155: * Get a local variable by name
156: */
157: public LocalMember getLocalField(Identifier name) {
158: for (LocalMember f = locals; f != null; f = f.prev) {
159: if (name.equals(f.getName())) {
160: return f;
161: }
162: }
163: return null;
164: }
165:
166: /**
167: * Get the scope number for a reference to a member of this class
168: * (Larger scope numbers are more deeply nested.)
169: * @see LocalMember#scopeNumber
170: */
171: public int getScopeNumber(ClassDefinition c) {
172: for (Context ctx = this ; ctx != null; ctx = ctx.prev) {
173: if (ctx.field == null)
174: continue;
175: if (ctx.field.getClassDefinition() == c) {
176: return ctx.frameNumber;
177: }
178: }
179: return -1;
180: }
181:
182: private MemberDefinition getFieldCommon(Environment env,
183: Identifier name, boolean apparentOnly)
184: throws AmbiguousMember, ClassNotFound {
185: // Note: This is structured as a pair of parallel lookups.
186: // If we were to redesign Context, we might prefer to walk
187: // along a single chain of scopes.
188:
189: LocalMember lf = getLocalField(name);
190: int ls = (lf == null) ? -2 : lf.scopeNumber;
191:
192: ClassDefinition this Class = field.getClassDefinition();
193:
194: // Also look for a class member in a shallower scope.
195: for (ClassDefinition c = this Class; c != null; c = c
196: .getOuterClass()) {
197: MemberDefinition f = c.getVariable(env, name, this Class);
198: if (f != null && getScopeNumber(c) > ls) {
199: if (apparentOnly && f.getClassDefinition() != c) {
200: continue;
201: }
202: return f;
203: }
204: }
205:
206: return lf;
207: }
208:
209: /**
210: * Assign a number to a class field.
211: * (This is used to track definite assignment of some blank finals.)
212: */
213: public int declareFieldNumber(MemberDefinition field) {
214: return declare(null, new LocalMember(field));
215: }
216:
217: /**
218: * Retrieve a number previously assigned by declareMember().
219: * Return -1 if there was no such assignment in this context.
220: */
221: public int getFieldNumber(MemberDefinition field) {
222: for (LocalMember f = locals; f != null; f = f.prev) {
223: if (f.getMember() == field) {
224: return f.number;
225: }
226: }
227: return -1;
228: }
229:
230: /**
231: * Return the local field or member field corresponding to a number.
232: * Return null if there is no such field.
233: */
234: public MemberDefinition getElement(int number) {
235: for (LocalMember f = locals; f != null; f = f.prev) {
236: if (f.number == number) {
237: MemberDefinition field = f.getMember();
238: return (field != null) ? field : f;
239: }
240: }
241: return null;
242: }
243:
244: /**
245: * Get a local class by name
246: */
247: public LocalMember getLocalClass(Identifier name) {
248: for (LocalMember f = classes; f != null; f = f.prev) {
249: if (name.equals(f.getName())) {
250: return f;
251: }
252: }
253: return null;
254: }
255:
256: private MemberDefinition getClassCommon(Environment env,
257: Identifier name, boolean apparentOnly) throws ClassNotFound {
258: LocalMember lf = getLocalClass(name);
259: int ls = (lf == null) ? -2 : lf.scopeNumber;
260:
261: // Also look for a class member in a shallower scope.
262: for (ClassDefinition c = field.getClassDefinition(); c != null; c = c
263: .getOuterClass()) {
264: // QUERY: We may need to get the inner class from a
265: // superclass of 'c'. This call is prepared to
266: // resolve the superclass if necessary. Can we arrange
267: // to assure that it is always previously resolved?
268: // This is one of a small number of problematic calls that
269: // requires 'getSuperClass' to resolve superclasses on demand.
270: // See 'ClassDefinition.getInnerClass(env, nm)'.
271: MemberDefinition f = c.getInnerClass(env, name);
272: if (f != null && getScopeNumber(c) > ls) {
273: if (apparentOnly && f.getClassDefinition() != c) {
274: continue;
275: }
276: return f;
277: }
278: }
279:
280: return lf;
281: }
282:
283: /**
284: * Get either a local variable, or a field in a current class
285: */
286: public final MemberDefinition getField(Environment env,
287: Identifier name) throws AmbiguousMember, ClassNotFound {
288: return getFieldCommon(env, name, false);
289: }
290:
291: /**
292: * Like getField, except that it skips over inherited fields.
293: * Used for error checking.
294: */
295: public final MemberDefinition getApparentField(Environment env,
296: Identifier name) throws AmbiguousMember, ClassNotFound {
297: return getFieldCommon(env, name, true);
298: }
299:
300: /**
301: * Check if the given field is active in this context.
302: */
303: public boolean isInScope(LocalMember field) {
304: for (LocalMember f = locals; f != null; f = f.prev) {
305: if (field == f) {
306: return true;
307: }
308: }
309: return false;
310: }
311:
312: /**
313: * Notice a reference (usually an uplevel one).
314: * Update the references list of every enclosing class
315: * which is enclosed by the scope of the target.
316: * Update decisions about which uplevels to make into fields.
317: * Return the uplevel reference descriptor, or null if it's local.
318: * <p>
319: * The target must be in scope in this context.
320: * So, call this method only from the check phase.
321: * (In other phases, the context may be less complete.)
322: * <p>
323: * This can and should be called both before and after classes are frozen.
324: * It should be a no-op, and will raise a compiler error if not.
325: */
326: public UplevelReference noteReference(Environment env,
327: LocalMember target) {
328: int targetScopeNumber = !isInScope(target) ? -1
329: : target.scopeNumber;
330:
331: // Walk outward visiting each scope.
332: // Note each distinct frame (i.e., enclosing method).
333: // For each frame in which the variable is uplevel,
334: // record the event in the references list of the enclosing class.
335: UplevelReference res = null;
336: int currentFrameNumber = -1;
337: for (Context refctx = this ; refctx != null; refctx = refctx.prev) {
338: if (currentFrameNumber == refctx.frameNumber) {
339: continue; // we're processing frames, not contexts
340: }
341: currentFrameNumber = refctx.frameNumber;
342: if (targetScopeNumber >= currentFrameNumber) {
343: break; // the target is native to this frame
344: }
345:
346: // process a frame which is using this variable as an uplevel
347: ClassDefinition refc = refctx.field.getClassDefinition();
348: UplevelReference r = refc.getReference(target);
349: r.noteReference(env, refctx);
350:
351: // remember the reference pertaining to the innermost frame
352: if (res == null) {
353: res = r;
354: }
355: }
356: return res;
357: }
358:
359: /**
360: * Implement a reference (usually an uplevel one).
361: * Call noteReference() first, to make sure the reference
362: * lists are up to date.
363: * <p>
364: * The resulting expression tree does not need checking;
365: * it can be code-generated right away.
366: * If the reference is not uplevel, the result is an IDENT or THIS.
367: */
368: public Expression makeReference(Environment env, LocalMember target) {
369: UplevelReference r = noteReference(env, target);
370:
371: // Now create a referencing expression.
372: if (r != null) {
373: return r.makeLocalReference(env, this );
374: } else if (idThis.equals(target.getName())) {
375: return new ThisExpression(0, target);
376: } else {
377: return new IdentifierExpression(0, target);
378: }
379: }
380:
381: /**
382: * Return a local expression which can serve as the base reference
383: * for the given field. If the field is a constructor, return an
384: * expression for the implicit enclosing instance argument.
385: * <p>
386: * Return null if there is no need for such an argument,
387: * or if there was an error.
388: */
389: public Expression findOuterLink(Environment env, long where,
390: MemberDefinition f) {
391: // reqc is the base pointer type required to use f
392: ClassDefinition fc = f.getClassDefinition();
393: ClassDefinition reqc = f.isStatic() ? null
394: : !f.isConstructor() ? fc : fc.isTopLevel() ? null : fc
395: .getOuterClass();
396: if (reqc == null) {
397: return null;
398: }
399: return findOuterLink(env, where, reqc, f, false);
400: }
401:
402: private static boolean match(Environment env,
403: ClassDefinition this c, ClassDefinition reqc) {
404: try {
405: return this c == reqc
406: || reqc.implementedBy(env, this c
407: .getClassDeclaration());
408: } catch (ClassNotFound ee) {
409: return false;
410: }
411: }
412:
413: public Expression findOuterLink(Environment env, long where,
414: ClassDefinition reqc, MemberDefinition f,
415: boolean needExactMatch) {
416: if (field.isStatic()) {
417: if (f == null) {
418: // say something like: undefined variable A.this
419: Identifier nm = reqc.getName().getFlatName().getName();
420: env.error(where, "undef.var", Identifier.lookup(nm,
421: idThis));
422: } else if (f.isConstructor()) {
423: env.error(where, "no.outer.arg", reqc, f
424: .getClassDeclaration());
425: } else if (f.isMethod()) {
426: env.error(where, "no.static.meth.access", f, f
427: .getClassDeclaration());
428: } else {
429: env.error(where, "no.static.field.access", f.getName(),
430: f.getClassDeclaration());
431: }
432: // This is an attempt at error recovery.
433: // Unfortunately, the constructor may throw
434: // a null pointer exception after failing to resolve
435: // 'idThis'. Since an error message has already been
436: // issued previously, this exception is caught and
437: // silently ignored. Ideally, we should avoid throwing
438: // the exception.
439: Expression e = new ThisExpression(where, this );
440: e.type = reqc.getType();
441: return e;
442: }
443:
444: // use lp to scan for current instances (locals named "this")
445: LocalMember lp = locals;
446:
447: // thise is a link expression being built up
448: Expression this e = null;
449:
450: // root is the local variable (idThis) at the far left of thise
451: LocalMember root = null;
452:
453: // thisc is the class of the link expression thise
454: ClassDefinition this c = null;
455:
456: // conCls is the class of the "this", in a constructor
457: ClassDefinition conCls = null;
458: if (field.isConstructor()) {
459: conCls = field.getClassDefinition();
460: }
461:
462: if (!field.isMethod()) {
463: this c = field.getClassDefinition();
464: this e = new ThisExpression(where, this );
465: }
466:
467: while (true) {
468: if (this e == null) {
469: // start fresh from lp
470: while (lp != null && !idThis.equals(lp.getName())) {
471: lp = lp.prev;
472: }
473: if (lp == null) {
474: break;
475: }
476: this e = new ThisExpression(where, lp);
477: this c = lp.getClassDefinition();
478: root = lp;
479: lp = lp.prev;
480: }
481:
482: // Require exact class identity when called with
483: // 'needExactMatch' true. This is done when checking
484: // the '<class>.this' syntax. Fixes 4102393 and 4133457.
485: if (this c == reqc
486: || (!needExactMatch && match(env, this c, reqc))) {
487: break;
488: }
489:
490: // move out one step, if the current instance has an outer link
491:
492: MemberDefinition outerMember = this c.findOuterMember();
493: if (outerMember == null) {
494: this e = null;
495: continue; // try to find more help in lp
496: }
497: ClassDefinition prevc = this c;
498: this c = prevc.getOuterClass();
499:
500: if (prevc == conCls) {
501: // Must pick up "this$C" from the constructor argument,
502: // not from "this.this$C", since the latter may not be
503: // initialized properly. (This way is cheaper too.)
504: Identifier nm = outerMember.getName();
505: IdentifierExpression arg = new IdentifierExpression(
506: where, nm);
507: arg.bind(env, this );
508: this e = arg;
509: } else {
510: this e = new FieldExpression(where, this e, outerMember);
511: }
512: }
513: if (this e != null) {
514: // mark crossed scopes
515: // ?????
516: //ensureAvailable(root);
517: return this e;
518: }
519:
520: if (f == null) {
521: // say something like: undefined variable A.this
522: Identifier nm = reqc.getName().getFlatName().getName();
523: env
524: .error(where, "undef.var", Identifier.lookup(nm,
525: idThis));
526: } else if (f.isConstructor()) {
527: env.error(where, "no.outer.arg", reqc, f
528: .getClassDefinition());
529: } else {
530: env.error(where, "no.static.field.access", f, field);
531: }
532:
533: // avoid floodgating:
534: Expression e = new ThisExpression(where, this );
535: e.type = reqc.getType();
536: return e;
537: }
538:
539: /**
540: * Is there a "this" of type reqc in scope?
541: */
542: public static boolean outerLinkExists(Environment env,
543: ClassDefinition reqc, ClassDefinition this c) {
544: while (!match(env, this c, reqc)) {
545: if (this c.isTopLevel()) {
546: return false;
547: }
548: this c = this c.getOuterClass();
549: }
550: return true;
551: }
552:
553: /**
554: * From which enclosing class do members of this type come?
555: */
556: public ClassDefinition findScope(Environment env,
557: ClassDefinition reqc) {
558: ClassDefinition this c = field.getClassDefinition();
559: while (this c != null && !match(env, this c, reqc)) {
560: this c = this c.getOuterClass();
561: }
562: return this c;
563: }
564:
565: /**
566: * Resolve a type name from within a local scope.
567: * @see Environment#resolveName
568: */
569: Identifier resolveName(Environment env, Identifier name) {
570: // This logic is pretty much exactly parallel to that of
571: // Environment.resolveName().
572: if (name.isQualified()) {
573: // Try to resolve the first identifier component,
574: // because inner class names take precedence over
575: // package prefixes. (Cf. Environment.resolveName.)
576: Identifier rhead = resolveName(env, name.getHead());
577:
578: if (rhead.hasAmbigPrefix()) {
579: // The first identifier component refers to an
580: // ambiguous class. Limp on. We throw away the
581: // rest of the classname as it is irrelevant.
582: // (part of solution for 4059855).
583: return rhead;
584: }
585:
586: if (!env.classExists(rhead)) {
587: return env.resolvePackageQualifiedName(name);
588: }
589: try {
590: return env.getClassDefinition(rhead).resolveInnerClass(
591: env, name.getTail());
592: } catch (ClassNotFound ee) {
593: // return partially-resolved name someone else can fail on
594: return Identifier.lookupInner(rhead, name.getTail());
595: }
596: }
597:
598: // Look for an unqualified name in enclosing scopes.
599: try {
600: MemberDefinition f = getClassCommon(env, name, false);
601: if (f != null) {
602: return f.getInnerClass().getName();
603: }
604: } catch (ClassNotFound ee) {
605: // a missing superclass, or something catastrophic
606: }
607:
608: // look in imports, etc.
609: return env.resolveName(name);
610: }
611:
612: /**
613: * Return the name of a lexically apparent type,
614: * skipping inherited members, and ignoring
615: * the current pacakge and imports.
616: * This is used for error checking.
617: */
618: public Identifier getApparentClassName(Environment env,
619: Identifier name) {
620: if (name.isQualified()) {
621: // Try to resolve the first identifier component,
622: // because inner class names take precedence over
623: // package prefixes. (Cf. Environment.resolveName.)
624: Identifier rhead = getApparentClassName(env, name.getHead());
625: return (rhead == null) ? idNull : Identifier.lookup(rhead,
626: name.getTail());
627: }
628:
629: // Look for an unqualified name in enclosing scopes.
630: try {
631: MemberDefinition f = getClassCommon(env, name, true);
632: if (f != null) {
633: return f.getInnerClass().getName();
634: }
635: } catch (ClassNotFound ee) {
636: // a missing superclass, or something catastrophic
637: }
638:
639: // the enclosing class name is the only apparent package member:
640: Identifier topnm = field.getClassDefinition().getTopClass()
641: .getName();
642: if (topnm.getName().equals(name)) {
643: return topnm;
644: }
645: return idNull;
646: }
647:
648: /**
649: * Raise an error if a blank final was definitely unassigned
650: * on entry to a loop, but has possibly been assigned on the
651: * back-branch. If this is the case, the loop may be assigning
652: * it multiple times.
653: */
654: public void checkBackBranch(Environment env, Statement loop,
655: Vset vsEntry, Vset vsBack) {
656: for (LocalMember f = locals; f != null; f = f.prev) {
657: if (f.isBlankFinal() && vsEntry.testVarUnassigned(f.number)
658: && !vsBack.testVarUnassigned(f.number)) {
659: env.error(loop.where, "assign.to.blank.final.in.loop",
660: f.getName());
661: }
662: }
663: }
664:
665: /**
666: * Check if a field can reach another field (only considers
667: * forward references, not the access modifiers).
668: */
669: public boolean canReach(Environment env, MemberDefinition f) {
670: return field.canReach(env, f);
671: }
672:
673: /**
674: * Get the context that corresponds to a label, return null if
675: * not found.
676: */
677: public Context getLabelContext(Identifier lbl) {
678: for (Context ctx = this ; ctx != null; ctx = ctx.prev) {
679: if ((ctx.node != null) && (ctx.node instanceof Statement)) {
680: if (((Statement) (ctx.node)).hasLabel(lbl))
681: return ctx;
682: }
683: }
684: return null;
685: }
686:
687: /**
688: * Get the destination context of a break
689: */
690: public Context getBreakContext(Identifier lbl) {
691: if (lbl != null) {
692: return getLabelContext(lbl);
693: }
694: for (Context ctx = this ; ctx != null; ctx = ctx.prev) {
695: if (ctx.node != null) {
696: switch (ctx.node.op) {
697: case SWITCH:
698: case FOR:
699: case DO:
700: case WHILE:
701: return ctx;
702: }
703: }
704: }
705: return null;
706: }
707:
708: /**
709: * Get the destination context of a continue
710: */
711: public Context getContinueContext(Identifier lbl) {
712: if (lbl != null) {
713: return getLabelContext(lbl);
714: }
715: for (Context ctx = this ; ctx != null; ctx = ctx.prev) {
716: if (ctx.node != null) {
717: switch (ctx.node.op) {
718: case FOR:
719: case DO:
720: case WHILE:
721: return ctx;
722: }
723: }
724: }
725: return null;
726: }
727:
728: /**
729: * Get the destination context of a return (the method body)
730: */
731: public CheckContext getReturnContext() {
732: for (Context ctx = this ; ctx != null; ctx = ctx.prev) {
733: // The METHOD node is set up by Statement.checkMethod().
734: if (ctx.node != null && ctx.node.op == METHOD) {
735: return (CheckContext) ctx;
736: }
737: }
738: return null;
739: }
740:
741: /**
742: * Get the context of the innermost surrounding try-block.
743: * Consider only try-blocks contained within the same method.
744: * (There could be others when searching from within a method
745: * of a local class, but they are irrelevant to our purpose.)
746: * This is used for recording DA/DU information preceding
747: * all abnormal transfers of control: break, continue, return,
748: * and throw.
749: */
750: public CheckContext getTryExitContext() {
751: for (Context ctx = this ; ctx != null && ctx.node != null
752: && ctx.node.op != METHOD; ctx = ctx.prev) {
753: if (ctx.node.op == TRY) {
754: return (CheckContext) ctx;
755: }
756: }
757: return null;
758: }
759:
760: /**
761: * Get the nearest inlined context
762: */
763: Context getInlineContext() {
764: for (Context ctx = this ; ctx != null; ctx = ctx.prev) {
765: if (ctx.node != null) {
766: switch (ctx.node.op) {
767: case INLINEMETHOD:
768: case INLINENEWINSTANCE:
769: return ctx;
770: }
771: }
772: }
773: return null;
774: }
775:
776: /**
777: * Get the context of a field that is being inlined
778: */
779: Context getInlineMemberContext(MemberDefinition field) {
780: for (Context ctx = this ; ctx != null; ctx = ctx.prev) {
781: if (ctx.node != null) {
782: switch (ctx.node.op) {
783: case INLINEMETHOD:
784: if (((InlineMethodExpression) ctx.node).field
785: .equals(field)) {
786: return ctx;
787: }
788: break;
789: case INLINENEWINSTANCE:
790: if (((InlineNewInstanceExpression) ctx.node).field
791: .equals(field)) {
792: return ctx;
793: }
794: }
795: }
796: }
797: return null;
798: }
799:
800: /**
801: * Remove variables from the vset set that are no longer part of
802: * this context.
803: */
804: public final Vset removeAdditionalVars(Vset vset) {
805: return vset.removeAdditionalVars(varNumber);
806: }
807:
808: public final int getVarNumber() {
809: return varNumber;
810: }
811:
812: /**
813: * Return the number of the innermost current instance reference.
814: */
815: public int getThisNumber() {
816: LocalMember this f = getLocalField(idThis);
817: if (this f != null
818: && this f.getClassDefinition() == field
819: .getClassDefinition()) {
820: return this f.number;
821: }
822: // this is a variable; there is no "this" (should not happen)
823: return varNumber;
824: }
825:
826: /**
827: * Return the field containing the present context.
828: */
829: public final MemberDefinition getField() {
830: return field;
831: }
832:
833: /**
834: * Extend an environment with the given context.
835: * The resulting environment behaves the same as
836: * the given one, except that resolveName() takes
837: * into account local class names in this context.
838: */
839: public static Environment newEnvironment(Environment env,
840: Context ctx) {
841: return new ContextEnvironment(env, ctx);
842: }
843: }
844:
845: final class ContextEnvironment extends Environment {
846: Context ctx;
847: Environment innerEnv;
848:
849: ContextEnvironment(Environment env, Context ctx) {
850: super (env, env.getSource());
851: this .ctx = ctx;
852: this .innerEnv = env;
853: }
854:
855: public Identifier resolveName(Identifier name) {
856: return ctx.resolveName(innerEnv, name);
857: }
858: }
|