Scope.java revision 4037:1d3c7096b3b6
11592Srgrimes/* 21592Srgrimes * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. 31592Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41592Srgrimes * 51592Srgrimes * This code is free software; you can redistribute it and/or modify it 61592Srgrimes * under the terms of the GNU General Public License version 2 only, as 71592Srgrimes * published by the Free Software Foundation. Oracle designates this 81592Srgrimes * particular file as subject to the "Classpath" exception as provided 91592Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101592Srgrimes * 111592Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121592Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131592Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141592Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151592Srgrimes * accompanied this code). 161592Srgrimes * 171592Srgrimes * You should have received a copy of the GNU General Public License version 181592Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191592Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201592Srgrimes * 211592Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221592Srgrimes * or visit www.oracle.com if you need additional information or have any 231592Srgrimes * questions. 241592Srgrimes */ 251592Srgrimes 261592Srgrimespackage com.sun.tools.javac.code; 271592Srgrimes 281592Srgrimesimport com.sun.tools.javac.code.Kinds.Kind; 291592Srgrimesimport java.lang.ref.WeakReference; 301592Srgrimesimport java.util.*; 311592Srgrimesimport java.util.function.BiConsumer; 321592Srgrimes 331592Srgrimesimport com.sun.tools.javac.code.Symbol.CompletionFailure; 3417478Smarkmimport com.sun.tools.javac.code.Symbol.TypeSymbol; 351592Srgrimesimport com.sun.tools.javac.tree.JCTree.JCImport; 361592Srgrimesimport com.sun.tools.javac.util.*; 371592Srgrimesimport com.sun.tools.javac.util.List; 381592Srgrimes 391592Srgrimesimport static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; 4017478Smarkmimport static com.sun.tools.javac.code.Scope.LookupKind.RECURSIVE; 411592Srgrimesimport static com.sun.tools.javac.util.Iterators.createCompoundIterator; 4231329Scharnierimport static com.sun.tools.javac.util.Iterators.createFilterIterator; 4317478Smarkm 441592Srgrimes/** A scope represents an area of visibility in a Java program. The 4531329Scharnier * Scope class is a container for symbols which provides 4631329Scharnier * efficient access to symbols given their names. Scopes are implemented 4750476Speter * as hash tables with "open addressing" and "double hashing". 481592Srgrimes * Scopes can be nested. Nested scopes can share their hash tables. 491592Srgrimes * 501592Srgrimes * <p><b>This is NOT part of any supported API. 511592Srgrimes * If you write code that depends on this, you do so at your own risk. 521592Srgrimes * This code and its internal interfaces are subject to change or 531592Srgrimes * deletion without notice.</b> 541592Srgrimes */ 551592Srgrimespublic abstract class Scope { 561592Srgrimes 571592Srgrimes /** The scope's owner. 588240Swollman */ 591592Srgrimes public final Symbol owner; 601592Srgrimes 611592Srgrimes protected Scope(Symbol owner) { 621592Srgrimes this.owner = owner; 638240Swollman } 641592Srgrimes 651592Srgrimes /**Returns all Symbols in this Scope. Symbols from outward Scopes are included. 661592Srgrimes */ 671592Srgrimes public final Iterable<Symbol> getSymbols() { 681592Srgrimes return getSymbols(noFilter); 691592Srgrimes } 701592Srgrimes 711592Srgrimes /**Returns Symbols that match the given filter. Symbols from outward Scopes are included. 721592Srgrimes */ 731592Srgrimes public final Iterable<Symbol> getSymbols(Filter<Symbol> sf) { 741592Srgrimes return getSymbols(sf, RECURSIVE); 751592Srgrimes } 761592Srgrimes 771592Srgrimes /**Returns all Symbols in this Scope. Symbols from outward Scopes are included 781592Srgrimes * iff lookupKind == RECURSIVE. 7925187Sdavidn */ 801592Srgrimes public final Iterable<Symbol> getSymbols(LookupKind lookupKind) { 811592Srgrimes return getSymbols(noFilter, lookupKind); 821592Srgrimes } 831592Srgrimes 841592Srgrimes /**Returns Symbols that match the given filter. Symbols from outward Scopes are included 851592Srgrimes * iff lookupKind == RECURSIVE. 861592Srgrimes */ 871592Srgrimes public abstract Iterable<Symbol> getSymbols(Filter<Symbol> sf, LookupKind lookupKind); 8813139Speter 8925101Sdavidn /**Returns Symbols with the given name. Symbols from outward Scopes are included. 9025101Sdavidn */ 9125101Sdavidn public final Iterable<Symbol> getSymbolsByName(Name name) { 921592Srgrimes return getSymbolsByName(name, RECURSIVE); 933938Spst } 943938Spst 953938Spst /**Returns Symbols with the given name that match the given filter. 963938Spst * Symbols from outward Scopes are included. 971592Srgrimes */ 981592Srgrimes public final Iterable<Symbol> getSymbolsByName(final Name name, final Filter<Symbol> sf) { 991592Srgrimes return getSymbolsByName(name, sf, RECURSIVE); 1001592Srgrimes } 1011592Srgrimes 1021592Srgrimes /**Returns Symbols with the given name. Symbols from outward Scopes are included 1031592Srgrimes * iff lookupKind == RECURSIVE. 1041592Srgrimes */ 1051592Srgrimes public final Iterable<Symbol> getSymbolsByName(Name name, LookupKind lookupKind) { 10625165Sdavidn return getSymbolsByName(name, noFilter, lookupKind); 10725165Sdavidn } 1081592Srgrimes 1091592Srgrimes /**Returns Symbols with the given name that match the given filter. 1101592Srgrimes * Symbols from outward Scopes are included iff lookupKind == RECURSIVE. 1111592Srgrimes */ 11215196Sdg public abstract Iterable<Symbol> getSymbolsByName(final Name name, final Filter<Symbol> sf, 1131592Srgrimes final LookupKind lookupKind); 1141592Srgrimes 1151592Srgrimes /** Return the first Symbol from this or outward scopes with the given name. 1161592Srgrimes * Returns null if none. 1171592Srgrimes */ 1181592Srgrimes public final Symbol findFirst(Name name) { 11915196Sdg return findFirst(name, noFilter); 1201592Srgrimes } 1211592Srgrimes 1221592Srgrimes /** Return the first Symbol from this or outward scopes with the given name that matches the 1231592Srgrimes * given filter. Returns null if none. 1241592Srgrimes */ 1251592Srgrimes public Symbol findFirst(Name name, Filter<Symbol> sf) { 1261592Srgrimes Iterator<Symbol> it = getSymbolsByName(name, sf).iterator(); 1271592Srgrimes return it.hasNext() ? it.next() : null; 1289933Spst } 12917435Spst 13020042Storstenb /** Returns true iff there are is at least one Symbol in this scope matching the given filter. 1311592Srgrimes * Does not inspect outward scopes. 13217435Spst */ 1336740Sguido public boolean anyMatch(Filter<Symbol> filter) { 1346740Sguido return getSymbols(filter, NON_RECURSIVE).iterator().hasNext(); 1351592Srgrimes } 1361592Srgrimes 1371592Srgrimes /** Returns true iff the given Symbol is in this scope or any outward scope. 1381592Srgrimes */ 1391592Srgrimes public boolean includes(final Symbol sym) { 1401592Srgrimes return includes(sym, RECURSIVE); 1411592Srgrimes } 1421592Srgrimes 1431592Srgrimes /** Returns true iff the given Symbol is in this scope, optionally checking outward scopes. 1441592Srgrimes */ 1451592Srgrimes public boolean includes(final Symbol sym, LookupKind lookupKind) { 1461592Srgrimes return getSymbolsByName(sym.name, t -> t == sym, lookupKind).iterator().hasNext(); 1471592Srgrimes } 1481592Srgrimes 1491592Srgrimes /** Returns true iff this scope does not contain any Symbol. Does not inspect outward scopes. 15027650Sdavidn */ 15125283Sdavidn public boolean isEmpty() { 15225283Sdavidn return !getSymbols(NON_RECURSIVE).iterator().hasNext(); 15325283Sdavidn } 15425283Sdavidn 15525283Sdavidn /** Returns the Scope from which the givins Symbol originates in this scope. 15625283Sdavidn */ 15725283Sdavidn public abstract Scope getOrigin(Symbol byName); 15825283Sdavidn 15925283Sdavidn /** Returns true iff the given Symbol is part of this scope due to a static import. 16025283Sdavidn */ 16125283Sdavidn public abstract boolean isStaticallyImported(Symbol byName); 16225283Sdavidn 16325283Sdavidn private static final Filter<Symbol> noFilter = null; 16425283Sdavidn 16545422Sbrian /** A list of scopes to be notified if items are to be removed from this scope. 1666740Sguido */ 16717435Spst ScopeListenerList listeners = new ScopeListenerList(); 16817435Spst 16917435Spst public interface ScopeListener { 17017435Spst void symbolAdded(Symbol sym, Scope s); 17117478Smarkm void symbolRemoved(Symbol sym, Scope s); 17217478Smarkm } 17317478Smarkm 17417478Smarkm /** 17517483Sjulian * A list of scope listeners; listeners are stored in weak references, to avoid memory leaks. 17617483Sjulian * When the listener list is scanned (upon notification), elements corresponding to GC-ed 17717483Sjulian * listeners are removed so that the listener list size is kept in check. 17817435Spst */ 17917435Spst public static class ScopeListenerList { 18017478Smarkm 18117435Spst List<WeakReference<ScopeListener>> listeners = List.nil(); 1826740Sguido 1831592Srgrimes void add(ScopeListener sl) { 1841592Srgrimes listeners = listeners.prepend(new WeakReference<>(sl)); 1851592Srgrimes } 1861592Srgrimes 1871592Srgrimes void symbolAdded(Symbol sym, Scope scope) { 1881592Srgrimes walkReferences(sym, scope, false); 1891592Srgrimes } 1901592Srgrimes 1911592Srgrimes void symbolRemoved(Symbol sym, Scope scope) { 1921592Srgrimes walkReferences(sym, scope, true); 1931592Srgrimes } 1941592Srgrimes 1951592Srgrimes private void walkReferences(Symbol sym, Scope scope, boolean isRemove) { 19613139Speter ListBuffer<WeakReference<ScopeListener>> newListeners = new ListBuffer<>(); 1971592Srgrimes for (WeakReference<ScopeListener> wsl : listeners) { 1981592Srgrimes ScopeListener sl = wsl.get(); 19913139Speter if (sl != null) { 2001592Srgrimes if (isRemove) { 2011592Srgrimes sl.symbolRemoved(sym, scope); 2021592Srgrimes } else { 2032193Sguido sl.symbolAdded(sym, scope); 2042193Sguido } 2053938Spst newListeners.add(wsl); 2062193Sguido } 2072193Sguido } 2081592Srgrimes listeners = newListeners.toList(); 2091592Srgrimes } 2101592Srgrimes } 2111592Srgrimes 2121592Srgrimes public enum LookupKind { 2131592Srgrimes RECURSIVE, 2141592Srgrimes NON_RECURSIVE; 2151592Srgrimes } 2161592Srgrimes 2171592Srgrimes /**A scope into which Symbols can be added.*/ 2181592Srgrimes public abstract static class WriteableScope extends Scope { 2191592Srgrimes 2201592Srgrimes public WriteableScope(Symbol owner) { 2211592Srgrimes super(owner); 2221592Srgrimes } 2231592Srgrimes 2241592Srgrimes /** Enter the given Symbol into this scope. 2251592Srgrimes */ 2261592Srgrimes public abstract void enter(Symbol c); 22725283Sdavidn /** Enter symbol sym in this scope if not already there. 22825283Sdavidn */ 22925283Sdavidn public abstract void enterIfAbsent(Symbol c); 23025283Sdavidn 2311592Srgrimes public abstract void remove(Symbol c); 2321592Srgrimes 23336349Ssteve /** Construct a fresh scope within this scope, with same owner. The new scope may 2341592Srgrimes * shares internal structures with the this scope. Used in connection with 2351592Srgrimes * method leave if scope access is stack-like in order to avoid allocation 2361592Srgrimes * of fresh tables. 2371592Srgrimes */ 2381592Srgrimes public final WriteableScope dup() { 2391592Srgrimes return dup(this.owner); 2401592Srgrimes } 2411592Srgrimes 2428240Swollman /** Construct a fresh scope within this scope, with new owner. The new scope may 2431592Srgrimes * shares internal structures with the this scope. Used in connection with 2441592Srgrimes * method leave if scope access is stack-like in order to avoid allocation 2451592Srgrimes * of fresh tables. 24615196Sdg */ 24717433Spst public abstract WriteableScope dup(Symbol newOwner); 2481592Srgrimes 2491592Srgrimes /** Must be called on dup-ed scopes to be able to work with the outward scope again. 2501592Srgrimes */ 2511592Srgrimes public abstract WriteableScope leave(); 2521592Srgrimes 2531592Srgrimes /** Construct a fresh scope within this scope, with same owner. The new scope 2541592Srgrimes * will not share internal structures with this scope. 2551592Srgrimes */ 2561592Srgrimes public final WriteableScope dupUnshared() { 2571592Srgrimes return dupUnshared(owner); 2581592Srgrimes } 2591592Srgrimes 2601592Srgrimes /** Construct a fresh scope within this scope, with new owner. The new scope 2611592Srgrimes * will not share internal structures with this scope. 2621592Srgrimes */ 2631592Srgrimes public abstract WriteableScope dupUnshared(Symbol newOwner); 2641592Srgrimes 2651592Srgrimes /** Create a new WriteableScope. 2661592Srgrimes */ 2671592Srgrimes public static WriteableScope create(Symbol owner) { 2681592Srgrimes return new ScopeImpl(owner); 2691592Srgrimes } 2701592Srgrimes 2711592Srgrimes } 27236105Sache 27336105Sache private static class ScopeImpl extends WriteableScope { 27413139Speter /** The number of scopes that share this scope's hash table. 2751592Srgrimes */ 2761592Srgrimes private int shared; 2771592Srgrimes 2781592Srgrimes /** Next enclosing scope (with whom this scope may share a hashtable) 2791592Srgrimes */ 2801592Srgrimes public ScopeImpl next; 2811592Srgrimes 28213139Speter /** A hash table for the scope's entries. 2831592Srgrimes */ 2846740Sguido Entry[] table; 28517483Sjulian 28624349Simp /** Mask for hash codes, always equal to (table.length - 1). 2871592Srgrimes */ 28815196Sdg int hashMask; 28915196Sdg 29015196Sdg /** A linear list that also contains all entries in 29115196Sdg * reverse order of appearance (i.e later entries are pushed on top). 2921592Srgrimes */ 29317435Spst public Entry elems; 2941592Srgrimes 2951592Srgrimes /** The number of elements in this scope. 2961592Srgrimes * This includes deleted elements, whose value is the sentinel. 2971592Srgrimes */ 2981592Srgrimes int nelems = 0; 2991592Srgrimes 30017435Spst int removeCount = 0; 30117435Spst 3029933Spst /** Use as a "not-found" result for lookup. 3039933Spst * Also used to mark deleted entries in the table. 3046740Sguido */ 30517435Spst private static final Entry sentinel = new Entry(null, null, null, null); 3066740Sguido 30717435Spst /** The hash table's initial size. 3081592Srgrimes */ 3091592Srgrimes private static final int INITIAL_SIZE = 0x10; 3101592Srgrimes 3111592Srgrimes /** Construct a new scope, within scope next, with given owner, using 3121592Srgrimes * given table. The table's length must be an exponent of 2. 3131592Srgrimes */ 31417435Spst private ScopeImpl(ScopeImpl next, Symbol owner, Entry[] table) { 31517435Spst super(owner); 31617435Spst this.next = next; 31717435Spst Assert.check(owner != null); 31817435Spst this.table = table; 31917435Spst this.hashMask = table.length - 1; 32017435Spst } 32117435Spst 32217435Spst /** Convenience constructor used for dup and dupUnshared. */ 32317435Spst private ScopeImpl(ScopeImpl next, Symbol owner, Entry[] table, int nelems) { 32417483Sjulian this(next, owner, table); 32517483Sjulian this.nelems = nelems; 32617483Sjulian } 32717483Sjulian 32817483Sjulian /** Construct a new scope, within scope next, with given owner, 32917483Sjulian * using a fresh table of length INITIAL_SIZE. 33017483Sjulian */ 33117483Sjulian public ScopeImpl(Symbol owner) { 33217483Sjulian this(null, owner, new Entry[INITIAL_SIZE]); 3331592Srgrimes } 3341592Srgrimes 3351592Srgrimes /** Construct a fresh scope within this scope, with new owner, 3361592Srgrimes * which shares its table with the outer scope. Used in connection with 3371592Srgrimes * method leave if scope access is stack-like in order to avoid allocation 3381592Srgrimes * of fresh tables. 3391592Srgrimes */ 3401592Srgrimes public WriteableScope dup(Symbol newOwner) { 3411592Srgrimes ScopeImpl result = new ScopeImpl(this, newOwner, this.table, this.nelems); 3421592Srgrimes shared++; 3431592Srgrimes // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode()); 34420042Storstenb // new Error().printStackTrace(System.out); 34520042Storstenb return result; 34620042Storstenb } 3471592Srgrimes 3481592Srgrimes /** Construct a fresh scope within this scope, with new owner, 3491592Srgrimes * with a new hash table, whose contents initially are those of 3501592Srgrimes * the table of its outer scope. 3511592Srgrimes */ 3521592Srgrimes public WriteableScope dupUnshared(Symbol newOwner) { 3531592Srgrimes if (shared > 0) { 3541592Srgrimes //The nested Scopes might have already added something to the table, so all items 3551592Srgrimes //that don't originate in this Scope or any of its outer Scopes need to be cleared: 3561592Srgrimes Set<Scope> acceptScopes = Collections.newSetFromMap(new IdentityHashMap<>()); 35715196Sdg ScopeImpl c = this; 35825283Sdavidn while (c != null) { 35925283Sdavidn acceptScopes.add(c); 36025283Sdavidn c = c.next; 3611592Srgrimes } 36215196Sdg int n = 0; 36315196Sdg Entry[] oldTable = this.table; 36415196Sdg Entry[] newTable = new Entry[this.table.length]; 36515196Sdg for (int i = 0; i < oldTable.length; i++) { 36615196Sdg Entry e = oldTable[i]; 36715196Sdg while (e != null && e != sentinel && !acceptScopes.contains(e.scope)) { 36815196Sdg e = e.shadowed; 36915196Sdg } 37015196Sdg if (e != null) { 37115196Sdg n++; 37215196Sdg newTable[i] = e; 37315196Sdg } 37415196Sdg } 37515196Sdg return new ScopeImpl(this, newOwner, newTable, n); 37615196Sdg } else { 37715196Sdg return new ScopeImpl(this, newOwner, this.table.clone(), this.nelems); 37815196Sdg } 37915196Sdg } 38015196Sdg 38115196Sdg /** Remove all entries of this scope from its table, if shared 38215196Sdg * with next. 38315196Sdg */ 38415196Sdg public WriteableScope leave() { 38515196Sdg Assert.check(shared == 0); 38615196Sdg if (table != next.table) return next; 38715196Sdg while (elems != null) { 38815196Sdg int hash = getIndex(elems.sym.name); 38915196Sdg Entry e = table[hash]; 39015196Sdg Assert.check(e == elems, elems.sym); 39115196Sdg table[hash] = elems.shadowed; 39215196Sdg elems = elems.sibling; 39315196Sdg } 39415196Sdg Assert.check(next.shared > 0); 39515196Sdg next.shared--; 39615196Sdg next.nelems = nelems; 39715196Sdg // System.out.println("====> leaving scope " + this.hashCode() + " owned by " + this.owner + " to " + next.hashCode()); 39815196Sdg // new Error().printStackTrace(System.out); 39915196Sdg return next; 40015196Sdg } 40115196Sdg 40217483Sjulian /** Double size of hash table. 40315196Sdg */ 40415196Sdg private void dble() { 40515196Sdg Assert.check(shared == 0); 40615196Sdg Entry[] oldtable = table; 40715196Sdg Entry[] newtable = new Entry[oldtable.length * 2]; 40815196Sdg for (ScopeImpl s = this; s != null; s = s.next) { 40915196Sdg if (s.table == oldtable) { 41015196Sdg Assert.check(s == this || s.shared != 0); 41115196Sdg s.table = newtable; 41215196Sdg s.hashMask = newtable.length - 1; 41317483Sjulian } 41417483Sjulian } 41517483Sjulian int n = 0; 41617483Sjulian for (int i = oldtable.length; --i >= 0; ) { 41717483Sjulian Entry e = oldtable[i]; 41817483Sjulian if (e != null && e != sentinel) { 41917483Sjulian table[getIndex(e.sym.name)] = e; 42017483Sjulian n++; 42117483Sjulian } 42246078Simp } 42317483Sjulian // We don't need to update nelems for shared inherited scopes, 42417483Sjulian // since that gets handled by leave(). 42517483Sjulian nelems = n; 42617483Sjulian } 42746078Simp 42817483Sjulian /** Enter symbol sym in this scope. 42917483Sjulian */ 43017483Sjulian public void enter(Symbol sym) { 43117483Sjulian Assert.check(shared == 0); 43217483Sjulian if (nelems * 3 >= hashMask * 2) 43317483Sjulian dble(); 43417483Sjulian int hash = getIndex(sym.name); 43515196Sdg Entry old = table[hash]; 43615196Sdg if (old == null) { 43715196Sdg old = sentinel; 43815196Sdg nelems++; 43915196Sdg } 44015196Sdg Entry e = new Entry(sym, old, elems, this); 44115196Sdg table[hash] = e; 44215196Sdg elems = e; 44315196Sdg 44415196Sdg //notify listeners 44515196Sdg listeners.symbolAdded(sym, this); 44615196Sdg } 44715196Sdg 44815196Sdg /** Remove symbol from this scope. 44915196Sdg */ 45015196Sdg public void remove(Symbol sym) { 45115196Sdg Assert.check(shared == 0); 45215196Sdg Entry e = lookup(sym.name, candidate -> candidate == sym); 45315196Sdg if (e.scope == null) return; 45415196Sdg 45515196Sdg // remove e from table and shadowed list; 45615196Sdg int i = getIndex(sym.name); 45715196Sdg Entry te = table[i]; 45815196Sdg if (te == e) 4591592Srgrimes table[i] = e.shadowed; 46036612Sjb else while (true) { 4611592Srgrimes if (te.shadowed == e) { 4621592Srgrimes te.shadowed = e.shadowed; 46315196Sdg break; 46417433Spst } 46515196Sdg te = te.shadowed; 46615196Sdg } 46715196Sdg 46815196Sdg // remove e from elems and sibling list 46915196Sdg te = elems; 47015196Sdg if (te == e) 47125283Sdavidn elems = e.sibling; 47225283Sdavidn else while (true) { 47325283Sdavidn if (te.sibling == e) { 47425283Sdavidn te.sibling = e.sibling; 47515196Sdg break; 47615196Sdg } 47715196Sdg te = te.sibling; 47815196Sdg } 47915196Sdg 48035482Sdg removeCount++; 48135482Sdg 48235482Sdg //notify listeners 48335482Sdg listeners.symbolRemoved(sym, this); 48435482Sdg } 48535482Sdg 48635482Sdg /** Enter symbol sym in this scope if not already there. 48715196Sdg */ 48815196Sdg public void enterIfAbsent(Symbol sym) { 48917435Spst Assert.check(shared == 0); 49031973Simp Entry e = lookup(sym.name); 49117435Spst while (e.scope == this && e.sym.kind != sym.kind) e = e.next(); 4921592Srgrimes if (e.scope != this) enter(sym); 4931592Srgrimes } 4941592Srgrimes 4951592Srgrimes /** Given a class, is there already a class with same fully 4961592Srgrimes * qualified name in this (import) scope? 4971592Srgrimes */ 4981592Srgrimes public boolean includes(Symbol c) { 4991592Srgrimes for (Scope.Entry e = lookup(c.name); 5001592Srgrimes e.scope == this; 5011592Srgrimes e = e.next()) { 5021592Srgrimes if (e.sym == c) return true; 5031592Srgrimes } 5041592Srgrimes return false; 5051592Srgrimes } 5061592Srgrimes 5071592Srgrimes /** Return the entry associated with given name, starting in 5081592Srgrimes * this scope and proceeding outwards. If no entry was found, 5091592Srgrimes * return the sentinel, which is characterized by having a null in 5101592Srgrimes * both its scope and sym fields, whereas both fields are non-null 5111592Srgrimes * for regular entries. 5121592Srgrimes */ 5131592Srgrimes protected Entry lookup(Name name) { 5141592Srgrimes return lookup(name, noFilter); 5151592Srgrimes } 5161592Srgrimes 5171592Srgrimes protected Entry lookup(Name name, Filter<Symbol> sf) { 5181592Srgrimes Entry e = table[getIndex(name)]; 5191592Srgrimes if (e == null || e == sentinel) 5201592Srgrimes return sentinel; 5211592Srgrimes while (e.scope != null && (e.sym.name != name || (sf != null && !sf.accepts(e.sym)))) 5221592Srgrimes e = e.shadowed; 5231592Srgrimes return e; 5241592Srgrimes } 52525283Sdavidn 52625283Sdavidn public Symbol findFirst(Name name, Filter<Symbol> sf) { 52725283Sdavidn return lookup(name, sf).sym; 5281592Srgrimes } 52925283Sdavidn 5301592Srgrimes /*void dump (java.io.PrintStream out) { 5311592Srgrimes out.println(this); 5321592Srgrimes for (int l=0; l < table.length; l++) { 5331592Srgrimes Entry le = table[l]; 5341592Srgrimes out.print("#"+l+": "); 5351592Srgrimes if (le==sentinel) out.println("sentinel"); 5361592Srgrimes else if(le == null) out.println("null"); 5371592Srgrimes else out.println(""+le+" s:"+le.sym); 5381592Srgrimes } 53925283Sdavidn }*/ 54027650Sdavidn 54127650Sdavidn /** Look for slot in the table. 54245422Sbrian * We use open addressing with double hashing. 54345422Sbrian */ 54425283Sdavidn int getIndex (Name name) { 5451592Srgrimes int h = name.hashCode(); 5461592Srgrimes int i = h & hashMask; 5471592Srgrimes // The expression below is always odd, so it is guaranteed 5481592Srgrimes // to be mutually prime with table.length, a power of 2. 5491592Srgrimes int x = hashMask - ((h + (h >> 16)) << 1); 5501592Srgrimes int d = -1; // Index of a deleted item. 5511592Srgrimes for (;;) { 5521592Srgrimes Entry e = table[i]; 5531592Srgrimes if (e == null) 5541592Srgrimes return d >= 0 ? d : i; 5551592Srgrimes if (e == sentinel) { 5561592Srgrimes // We have to keep searching even if we see a deleted item. 5571592Srgrimes // However, remember the index in case we fail to find the name. 5581592Srgrimes if (d < 0) 55931329Scharnier d = i; 5601592Srgrimes } else if (e.sym.name == name) 5611592Srgrimes return i; 56225283Sdavidn i = (i + x) & hashMask; 5631592Srgrimes } 56425283Sdavidn } 56525283Sdavidn 56625283Sdavidn public boolean anyMatch(Filter<Symbol> sf) { 56725283Sdavidn return getSymbols(sf, NON_RECURSIVE).iterator().hasNext(); 56825283Sdavidn } 56925283Sdavidn 57025283Sdavidn public Iterable<Symbol> getSymbols(final Filter<Symbol> sf, 57125283Sdavidn final LookupKind lookupKind) { 57225283Sdavidn return () -> new Iterator<Symbol>() { 57325283Sdavidn private ScopeImpl currScope = ScopeImpl.this; 57425283Sdavidn private Entry currEntry = elems; 57525283Sdavidn private int seenRemoveCount = currScope.removeCount; 57625283Sdavidn { 57725283Sdavidn update(); 57825283Sdavidn } 57925283Sdavidn 58025283Sdavidn public boolean hasNext() { 58125283Sdavidn if (seenRemoveCount != currScope.removeCount && 58225283Sdavidn currEntry != null && 58325283Sdavidn !currEntry.scope.includes(currEntry.sym)) { 58425283Sdavidn doNext(); //skip entry that is no longer in the Scope 58525283Sdavidn seenRemoveCount = currScope.removeCount; 58625283Sdavidn } 58725283Sdavidn return currEntry != null; 58825283Sdavidn } 58925283Sdavidn 59025283Sdavidn public Symbol next() { 59125283Sdavidn if (!hasNext()) { 59225283Sdavidn throw new NoSuchElementException(); 59325283Sdavidn } 59425283Sdavidn 59525283Sdavidn return doNext(); 59625283Sdavidn } 59725283Sdavidn private Symbol doNext() { 59825283Sdavidn Symbol sym = (currEntry == null ? null : currEntry.sym); 59925283Sdavidn if (currEntry != null) { 60025283Sdavidn currEntry = currEntry.sibling; 60125283Sdavidn } 60225283Sdavidn update(); 60325283Sdavidn return sym; 60425283Sdavidn } 60525283Sdavidn 60625283Sdavidn private void update() { 60725283Sdavidn skipToNextMatchingEntry(); 60825283Sdavidn if (lookupKind == RECURSIVE) { 60925283Sdavidn while (currEntry == null && currScope.next != null) { 61025283Sdavidn currScope = currScope.next; 61125283Sdavidn currEntry = currScope.elems; 61225283Sdavidn seenRemoveCount = currScope.removeCount; 61325283Sdavidn skipToNextMatchingEntry(); 61425283Sdavidn } 61525283Sdavidn } 61625283Sdavidn } 61725283Sdavidn 61825283Sdavidn void skipToNextMatchingEntry() { 61925283Sdavidn while (currEntry != null && sf != null && !sf.accepts(currEntry.sym)) { 62025283Sdavidn currEntry = currEntry.sibling; 62125283Sdavidn } 62225283Sdavidn } 62325283Sdavidn }; 62425283Sdavidn } 62525283Sdavidn 62625283Sdavidn public Iterable<Symbol> getSymbolsByName(final Name name, 62725283Sdavidn final Filter<Symbol> sf, 62825283Sdavidn final LookupKind lookupKind) { 62925283Sdavidn return () -> new Iterator<Symbol>() { 63025283Sdavidn Entry currentEntry = lookup(name, sf); 63125283Sdavidn int seenRemoveCount = currentEntry.scope != null ? 63225283Sdavidn currentEntry.scope.removeCount : -1; 63325283Sdavidn 63425283Sdavidn public boolean hasNext() { 63525283Sdavidn if (currentEntry.scope != null && 63625283Sdavidn seenRemoveCount != currentEntry.scope.removeCount && 63725283Sdavidn !currentEntry.scope.includes(currentEntry.sym)) { 63825283Sdavidn doNext(); //skip entry that is no longer in the Scope 63925283Sdavidn } 64025283Sdavidn return currentEntry.scope != null && 64125283Sdavidn (lookupKind == RECURSIVE || 64225283Sdavidn currentEntry.scope == ScopeImpl.this); 64325283Sdavidn } 64425283Sdavidn public Symbol next() { 64525283Sdavidn if (!hasNext()) { 64625283Sdavidn throw new NoSuchElementException(); 64725283Sdavidn } 64825283Sdavidn return doNext(); 64925283Sdavidn } 65025283Sdavidn private Symbol doNext() { 65125283Sdavidn Entry prevEntry = currentEntry; 65225283Sdavidn currentEntry = currentEntry.next(sf); 65325283Sdavidn return prevEntry.sym; 65425283Sdavidn } 65525283Sdavidn public void remove() { 65625283Sdavidn throw new UnsupportedOperationException(); 65725283Sdavidn } 65825283Sdavidn }; 65925283Sdavidn } 66025283Sdavidn 66125283Sdavidn public Scope getOrigin(Symbol s) { 66225283Sdavidn for (Scope.Entry e = lookup(s.name); e.scope != null ; e = e.next()) { 66325283Sdavidn if (e.sym == s) { 66425283Sdavidn return this; 66525283Sdavidn } 66625283Sdavidn } 66725283Sdavidn return null; 66825283Sdavidn } 66925283Sdavidn 67025283Sdavidn @Override 67125283Sdavidn public boolean isStaticallyImported(Symbol s) { 67225283Sdavidn return false; 67325283Sdavidn } 67425283Sdavidn 67525283Sdavidn public String toString() { 67625283Sdavidn StringBuilder result = new StringBuilder(); 67725283Sdavidn result.append("Scope["); 67825283Sdavidn for (ScopeImpl s = this; s != null ; s = s.next) { 67925283Sdavidn if (s != this) result.append(" | "); 68025283Sdavidn for (Entry e = s.elems; e != null; e = e.sibling) { 68125283Sdavidn if (e != s.elems) result.append(", "); 68225283Sdavidn result.append(e.sym); 68325283Sdavidn } 68425283Sdavidn } 68525283Sdavidn result.append("]"); 68625283Sdavidn return result.toString(); 68725283Sdavidn } 68825283Sdavidn } 68925283Sdavidn 69025283Sdavidn /** A class for scope entries. 69125283Sdavidn */ 69225283Sdavidn private static class Entry { 69325283Sdavidn 69425283Sdavidn /** The referenced symbol. 69525283Sdavidn * sym == null iff this == sentinel 69625283Sdavidn */ 69725283Sdavidn public Symbol sym; 69825283Sdavidn 69925283Sdavidn /** An entry with the same hash code, or sentinel. 70025283Sdavidn */ 70125283Sdavidn private Entry shadowed; 70225283Sdavidn 70325283Sdavidn /** Next entry in same scope. 7041592Srgrimes */ 7051592Srgrimes public Entry sibling; 7061592Srgrimes 7071592Srgrimes /** The entry's scope. 7081592Srgrimes * scope == null iff this == sentinel 7091592Srgrimes */ 7101592Srgrimes public ScopeImpl scope; 7111592Srgrimes 7121592Srgrimes public Entry(Symbol sym, Entry shadowed, Entry sibling, ScopeImpl scope) { 7131592Srgrimes this.sym = sym; 7141592Srgrimes this.shadowed = shadowed; 7151592Srgrimes this.sibling = sibling; 7161592Srgrimes this.scope = scope; 7171592Srgrimes } 7181592Srgrimes 7191592Srgrimes /** Return next entry with the same name as this entry, proceeding 7201592Srgrimes * outwards if not found in this scope. 7211592Srgrimes */ 7221592Srgrimes public Entry next() { 7231592Srgrimes return shadowed; 7241592Srgrimes } 7251592Srgrimes 7261592Srgrimes public Entry next(Filter<Symbol> sf) { 7271592Srgrimes if (shadowed.sym == null || sf == null || sf.accepts(shadowed.sym)) return shadowed; 7281592Srgrimes else return shadowed.next(sf); 7291592Srgrimes } 7301592Srgrimes 7311592Srgrimes } 7321592Srgrimes 7331592Srgrimes public static class ImportScope extends CompoundScope { 7341592Srgrimes 7351592Srgrimes public ImportScope(Symbol owner) { 7361592Srgrimes super(owner); 7371592Srgrimes } 7381592Srgrimes 7391592Srgrimes /**Finalize the content of the ImportScope to speed-up future lookups. 7401592Srgrimes * No further changes to class hierarchy or class content will be reflected. 7411592Srgrimes */ 7421592Srgrimes public void finalizeScope() { 7431592Srgrimes for (List<Scope> scopes = this.subScopes; scopes.nonEmpty(); scopes = scopes.tail) { 7441592Srgrimes Scope impScope = scopes.head; 7451592Srgrimes 7461592Srgrimes if (impScope instanceof FilterImportScope && impScope.owner.kind == Kind.TYP) { 7471592Srgrimes WriteableScope finalized = WriteableScope.create(impScope.owner); 7481592Srgrimes 7491592Srgrimes for (Symbol sym : impScope.getSymbols()) { 7501592Srgrimes finalized.enter(sym); 7511592Srgrimes } 7521592Srgrimes 7531592Srgrimes finalized.listeners.add(new ScopeListener() { 7541592Srgrimes @Override 7551592Srgrimes public void symbolAdded(Symbol sym, Scope s) { 7561592Srgrimes Assert.error("The scope is sealed."); 7571592Srgrimes } 7581592Srgrimes 7591592Srgrimes @Override 7601592Srgrimes public void symbolRemoved(Symbol sym, Scope s) { 7611592Srgrimes Assert.error("The scope is sealed."); 7621592Srgrimes } 7631592Srgrimes }); 7641592Srgrimes 7651592Srgrimes scopes.head = finalized; 7661592Srgrimes } 7671592Srgrimes } 7681592Srgrimes } 7691592Srgrimes 7701592Srgrimes } 7711592Srgrimes 7721592Srgrimes public static class NamedImportScope extends ImportScope { 7731592Srgrimes 7741592Srgrimes public NamedImportScope(Symbol owner, Scope currentFileScope) { 7751592Srgrimes super(owner); 77617435Spst prependSubScope(currentFileScope); 77717435Spst } 77817435Spst 7791592Srgrimes public Scope importByName(Types types, Scope origin, Name name, ImportFilter filter, JCImport imp, BiConsumer<JCImport, CompletionFailure> cfHandler) { 7801592Srgrimes return appendScope(new FilterImportScope(types, origin, name, filter, imp, cfHandler)); 7811592Srgrimes } 7821592Srgrimes 7831592Srgrimes public Scope importType(Scope delegate, Scope origin, Symbol sym) { 7841592Srgrimes return appendScope(new SingleEntryScope(delegate.owner, sym, origin)); 78536349Ssteve } 78636349Ssteve 7871592Srgrimes private Scope appendScope(Scope newScope) { 78825283Sdavidn List<Scope> existingScopes = this.subScopes.reverse(); 78925283Sdavidn subScopes = List.of(existingScopes.head); 79025283Sdavidn subScopes = subScopes.prepend(newScope); 7911592Srgrimes for (Scope s : existingScopes.tail) { 79225283Sdavidn subScopes = subScopes.prepend(s); 7931592Srgrimes } 7941592Srgrimes return newScope; 7951592Srgrimes } 7963938Spst 7971592Srgrimes private static class SingleEntryScope extends Scope { 7981592Srgrimes 7991592Srgrimes private final Symbol sym; 8001592Srgrimes private final List<Symbol> content; 8011592Srgrimes private final Scope origin; 8021592Srgrimes 8031592Srgrimes public SingleEntryScope(Symbol owner, Symbol sym, Scope origin) { 80420042Storstenb super(owner); 80520042Storstenb this.sym = sym; 80620042Storstenb this.content = List.of(sym); 80720042Storstenb this.origin = origin; 80820042Storstenb } 80917478Smarkm 8101592Srgrimes @Override 8111592Srgrimes public Iterable<Symbol> getSymbols(Filter<Symbol> sf, LookupKind lookupKind) { 8121592Srgrimes return sf == null || sf.accepts(sym) ? content : Collections.emptyList(); 8131592Srgrimes } 8141592Srgrimes 8151592Srgrimes @Override 8161592Srgrimes public Iterable<Symbol> getSymbolsByName(Name name, 81736349Ssteve Filter<Symbol> sf, 8181592Srgrimes LookupKind lookupKind) { 8191592Srgrimes return sym.name == name && 8201592Srgrimes (sf == null || sf.accepts(sym)) ? content : Collections.emptyList(); 8211592Srgrimes } 8221592Srgrimes 8231592Srgrimes @Override 8241592Srgrimes public Scope getOrigin(Symbol byName) { 8251592Srgrimes return sym == byName ? origin : null; 8261592Srgrimes } 8271592Srgrimes 8281592Srgrimes @Override 8292193Sguido public boolean isStaticallyImported(Symbol byName) { 8303938Spst return false; 83119018Sache } 8322193Sguido 8331592Srgrimes } 8342193Sguido } 8351592Srgrimes 8361592Srgrimes public static class StarImportScope extends ImportScope { 8371592Srgrimes 8381592Srgrimes public StarImportScope(Symbol owner) { 8391592Srgrimes super(owner); 8401592Srgrimes } 8411592Srgrimes 8421592Srgrimes public void importAll(Types types, Scope origin, 8431592Srgrimes ImportFilter filter, 8441592Srgrimes JCImport imp, 84517435Spst BiConsumer<JCImport, CompletionFailure> cfHandler) { 8461592Srgrimes for (Scope existing : subScopes) { 8471592Srgrimes Assert.check(existing instanceof FilterImportScope); 84836349Ssteve FilterImportScope fis = (FilterImportScope) existing; 84917435Spst if (fis.origin == origin && fis.filter == filter && 8501592Srgrimes fis.imp.staticImport == imp.staticImport) 85136349Ssteve return ; //avoid entering the same scope twice 8521592Srgrimes } 8531592Srgrimes prependSubScope(new FilterImportScope(types, origin, null, filter, imp, cfHandler)); 8541592Srgrimes } 8551592Srgrimes 8561592Srgrimes public boolean isFilled() { 85717435Spst return subScopes.nonEmpty(); 85825187Sdavidn } 8591592Srgrimes 8601592Srgrimes } 8611592Srgrimes 8621592Srgrimes public interface ImportFilter { 86325187Sdavidn public boolean accepts(Scope origin, Symbol sym); 86425187Sdavidn } 86525187Sdavidn 86625187Sdavidn private static class FilterImportScope extends Scope { 86725187Sdavidn 86825187Sdavidn private final Types types; 86925187Sdavidn private final Scope origin; 87025187Sdavidn private final Name filterName; 87125187Sdavidn private final ImportFilter filter; 87236349Ssteve private final JCImport imp; 87336349Ssteve private final BiConsumer<JCImport, CompletionFailure> cfHandler; 87436349Ssteve 87536349Ssteve public FilterImportScope(Types types, 87636349Ssteve Scope origin, 87736349Ssteve Name filterName, 87836349Ssteve ImportFilter filter, 87936349Ssteve JCImport imp, 88025187Sdavidn BiConsumer<JCImport, CompletionFailure> cfHandler) { 88125187Sdavidn super(origin.owner); 88225187Sdavidn this.types = types; 88325187Sdavidn this.origin = origin; 8841592Srgrimes this.filterName = filterName; 88525187Sdavidn this.filter = filter; 88625187Sdavidn this.imp = imp; 88725187Sdavidn this.cfHandler = cfHandler; 88825187Sdavidn } 88925187Sdavidn 8901592Srgrimes @Override 8911592Srgrimes public Iterable<Symbol> getSymbols(final Filter<Symbol> sf, final LookupKind lookupKind) { 8921592Srgrimes if (filterName != null) 8931592Srgrimes return getSymbolsByName(filterName, sf, lookupKind); 8941592Srgrimes try { 8951592Srgrimes SymbolImporter si = new SymbolImporter(imp.staticImport) { 8961592Srgrimes @Override 8971592Srgrimes Iterable<Symbol> doLookup(TypeSymbol tsym) { 8981592Srgrimes return tsym.members().getSymbols(sf, lookupKind); 8991592Srgrimes } 9001592Srgrimes }; 9011592Srgrimes List<Iterable<Symbol>> results = 9021592Srgrimes si.importFrom((TypeSymbol) origin.owner, List.nil()); 9031592Srgrimes return () -> createFilterIterator(createCompoundIterator(results, 9041592Srgrimes Iterable::iterator), 9051592Srgrimes s -> filter.accepts(origin, s)); 90629140Stg } catch (CompletionFailure cf) { 9071592Srgrimes cfHandler.accept(imp, cf); 90825101Sdavidn return Collections.emptyList(); 90925101Sdavidn } 91025101Sdavidn } 91125101Sdavidn 9121592Srgrimes @Override 9131592Srgrimes public Iterable<Symbol> getSymbolsByName(final Name name, 91417435Spst final Filter<Symbol> sf, 9151592Srgrimes final LookupKind lookupKind) { 9161592Srgrimes if (filterName != null && filterName != name) 9171592Srgrimes return Collections.emptyList(); 9181592Srgrimes try { 9191592Srgrimes SymbolImporter si = new SymbolImporter(imp.staticImport) { 9201592Srgrimes @Override 92117435Spst Iterable<Symbol> doLookup(TypeSymbol tsym) { 9221592Srgrimes return tsym.members().getSymbolsByName(name, sf, lookupKind); 92325101Sdavidn } 92425101Sdavidn }; 92525101Sdavidn List<Iterable<Symbol>> results = 9261592Srgrimes si.importFrom((TypeSymbol) origin.owner, List.nil()); 9271592Srgrimes return () -> createFilterIterator(createCompoundIterator(results, 9281592Srgrimes Iterable::iterator), 9291592Srgrimes s -> filter.accepts(origin, s)); 9301592Srgrimes } catch (CompletionFailure cf) { 9311592Srgrimes cfHandler.accept(imp, cf); 9321592Srgrimes return Collections.emptyList(); 93317435Spst } 93417435Spst } 93517435Spst 93617435Spst @Override 93717435Spst public Scope getOrigin(Symbol byName) { 93817435Spst return origin; 93917435Spst } 94017435Spst 94117435Spst @Override 9422193Sguido public boolean isStaticallyImported(Symbol byName) { 94317435Spst return imp.staticImport; 94417451Sphk } 9453206Spst 9462193Sguido abstract class SymbolImporter { 94717453Sphk Set<Symbol> processed = new HashSet<>(); 9482193Sguido List<Iterable<Symbol>> delegates = List.nil(); 9491592Srgrimes final boolean inspectSuperTypes; 95017435Spst public SymbolImporter(boolean inspectSuperTypes) { 95117435Spst this.inspectSuperTypes = inspectSuperTypes; 95217435Spst } 95317435Spst List<Iterable<Symbol>> importFrom(TypeSymbol tsym, List<Iterable<Symbol>> results) { 95417435Spst if (tsym == null || !processed.add(tsym)) 95517435Spst return results; 95617435Spst 95717435Spst 95817435Spst if (inspectSuperTypes) { 95917435Spst // also import inherited names 9601592Srgrimes results = importFrom(types.supertype(tsym.type).tsym, results); 9611592Srgrimes for (Type t : types.interfaces(tsym.type)) 9621592Srgrimes results = importFrom(t.tsym, results); 9631592Srgrimes } 9641592Srgrimes 9651592Srgrimes return results.prepend(doLookup(tsym)); 9661592Srgrimes } 9671592Srgrimes abstract Iterable<Symbol> doLookup(TypeSymbol tsym); 9681592Srgrimes } 9691592Srgrimes 9701592Srgrimes } 9711592Srgrimes 9721592Srgrimes /** A class scope adds capabilities to keep track of changes in related 9731592Srgrimes * class scopes - this allows client to realize whether a class scope 9741592Srgrimes * has changed, either directly (because a new member has been added/removed 9751592Srgrimes * to this scope) or indirectly (i.e. because a new member has been 9761592Srgrimes * added/removed into a supertype scope) 9771592Srgrimes */ 9781592Srgrimes public static class CompoundScope extends Scope implements ScopeListener { 9791592Srgrimes 98025101Sdavidn List<Scope> subScopes = List.nil(); 98125101Sdavidn private int mark = 0; 98225101Sdavidn 98325674Sdavidn public CompoundScope(Symbol owner) { 98425101Sdavidn super(owner); 98525101Sdavidn } 98625101Sdavidn 98725101Sdavidn public void prependSubScope(Scope that) { 98825101Sdavidn if (that != null) { 98925101Sdavidn subScopes = subScopes.prepend(that); 99025101Sdavidn that.listeners.add(this); 99125101Sdavidn mark++; 99225101Sdavidn listeners.symbolAdded(null, this); 99325101Sdavidn } 99425101Sdavidn } 99525101Sdavidn 99625101Sdavidn public void symbolAdded(Symbol sym, Scope s) { 99725101Sdavidn mark++; 99825101Sdavidn listeners.symbolAdded(sym, s); 99925101Sdavidn } 100025101Sdavidn 100125101Sdavidn public void symbolRemoved(Symbol sym, Scope s) { 100225101Sdavidn mark++; 100325101Sdavidn listeners.symbolRemoved(sym, s); 100440310Sdes } 100540310Sdes 100625101Sdavidn public int getMark() { 100740310Sdes return mark; 10081592Srgrimes } 100925101Sdavidn 10101592Srgrimes @Override 10111592Srgrimes public String toString() { 101229140Stg StringBuilder buf = new StringBuilder(); 10131592Srgrimes buf.append("CompoundScope{"); 10141592Srgrimes String sep = ""; 101517435Spst for (Scope s : subScopes) { 101625283Sdavidn buf.append(sep); 101725283Sdavidn buf.append(s); 101825283Sdavidn sep = ","; 10196740Sguido } 102025283Sdavidn buf.append("}"); 10216740Sguido return buf.toString(); 10226740Sguido } 102325101Sdavidn 102425101Sdavidn @Override 102525101Sdavidn public Iterable<Symbol> getSymbols(final Filter<Symbol> sf, 102625101Sdavidn final LookupKind lookupKind) { 102736349Ssteve return () -> Iterators.createCompoundIterator(subScopes, 10281592Srgrimes scope -> scope.getSymbols(sf, 10291592Srgrimes lookupKind) 10301592Srgrimes .iterator()); 10311592Srgrimes } 10321592Srgrimes 10331592Srgrimes @Override 10341592Srgrimes public Iterable<Symbol> getSymbolsByName(final Name name, 10351592Srgrimes final Filter<Symbol> sf, 10361592Srgrimes final LookupKind lookupKind) { 10371592Srgrimes return () -> Iterators.createCompoundIterator(subScopes, 103817435Spst scope -> scope.getSymbolsByName(name, 103917435Spst sf, 104017435Spst lookupKind) 104117435Spst .iterator()); 104217435Spst } 10431592Srgrimes 10441592Srgrimes @Override 10451592Srgrimes public Scope getOrigin(Symbol sym) { 10461592Srgrimes for (Scope delegate : subScopes) { 10471592Srgrimes if (delegate.includes(sym)) 10481592Srgrimes return delegate.getOrigin(sym); 10491592Srgrimes } 10501592Srgrimes 10511592Srgrimes return null; 10521592Srgrimes } 10531592Srgrimes 10541592Srgrimes @Override 10558696Sdg public boolean isStaticallyImported(Symbol sym) { 10561592Srgrimes for (Scope delegate : subScopes) { 10571592Srgrimes if (delegate.includes(sym)) 10581592Srgrimes return delegate.isStaticallyImported(sym); 10591592Srgrimes } 106025283Sdavidn 106125283Sdavidn return false; 106225283Sdavidn } 10631592Srgrimes 106425283Sdavidn } 10651592Srgrimes 10661592Srgrimes /** An error scope, for which the owner should be an error symbol. */ 10671592Srgrimes public static class ErrorScope extends ScopeImpl { 10681592Srgrimes ErrorScope(ScopeImpl next, Symbol errSymbol, Entry[] table) { 10691592Srgrimes super(next, /*owner=*/errSymbol, table); 10701592Srgrimes } 10711592Srgrimes public ErrorScope(Symbol errSymbol) { 10721592Srgrimes super(errSymbol); 10731592Srgrimes } 10741592Srgrimes public WriteableScope dup(Symbol newOwner) { 10751592Srgrimes return new ErrorScope(this, newOwner, table); 10766740Sguido } 10776740Sguido public WriteableScope dupUnshared(Symbol newOwner) { 107817433Spst return new ErrorScope(this, newOwner, table.clone()); 107917433Spst } 108017433Spst public Entry lookup(Name name) { 108117433Spst Entry e = super.lookup(name); 10821592Srgrimes if (e.scope == null) 10831592Srgrimes return new Entry(owner, null, null, null); 108425283Sdavidn else 108525283Sdavidn return e; 108625283Sdavidn } 108725283Sdavidn } 108825283Sdavidn} 108925283Sdavidn