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/Context.java (1 of 18352 files). Show all

Unified · Split

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