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