Scope.java revision 2571:10fc81ac75b4
1/* 2 * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.tools.javac.code; 27 28import java.util.*; 29 30import com.sun.tools.javac.util.*; 31import com.sun.tools.javac.util.List; 32 33import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; 34import static com.sun.tools.javac.code.Scope.LookupKind.RECURSIVE; 35 36/** A scope represents an area of visibility in a Java program. The 37 * Scope class is a container for symbols which provides 38 * efficient access to symbols given their names. Scopes are implemented 39 * as hash tables with "open addressing" and "double hashing". 40 * Scopes can be nested. Nested scopes can share their hash tables. 41 * 42 * <p><b>This is NOT part of any supported API. 43 * If you write code that depends on this, you do so at your own risk. 44 * This code and its internal interfaces are subject to change or 45 * deletion without notice.</b> 46 */ 47public abstract class Scope { 48 49 /** The scope's owner. 50 */ 51 public final Symbol owner; 52 53 protected Scope(Symbol owner) { 54 this.owner = owner; 55 } 56 57 /**Returns all Symbols in this Scope. Symbols from outward Scopes are included. 58 */ 59 public final Iterable<Symbol> getSymbols() { 60 return getSymbols(noFilter); 61 } 62 63 /**Returns Symbols that match the given filter. Symbols from outward Scopes are included. 64 */ 65 public final Iterable<Symbol> getSymbols(Filter<Symbol> sf) { 66 return getSymbols(sf, RECURSIVE); 67 } 68 69 /**Returns all Symbols in this Scope. Symbols from outward Scopes are included 70 * iff lookupKind == RECURSIVE. 71 */ 72 public final Iterable<Symbol> getSymbols(LookupKind lookupKind) { 73 return getSymbols(noFilter, lookupKind); 74 } 75 76 /**Returns Symbols that match the given filter. Symbols from outward Scopes are included 77 * iff lookupKind == RECURSIVE. 78 */ 79 public abstract Iterable<Symbol> getSymbols(Filter<Symbol> sf, LookupKind lookupKind); 80 81 /**Returns Symbols with the given name. Symbols from outward Scopes are included. 82 */ 83 public final Iterable<Symbol> getSymbolsByName(Name name) { 84 return getSymbolsByName(name, RECURSIVE); 85 } 86 87 /**Returns Symbols with the given name that match the given filter. 88 * Symbols from outward Scopes are included. 89 */ 90 public final Iterable<Symbol> getSymbolsByName(final Name name, final Filter<Symbol> sf) { 91 return getSymbolsByName(name, sf, RECURSIVE); 92 } 93 94 /**Returns Symbols with the given name. Symbols from outward Scopes are included 95 * iff lookupKind == RECURSIVE. 96 */ 97 public final Iterable<Symbol> getSymbolsByName(Name name, LookupKind lookupKind) { 98 return getSymbolsByName(name, noFilter, lookupKind); 99 } 100 101 /**Returns Symbols with the given name that match the given filter. 102 * Symbols from outward Scopes are included iff lookupKind == RECURSIVE. 103 */ 104 public abstract Iterable<Symbol> getSymbolsByName(final Name name, final Filter<Symbol> sf, 105 final LookupKind lookupKind); 106 107 /** Return the first Symbol from this or outward scopes with the given name. 108 * Returns null if none. 109 */ 110 public final Symbol findFirst(Name name) { 111 return findFirst(name, noFilter); 112 } 113 114 /** Return the first Symbol from this or outward scopes with the given name that matches the 115 * given filter. Returns null if none. 116 */ 117 public Symbol findFirst(Name name, Filter<Symbol> sf) { 118 Iterator<Symbol> it = getSymbolsByName(name, sf).iterator(); 119 return it.hasNext() ? it.next() : null; 120 } 121 122 /** Returns true iff there are is at least one Symbol in this scope matching the given filter. 123 * Does not inspect outward scopes. 124 */ 125 public boolean anyMatch(Filter<Symbol> filter) { 126 return getSymbols(filter, NON_RECURSIVE).iterator().hasNext(); 127 } 128 129 /** Returns true iff the given Symbol is in this scope or any outward scope. 130 */ 131 public boolean includes(final Symbol sym) { 132 return getSymbolsByName(sym.name, new Filter<Symbol>() { 133 @Override 134 public boolean accepts(Symbol t) { 135 return t == sym; 136 } 137 }).iterator().hasNext(); 138 } 139 140 /** Returns true iff this scope does not contain any Symbol. Does not inspect outward scopes. 141 */ 142 public boolean isEmpty() { 143 return !getSymbols(NON_RECURSIVE).iterator().hasNext(); 144 } 145 146 /** Returns the Scope from which the givins Symbol originates in this scope. 147 */ 148 public abstract Scope getOrigin(Symbol byName); 149 150 /** Returns true iff the given Symbol is part of this scope due to a static import. 151 */ 152 public abstract boolean isStaticallyImported(Symbol byName); 153 154 private static final Filter<Symbol> noFilter = null; 155 156 /** A list of scopes to be notified if items are to be removed from this scope. 157 */ 158 List<ScopeListener> listeners = List.nil(); 159 160 public void addScopeListener(ScopeListener sl) { 161 listeners = listeners.prepend(sl); 162 } 163 164 public interface ScopeListener { 165 public void symbolAdded(Symbol sym, Scope s); 166 public void symbolRemoved(Symbol sym, Scope s); 167 } 168 169 public enum LookupKind { 170 RECURSIVE, 171 NON_RECURSIVE; 172 } 173 174 /**A scope into which Symbols can be added.*/ 175 public abstract static class WriteableScope extends Scope { 176 177 public WriteableScope(Symbol owner) { 178 super(owner); 179 } 180 181 /** Enter the given Symbol into this scope. 182 */ 183 public abstract void enter(Symbol c); 184 /** Enter symbol sym in this scope if not already there. 185 */ 186 public abstract void enterIfAbsent(Symbol c); 187 188 public abstract void remove(Symbol c); 189 190 /** Construct a fresh scope within this scope, with same owner. The new scope may 191 * shares internal structures with the this scope. Used in connection with 192 * method leave if scope access is stack-like in order to avoid allocation 193 * of fresh tables. 194 */ 195 public final WriteableScope dup() { 196 return dup(this.owner); 197 } 198 199 /** Construct a fresh scope within this scope, with new owner. The new scope may 200 * shares internal structures with the this scope. Used in connection with 201 * method leave if scope access is stack-like in order to avoid allocation 202 * of fresh tables. 203 */ 204 public abstract WriteableScope dup(Symbol newOwner); 205 206 /** Must be called on dup-ed scopes to be able to work with the outward scope again. 207 */ 208 public abstract WriteableScope leave(); 209 210 /** Construct a fresh scope within this scope, with same owner. The new scope 211 * will not share internal structures with this scope. 212 */ 213 public final WriteableScope dupUnshared() { 214 return dupUnshared(owner); 215 } 216 217 /** Construct a fresh scope within this scope, with new owner. The new scope 218 * will not share internal structures with this scope. 219 */ 220 public abstract WriteableScope dupUnshared(Symbol newOwner); 221 222 /** Create a new WriteableScope. 223 */ 224 public static WriteableScope create(Symbol owner) { 225 return new ScopeImpl(owner); 226 } 227 228 } 229 230 private static class ScopeImpl extends WriteableScope { 231 /** The number of scopes that share this scope's hash table. 232 */ 233 private int shared; 234 235 /** Next enclosing scope (with whom this scope may share a hashtable) 236 */ 237 public ScopeImpl next; 238 239 /** A hash table for the scope's entries. 240 */ 241 Entry[] table; 242 243 /** Mask for hash codes, always equal to (table.length - 1). 244 */ 245 int hashMask; 246 247 /** A linear list that also contains all entries in 248 * reverse order of appearance (i.e later entries are pushed on top). 249 */ 250 public Entry elems; 251 252 /** The number of elements in this scope. 253 * This includes deleted elements, whose value is the sentinel. 254 */ 255 int nelems = 0; 256 257 /** Use as a "not-found" result for lookup. 258 * Also used to mark deleted entries in the table. 259 */ 260 private static final Entry sentinel = new Entry(null, null, null, null); 261 262 /** The hash table's initial size. 263 */ 264 private static final int INITIAL_SIZE = 0x10; 265 266 /** Construct a new scope, within scope next, with given owner, using 267 * given table. The table's length must be an exponent of 2. 268 */ 269 private ScopeImpl(ScopeImpl next, Symbol owner, Entry[] table) { 270 super(owner); 271 this.next = next; 272 Assert.check(owner != null); 273 this.table = table; 274 this.hashMask = table.length - 1; 275 } 276 277 /** Convenience constructor used for dup and dupUnshared. */ 278 private ScopeImpl(ScopeImpl next, Symbol owner, Entry[] table, int nelems) { 279 this(next, owner, table); 280 this.nelems = nelems; 281 } 282 283 /** Construct a new scope, within scope next, with given owner, 284 * using a fresh table of length INITIAL_SIZE. 285 */ 286 public ScopeImpl(Symbol owner) { 287 this(null, owner, new Entry[INITIAL_SIZE]); 288 } 289 290 /** Construct a fresh scope within this scope, with new owner, 291 * which shares its table with the outer scope. Used in connection with 292 * method leave if scope access is stack-like in order to avoid allocation 293 * of fresh tables. 294 */ 295 public WriteableScope dup(Symbol newOwner) { 296 ScopeImpl result = new ScopeImpl(this, newOwner, this.table, this.nelems); 297 shared++; 298 // System.out.println("====> duping scope " + this.hashCode() + " owned by " + newOwner + " to " + result.hashCode()); 299 // new Error().printStackTrace(System.out); 300 return result; 301 } 302 303 /** Construct a fresh scope within this scope, with new owner, 304 * with a new hash table, whose contents initially are those of 305 * the table of its outer scope. 306 */ 307 public WriteableScope dupUnshared(Symbol newOwner) { 308 return new ScopeImpl(this, newOwner, this.table.clone(), this.nelems); 309 } 310 311 /** Remove all entries of this scope from its table, if shared 312 * with next. 313 */ 314 public WriteableScope leave() { 315 Assert.check(shared == 0); 316 if (table != next.table) return next; 317 while (elems != null) { 318 int hash = getIndex(elems.sym.name); 319 Entry e = table[hash]; 320 Assert.check(e == elems, elems.sym); 321 table[hash] = elems.shadowed; 322 elems = elems.sibling; 323 } 324 Assert.check(next.shared > 0); 325 next.shared--; 326 next.nelems = nelems; 327 // System.out.println("====> leaving scope " + this.hashCode() + " owned by " + this.owner + " to " + next.hashCode()); 328 // new Error().printStackTrace(System.out); 329 return next; 330 } 331 332 /** Double size of hash table. 333 */ 334 private void dble() { 335 Assert.check(shared == 0); 336 Entry[] oldtable = table; 337 Entry[] newtable = new Entry[oldtable.length * 2]; 338 for (ScopeImpl s = this; s != null; s = s.next) { 339 if (s.table == oldtable) { 340 Assert.check(s == this || s.shared != 0); 341 s.table = newtable; 342 s.hashMask = newtable.length - 1; 343 } 344 } 345 int n = 0; 346 for (int i = oldtable.length; --i >= 0; ) { 347 Entry e = oldtable[i]; 348 if (e != null && e != sentinel) { 349 table[getIndex(e.sym.name)] = e; 350 n++; 351 } 352 } 353 // We don't need to update nelems for shared inherited scopes, 354 // since that gets handled by leave(). 355 nelems = n; 356 } 357 358 /** Enter symbol sym in this scope. 359 */ 360 public void enter(Symbol sym) { 361 Assert.check(shared == 0); 362 if (nelems * 3 >= hashMask * 2) 363 dble(); 364 int hash = getIndex(sym.name); 365 Entry old = table[hash]; 366 if (old == null) { 367 old = sentinel; 368 nelems++; 369 } 370 Entry e = new Entry(sym, old, elems, this); 371 table[hash] = e; 372 elems = e; 373 374 //notify listeners 375 for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) { 376 l.head.symbolAdded(sym, this); 377 } 378 } 379 380 /** Remove symbol from this scope. Used when an inner class 381 * attribute tells us that the class isn't a package member. 382 */ 383 public void remove(Symbol sym) { 384 Assert.check(shared == 0); 385 Entry e = lookup(sym.name); 386 if (e.scope == null) return; 387 388 // remove e from table and shadowed list; 389 int i = getIndex(sym.name); 390 Entry te = table[i]; 391 if (te == e) 392 table[i] = e.shadowed; 393 else while (true) { 394 if (te.shadowed == e) { 395 te.shadowed = e.shadowed; 396 break; 397 } 398 te = te.shadowed; 399 } 400 401 // remove e from elems and sibling list 402 te = elems; 403 if (te == e) 404 elems = e.sibling; 405 else while (true) { 406 if (te.sibling == e) { 407 te.sibling = e.sibling; 408 break; 409 } 410 te = te.sibling; 411 } 412 413 //notify listeners 414 for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) { 415 l.head.symbolRemoved(sym, this); 416 } 417 } 418 419 /** Enter symbol sym in this scope if not already there. 420 */ 421 public void enterIfAbsent(Symbol sym) { 422 Assert.check(shared == 0); 423 Entry e = lookup(sym.name); 424 while (e.scope == this && e.sym.kind != sym.kind) e = e.next(); 425 if (e.scope != this) enter(sym); 426 } 427 428 /** Given a class, is there already a class with same fully 429 * qualified name in this (import) scope? 430 */ 431 public boolean includes(Symbol c) { 432 for (Scope.Entry e = lookup(c.name); 433 e.scope == this; 434 e = e.next()) { 435 if (e.sym == c) return true; 436 } 437 return false; 438 } 439 440 /** Return the entry associated with given name, starting in 441 * this scope and proceeding outwards. If no entry was found, 442 * return the sentinel, which is characterized by having a null in 443 * both its scope and sym fields, whereas both fields are non-null 444 * for regular entries. 445 */ 446 protected Entry lookup(Name name) { 447 return lookup(name, noFilter); 448 } 449 450 protected Entry lookup(Name name, Filter<Symbol> sf) { 451 Entry e = table[getIndex(name)]; 452 if (e == null || e == sentinel) 453 return sentinel; 454 while (e.scope != null && (e.sym.name != name || (sf != null && !sf.accepts(e.sym)))) 455 e = e.shadowed; 456 return e; 457 } 458 459 public Symbol findFirst(Name name, Filter<Symbol> sf) { 460 return lookup(name, sf).sym; 461 } 462 463 /*void dump (java.io.PrintStream out) { 464 out.println(this); 465 for (int l=0; l < table.length; l++) { 466 Entry le = table[l]; 467 out.print("#"+l+": "); 468 if (le==sentinel) out.println("sentinel"); 469 else if(le == null) out.println("null"); 470 else out.println(""+le+" s:"+le.sym); 471 } 472 }*/ 473 474 /** Look for slot in the table. 475 * We use open addressing with double hashing. 476 */ 477 int getIndex (Name name) { 478 int h = name.hashCode(); 479 int i = h & hashMask; 480 // The expression below is always odd, so it is guaranteed 481 // to be mutually prime with table.length, a power of 2. 482 int x = hashMask - ((h + (h >> 16)) << 1); 483 int d = -1; // Index of a deleted item. 484 for (;;) { 485 Entry e = table[i]; 486 if (e == null) 487 return d >= 0 ? d : i; 488 if (e == sentinel) { 489 // We have to keep searching even if we see a deleted item. 490 // However, remember the index in case we fail to find the name. 491 if (d < 0) 492 d = i; 493 } else if (e.sym.name == name) 494 return i; 495 i = (i + x) & hashMask; 496 } 497 } 498 499 public boolean anyMatch(Filter<Symbol> sf) { 500 return getSymbols(sf, NON_RECURSIVE).iterator().hasNext(); 501 } 502 503 public Iterable<Symbol> getSymbols(final Filter<Symbol> sf, 504 final LookupKind lookupKind) { 505 return new Iterable<Symbol>() { 506 public Iterator<Symbol> iterator() { 507 return new Iterator<Symbol>() { 508 private ScopeImpl currScope = ScopeImpl.this; 509 private Scope.Entry currEntry = elems; 510 { 511 update(); 512 } 513 514 public boolean hasNext() { 515 return currEntry != null; 516 } 517 518 public Symbol next() { 519 Symbol sym = (currEntry == null ? null : currEntry.sym); 520 if (currEntry != null) { 521 currEntry = currEntry.sibling; 522 } 523 update(); 524 return sym; 525 } 526 527 public void remove() { 528 throw new UnsupportedOperationException(); 529 } 530 531 private void update() { 532 skipToNextMatchingEntry(); 533 if (lookupKind == RECURSIVE) { 534 while (currEntry == null && currScope.next != null) { 535 currScope = currScope.next; 536 currEntry = currScope.elems; 537 skipToNextMatchingEntry(); 538 } 539 } 540 } 541 542 void skipToNextMatchingEntry() { 543 while (currEntry != null && sf != null && !sf.accepts(currEntry.sym)) { 544 currEntry = currEntry.sibling; 545 } 546 } 547 }; 548 } 549 }; 550 } 551 552 public Iterable<Symbol> getSymbolsByName(final Name name, 553 final Filter<Symbol> sf, 554 final LookupKind lookupKind) { 555 return new Iterable<Symbol>() { 556 public Iterator<Symbol> iterator() { 557 return new Iterator<Symbol>() { 558 Scope.Entry currentEntry = lookup(name, sf); 559 560 public boolean hasNext() { 561 return currentEntry.scope != null && 562 (lookupKind == RECURSIVE || 563 currentEntry.scope == ScopeImpl.this); 564 } 565 public Symbol next() { 566 Scope.Entry prevEntry = currentEntry; 567 currentEntry = currentEntry.next(sf); 568 return prevEntry.sym; 569 } 570 public void remove() { 571 throw new UnsupportedOperationException(); 572 } 573 }; 574 } 575 }; 576 } 577 578 public Scope getOrigin(Symbol s) { 579 for (Scope.Entry e = lookup(s.name); e.scope != null ; e = e.next()) { 580 if (e.sym == s) { 581 return this; 582 } 583 } 584 return null; 585 } 586 587 @Override 588 public boolean isStaticallyImported(Symbol s) { 589 return false; 590 } 591 592 public String toString() { 593 StringBuilder result = new StringBuilder(); 594 result.append("Scope["); 595 for (ScopeImpl s = this; s != null ; s = s.next) { 596 if (s != this) result.append(" | "); 597 for (Entry e = s.elems; e != null; e = e.sibling) { 598 if (e != s.elems) result.append(", "); 599 result.append(e.sym); 600 } 601 } 602 result.append("]"); 603 return result.toString(); 604 } 605 } 606 607 /** A class for scope entries. 608 */ 609 private static class Entry { 610 611 /** The referenced symbol. 612 * sym == null iff this == sentinel 613 */ 614 public Symbol sym; 615 616 /** An entry with the same hash code, or sentinel. 617 */ 618 private Entry shadowed; 619 620 /** Next entry in same scope. 621 */ 622 public Entry sibling; 623 624 /** The entry's scope. 625 * scope == null iff this == sentinel 626 */ 627 public Scope scope; 628 629 public Entry(Symbol sym, Entry shadowed, Entry sibling, Scope scope) { 630 this.sym = sym; 631 this.shadowed = shadowed; 632 this.sibling = sibling; 633 this.scope = scope; 634 } 635 636 /** Return next entry with the same name as this entry, proceeding 637 * outwards if not found in this scope. 638 */ 639 public Entry next() { 640 return shadowed; 641 } 642 643 public Entry next(Filter<Symbol> sf) { 644 if (shadowed.sym == null || sf == null || sf.accepts(shadowed.sym)) return shadowed; 645 else return shadowed.next(sf); 646 } 647 648 } 649 650 public static class NamedImportScope extends CompoundScope { 651 652 public NamedImportScope(Symbol owner, Scope currentFileScope) { 653 super(owner); 654 prependSubScope(currentFileScope); 655 } 656 657 public void importByName(Scope delegate, Scope origin, Name name, ImportFilter filter) { 658 appendScope(new FilterImportScope(delegate, origin, name, filter, true)); 659 } 660 661 public void importType(Scope delegate, Scope origin, Symbol sym) { 662 appendScope(new SingleEntryScope(delegate.owner, sym, origin)); 663 } 664 665 private void appendScope(Scope newScope) { 666 List<Scope> existingScopes = this.subScopes.reverse(); 667 subScopes = List.of(existingScopes.head); 668 subScopes = subScopes.prepend(newScope); 669 for (Scope s : existingScopes.tail) { 670 subScopes = subScopes.prepend(s); 671 } 672 } 673 674 private static class SingleEntryScope extends Scope { 675 676 private final Symbol sym; 677 private final List<Symbol> content; 678 private final Scope origin; 679 680 public SingleEntryScope(Symbol owner, Symbol sym, Scope origin) { 681 super(owner); 682 this.sym = sym; 683 this.content = List.of(sym); 684 this.origin = origin; 685 } 686 687 @Override 688 public Iterable<Symbol> getSymbols(Filter<Symbol> sf, LookupKind lookupKind) { 689 return sf == null || sf.accepts(sym) ? content : Collections.<Symbol>emptyList(); 690 } 691 692 @Override 693 public Iterable<Symbol> getSymbolsByName(Name name, 694 Filter<Symbol> sf, 695 LookupKind lookupKind) { 696 return sym.name == name && 697 (sf == null || sf.accepts(sym)) ? content : Collections.<Symbol>emptyList(); 698 } 699 700 @Override 701 public Scope getOrigin(Symbol byName) { 702 return sym == byName ? origin : null; 703 } 704 705 @Override 706 public boolean isStaticallyImported(Symbol byName) { 707 return false; 708 } 709 710 } 711 } 712 713 public static class StarImportScope extends CompoundScope { 714 715 public StarImportScope(Symbol owner) { 716 super(owner); 717 } 718 719 public void importAll(Scope delegate, 720 Scope origin, 721 ImportFilter filter, 722 boolean staticImport) { 723 for (Scope existing : subScopes) { 724 Assert.check(existing instanceof FilterImportScope); 725 FilterImportScope fis = (FilterImportScope) existing; 726 if (fis.delegate == delegate && fis.origin == origin && 727 fis.filter == filter && fis.staticImport == staticImport) 728 return ; //avoid entering the same scope twice 729 } 730 prependSubScope(new FilterImportScope(delegate, origin, null, filter, staticImport)); 731 } 732 733 } 734 735 public interface ImportFilter { 736 public boolean accepts(Scope origin, Symbol sym); 737 } 738 739 private static class FilterImportScope extends Scope { 740 741 private final Scope delegate; 742 private final Scope origin; 743 private final Name filterName; 744 private final ImportFilter filter; 745 private final boolean staticImport; 746 747 public FilterImportScope(Scope delegate, 748 Scope origin, 749 Name filterName, 750 ImportFilter filter, 751 boolean staticImport) { 752 super(delegate.owner); 753 this.delegate = delegate; 754 this.origin = origin; 755 this.filterName = filterName; 756 this.filter = filter; 757 this.staticImport = staticImport; 758 } 759 760 @Override 761 public Iterable<Symbol> getSymbols(Filter<Symbol> sf, LookupKind lookupKind) { 762 if (filterName != null) 763 return getSymbolsByName(filterName, sf, lookupKind); 764 return new FilteredIterable(delegate.getSymbols(sf, lookupKind)); 765 } 766 767 @Override 768 public Iterable<Symbol> getSymbolsByName(Name name, 769 Filter<Symbol> sf, 770 LookupKind lookupKind) { 771 if (filterName != null && filterName != name) 772 return Collections.emptyList(); 773 return new FilteredIterable(delegate.getSymbolsByName(name, sf, lookupKind)); 774 } 775 776 @Override 777 public Scope getOrigin(Symbol byName) { 778 return origin; 779 } 780 781 @Override 782 public boolean isStaticallyImported(Symbol byName) { 783 return staticImport; 784 } 785 786 private class FilteredIterator implements Iterator<Symbol> { 787 private final Iterator<Symbol> delegate; 788 private Symbol next; 789 790 public FilteredIterator(Iterator<Symbol> delegate) { 791 this.delegate = delegate; 792 update(); 793 } 794 795 void update() { 796 while (delegate.hasNext()) { 797 if (filter.accepts(origin, next = delegate.next())) 798 return; 799 } 800 801 next = null; 802 } 803 804 @Override 805 public boolean hasNext() { 806 return next != null; 807 } 808 809 @Override 810 public Symbol next() { 811 Symbol result = next; 812 813 update(); 814 815 return result; 816 } 817 818 @Override 819 public void remove() { 820 throw new UnsupportedOperationException("Not supported."); 821 } 822 823 } 824 825 private class FilteredIterable implements Iterable<Symbol> { 826 827 private final Iterable<Symbol> unfiltered; 828 829 public FilteredIterable(Iterable<Symbol> unfiltered) { 830 this.unfiltered = unfiltered; 831 } 832 833 @Override 834 public Iterator<Symbol> iterator() { 835 return new FilteredIterator(unfiltered.iterator()); 836 } 837 } 838 839 } 840 841 /** A class scope adds capabilities to keep track of changes in related 842 * class scopes - this allows client to realize whether a class scope 843 * has changed, either directly (because a new member has been added/removed 844 * to this scope) or indirectly (i.e. because a new member has been 845 * added/removed into a supertype scope) 846 */ 847 public static class CompoundScope extends Scope implements ScopeListener { 848 849 List<Scope> subScopes = List.nil(); 850 private int mark = 0; 851 852 public CompoundScope(Symbol owner) { 853 super(owner); 854 } 855 856 public void prependSubScope(Scope that) { 857 if (that != null) { 858 subScopes = subScopes.prepend(that); 859 that.addScopeListener(this); 860 mark++; 861 for (ScopeListener sl : listeners) { 862 sl.symbolAdded(null, this); //propagate upwards in case of nested CompoundScopes 863 } 864 } 865 } 866 867 public void symbolAdded(Symbol sym, Scope s) { 868 mark++; 869 for (ScopeListener sl : listeners) { 870 sl.symbolAdded(sym, s); 871 } 872 } 873 874 public void symbolRemoved(Symbol sym, Scope s) { 875 mark++; 876 for (ScopeListener sl : listeners) { 877 sl.symbolRemoved(sym, s); 878 } 879 } 880 881 public int getMark() { 882 return mark; 883 } 884 885 @Override 886 public String toString() { 887 StringBuilder buf = new StringBuilder(); 888 buf.append("CompoundScope{"); 889 String sep = ""; 890 for (Scope s : subScopes) { 891 buf.append(sep); 892 buf.append(s); 893 sep = ","; 894 } 895 buf.append("}"); 896 return buf.toString(); 897 } 898 899 @Override 900 public Iterable<Symbol> getSymbols(final Filter<Symbol> sf, 901 final LookupKind lookupKind) { 902 return new Iterable<Symbol>() { 903 public Iterator<Symbol> iterator() { 904 return new CompoundScopeIterator(subScopes) { 905 Iterator<Symbol> nextIterator(Scope s) { 906 return s.getSymbols(sf, lookupKind).iterator(); 907 } 908 }; 909 } 910 }; 911 } 912 913 @Override 914 public Iterable<Symbol> getSymbolsByName(final Name name, 915 final Filter<Symbol> sf, 916 final LookupKind lookupKind) { 917 return new Iterable<Symbol>() { 918 public Iterator<Symbol> iterator() { 919 return new CompoundScopeIterator(subScopes) { 920 Iterator<Symbol> nextIterator(Scope s) { 921 return s.getSymbolsByName(name, sf, lookupKind).iterator(); 922 } 923 }; 924 } 925 }; 926 } 927 928 @Override 929 public Scope getOrigin(Symbol sym) { 930 for (Scope delegate : subScopes) { 931 if (delegate.includes(sym)) 932 return delegate.getOrigin(sym); 933 } 934 935 return null; 936 } 937 938 @Override 939 public boolean isStaticallyImported(Symbol sym) { 940 for (Scope delegate : subScopes) { 941 if (delegate.includes(sym)) 942 return delegate.isStaticallyImported(sym); 943 } 944 945 return false; 946 } 947 948 abstract class CompoundScopeIterator implements Iterator<Symbol> { 949 950 private Iterator<Symbol> currentIterator; 951 private List<Scope> scopesToScan; 952 953 public CompoundScopeIterator(List<Scope> scopesToScan) { 954 this.scopesToScan = scopesToScan; 955 update(); 956 } 957 958 abstract Iterator<Symbol> nextIterator(Scope s); 959 960 public boolean hasNext() { 961 return currentIterator != null; 962 } 963 964 public Symbol next() { 965 Symbol sym = currentIterator.next(); 966 if (!currentIterator.hasNext()) { 967 update(); 968 } 969 return sym; 970 } 971 972 public void remove() { 973 throw new UnsupportedOperationException(); 974 } 975 976 private void update() { 977 while (scopesToScan.nonEmpty()) { 978 currentIterator = nextIterator(scopesToScan.head); 979 scopesToScan = scopesToScan.tail; 980 if (currentIterator.hasNext()) return; 981 } 982 currentIterator = null; 983 } 984 } 985 } 986 987 /** An error scope, for which the owner should be an error symbol. */ 988 public static class ErrorScope extends ScopeImpl { 989 ErrorScope(ScopeImpl next, Symbol errSymbol, Entry[] table) { 990 super(next, /*owner=*/errSymbol, table); 991 } 992 public ErrorScope(Symbol errSymbol) { 993 super(errSymbol); 994 } 995 public WriteableScope dup(Symbol newOwner) { 996 return new ErrorScope(this, newOwner, table); 997 } 998 public WriteableScope dupUnshared(Symbol newOwner) { 999 return new ErrorScope(this, newOwner, table.clone()); 1000 } 1001 public Entry lookup(Name name) { 1002 Entry e = super.lookup(name); 1003 if (e.scope == null) 1004 return new Entry(owner, null, null, null); 1005 else 1006 return e; 1007 } 1008 } 1009} 1010