/* * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.tree; import sun.tools.java.*;import sun.tools.asm.Assembler; /** * WARNING: The contents of this source file are not part of any * supported API. Code that depends on them does so at its own risk: * they are subject to change or removal without notice. */publicclass Context implements Constants { Context prev; Node node; int varNumber; LocalMember locals; LocalMember classes; MemberDefinition field; int scopeNumber; int frameNumber; /** * Create the initial context for a method * The incoming context is inherited from */ public Context(Context ctx, MemberDefinition field) { this.field = field; if (ctx == null) { this.frameNumber = 1; this.scopeNumber = 2; this.varNumber = 0; } else { this.prev = ctx; this.locals = ctx.locals; this.classes = ctx.classes; if (field != null && (field.isVariable() || field.isInitializer())) { // Variables and initializers are inlined into a constructor. // Model this by inheriting the frame number of the parent, // which will contain a "this" parameter. this.frameNumber = ctx.frameNumber; this.scopeNumber = ctx.scopeNumber + 1; } else { this.frameNumber = ctx.scopeNumber + 1; this.scopeNumber = this.frameNumber + 1; } this.varNumber = ctx.varNumber; } } /** * Create a new context, for initializing a class. */ public Context(Context ctx, ClassDefinition c) { this(ctx, (MemberDefinition)null); } /** * Create a new nested context, for a block statement */ Context(Context ctx, Node node) { if (ctx == null) { this.frameNumber = 1; this.scopeNumber = 2; this.varNumber = 0; } else { this.prev = ctx; this.locals = ctx.locals; // Inherit local classes from surrounding block, // just as for local variables. Fixes 4074421. this.classes = ctx.classes; this.varNumber = ctx.varNumber; this.field = ctx.field; this.frameNumber = ctx.frameNumber; this.scopeNumber = ctx.scopeNumber + 1; this.node = node; } } public Context(Context ctx) { this(ctx, (Node)null); } /** * Declare local */ public int declare(Environment env, LocalMember local) { //System.out.println( "DECLARE= " + local.getName() + "=" + varNumber + ", read=" + local.readcount + ", write=" + local.writecount + ", hash=" + local.hashCode()); local.scopeNumber = scopeNumber; if (this.field == null && idThis.equals(local.getName())) { local.scopeNumber += 1; // Anticipate variable or initializer. } if (local.isInnerClass()) { local.prev = classes; classes = local; return 0; } // Originally the statement: // // local.subModifiers(M_INLINEABLE); // // was here with the comment: // // // prevent inlining across call sites // // This statement prevented constant local variables from // inlining. It didn't seem to do anything useful. // // The statement has been removed and an assertion has been // added which mandates that the only members which are marked // with M_INLINEABLE are the ones for which isConstant() is true. // (Fix for 4106244.) // // Addition to the above comment: they might also be // final variables initialized with 'this', 'super', or other // final identifiers. See VarDeclarationStatement.inline(). // So I've removed the assertion. The original subModifiers // call appears to have been there to fix nested class translation // breakage, which has been fixed in VarDeclarationStatement // now instead. (Fix for 4073244.) local.prev = locals; locals = local; local.number = varNumber; varNumber += local.getType().stackSize(); return local.number; } /** * Get a local variable by name */ public LocalMember getLocalField(Identifier name) { for (LocalMember f = locals ; f != null ; f = f.prev) { if (name.equals(f.getName())) { return f; } } return null; } /** * Get the scope number for a reference to a member of this class * (Larger scope numbers are more deeply nested.) * @see LocalMember#scopeNumber */ public int getScopeNumber(ClassDefinition c) { for (Context ctx = this; ctx != null; ctx = ctx.prev) { if (ctx.field == null) continue; if (ctx.field.getClassDefinition() == c) { return ctx.frameNumber; } } return -1; } private MemberDefinition getFieldCommon(Environment env, Identifier name, boolean apparentOnly) throws AmbiguousMember, ClassNotFound { // Note: This is structured as a pair of parallel lookups. // If we were to redesign Context, we might prefer to walk // along a single chain of scopes. LocalMember lf = getLocalField(name); int ls = (lf == null) ? -2 : lf.scopeNumber; ClassDefinition thisClass = field.getClassDefinition(); // Also look for a class member in a shallower scope. for (ClassDefinition c = thisClass; c != null; c = c.getOuterClass()) { MemberDefinition f = c.getVariable(env, name, thisClass); if (f != null && getScopeNumber(c) > ls) { if (apparentOnly && f.getClassDefinition() != c) { continue; } return f; } } return lf; } /** * Assign a number to a class field. * (This is used to track definite assignment of some blank finals.) */ public int declareFieldNumber(MemberDefinition field) { return declare(null, new LocalMember(field)); } /** * Retrieve a number previously assigned by declareMember(). * Return -1 if there was no such assignment in this context. */ public int getFieldNumber(MemberDefinition field) { for (LocalMember f = locals ; f != null ; f = f.prev) { if (f.getMember() == field) { return f.number; } } return -1; } /** * Return the local field or member field corresponding to a number. * Return null if there is no such field. */ public MemberDefinition getElement(int number) { for (LocalMember f = locals ; f != null ; f = f.prev) { if (f.number == number) { MemberDefinition field = f.getMember(); return (field != null) ? field : f; } } return null; } /** * Get a local class by name */ public LocalMember getLocalClass(Identifier name) { for (LocalMember f = classes ; f != null ; f = f.prev) { if (name.equals(f.getName())) { return f; } } return null; } private MemberDefinition getClassCommon(Environment env, Identifier name, boolean apparentOnly) throws ClassNotFound { LocalMember lf = getLocalClass(name); int ls = (lf == null) ? -2 : lf.scopeNumber; // Also look for a class member in a shallower scope. for (ClassDefinition c = field.getClassDefinition(); c != null; c = c.getOuterClass()) { // QUERY: We may need to get the inner class from a // superclass of 'c'. This call is prepared to // resolve the superclass if necessary. Can we arrange // to assure that it is always previously resolved? // This is one of a small number of problematic calls that // requires 'getSuperClass' to resolve superclasses on demand. // See 'ClassDefinition.getInnerClass(env, nm)'. MemberDefinition f = c.getInnerClass(env, name); if (f != null && getScopeNumber(c) > ls) { if (apparentOnly && f.getClassDefinition() != c) { continue; } return f; } } return lf; } /** * Get either a local variable, or a field in a current class */ public final MemberDefinition getField(Environment env, Identifier name) throws AmbiguousMember, ClassNotFound { return getFieldCommon(env, name, false); } /** * Like getField, except that it skips over inherited fields. * Used for error checking. */ public final MemberDefinition getApparentField(Environment env, Identifier name) throws AmbiguousMember, ClassNotFound { return getFieldCommon(env, name, true); } /** * Check if the given field is active in this context. */ public boolean isInScope(LocalMember field) { for (LocalMember f = locals ; f != null ; f = f.prev) { if (field == f) { return true; } } return false; } /** * Notice a reference (usually an uplevel one). * Update the references list of every enclosing class * which is enclosed by the scope of the target. * Update decisions about which uplevels to make into fields. * Return the uplevel reference descriptor, or null if it's local. * <p> * The target must be in scope in this context. * So, call this method only from the check phase. * (In other phases, the context may be less complete.) * <p> * This can and should be called both before and after classes are frozen. * It should be a no-op, and will raise a compiler error if not. */ public UplevelReference noteReference(Environment env, LocalMember target) { int targetScopeNumber = !isInScope(target) ? -1 : target.scopeNumber; // Walk outward visiting each scope. // Note each distinct frame (i.e., enclosing method). // For each frame in which the variable is uplevel, // record the event in the references list of the enclosing class. UplevelReference res = null; int currentFrameNumber = -1; for (Context refctx = this; refctx != null; refctx = refctx.prev) { if (currentFrameNumber == refctx.frameNumber) { continue; // we're processing frames, not contexts } currentFrameNumber = refctx.frameNumber; if (targetScopeNumber >= currentFrameNumber) { break; // the target is native to this frame } // process a frame which is using this variable as an uplevel ClassDefinition refc = refctx.field.getClassDefinition(); UplevelReference r = refc.getReference(target); r.noteReference(env, refctx); // remember the reference pertaining to the innermost frame if (res == null) { res = r; } } return res; } /** * Implement a reference (usually an uplevel one). * Call noteReference() first, to make sure the reference * lists are up to date. * <p> * The resulting expression tree does not need checking; * it can be code-generated right away. * If the reference is not uplevel, the result is an IDENT or THIS. */ public Expression makeReference(Environment env, LocalMember target) { UplevelReference r = noteReference(env, target); // Now create a referencing expression. if (r != null) { return r.makeLocalReference(env, this); } else if (idThis.equals(target.getName())) { return new ThisExpression(0, target); } else { return new IdentifierExpression(0, target); } } /** * Return a local expression which can serve as the base reference * for the given field. If the field is a constructor, return an * expression for the implicit enclosing instance argument. * <p> * Return null if there is no need for such an argument, * or if there was an error. */ public Expression findOuterLink(Environment env, long where, MemberDefinition f) { // reqc is the base pointer type required to use f ClassDefinition fc = f.getClassDefinition(); ClassDefinition reqc = f.isStatic() ? null : !f.isConstructor() ? fc : fc.isTopLevel() ? null : fc.getOuterClass(); if (reqc == null) { return null; } return findOuterLink(env, where, reqc, f, false); } private static boolean match(Environment env, ClassDefinition thisc, ClassDefinition reqc) { try { return thisc == reqc || reqc.implementedBy(env, thisc.getClassDeclaration()); } catch (ClassNotFound ee) { return false; } } public Expression findOuterLink(Environment env, long where, ClassDefinition reqc, MemberDefinition f, boolean needExactMatch) { if (field.isStatic()) { if (f == null) { // say something like: undefined variable A.this Identifier nm = reqc.getName().getFlatName().getName(); env.error(where, "undef.var", Identifier.lookup(nm,idThis)); } else if (f.isConstructor()) { env.error(where, "no.outer.arg", reqc, f.getClassDeclaration()); } else if (f.isMethod()) { env.error(where, "no.static.meth.access", f, f.getClassDeclaration()); } else { env.error(where, "no.static.field.access", f.getName(), f.getClassDeclaration()); } // This is an attempt at error recovery. // Unfortunately, the constructor may throw // a null pointer exception after failing to resolve // 'idThis'. Since an error message has already been // issued previously, this exception is caught and // silently ignored. Ideally, we should avoid throwing // the exception. Expression e = new ThisExpression(where, this); e.type = reqc.getType(); return e; } // use lp to scan for current instances (locals named "this") LocalMember lp = locals; // thise is a link expression being built up Expression thise = null; // root is the local variable (idThis) at the far left of thise LocalMember root = null; // thisc is the class of the link expression thise ClassDefinition thisc = null; // conCls is the class of the "this", in a constructor ClassDefinition conCls = null; if (field.isConstructor()) { conCls = field.getClassDefinition(); } if (!field.isMethod()) { thisc = field.getClassDefinition(); thise = new ThisExpression(where, this); } while (true) { if (thise == null) { // start fresh from lp while (lp != null && !idThis.equals(lp.getName())) { lp = lp.prev; } if (lp == null) { break; } thise = new ThisExpression(where, lp); thisc = lp.getClassDefinition(); root = lp; lp = lp.prev; } // Require exact class identity when called with // 'needExactMatch' true. This is done when checking // the '<class>.this' syntax. Fixes 4102393 and 4133457. if (thisc == reqc || (!needExactMatch && match(env, thisc, reqc))) { break; } // move out one step, if the current instance has an outer link MemberDefinition outerMember = thisc.findOuterMember(); if (outerMember == null) { thise = null; continue; // try to find more help in lp } ClassDefinition prevc = thisc;Lines 1–500 of 861. Load more
/* * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.tools.tree; import sun.tools.java.*; import sun.tools.asm.Assembler; /** * WARNING: The contents of this source file are not part of any * supported API. Code that depends on them does so at its own risk: * they are subject to change or removal without notice. */ public class Context implements Constants { Context prev; Node node; int varNumber; LocalMember locals; LocalMember classes; MemberDefinition field; int scopeNumber; int frameNumber; /** * Create the initial context for a method * The incoming context is inherited from */ public Context(Context ctx, MemberDefinition field) { this.field = field; if (ctx == null) { this.frameNumber = 1; this.scopeNumber = 2; this.varNumber = 0; } else { this.prev = ctx; this.locals = ctx.locals; this.classes = ctx.classes; if (field != null && (field.isVariable() || field.isInitializer())) { // Variables and initializers are inlined into a constructor. // Model this by inheriting the frame number of the parent, // which will contain a "this" parameter. this.frameNumber = ctx.frameNumber; this.scopeNumber = ctx.scopeNumber + 1; } else { this.frameNumber = ctx.scopeNumber + 1; this.scopeNumber = this.frameNumber + 1; } this.varNumber = ctx.varNumber; } } /** * Create a new context, for initializing a class. */ public Context(Context ctx, ClassDefinition c) { this(ctx, (MemberDefinition)null); } /** * Create a new nested context, for a block statement */ Context(Context ctx, Node node) { if (ctx == null) { this.frameNumber = 1; this.scopeNumber = 2; this.varNumber = 0; } else { this.prev = ctx; this.locals = ctx.locals; // Inherit local classes from surrounding block, // just as for local variables. Fixes 4074421. this.classes = ctx.classes; this.varNumber = ctx.varNumber; this.field = ctx.field; this.frameNumber = ctx.frameNumber; this.scopeNumber = ctx.scopeNumber + 1; this.node = node; } } public Context(Context ctx) { this(ctx, (Node)null); } /** * Declare local */ public int declare(Environment env, LocalMember local) { //System.out.println( "DECLARE= " + local.getName() + "=" + varNumber + ", read=" + local.readcount + ", write=" + local.writecount + ", hash=" + local.hashCode()); local.scopeNumber = scopeNumber; if (this.field == null && idThis.equals(local.getName())) { local.scopeNumber += 1; // Anticipate variable or initializer. } if (local.isInnerClass()) { local.prev = classes; classes = local; return 0; } // Originally the statement: // // local.subModifiers(M_INLINEABLE); // // was here with the comment: // // // prevent inlining across call sites // // This statement prevented constant local variables from // inlining. It didn't seem to do anything useful. // // The statement has been removed and an assertion has been // added which mandates that the only members which are marked // with M_INLINEABLE are the ones for which isConstant() is true. // (Fix for 4106244.) // // Addition to the above comment: they might also be // final variables initialized with 'this', 'super', or other // final identifiers. See VarDeclarationStatement.inline(). // So I've removed the assertion. The original subModifiers // call appears to have been there to fix nested class translation // breakage, which has been fixed in VarDeclarationStatement // now instead. (Fix for 4073244.) local.prev = locals; locals = local; local.number = varNumber; varNumber += local.getType().stackSize(); return local.number; } /** * Get a local variable by name */ public LocalMember getLocalField(Identifier name) { for (LocalMember f = locals ; f != null ; f = f.prev) { if (name.equals(f.getName())) { return f; } } return null; } /** * Get the scope number for a reference to a member of this class * (Larger scope numbers are more deeply nested.) * @see LocalMember#scopeNumber */ public int getScopeNumber(ClassDefinition c) { for (Context ctx = this; ctx != null; ctx = ctx.prev) { if (ctx.field == null) continue; if (ctx.field.getClassDefinition() == c) { return ctx.frameNumber; } } return -1; } private MemberDefinition getFieldCommon(Environment env, Identifier name, boolean apparentOnly) throws AmbiguousMember, ClassNotFound { // Note: This is structured as a pair of parallel lookups. // If we were to redesign Context, we might prefer to walk // along a single chain of scopes. LocalMember lf = getLocalField(name); int ls = (lf == null) ? -2 : lf.scopeNumber; ClassDefinition thisClass = field.getClassDefinition(); // Also look for a class member in a shallower scope. for (ClassDefinition c = thisClass; c != null; c = c.getOuterClass()) { MemberDefinition f = c.getVariable(env, name, thisClass); if (f != null && getScopeNumber(c) > ls) { if (apparentOnly && f.getClassDefinition() != c) { continue; } return f; } } return lf; } /** * Assign a number to a class field. * (This is used to track definite assignment of some blank finals.) */ public int declareFieldNumber(MemberDefinition field) { return declare(null, new LocalMember(field)); } /** * Retrieve a number previously assigned by declareMember(). * Return -1 if there was no such assignment in this context. */ public int getFieldNumber(MemberDefinition field) { for (LocalMember f = locals ; f != null ; f = f.prev) { if (f.getMember() == field) { return f.number; } } return -1; } /** * Return the local field or member field corresponding to a number. * Return null if there is no such field. */ public MemberDefinition getElement(int number) { for (LocalMember f = locals ; f != null ; f = f.prev) { if (f.number == number) { MemberDefinition field = f.getMember(); return (field != null) ? field : f; } } return null; } /** * Get a local class by name */ public LocalMember getLocalClass(Identifier name) { for (LocalMember f = classes ; f != null ; f = f.prev) { if (name.equals(f.getName())) { return f; } } return null; } private MemberDefinition getClassCommon(Environment env, Identifier name, boolean apparentOnly) throws ClassNotFound { LocalMember lf = getLocalClass(name); int ls = (lf == null) ? -2 : lf.scopeNumber; // Also look for a class member in a shallower scope. for (ClassDefinition c = field.getClassDefinition(); c != null; c = c.getOuterClass()) { // QUERY: We may need to get the inner class from a // superclass of 'c'. This call is prepared to // resolve the superclass if necessary. Can we arrange // to assure that it is always previously resolved? // This is one of a small number of problematic calls that // requires 'getSuperClass' to resolve superclasses on demand. // See 'ClassDefinition.getInnerClass(env, nm)'. MemberDefinition f = c.getInnerClass(env, name); if (f != null && getScopeNumber(c) > ls) { if (apparentOnly && f.getClassDefinition() != c) { continue; } return f; } } return lf; } /** * Get either a local variable, or a field in a current class */ public final MemberDefinition getField(Environment env, Identifier name) throws AmbiguousMember, ClassNotFound { return getFieldCommon(env, name, false); } /** * Like getField, except that it skips over inherited fields. * Used for error checking. */ public final MemberDefinition getApparentField(Environment env, Identifier name) throws AmbiguousMember, ClassNotFound { return getFieldCommon(env, name, true); } /** * Check if the given field is active in this context. */ public boolean isInScope(LocalMember field) { for (LocalMember f = locals ; f != null ; f = f.prev) { if (field == f) { return true; } } return false; } /** * Notice a reference (usually an uplevel one). * Update the references list of every enclosing class * which is enclosed by the scope of the target. * Update decisions about which uplevels to make into fields. * Return the uplevel reference descriptor, or null if it's local. * <p> * The target must be in scope in this context. * So, call this method only from the check phase. * (In other phases, the context may be less complete.) * <p> * This can and should be called both before and after classes are frozen. * It should be a no-op, and will raise a compiler error if not. */ public UplevelReference noteReference(Environment env, LocalMember target) { int targetScopeNumber = !isInScope(target) ? -1 : target.scopeNumber; // Walk outward visiting each scope. // Note each distinct frame (i.e., enclosing method). // For each frame in which the variable is uplevel, // record the event in the references list of the enclosing class. UplevelReference res = null; int currentFrameNumber = -1; for (Context refctx = this; refctx != null; refctx = refctx.prev) { if (currentFrameNumber == refctx.frameNumber) { continue; // we're processing frames, not contexts } currentFrameNumber = refctx.frameNumber; if (targetScopeNumber >= currentFrameNumber) { break; // the target is native to this frame } // process a frame which is using this variable as an uplevel ClassDefinition refc = refctx.field.getClassDefinition(); UplevelReference r = refc.getReference(target); r.noteReference(env, refctx); // remember the reference pertaining to the innermost frame if (res == null) { res = r; } } return res; } /** * Implement a reference (usually an uplevel one). * Call noteReference() first, to make sure the reference * lists are up to date. * <p> * The resulting expression tree does not need checking; * it can be code-generated right away. * If the reference is not uplevel, the result is an IDENT or THIS. */ public Expression makeReference(Environment env, LocalMember target) { UplevelReference r = noteReference(env, target); // Now create a referencing expression. if (r != null) { return r.makeLocalReference(env, this); } else if (idThis.equals(target.getName())) { return new ThisExpression(0, target); } else { return new IdentifierExpression(0, target); } } /** * Return a local expression which can serve as the base reference * for the given field. If the field is a constructor, return an * expression for the implicit enclosing instance argument. * <p> * Return null if there is no need for such an argument, * or if there was an error. */ public Expression findOuterLink(Environment env, long where, MemberDefinition f) { // reqc is the base pointer type required to use f ClassDefinition fc = f.getClassDefinition(); ClassDefinition reqc = f.isStatic() ? null : !f.isConstructor() ? fc : fc.isTopLevel() ? null : fc.getOuterClass(); if (reqc == null) { return null; } return findOuterLink(env, where, reqc, f, false); } private static boolean match(Environment env, ClassDefinition thisc, ClassDefinition reqc) { try { return thisc == reqc || reqc.implementedBy(env, thisc.getClassDeclaration()); } catch (ClassNotFound ee) { return false; } } public Expression findOuterLink(Environment env, long where, ClassDefinition reqc, MemberDefinition f, boolean needExactMatch) { if (field.isStatic()) { if (f == null) { // say something like: undefined variable A.this Identifier nm = reqc.getName().getFlatName().getName(); env.error(where, "undef.var", Identifier.lookup(nm,idThis)); } else if (f.isConstructor()) { env.error(where, "no.outer.arg", reqc, f.getClassDeclaration()); } else if (f.isMethod()) { env.error(where, "no.static.meth.access", f, f.getClassDeclaration()); } else { env.error(where, "no.static.field.access", f.getName(), f.getClassDeclaration()); } // This is an attempt at error recovery. // Unfortunately, the constructor may throw // a null pointer exception after failing to resolve // 'idThis'. Since an error message has already been // issued previously, this exception is caught and // silently ignored. Ideally, we should avoid throwing // the exception. Expression e = new ThisExpression(where, this); e.type = reqc.getType(); return e; } // use lp to scan for current instances (locals named "this") LocalMember lp = locals; // thise is a link expression being built up Expression thise = null; // root is the local variable (idThis) at the far left of thise LocalMember root = null; // thisc is the class of the link expression thise ClassDefinition thisc = null; // conCls is the class of the "this", in a constructor ClassDefinition conCls = null; if (field.isConstructor()) { conCls = field.getClassDefinition(); } if (!field.isMethod()) { thisc = field.getClassDefinition(); thise = new ThisExpression(where, this); } while (true) { if (thise == null) { // start fresh from lp while (lp != null && !idThis.equals(lp.getName())) { lp = lp.prev; } if (lp == null) { break; } thise = new ThisExpression(where, lp); thisc = lp.getClassDefinition(); root = lp; lp = lp.prev; } // Require exact class identity when called with // 'needExactMatch' true. This is done when checking // the '<class>.this' syntax. Fixes 4102393 and 4133457. if (thisc == reqc || (!needExactMatch && match(env, thisc, reqc))) { break; } // move out one step, if the current instance has an outer link MemberDefinition outerMember = thisc.findOuterMember(); if (outerMember == null) { thise = null; continue; // try to find more help in lp } ClassDefinition prevc = thisc;