Scope.java revision 3563:45241cff9d3a
156893Sfenner/* 256893Sfenner * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. 356893Sfenner * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 456893Sfenner * 556893Sfenner * This code is free software; you can redistribute it and/or modify it 656893Sfenner * under the terms of the GNU General Public License version 2 only, as 756893Sfenner * published by the Free Software Foundation. Oracle designates this 856893Sfenner * particular file as subject to the "Classpath" exception as provided 956893Sfenner * by Oracle in the LICENSE file that accompanied this code. 1056893Sfenner * 1156893Sfenner * This code is distributed in the hope that it will be useful, but WITHOUT 1256893Sfenner * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1356893Sfenner * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1456893Sfenner * version 2 for more details (a copy is included in the LICENSE file that 1556893Sfenner * accompanied this code). 1656893Sfenner * 1756893Sfenner * You should have received a copy of the GNU General Public License version 1856893Sfenner * 2 along with this work; if not, write to the Free Software Foundation, 1956893Sfenner * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2056893Sfenner * 2156893Sfenner * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2256893Sfenner * or visit www.oracle.com if you need additional information or have any 23127668Sbms * questions. 24147899Ssam */ 2556893Sfenner 2656893Sfennerpackage com.sun.tools.javac.code; 2756893Sfenner 2856893Sfennerimport com.sun.tools.javac.code.Kinds.Kind; 2956893Sfennerimport java.lang.ref.WeakReference; 3056893Sfennerimport java.util.*; 3156893Sfennerimport java.util.function.BiConsumer; 3256893Sfennerimport java.util.stream.Stream; 33127668Sbmsimport java.util.stream.StreamSupport; 3456893Sfenner 3556893Sfennerimport com.sun.tools.javac.code.Symbol.CompletionFailure; 3698524Sfennerimport com.sun.tools.javac.code.Symbol.TypeSymbol; 3756893Sfennerimport com.sun.tools.javac.tree.JCTree.JCImport; 38147899Ssamimport com.sun.tools.javac.util.*; 39147899Ssamimport com.sun.tools.javac.util.List; 40147899Ssam 41147899Ssamimport static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; 4275115Sfennerimport static com.sun.tools.javac.code.Scope.LookupKind.RECURSIVE; 4375115Sfenner 44127668Sbms/** A scope represents an area of visibility in a Java program. The 4556893Sfenner * Scope class is a container for symbols which provides 4675115Sfenner * efficient access to symbols given their names. Scopes are implemented 4775115Sfenner * as hash tables with "open addressing" and "double hashing". 4875115Sfenner * Scopes can be nested. Nested scopes can share their hash tables. 4998524Sfenner * 5098524Sfenner * <p><b>This is NOT part of any supported API. 5198524Sfenner * If you write code that depends on this, you do so at your own risk. 52127668Sbms * This code and its internal interfaces are subject to change or 53127668Sbms * deletion without notice.</b> 54146773Ssam */ 55146773Ssampublic abstract class Scope { 56127668Sbms 5775115Sfenner /** The scope's owner. 58127668Sbms */ 59127668Sbms public final Symbol owner; 6056893Sfenner 6175115Sfenner protected Scope(Symbol owner) { 6275115Sfenner this.owner = owner; 6375115Sfenner } 6475115Sfenner 65146773Ssam /**Returns all Symbols in this Scope. Symbols from outward Scopes are included. 66146773Ssam */ 67146773Ssam public final Iterable<Symbol> getSymbols() { 68146773Ssam return getSymbols(noFilter); 69146773Ssam } 70146773Ssam 71146773Ssam /**Returns Symbols that match the given filter. Symbols from outward Scopes are included. 72147899Ssam */ 73147899Ssam public final Iterable<Symbol> getSymbols(Filter<Symbol> sf) { 74147899Ssam return getSymbols(sf, RECURSIVE); 75147899Ssam } 76146773Ssam 77146773Ssam /**Returns all Symbols in this Scope. Symbols from outward Scopes are included 78146773Ssam * iff lookupKind == RECURSIVE. 79146773Ssam */ 80146773Ssam public final Iterable<Symbol> getSymbols(LookupKind lookupKind) { 81146773Ssam return getSymbols(noFilter, lookupKind); 82146773Ssam } 83147899Ssam 84146773Ssam /**Returns Symbols that match the given filter. Symbols from outward Scopes are included 85146773Ssam * iff lookupKind == RECURSIVE. 86146773Ssam */ 87146773Ssam public abstract Iterable<Symbol> getSymbols(Filter<Symbol> sf, LookupKind lookupKind); 88146773Ssam 89146773Ssam /**Returns Symbols with the given name. Symbols from outward Scopes are included. 90146773Ssam */ 91146773Ssam public final Iterable<Symbol> getSymbolsByName(Name name) { 92146773Ssam return getSymbolsByName(name, RECURSIVE); 93146773Ssam } 94146773Ssam 95146773Ssam /**Returns Symbols with the given name that match the given filter. 96146773Ssam * Symbols from outward Scopes are included. 97146773Ssam */ 98146773Ssam public final Iterable<Symbol> getSymbolsByName(final Name name, final Filter<Symbol> sf) { 99146773Ssam return getSymbolsByName(name, sf, RECURSIVE); 100146773Ssam } 101146773Ssam 102146773Ssam /**Returns Symbols with the given name. Symbols from outward Scopes are included 103146773Ssam * iff lookupKind == RECURSIVE. 104146773Ssam */ 105146773Ssam public final Iterable<Symbol> getSymbolsByName(Name name, LookupKind lookupKind) { 106146773Ssam return getSymbolsByName(name, noFilter, lookupKind); 107146773Ssam } 108146773Ssam 109146773Ssam /**Returns Symbols with the given name that match the given filter. 110146773Ssam * Symbols from outward Scopes are included iff lookupKind == RECURSIVE. 111146773Ssam */ 112146773Ssam public abstract Iterable<Symbol> getSymbolsByName(final Name name, final Filter<Symbol> sf, 113146773Ssam final LookupKind lookupKind); 114146773Ssam 115146773Ssam /** Return the first Symbol from this or outward scopes with the given name. 116146773Ssam * Returns null if none. 117146773Ssam */ 118146773Ssam public final Symbol findFirst(Name name) { 119146773Ssam return findFirst(name, noFilter); 120146773Ssam } 121146773Ssam 122146773Ssam /** Return the first Symbol from this or outward scopes with the given name that matches the 123146773Ssam * given filter. Returns null if none. 124146773Ssam */ 125146773Ssam public Symbol findFirst(Name name, Filter<Symbol> sf) { 126146773Ssam Iterator<Symbol> it = getSymbolsByName(name, sf).iterator(); 127146773Ssam return it.hasNext() ? it.next() : null; 128146773Ssam } 129146773Ssam 130146773Ssam /** Returns true iff there are is at least one Symbol in this scope matching the given filter. 131146773Ssam * Does not inspect outward scopes. 132146773Ssam */ 133146773Ssam public boolean anyMatch(Filter<Symbol> filter) { 134146773Ssam return getSymbols(filter, NON_RECURSIVE).iterator().hasNext(); 135146773Ssam } 136146773Ssam 137146773Ssam /** Returns true iff the given Symbol is in this scope or any outward scope. 138146773Ssam */ 139146773Ssam public boolean includes(final Symbol sym) { 140146773Ssam return getSymbolsByName(sym.name, new Filter<Symbol>() { 141146773Ssam @Override 142146773Ssam public boolean accepts(Symbol t) { 143146773Ssam return t == sym; 144146773Ssam } 145146773Ssam }).iterator().hasNext(); 146146773Ssam } 147146773Ssam 148146773Ssam /** Returns true iff this scope does not contain any Symbol. Does not inspect outward scopes. 149146773Ssam */ 150146773Ssam public boolean isEmpty() { 15198524Sfenner return !getSymbols(NON_RECURSIVE).iterator().hasNext(); 15298524Sfenner } 15398524Sfenner 15498524Sfenner /** Returns the Scope from which the givins Symbol originates in this scope. 15598524Sfenner */ 15698524Sfenner public abstract Scope getOrigin(Symbol byName); 15798524Sfenner 15898524Sfenner /** Returns true iff the given Symbol is part of this scope due to a static import. 15998524Sfenner */ 16098524Sfenner public abstract boolean isStaticallyImported(Symbol byName); 16198524Sfenner 16298524Sfenner private static final Filter<Symbol> noFilter = null; 16398524Sfenner 16498524Sfenner /** A list of scopes to be notified if items are to be removed from this scope. 16598524Sfenner */ 16698524Sfenner ScopeListenerList listeners = new ScopeListenerList(); 16798524Sfenner 16898524Sfenner public interface ScopeListener { 16998524Sfenner void symbolAdded(Symbol sym, Scope s); 17098524Sfenner void symbolRemoved(Symbol sym, Scope s); 17198524Sfenner } 17298524Sfenner 17398524Sfenner /** 17498524Sfenner * A list of scope listeners; listeners are stored in weak references, to avoid memory leaks. 17598524Sfenner * When the listener list is scanned (upon notification), elements corresponding to GC-ed 17698524Sfenner * listeners are removed so that the listener list size is kept in check. 17798524Sfenner */ 17898524Sfenner public static class ScopeListenerList { 17998524Sfenner 18098524Sfenner List<WeakReference<ScopeListener>> listeners = List.nil(); 18198524Sfenner 18298524Sfenner void add(ScopeListener sl) { 18398524Sfenner listeners = listeners.prepend(new WeakReference<>(sl)); 18498524Sfenner } 18598524Sfenner 18698524Sfenner void symbolAdded(Symbol sym, Scope scope) { 18798524Sfenner walkReferences(sym, scope, false); 18898524Sfenner } 18998524Sfenner 19098524Sfenner void symbolRemoved(Symbol sym, Scope scope) { 19198524Sfenner walkReferences(sym, scope, true); 192127668Sbms } 193127668Sbms 194127668Sbms private void walkReferences(Symbol sym, Scope scope, boolean isRemove) { 195127668Sbms ListBuffer<WeakReference<ScopeListener>> newListeners = new ListBuffer<>(); 196127668Sbms for (WeakReference<ScopeListener> wsl : listeners) { 197127668Sbms ScopeListener sl = wsl.get(); 198127668Sbms if (sl != null) { 199127668Sbms if (isRemove) { 200127668Sbms sl.symbolRemoved(sym, scope); 201127668Sbms } else { 202127668Sbms sl.symbolAdded(sym, scope); 203127668Sbms } 204127668Sbms newListeners.add(wsl); 205127668Sbms } 206127668Sbms } 207127668Sbms listeners = newListeners.toList(); 208127668Sbms } 209127668Sbms } 210127668Sbms 211127668Sbms public enum LookupKind { 212127668Sbms RECURSIVE, 213127668Sbms NON_RECURSIVE; 214127668Sbms } 215127668Sbms 216127668Sbms /**A scope into which Symbols can be added.*/ 217127668Sbms public abstract static class WriteableScope extends Scope { 218127668Sbms 219127668Sbms public WriteableScope(Symbol owner) { 220127668Sbms super(owner); 221127668Sbms } 222127668Sbms 223127668Sbms /** Enter the given Symbol into this scope. 224127668Sbms */ 225127668Sbms public abstract void enter(Symbol c); 226127668Sbms /** Enter symbol sym in this scope if not already there. 227127668Sbms */ 228127668Sbms public abstract void enterIfAbsent(Symbol c); 229127668Sbms 230127668Sbms public abstract void remove(Symbol c); 231127668Sbms 232127668Sbms /** Construct a fresh scope within this scope, with same owner. The new scope may 233127668Sbms * shares internal structures with the this scope. Used in connection with 234127668Sbms * method leave if scope access is stack-like in order to avoid allocation 23556893Sfenner * of fresh tables. 236127668Sbms */ 23756893Sfenner public final WriteableScope dup() { 23875115Sfenner return dup(this.owner); 23998524Sfenner } 24098524Sfenner 24198524Sfenner /** Construct a fresh scope within this scope, with new owner. The new scope may 24298524Sfenner * shares internal structures with the this scope. Used in connection with 24398524Sfenner * method leave if scope access is stack-like in order to avoid allocation 244127668Sbms * of fresh tables. 24556893Sfenner */ 24656893Sfenner public abstract WriteableScope dup(Symbol newOwner); 24756893Sfenner 24856893Sfenner /** Must be called on dup-ed scopes to be able to work with the outward scope again. 24975115Sfenner */ 25056893Sfenner public abstract WriteableScope leave(); 25156893Sfenner 252127668Sbms /** Construct a fresh scope within this scope, with same owner. The new scope 253127668Sbms * will not share internal structures with this scope. 254127668Sbms */ 255127668Sbms public final WriteableScope dupUnshared() { 256127668Sbms return dupUnshared(owner); 257127668Sbms } 258127668Sbms 259127668Sbms /** Construct a fresh scope within this scope, with new owner. The new scope 260127668Sbms * will not share internal structures with this scope. 261127668Sbms */ 262127668Sbms public abstract WriteableScope dupUnshared(Symbol newOwner); 263127668Sbms 264127668Sbms /** Create a new WriteableScope. 265127668Sbms */ 266146773Ssam public static WriteableScope create(Symbol owner) { 267146773Ssam return new ScopeImpl(owner); 268146773Ssam } 269146773Ssam 270146773Ssam } 271146773Ssam 272146773Ssam private static class ScopeImpl extends WriteableScope { 273146773Ssam /** The number of scopes that share this scope's hash table. 274146773Ssam */ 275146773Ssam private int shared; 276146773Ssam 277146773Ssam /** Next enclosing scope (with whom this scope may share a hashtable) 278146773Ssam */ 27975115Sfenner public ScopeImpl next; 28056893Sfenner 28156893Sfenner /** A hash table for the scope's entries. 282146773Ssam */ 28356893Sfenner Entry[] table; 284146773Ssam 285146773Ssam /** Mask for hash codes, always equal to (table.length - 1). 28656893Sfenner */ 287146773Ssam int hashMask; 288146773Ssam 289146773Ssam /** A linear list that also contains all entries in 29056893Sfenner * reverse order of appearance (i.e later entries are pushed on top). 291146773Ssam */ 29256893Sfenner public Entry elems; 29356893Sfenner 29456893Sfenner /** The number of elements in this scope. 29556893Sfenner * This includes deleted elements, whose value is the sentinel. 29675115Sfenner */ 29775115Sfenner int nelems = 0; 29875115Sfenner 29975115Sfenner int removeCount = 0; 300127668Sbms 30175115Sfenner /** Use as a "not-found" result for lookup. 30256893Sfenner * Also used to mark deleted entries in the table. 303146773Ssam */ 30456893Sfenner private static final Entry sentinel = new Entry(null, null, null, null); 30556893Sfenner 30656893Sfenner /** The hash table's initial size. 30756893Sfenner */ 308146773Ssam private static final int INITIAL_SIZE = 0x10; 30956893Sfenner 31056893Sfenner /** Construct a new scope, within scope next, with given owner, using 31156893Sfenner * given table. The table's length must be an exponent of 2. 31256893Sfenner */ 313146773Ssam private ScopeImpl(ScopeImpl next, Symbol owner, Entry[] table) { 31456893Sfenner super(owner); 31556893Sfenner this.next = next; 31656893Sfenner Assert.check(owner != null); 31756893Sfenner this.table = table; 31856893Sfenner this.hashMask = table.length - 1; 31956893Sfenner } 320146773Ssam 321146773Ssam /** Convenience constructor used for dup and dupUnshared. */ 322146773Ssam private ScopeImpl(ScopeImpl next, Symbol owner, Entry[] table, int nelems) { 323146773Ssam this(next, owner, table); 324146773Ssam this.nelems = nelems; 32556893Sfenner } 32656893Sfenner 32756893Sfenner /** Construct a new scope, within scope next, with given owner, 32856893Sfenner * using a fresh table of length INITIAL_SIZE. 329146773Ssam */ 33056893Sfenner public ScopeImpl(Symbol owner) { 33156893Sfenner this(null, owner, new Entry[INITIAL_SIZE]); 33256893Sfenner } 33356893Sfenner 33456893Sfenner /** Construct a fresh scope within this scope, with new owner, 335146773Ssam * which shares its table with the outer scope. Used in connection with 33656893Sfenner * method leave if scope access is stack-like in order to avoid allocation 33756893Sfenner * of fresh tables. 33856893Sfenner */ 339146773Ssam public WriteableScope dup(Symbol newOwner) { 34056893Sfenner ScopeImpl result = new ScopeImpl(this, newOwner, this.table, this.nelems); 34156893Sfenner shared++; 342146773Ssam // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode()); 34356893Sfenner // new Error().printStackTrace(System.out); 34456893Sfenner return result; 34556893Sfenner } 34656893Sfenner 34756893Sfenner /** Construct a fresh scope within this scope, with new owner, 34856893Sfenner * with a new hash table, whose contents initially are those of 34956893Sfenner * the table of its outer scope. 350146773Ssam */ 35156893Sfenner public WriteableScope dupUnshared(Symbol newOwner) { 35256893Sfenner if (shared > 0) { 353146773Ssam //The nested Scopes might have already added something to the table, so all items 35456893Sfenner //that don't originate in this Scope or any of its outer Scopes need to be cleared: 35556893Sfenner Set<Scope> acceptScopes = Collections.newSetFromMap(new IdentityHashMap<>()); 356146773Ssam ScopeImpl c = this; 35756893Sfenner while (c != null) { 35856893Sfenner acceptScopes.add(c); 359146773Ssam c = c.next; 36056893Sfenner } 36156893Sfenner int n = 0; 36256893Sfenner Entry[] oldTable = this.table; 36356893Sfenner Entry[] newTable = new Entry[this.table.length]; 36456893Sfenner for (int i = 0; i < oldTable.length; i++) { 36556893Sfenner Entry e = oldTable[i]; 366127668Sbms while (e != null && e != sentinel && !acceptScopes.contains(e.scope)) { 367146773Ssam e = e.shadowed; 36856893Sfenner } 36956893Sfenner if (e != null) { 370146773Ssam n++; 371146773Ssam newTable[i] = e; 372146773Ssam } 373146773Ssam } 374146773Ssam return new ScopeImpl(this, newOwner, newTable, n); 375146773Ssam } else { 376146773Ssam return new ScopeImpl(this, newOwner, this.table.clone(), this.nelems); 377146773Ssam } 37856893Sfenner } 37956893Sfenner 38056893Sfenner /** Remove all entries of this scope from its table, if shared 38156893Sfenner * with next. 38256893Sfenner */ 38356893Sfenner public WriteableScope leave() { 38456893Sfenner Assert.check(shared == 0); 38556893Sfenner if (table != next.table) return next; 386146773Ssam while (elems != null) { 38756893Sfenner int hash = getIndex(elems.sym.name); 38875115Sfenner Entry e = table[hash]; 389127668Sbms Assert.check(e == elems, elems.sym); 39056893Sfenner table[hash] = elems.shadowed; 39156893Sfenner elems = elems.sibling; 39256893Sfenner } 393146773Ssam Assert.check(next.shared > 0); 39456893Sfenner next.shared--; 39556893Sfenner next.nelems = nelems; 39656893Sfenner // System.out.println("====> leaving scope " + this.hashCode() + " owned by " + this.owner + " to " + next.hashCode()); 39756893Sfenner // new Error().printStackTrace(System.out); 39856893Sfenner return next; 399146773Ssam } 400146773Ssam 401146773Ssam /** Double size of hash table. 402146773Ssam */ 403146773Ssam private void dble() { 404146773Ssam Assert.check(shared == 0); 405146773Ssam Entry[] oldtable = table; 406146773Ssam Entry[] newtable = new Entry[oldtable.length * 2]; 40798524Sfenner for (ScopeImpl s = this; s != null; s = s.next) { 40875115Sfenner if (s.table == oldtable) { 409127668Sbms Assert.check(s == this || s.shared != 0); 41056893Sfenner s.table = newtable; 41156893Sfenner s.hashMask = newtable.length - 1; 41256893Sfenner } 41356893Sfenner } 41456893Sfenner int n = 0; 41556893Sfenner for (int i = oldtable.length; --i >= 0; ) { 41656893Sfenner Entry e = oldtable[i]; 417146773Ssam if (e != null && e != sentinel) { 41856893Sfenner table[getIndex(e.sym.name)] = e; 41956893Sfenner n++; 42075115Sfenner } 421127668Sbms } 42256893Sfenner // We don't need to update nelems for shared inherited scopes, 42356893Sfenner // since that gets handled by leave(). 42456893Sfenner nelems = n; 42556893Sfenner } 42656893Sfenner 42756893Sfenner /** Enter symbol sym in this scope. 42856893Sfenner */ 42956893Sfenner public void enter(Symbol sym) { 43056893Sfenner Assert.check(shared == 0); 431146773Ssam if (nelems * 3 >= hashMask * 2) 43256893Sfenner dble(); 43375115Sfenner int hash = getIndex(sym.name); 434146773Ssam Entry old = table[hash]; 435146773Ssam if (old == null) { 436146773Ssam old = sentinel; 437146773Ssam nelems++; 43856893Sfenner } 43975115Sfenner Entry e = new Entry(sym, old, elems, this); 440127668Sbms table[hash] = e; 44175115Sfenner elems = e; 44256893Sfenner 44356893Sfenner //notify listeners 44456893Sfenner listeners.symbolAdded(sym, this); 44556893Sfenner } 44656893Sfenner 44756893Sfenner /** Remove symbol from this scope. 448146773Ssam */ 449127668Sbms public void remove(Symbol sym) { 45075115Sfenner Assert.check(shared == 0); 45175115Sfenner Entry e = lookup(sym.name, candidate -> candidate == sym); 45256893Sfenner if (e.scope == null) return; 45356893Sfenner 45456893Sfenner // remove e from table and shadowed list; 455127668Sbms int i = getIndex(sym.name); 45656893Sfenner Entry te = table[i]; 45756893Sfenner if (te == e) 45875115Sfenner table[i] = e.shadowed; 45975115Sfenner else while (true) { 46056893Sfenner if (te.shadowed == e) { 461127668Sbms te.shadowed = e.shadowed; 46256893Sfenner break; 46375115Sfenner } 46475115Sfenner te = te.shadowed; 465127668Sbms } 46656893Sfenner 467146773Ssam // remove e from elems and sibling list 468146773Ssam te = elems; 469146773Ssam if (te == e) 470146773Ssam elems = e.sibling; 471146773Ssam else while (true) { 472146773Ssam if (te.sibling == e) { 473146773Ssam te.sibling = e.sibling; 474127668Sbms break; 475146773Ssam } 476146773Ssam te = te.sibling; 477146773Ssam } 478127668Sbms 479127668Sbms removeCount++; 480127668Sbms 481127668Sbms //notify listeners 482127668Sbms listeners.symbolRemoved(sym, this); 483127668Sbms } 484146773Ssam 485127668Sbms /** Enter symbol sym in this scope if not already there. 486127668Sbms */ 487127668Sbms public void enterIfAbsent(Symbol sym) { 488127668Sbms Assert.check(shared == 0); 489127668Sbms Entry e = lookup(sym.name); 490127668Sbms while (e.scope == this && e.sym.kind != sym.kind) e = e.next(); 491127668Sbms if (e.scope != this) enter(sym); 492127668Sbms } 493127668Sbms 494127668Sbms /** Given a class, is there already a class with same fully 495127668Sbms * qualified name in this (import) scope? 496146773Ssam */ 497127668Sbms public boolean includes(Symbol c) { 498127668Sbms for (Scope.Entry e = lookup(c.name); 499127668Sbms e.scope == this; 500127668Sbms e = e.next()) { 501127668Sbms if (e.sym == c) return true; 502127668Sbms } 503127668Sbms return false; 504127668Sbms } 505127668Sbms 506127668Sbms /** Return the entry associated with given name, starting in 507127668Sbms * this scope and proceeding outwards. If no entry was found, 50856893Sfenner * return the sentinel, which is characterized by having a null in 509146773Ssam * both its scope and sym fields, whereas both fields are non-null 510146773Ssam * for regular entries. 511146773Ssam */ 512146773Ssam protected Entry lookup(Name name) { 513146773Ssam return lookup(name, noFilter); 514146773Ssam } 515146773Ssam 51656893Sfenner protected Entry lookup(Name name, Filter<Symbol> sf) { 51756893Sfenner Entry e = table[getIndex(name)]; 51856893Sfenner if (e == null || e == sentinel) 51956893Sfenner return sentinel; 52056893Sfenner while (e.scope != null && (e.sym.name != name || (sf != null && !sf.accepts(e.sym)))) 52175115Sfenner e = e.shadowed; 522127668Sbms return e; 52375115Sfenner } 52498524Sfenner 52575115Sfenner public Symbol findFirst(Name name, Filter<Symbol> sf) { 52675115Sfenner return lookup(name, sf).sym; 52775115Sfenner } 52875115Sfenner 52975115Sfenner /*void dump (java.io.PrintStream out) { 530127668Sbms out.println(this); 531127668Sbms for (int l=0; l < table.length; l++) { 53275115Sfenner Entry le = table[l]; 53375115Sfenner out.print("#"+l+": "); 53475115Sfenner if (le==sentinel) out.println("sentinel"); 53575115Sfenner else if(le == null) out.println("null"); 536127668Sbms else out.println(""+le+" s:"+le.sym); 53775115Sfenner } 53875115Sfenner }*/ 53975115Sfenner 54075115Sfenner /** Look for slot in the table. 54175115Sfenner * We use open addressing with double hashing. 542147899Ssam */ 54375115Sfenner int getIndex (Name name) { 54475115Sfenner int h = name.hashCode(); 54575115Sfenner int i = h & hashMask; 54675115Sfenner // The expression below is always odd, so it is guaranteed 54775115Sfenner // to be mutually prime with table.length, a power of 2. 54875115Sfenner int x = hashMask - ((h + (h >> 16)) << 1); 54975115Sfenner int d = -1; // Index of a deleted item. 55075115Sfenner for (;;) { 55175115Sfenner Entry e = table[i]; 55275115Sfenner if (e == null) 55375115Sfenner return d >= 0 ? d : i; 55475115Sfenner if (e == sentinel) { 55575115Sfenner // We have to keep searching even if we see a deleted item. 55675115Sfenner // However, remember the index in case we fail to find the name. 55775115Sfenner if (d < 0) 55875115Sfenner d = i; 55975115Sfenner } else if (e.sym.name == name) 56075115Sfenner return i; 561127668Sbms i = (i + x) & hashMask; 56275115Sfenner } 56375115Sfenner } 56475115Sfenner 56575115Sfenner public boolean anyMatch(Filter<Symbol> sf) { 56675115Sfenner return getSymbols(sf, NON_RECURSIVE).iterator().hasNext(); 56775115Sfenner } 56875115Sfenner 569127668Sbms public Iterable<Symbol> getSymbols(final Filter<Symbol> sf, 57075115Sfenner final LookupKind lookupKind) { 57175115Sfenner return new Iterable<Symbol>() { 572127668Sbms public Iterator<Symbol> iterator() { 57375115Sfenner return new Iterator<Symbol>() { 57475115Sfenner private ScopeImpl currScope = ScopeImpl.this; 57575115Sfenner private Scope.Entry currEntry = elems; 57675115Sfenner private int seenRemoveCount = currScope.removeCount; 57775115Sfenner { 57875115Sfenner update(); 57975115Sfenner } 580127668Sbms 58175115Sfenner public boolean hasNext() { 58275115Sfenner if (seenRemoveCount != currScope.removeCount && 58375115Sfenner currEntry != null && 58475115Sfenner !currEntry.scope.includes(currEntry.sym)) { 58575115Sfenner doNext(); //skip entry that is no longer in the Scope 58675115Sfenner seenRemoveCount = currScope.removeCount; 58775115Sfenner } 58875115Sfenner return currEntry != null; 58975115Sfenner } 59075115Sfenner 59175115Sfenner public Symbol next() { 59275115Sfenner if (!hasNext()) { 59375115Sfenner throw new NoSuchElementException(); 59475115Sfenner } 595127668Sbms 59698524Sfenner return doNext(); 59756893Sfenner } 59898524Sfenner private Symbol doNext() { 59998524Sfenner Symbol sym = (currEntry == null ? null : currEntry.sym); 60098524Sfenner if (currEntry != null) { 60198524Sfenner currEntry = currEntry.sibling; 60298524Sfenner } 60398524Sfenner update(); 604127668Sbms return sym; 60598524Sfenner } 60698524Sfenner 60798524Sfenner public void remove() { 60898524Sfenner throw new UnsupportedOperationException(); 60956893Sfenner } 61056893Sfenner 61156893Sfenner private void update() { 61298524Sfenner skipToNextMatchingEntry(); 61375115Sfenner if (lookupKind == RECURSIVE) { 61456893Sfenner while (currEntry == null && currScope.next != null) { 61556893Sfenner currScope = currScope.next; 61698524Sfenner currEntry = currScope.elems; 61798524Sfenner seenRemoveCount = currScope.removeCount; 61898524Sfenner skipToNextMatchingEntry(); 61998524Sfenner } 62098524Sfenner } 62198524Sfenner } 62298524Sfenner 62356893Sfenner void skipToNextMatchingEntry() { 62498524Sfenner while (currEntry != null && sf != null && !sf.accepts(currEntry.sym)) { 62556893Sfenner currEntry = currEntry.sibling; 62698524Sfenner } 627146773Ssam } 628146773Ssam }; 629146773Ssam } 630146773Ssam }; 631146773Ssam } 632146773Ssam 63398524Sfenner public Iterable<Symbol> getSymbolsByName(final Name name, 63498524Sfenner final Filter<Symbol> sf, 63598524Sfenner final LookupKind lookupKind) { 63698524Sfenner return new Iterable<Symbol>() { 63798524Sfenner public Iterator<Symbol> iterator() { 63898524Sfenner return new Iterator<Symbol>() { 63998524Sfenner Scope.Entry currentEntry = lookup(name, sf); 64098524Sfenner int seenRemoveCount = currentEntry.scope != null ? 64198524Sfenner currentEntry.scope.removeCount : -1; 64298524Sfenner 64398524Sfenner public boolean hasNext() { 64498524Sfenner if (currentEntry.scope != null && 64598524Sfenner seenRemoveCount != currentEntry.scope.removeCount && 64698524Sfenner !currentEntry.scope.includes(currentEntry.sym)) { 647146773Ssam doNext(); //skip entry that is no longer in the Scope 648146773Ssam } 649146773Ssam return currentEntry.scope != null && 650146773Ssam (lookupKind == RECURSIVE || 651146773Ssam currentEntry.scope == ScopeImpl.this); 652146773Ssam } 653146773Ssam public Symbol next() { 65498524Sfenner if (!hasNext()) { 65598524Sfenner throw new NoSuchElementException(); 65698524Sfenner } 657146773Ssam return doNext(); 65898524Sfenner } 65998524Sfenner private Symbol doNext() { 66098524Sfenner Scope.Entry prevEntry = currentEntry; 66198524Sfenner currentEntry = currentEntry.next(sf); 66298524Sfenner return prevEntry.sym; 663146773Ssam } 664146773Ssam public void remove() { 665146773Ssam throw new UnsupportedOperationException(); 666146773Ssam } 66798524Sfenner }; 66898524Sfenner } 66998524Sfenner }; 670146773Ssam } 671127668Sbms 672127668Sbms public Scope getOrigin(Symbol s) { 673127668Sbms for (Scope.Entry e = lookup(s.name); e.scope != null ; e = e.next()) { 674127668Sbms if (e.sym == s) { 675146773Ssam return this; 676146773Ssam } 677146773Ssam } 678127668Sbms return null; 67998524Sfenner } 68098524Sfenner 68198524Sfenner @Override 68298524Sfenner public boolean isStaticallyImported(Symbol s) { 68398524Sfenner return false; 68498524Sfenner } 68598524Sfenner 68698524Sfenner public String toString() { 68798524Sfenner StringBuilder result = new StringBuilder(); 68898524Sfenner result.append("Scope["); 68998524Sfenner for (ScopeImpl s = this; s != null ; s = s.next) { 69098524Sfenner if (s != this) result.append(" | "); 69198524Sfenner for (Entry e = s.elems; e != null; e = e.sibling) { 69298524Sfenner if (e != s.elems) result.append(", "); 69398524Sfenner result.append(e.sym); 69498524Sfenner } 69598524Sfenner } 69698524Sfenner result.append("]"); 69798524Sfenner return result.toString(); 69898524Sfenner } 69998524Sfenner } 70098524Sfenner 70198524Sfenner /** A class for scope entries. 702127668Sbms */ 70398524Sfenner private static class Entry { 70498524Sfenner 705146773Ssam /** The referenced symbol. 706146773Ssam * sym == null iff this == sentinel 707146773Ssam */ 708146773Ssam public Symbol sym; 709146773Ssam 71056893Sfenner /** An entry with the same hash code, or sentinel. 711146773Ssam */ 712146773Ssam private Entry shadowed; 713146773Ssam 71498524Sfenner /** Next entry in same scope. 71598524Sfenner */ 71698524Sfenner public Entry sibling; 71756893Sfenner 71856893Sfenner /** The entry's scope. 71998524Sfenner * scope == null iff this == sentinel 72056893Sfenner */ 72156893Sfenner public ScopeImpl scope; 72256893Sfenner 72356893Sfenner public Entry(Symbol sym, Entry shadowed, Entry sibling, ScopeImpl scope) { 72456893Sfenner this.sym = sym; 72556893Sfenner this.shadowed = shadowed; 726127668Sbms this.sibling = sibling; 72798524Sfenner this.scope = scope; 72856893Sfenner } 72998524Sfenner 73098524Sfenner /** Return next entry with the same name as this entry, proceeding 73156893Sfenner * outwards if not found in this scope. 73275115Sfenner */ 73356893Sfenner public Entry next() { 73456893Sfenner return shadowed; 73556893Sfenner } 73656893Sfenner 73756893Sfenner public Entry next(Filter<Symbol> sf) { 738127668Sbms if (shadowed.sym == null || sf == null || sf.accepts(shadowed.sym)) return shadowed; 73956893Sfenner else return shadowed.next(sf); 74075115Sfenner } 74156893Sfenner 74275115Sfenner } 743146773Ssam 744146773Ssam public static class ImportScope extends CompoundScope { 745146773Ssam 746146773Ssam public ImportScope(Symbol owner) { 747146773Ssam super(owner); 748146773Ssam } 749146773Ssam 750146773Ssam /**Finalize the content of the ImportScope to speed-up future lookups. 751146773Ssam * No further changes to class hierarchy or class content will be reflected. 752146773Ssam */ 753146773Ssam public void finalizeScope() { 754146773Ssam for (List<Scope> scopes = this.subScopes; scopes.nonEmpty(); scopes = scopes.tail) { 755146773Ssam Scope impScope = scopes.head; 756146773Ssam 757146773Ssam if (impScope instanceof FilterImportScope && impScope.owner.kind == Kind.TYP) { 758146773Ssam WriteableScope finalized = WriteableScope.create(impScope.owner); 759146773Ssam 760146773Ssam for (Symbol sym : impScope.getSymbols()) { 761146773Ssam finalized.enter(sym); 762146773Ssam } 763146773Ssam 764146773Ssam finalized.listeners.add(new ScopeListener() { 765146773Ssam @Override 766146773Ssam public void symbolAdded(Symbol sym, Scope s) { 767146773Ssam Assert.error("The scope is sealed."); 768146773Ssam } 769146773Ssam 770146773Ssam @Override 771146773Ssam public void symbolRemoved(Symbol sym, Scope s) { 772146773Ssam Assert.error("The scope is sealed."); 773146773Ssam } 774146773Ssam }); 775146773Ssam 776146773Ssam scopes.head = finalized; 777146773Ssam } 778146773Ssam } 779146773Ssam } 780146773Ssam 781146773Ssam } 782146773Ssam 783146773Ssam public static class NamedImportScope extends ImportScope { 784146773Ssam 785146773Ssam public NamedImportScope(Symbol owner, Scope currentFileScope) { 786146773Ssam super(owner); 787146773Ssam prependSubScope(currentFileScope); 788146773Ssam } 789146773Ssam 790146773Ssam public Scope importByName(Types types, Scope origin, Name name, ImportFilter filter, JCImport imp, BiConsumer<JCImport, CompletionFailure> cfHandler) { 791146773Ssam return appendScope(new FilterImportScope(types, origin, name, filter, imp, cfHandler)); 792146773Ssam } 793146773Ssam 794146773Ssam public Scope importType(Scope delegate, Scope origin, Symbol sym) { 795146773Ssam return appendScope(new SingleEntryScope(delegate.owner, sym, origin)); 796146773Ssam } 797146773Ssam 798146773Ssam private Scope appendScope(Scope newScope) { 799146773Ssam List<Scope> existingScopes = this.subScopes.reverse(); 800146773Ssam subScopes = List.of(existingScopes.head); 801146773Ssam subScopes = subScopes.prepend(newScope); 802146773Ssam for (Scope s : existingScopes.tail) { 803146773Ssam subScopes = subScopes.prepend(s); 804146773Ssam } 805146773Ssam return newScope; 806146773Ssam } 807146773Ssam 808146773Ssam private static class SingleEntryScope extends Scope { 809146773Ssam 810146773Ssam private final Symbol sym; 811146773Ssam private final List<Symbol> content; 812146773Ssam private final Scope origin; 813146773Ssam 814146773Ssam public SingleEntryScope(Symbol owner, Symbol sym, Scope origin) { 815146773Ssam super(owner); 816146773Ssam this.sym = sym; 817146773Ssam this.content = List.of(sym); 818146773Ssam this.origin = origin; 819146773Ssam } 820146773Ssam 821146773Ssam @Override 822146773Ssam public Iterable<Symbol> getSymbols(Filter<Symbol> sf, LookupKind lookupKind) { 823146773Ssam return sf == null || sf.accepts(sym) ? content : Collections.<Symbol>emptyList(); 824146773Ssam } 825146773Ssam 826146773Ssam @Override 827146773Ssam public Iterable<Symbol> getSymbolsByName(Name name, 828146773Ssam Filter<Symbol> sf, 829146773Ssam LookupKind lookupKind) { 830146773Ssam return sym.name == name && 831146773Ssam (sf == null || sf.accepts(sym)) ? content : Collections.<Symbol>emptyList(); 832146773Ssam } 833146773Ssam 834146773Ssam @Override 835146773Ssam public Scope getOrigin(Symbol byName) { 836146773Ssam return sym == byName ? origin : null; 837146773Ssam } 838146773Ssam 839146773Ssam @Override 840146773Ssam public boolean isStaticallyImported(Symbol byName) { 841146773Ssam return false; 842146773Ssam } 843146773Ssam 844146773Ssam } 845146773Ssam } 846146773Ssam 847146773Ssam public static class StarImportScope extends ImportScope { 848146773Ssam 849146773Ssam public StarImportScope(Symbol owner) { 850146773Ssam super(owner); 851146773Ssam } 852146773Ssam 853146773Ssam public void importAll(Types types, Scope origin, 854146773Ssam ImportFilter filter, 855146773Ssam JCImport imp, 856146773Ssam BiConsumer<JCImport, CompletionFailure> cfHandler) { 857146773Ssam for (Scope existing : subScopes) { 858146773Ssam Assert.check(existing instanceof FilterImportScope); 859146773Ssam FilterImportScope fis = (FilterImportScope) existing; 860146773Ssam if (fis.origin == origin && fis.filter == filter && 861146773Ssam fis.imp.staticImport == imp.staticImport) 862146773Ssam return ; //avoid entering the same scope twice 863146773Ssam } 864146773Ssam prependSubScope(new FilterImportScope(types, origin, null, filter, imp, cfHandler)); 86575115Sfenner } 86675115Sfenner 86775115Sfenner public boolean isFilled() { 86875115Sfenner return subScopes.nonEmpty(); 86975115Sfenner } 87075115Sfenner 87175115Sfenner } 87275115Sfenner 87375115Sfenner public interface ImportFilter { 87475115Sfenner public boolean accepts(Scope origin, Symbol sym); 87575115Sfenner } 87675115Sfenner 87775115Sfenner private static class FilterImportScope extends Scope { 87875115Sfenner 87975115Sfenner private final Types types; 88075115Sfenner private final Scope origin; 88175115Sfenner private final Name filterName; 88275115Sfenner private final ImportFilter filter; 88375115Sfenner private final JCImport imp; 88475115Sfenner private final BiConsumer<JCImport, CompletionFailure> cfHandler; 88575115Sfenner 88675115Sfenner public FilterImportScope(Types types, 88775115Sfenner Scope origin, 88875115Sfenner Name filterName, 88975115Sfenner ImportFilter filter, 89075115Sfenner JCImport imp, 89175115Sfenner BiConsumer<JCImport, CompletionFailure> cfHandler) { 89275115Sfenner super(origin.owner); 89375115Sfenner this.types = types; 89475115Sfenner this.origin = origin; 89575115Sfenner this.filterName = filterName; 89675115Sfenner this.filter = filter; 89775115Sfenner this.imp = imp; 89875115Sfenner this.cfHandler = cfHandler; 89975115Sfenner } 900127668Sbms 901127668Sbms @Override 90275115Sfenner public Iterable<Symbol> getSymbols(final Filter<Symbol> sf, final LookupKind lookupKind) { 90375115Sfenner if (filterName != null) 90475115Sfenner return getSymbolsByName(filterName, sf, lookupKind); 90575115Sfenner try { 906127668Sbms SymbolImporter si = new SymbolImporter(imp.staticImport) { 90775115Sfenner @Override 90875115Sfenner Iterable<Symbol> doLookup(TypeSymbol tsym) { 909127668Sbms return tsym.members().getSymbols(sf, lookupKind); 910127668Sbms } 91175115Sfenner }; 91275115Sfenner return si.importFrom((TypeSymbol) origin.owner) :: iterator; 91375115Sfenner } catch (CompletionFailure cf) { 91475115Sfenner cfHandler.accept(imp, cf); 91575115Sfenner return Collections.emptyList(); 91675115Sfenner } 91775115Sfenner } 91875115Sfenner 919146773Ssam @Override 92075115Sfenner public Iterable<Symbol> getSymbolsByName(final Name name, 92175115Sfenner final Filter<Symbol> sf, 922146773Ssam final LookupKind lookupKind) { 92375115Sfenner if (filterName != null && filterName != name) 92475115Sfenner return Collections.emptyList(); 92575115Sfenner try { 92675115Sfenner SymbolImporter si = new SymbolImporter(imp.staticImport) { 927127668Sbms @Override 92875115Sfenner Iterable<Symbol> doLookup(TypeSymbol tsym) { 92975115Sfenner return tsym.members().getSymbolsByName(name, sf, lookupKind); 93075115Sfenner } 93175115Sfenner }; 93275115Sfenner return si.importFrom((TypeSymbol) origin.owner) :: iterator; 933127668Sbms } catch (CompletionFailure cf) { 93475115Sfenner cfHandler.accept(imp, cf); 93575115Sfenner return Collections.emptyList(); 93675115Sfenner } 93775115Sfenner } 93875115Sfenner 93975115Sfenner @Override 94075115Sfenner public Scope getOrigin(Symbol byName) { 94175115Sfenner return origin; 94275115Sfenner } 94375115Sfenner 94475115Sfenner @Override 94575115Sfenner public boolean isStaticallyImported(Symbol byName) { 94675115Sfenner return imp.staticImport; 94775115Sfenner } 94875115Sfenner 94975115Sfenner abstract class SymbolImporter { 95075115Sfenner Set<Symbol> processed = new HashSet<>(); 95175115Sfenner List<Iterable<Symbol>> delegates = List.nil(); 95275115Sfenner final boolean inspectSuperTypes; 95375115Sfenner public SymbolImporter(boolean inspectSuperTypes) { 95475115Sfenner this.inspectSuperTypes = inspectSuperTypes; 95575115Sfenner } 95675115Sfenner Stream<Symbol> importFrom(TypeSymbol tsym) { 95775115Sfenner if (tsym == null || !processed.add(tsym)) 95875115Sfenner return Stream.empty(); 95975115Sfenner 96075115Sfenner Stream<Symbol> result = Stream.empty(); 96175115Sfenner 96275115Sfenner if (inspectSuperTypes) { 96375115Sfenner // also import inherited names 96475115Sfenner result = importFrom(types.supertype(tsym.type).tsym); 96575115Sfenner for (Type t : types.interfaces(tsym.type)) 96675115Sfenner result = Stream.concat(importFrom(t.tsym), result); 96775115Sfenner } 96875115Sfenner 96975115Sfenner return Stream.concat(StreamSupport.stream(doLookup(tsym).spliterator(), false) 97075115Sfenner .filter(s -> filter.accepts(origin, s)), 97175115Sfenner result); 97275115Sfenner } 97375115Sfenner abstract Iterable<Symbol> doLookup(TypeSymbol tsym); 97475115Sfenner } 97575115Sfenner 97675115Sfenner } 97775115Sfenner 97875115Sfenner /** A class scope adds capabilities to keep track of changes in related 97975115Sfenner * class scopes - this allows client to realize whether a class scope 98075115Sfenner * has changed, either directly (because a new member has been added/removed 98175115Sfenner * to this scope) or indirectly (i.e. because a new member has been 98275115Sfenner * added/removed into a supertype scope) 98375115Sfenner */ 98475115Sfenner public static class CompoundScope extends Scope implements ScopeListener { 98575115Sfenner 98675115Sfenner List<Scope> subScopes = List.nil(); 98775115Sfenner private int mark = 0; 98875115Sfenner 98975115Sfenner public CompoundScope(Symbol owner) { 99075115Sfenner super(owner); 99175115Sfenner } 99275115Sfenner 99375115Sfenner public void prependSubScope(Scope that) { 99475115Sfenner if (that != null) { 99575115Sfenner subScopes = subScopes.prepend(that); 99675115Sfenner that.listeners.add(this); 99775115Sfenner mark++; 99875115Sfenner listeners.symbolAdded(null, this); 99975115Sfenner } 100075115Sfenner } 100175115Sfenner 100275115Sfenner public void symbolAdded(Symbol sym, Scope s) { 100375115Sfenner mark++; 100475115Sfenner listeners.symbolAdded(sym, s); 100575115Sfenner } 100675115Sfenner 100775115Sfenner public void symbolRemoved(Symbol sym, Scope s) { 100875115Sfenner mark++; 100975115Sfenner listeners.symbolRemoved(sym, s); 101075115Sfenner } 101175115Sfenner 101275115Sfenner public int getMark() { 101375115Sfenner return mark; 101475115Sfenner } 101575115Sfenner 101675115Sfenner @Override 101775115Sfenner public String toString() { 101875115Sfenner StringBuilder buf = new StringBuilder(); 101975115Sfenner buf.append("CompoundScope{"); 102075115Sfenner String sep = ""; 102175115Sfenner for (Scope s : subScopes) { 102275115Sfenner buf.append(sep); 102375115Sfenner buf.append(s); 102475115Sfenner sep = ","; 102575115Sfenner } 102675115Sfenner buf.append("}"); 102775115Sfenner return buf.toString(); 102875115Sfenner } 102975115Sfenner 103075115Sfenner @Override 103175115Sfenner public Iterable<Symbol> getSymbols(final Filter<Symbol> sf, 103275115Sfenner final LookupKind lookupKind) { 103375115Sfenner return () -> Iterators.createCompoundIterator(subScopes, 103475115Sfenner scope -> scope.getSymbols(sf, 103575115Sfenner lookupKind) 103675115Sfenner .iterator()); 103775115Sfenner } 1038146773Ssam 103975115Sfenner @Override 104075115Sfenner public Iterable<Symbol> getSymbolsByName(final Name name, 104175115Sfenner final Filter<Symbol> sf, 104275115Sfenner final LookupKind lookupKind) { 104375115Sfenner return () -> Iterators.createCompoundIterator(subScopes, 104475115Sfenner scope -> scope.getSymbolsByName(name, 104575115Sfenner sf, 104675115Sfenner lookupKind) 104775115Sfenner .iterator()); 104875115Sfenner } 104975115Sfenner 105075115Sfenner @Override 105175115Sfenner public Scope getOrigin(Symbol sym) { 105275115Sfenner for (Scope delegate : subScopes) { 105375115Sfenner if (delegate.includes(sym)) 105475115Sfenner return delegate.getOrigin(sym); 105575115Sfenner } 105675115Sfenner 105775115Sfenner return null; 105875115Sfenner } 105975115Sfenner 106075115Sfenner @Override 106175115Sfenner public boolean isStaticallyImported(Symbol sym) { 106275115Sfenner for (Scope delegate : subScopes) { 106375115Sfenner if (delegate.includes(sym)) 106475115Sfenner return delegate.isStaticallyImported(sym); 106575115Sfenner } 106675115Sfenner 106775115Sfenner return false; 106875115Sfenner } 1069127668Sbms 107075115Sfenner } 107175115Sfenner 107275115Sfenner /** An error scope, for which the owner should be an error symbol. */ 107375115Sfenner public static class ErrorScope extends ScopeImpl { 107475115Sfenner ErrorScope(ScopeImpl next, Symbol errSymbol, Entry[] table) { 107575115Sfenner super(next, /*owner=*/errSymbol, table); 107675115Sfenner } 107775115Sfenner public ErrorScope(Symbol errSymbol) { 107875115Sfenner super(errSymbol); 107975115Sfenner } 108075115Sfenner public WriteableScope dup(Symbol newOwner) { 108175115Sfenner return new ErrorScope(this, newOwner, table); 1082127668Sbms } 108375115Sfenner public WriteableScope dupUnshared(Symbol newOwner) { 108475115Sfenner return new ErrorScope(this, newOwner, table.clone()); 108575115Sfenner } 108675115Sfenner public Entry lookup(Name name) { 108775115Sfenner Entry e = super.lookup(name); 108875115Sfenner if (e.scope == null) 108975115Sfenner return new Entry(owner, null, null, null); 109075115Sfenner else 109175115Sfenner return e; 109275115Sfenner } 109375115Sfenner } 109475115Sfenner} 109575115Sfenner