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+
26+package sun.tools.tree;
27+
28+import sun.tools.java.*;
29+import 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+ */
36+public
37+class 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+
847+final
848+class 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+}