Tue, 15 Feb 2011 11:49:46 +0000
7017664: Add listeners infrastracture to javac scopes
Summary: Add listeners to javac scopes, added CompoundScope and correct invalidation logic for ImplementationCache
Reviewed-by: jjg
1.1 --- a/src/share/classes/com/sun/tools/javac/code/Scope.java Mon Feb 14 14:27:47 2011 -0800 1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Scope.java Tue Feb 15 11:49:46 2011 +0000 1.3 @@ -74,7 +74,7 @@ 1.4 1.5 /** A list of scopes to be notified if items are to be removed from this scope. 1.6 */ 1.7 - List<Scope> listeners = List.nil(); 1.8 + List<ScopeListener> listeners = List.nil(); 1.9 1.10 /** Use as a "not-found" result for lookup. 1.11 * Also used to mark deleted entries in the table. 1.12 @@ -219,12 +219,27 @@ 1.13 Entry e = makeEntry(sym, old, elems, s, origin); 1.14 table[hash] = e; 1.15 elems = e; 1.16 + 1.17 + //notify listeners 1.18 + for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) { 1.19 + l.head.symbolAdded(sym, this); 1.20 + } 1.21 } 1.22 1.23 Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { 1.24 return new Entry(sym, shadowed, sibling, scope); 1.25 } 1.26 1.27 + 1.28 + public interface ScopeListener { 1.29 + public void symbolAdded(Symbol sym, Scope s); 1.30 + public void symbolRemoved(Symbol sym, Scope s); 1.31 + } 1.32 + 1.33 + public void addScopeListener(ScopeListener sl) { 1.34 + listeners = listeners.prepend(sl); 1.35 + } 1.36 + 1.37 /** Remove symbol from this scope. Used when an inner class 1.38 * attribute tells us that the class isn't a package member. 1.39 */ 1.40 @@ -258,9 +273,9 @@ 1.41 te = te.sibling; 1.42 } 1.43 1.44 - // remove items from scopes that have done importAll 1.45 - for (List<Scope> l = listeners; l.nonEmpty(); l = l.tail) { 1.46 - l.head.remove(sym); 1.47 + //notify listeners 1.48 + for (List<ScopeListener> l = listeners; l.nonEmpty(); l = l.tail) { 1.49 + l.head.symbolRemoved(sym, this); 1.50 } 1.51 } 1.52 1.53 @@ -393,7 +408,32 @@ 1.54 }; 1.55 } 1.56 }; 1.57 + } 1.58 1.59 + public Iterable<Symbol> getElementsByName(Name name) { 1.60 + return getElementsByName(name, noFilter); 1.61 + } 1.62 + 1.63 + public Iterable<Symbol> getElementsByName(final Name name, final Filter<Symbol> sf) { 1.64 + return new Iterable<Symbol>() { 1.65 + public Iterator<Symbol> iterator() { 1.66 + return new Iterator<Symbol>() { 1.67 + Scope.Entry currentEntry = lookup(name, sf); 1.68 + 1.69 + public boolean hasNext() { 1.70 + return currentEntry.scope != null; 1.71 + } 1.72 + public Symbol next() { 1.73 + Scope.Entry prevEntry = currentEntry; 1.74 + currentEntry = currentEntry.next(sf); 1.75 + return prevEntry.sym; 1.76 + } 1.77 + public void remove() { 1.78 + throw new UnsupportedOperationException(); 1.79 + } 1.80 + }; 1.81 + } 1.82 + }; 1.83 } 1.84 1.85 public String toString() { 1.86 @@ -488,7 +528,7 @@ 1.87 } 1.88 } 1.89 1.90 - public static class StarImportScope extends ImportScope { 1.91 + public static class StarImportScope extends ImportScope implements ScopeListener { 1.92 1.93 public StarImportScope(Symbol owner) { 1.94 super(owner); 1.95 @@ -500,8 +540,13 @@ 1.96 enter(e.sym, fromScope); 1.97 } 1.98 // Register to be notified when imported items are removed 1.99 - fromScope.listeners = fromScope.listeners.prepend(this); 1.100 + fromScope.addScopeListener(this); 1.101 } 1.102 + 1.103 + public void symbolRemoved(Symbol sym, Scope s) { 1.104 + remove(sym); 1.105 + } 1.106 + public void symbolAdded(Symbol sym, Scope s) { } 1.107 } 1.108 1.109 /** An empty scope, into which you can't place anything. Used for 1.110 @@ -538,6 +583,151 @@ 1.111 } 1.112 } 1.113 1.114 + /** A class scope adds capabilities to keep track of changes in related 1.115 + * class scopes - this allows client to realize whether a class scope 1.116 + * has changed, either directly (because a new member has been added/removed 1.117 + * to this scope) or indirectly (i.e. because a new member has been 1.118 + * added/removed into a supertype scope) 1.119 + */ 1.120 + public static class CompoundScope extends Scope implements ScopeListener { 1.121 + 1.122 + public static final Entry[] emptyTable = new Entry[0]; 1.123 + 1.124 + private List<Scope> subScopes = List.nil(); 1.125 + private int mark = 0; 1.126 + 1.127 + public CompoundScope(Symbol owner) { 1.128 + super(null, owner, emptyTable); 1.129 + } 1.130 + 1.131 + public void addSubScope(Scope that) { 1.132 + if (that != null) { 1.133 + subScopes = subScopes.prepend(that); 1.134 + that.addScopeListener(this); 1.135 + mark++; 1.136 + for (ScopeListener sl : listeners) { 1.137 + sl.symbolAdded(null, this); //propagate upwards in case of nested CompoundScopes 1.138 + } 1.139 + } 1.140 + } 1.141 + 1.142 + public void symbolAdded(Symbol sym, Scope s) { 1.143 + mark++; 1.144 + for (ScopeListener sl : listeners) { 1.145 + sl.symbolAdded(sym, s); 1.146 + } 1.147 + } 1.148 + 1.149 + public void symbolRemoved(Symbol sym, Scope s) { 1.150 + mark++; 1.151 + for (ScopeListener sl : listeners) { 1.152 + sl.symbolRemoved(sym, s); 1.153 + } 1.154 + } 1.155 + 1.156 + public int getMark() { 1.157 + return mark; 1.158 + } 1.159 + 1.160 + @Override 1.161 + public String toString() { 1.162 + StringBuilder buf = new StringBuilder(); 1.163 + buf.append("CompoundScope{"); 1.164 + String sep = ""; 1.165 + for (Scope s : subScopes) { 1.166 + buf.append(sep); 1.167 + buf.append(s); 1.168 + sep = ","; 1.169 + } 1.170 + buf.append("}"); 1.171 + return buf.toString(); 1.172 + } 1.173 + 1.174 + @Override 1.175 + public Iterable<Symbol> getElements(final Filter<Symbol> sf) { 1.176 + return new Iterable<Symbol>() { 1.177 + public Iterator<Symbol> iterator() { 1.178 + return new CompoundScopeIterator(subScopes) { 1.179 + Iterator<Symbol> nextIterator(Scope s) { 1.180 + return s.getElements().iterator(); 1.181 + } 1.182 + }; 1.183 + } 1.184 + }; 1.185 + } 1.186 + 1.187 + @Override 1.188 + public Iterable<Symbol> getElementsByName(final Name name, final Filter<Symbol> sf) { 1.189 + return new Iterable<Symbol>() { 1.190 + public Iterator<Symbol> iterator() { 1.191 + return new CompoundScopeIterator(subScopes) { 1.192 + Iterator<Symbol> nextIterator(Scope s) { 1.193 + return s.getElementsByName(name, sf).iterator(); 1.194 + } 1.195 + }; 1.196 + } 1.197 + }; 1.198 + } 1.199 + 1.200 + abstract class CompoundScopeIterator implements Iterator<Symbol> { 1.201 + 1.202 + private Iterator<Symbol> currentIterator; 1.203 + private List<Scope> scopesToScan; 1.204 + 1.205 + public CompoundScopeIterator(List<Scope> scopesToScan) { 1.206 + this.scopesToScan = scopesToScan; 1.207 + update(); 1.208 + } 1.209 + 1.210 + abstract Iterator<Symbol> nextIterator(Scope s); 1.211 + 1.212 + public boolean hasNext() { 1.213 + return currentIterator != null; 1.214 + } 1.215 + 1.216 + public Symbol next() { 1.217 + Symbol sym = currentIterator.next(); 1.218 + if (!currentIterator.hasNext()) { 1.219 + update(); 1.220 + } 1.221 + return sym; 1.222 + } 1.223 + 1.224 + public void remove() { 1.225 + throw new UnsupportedOperationException(); 1.226 + } 1.227 + 1.228 + private void update() { 1.229 + while (scopesToScan.nonEmpty()) { 1.230 + currentIterator = nextIterator(scopesToScan.head); 1.231 + scopesToScan = scopesToScan.tail; 1.232 + if (currentIterator.hasNext()) return; 1.233 + } 1.234 + currentIterator = null; 1.235 + } 1.236 + } 1.237 + 1.238 + @Override 1.239 + public Entry lookup(Name name, Filter<Symbol> sf) { 1.240 + throw new UnsupportedOperationException(); 1.241 + } 1.242 + 1.243 + @Override 1.244 + public Scope dup(Symbol newOwner) { 1.245 + throw new UnsupportedOperationException(); 1.246 + } 1.247 + 1.248 + @Override 1.249 + public void enter(Symbol sym, Scope s, Scope origin) { 1.250 + throw new UnsupportedOperationException(); 1.251 + } 1.252 + 1.253 + @Override 1.254 + public void remove(Symbol sym) { 1.255 + throw new UnsupportedOperationException(); 1.256 + } 1.257 + } 1.258 + 1.259 /** An error scope, for which the owner should be an error symbol. */ 1.260 public static class ErrorScope extends Scope { 1.261 ErrorScope(Scope next, Symbol errSymbol, Entry[] table) {
2.1 --- a/src/share/classes/com/sun/tools/javac/code/Symbol.java Mon Feb 14 14:27:47 2011 -0800 2.2 +++ b/src/share/classes/com/sun/tools/javac/code/Symbol.java Tue Feb 15 11:49:46 2011 +0000 2.3 @@ -731,7 +731,7 @@ 2.4 2.5 /** members closure cache (set by Types.membersClosure) 2.6 */ 2.7 - Scope membersClosure; 2.8 + Scope.CompoundScope membersClosure; 2.9 2.10 public ClassSymbol(long flags, Name name, Type type, Symbol owner) { 2.11 super(flags, name, type, owner);
3.1 --- a/src/share/classes/com/sun/tools/javac/code/Types.java Mon Feb 14 14:27:47 2011 -0800 3.2 +++ b/src/share/classes/com/sun/tools/javac/code/Types.java Tue Feb 15 11:49:46 2011 +0000 3.3 @@ -2023,18 +2023,22 @@ 3.4 final MethodSymbol cachedImpl; 3.5 final Filter<Symbol> implFilter; 3.6 final boolean checkResult; 3.7 + final int prevMark; 3.8 3.9 public Entry(MethodSymbol cachedImpl, 3.10 Filter<Symbol> scopeFilter, 3.11 - boolean checkResult) { 3.12 + boolean checkResult, 3.13 + int prevMark) { 3.14 this.cachedImpl = cachedImpl; 3.15 this.implFilter = scopeFilter; 3.16 this.checkResult = checkResult; 3.17 + this.prevMark = prevMark; 3.18 } 3.19 3.20 - boolean matches(Filter<Symbol> scopeFilter, boolean checkResult) { 3.21 + boolean matches(Filter<Symbol> scopeFilter, boolean checkResult, int mark) { 3.22 return this.implFilter == scopeFilter && 3.23 - this.checkResult == checkResult; 3.24 + this.checkResult == checkResult && 3.25 + this.prevMark == mark; 3.26 } 3.27 } 3.28 3.29 @@ -2046,10 +2050,11 @@ 3.30 _map.put(ms, new SoftReference<Map<TypeSymbol, Entry>>(cache)); 3.31 } 3.32 Entry e = cache.get(origin); 3.33 + CompoundScope members = membersClosure(origin.type); 3.34 if (e == null || 3.35 - !e.matches(implFilter, checkResult)) { 3.36 - MethodSymbol impl = implementationInternal(ms, origin, Types.this, checkResult, implFilter); 3.37 - cache.put(origin, new Entry(impl, implFilter, checkResult)); 3.38 + !e.matches(implFilter, checkResult, members.getMark())) { 3.39 + MethodSymbol impl = implementationInternal(ms, origin, checkResult, implFilter); 3.40 + cache.put(origin, new Entry(impl, implFilter, checkResult, members.getMark())); 3.41 return impl; 3.42 } 3.43 else { 3.44 @@ -2057,8 +2062,8 @@ 3.45 } 3.46 } 3.47 3.48 - private MethodSymbol implementationInternal(MethodSymbol ms, TypeSymbol origin, Types types, boolean checkResult, Filter<Symbol> implFilter) { 3.49 - for (Type t = origin.type; t.tag == CLASS || t.tag == TYPEVAR; t = types.supertype(t)) { 3.50 + private MethodSymbol implementationInternal(MethodSymbol ms, TypeSymbol origin, boolean checkResult, Filter<Symbol> implFilter) { 3.51 + for (Type t = origin.type; t.tag == CLASS || t.tag == TYPEVAR; t = supertype(t)) { 3.52 while (t.tag == TYPEVAR) 3.53 t = t.getUpperBound(); 3.54 TypeSymbol c = t.tsym; 3.55 @@ -2066,7 +2071,7 @@ 3.56 e.scope != null; 3.57 e = e.next(implFilter)) { 3.58 if (e.sym != null && 3.59 - e.sym.overrides(ms, origin, types, checkResult)) 3.60 + e.sym.overrides(ms, origin, Types.this, checkResult)) 3.61 return (MethodSymbol)e.sym; 3.62 } 3.63 } 3.64 @@ -2082,46 +2087,35 @@ 3.65 // </editor-fold> 3.66 3.67 // <editor-fold defaultstate="collapsed" desc="compute transitive closure of all members in given site"> 3.68 - public Scope membersClosure(Type site) { 3.69 + public CompoundScope membersClosure(Type site) { 3.70 return membersClosure.visit(site); 3.71 } 3.72 3.73 - UnaryVisitor<Scope> membersClosure = new UnaryVisitor<Scope>() { 3.74 - 3.75 - public Scope visitType(Type t, Void s) { 3.76 + UnaryVisitor<CompoundScope> membersClosure = new UnaryVisitor<CompoundScope>() { 3.77 + 3.78 + public CompoundScope visitType(Type t, Void s) { 3.79 return null; 3.80 } 3.81 3.82 @Override 3.83 - public Scope visitClassType(ClassType t, Void s) { 3.84 + public CompoundScope visitClassType(ClassType t, Void s) { 3.85 ClassSymbol csym = (ClassSymbol)t.tsym; 3.86 if (csym.membersClosure == null) { 3.87 - Scope membersClosure = new Scope(csym); 3.88 + CompoundScope membersClosure = new CompoundScope(csym); 3.89 for (Type i : interfaces(t)) { 3.90 - enterAll(visit(i), membersClosure); 3.91 + membersClosure.addSubScope(visit(i)); 3.92 } 3.93 - enterAll(visit(supertype(t)), membersClosure); 3.94 - enterAll(csym.members(), membersClosure); 3.95 + membersClosure.addSubScope(visit(supertype(t))); 3.96 + membersClosure.addSubScope(csym.members()); 3.97 csym.membersClosure = membersClosure; 3.98 } 3.99 return csym.membersClosure; 3.100 } 3.101 3.102 @Override 3.103 - public Scope visitTypeVar(TypeVar t, Void s) { 3.104 + public CompoundScope visitTypeVar(TypeVar t, Void s) { 3.105 return visit(t.getUpperBound()); 3.106 } 3.107 - 3.108 - public void enterAll(Scope s, Scope to) { 3.109 - if (s == null) return; 3.110 - List<Symbol> syms = List.nil(); 3.111 - for (Scope.Entry e = s.elems ; e != null ; e = e.sibling) { 3.112 - syms = syms.prepend(e.sym); 3.113 - } 3.114 - for (Symbol sym : syms) { 3.115 - to.enter(sym); 3.116 - } 3.117 - } 3.118 }; 3.119 // </editor-fold> 3.120
4.1 --- a/src/share/classes/com/sun/tools/javac/comp/Check.java Mon Feb 14 14:27:47 2011 -0800 4.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Check.java Tue Feb 15 11:49:46 2011 +0000 4.3 @@ -2106,32 +2106,32 @@ 4.4 void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) { 4.5 ClashFilter cf = new ClashFilter(site); 4.6 //for each method m1 that is a member of 'site'... 4.7 - for (Scope.Entry e1 = types.membersClosure(site).lookup(sym.name, cf) ; 4.8 - e1.scope != null ; e1 = e1.next(cf)) { 4.9 + for (Symbol s1 : types.membersClosure(site).getElementsByName(sym.name, cf)) { 4.10 //...find another method m2 that is overridden (directly or indirectly) 4.11 //by method 'sym' in 'site' 4.12 - for (Scope.Entry e2 = types.membersClosure(site).lookup(sym.name, cf) ; 4.13 - e2.scope != null ; e2 = e2.next(cf)) { 4.14 - if (e1.sym == e2.sym || !sym.overrides(e2.sym, site.tsym, types, false)) continue; 4.15 + for (Symbol s2 : types.membersClosure(site).getElementsByName(sym.name, cf)) { 4.16 + if (s1 == s2 || !sym.overrides(s2, site.tsym, types, false)) continue; 4.17 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as 4.18 //a member of 'site') and (ii) m1 has the same erasure as m2, issue an error 4.19 - if (!types.isSubSignature(sym.type, types.memberType(site, e1.sym)) && 4.20 - types.hasSameArgs(e1.sym.erasure(types), e2.sym.erasure(types))) { 4.21 + if (!types.isSubSignature(sym.type, types.memberType(site, s1)) && 4.22 + types.hasSameArgs(s1.erasure(types), s2.erasure(types))) { 4.23 sym.flags_field |= CLASH; 4.24 - String key = e2.sym == sym ? 4.25 + String key = s2 == sym ? 4.26 "name.clash.same.erasure.no.override" : 4.27 "name.clash.same.erasure.no.override.1"; 4.28 log.error(pos, 4.29 key, 4.30 sym, sym.location(), 4.31 - e1.sym, e1.sym.location(), 4.32 - e2.sym, e2.sym.location()); 4.33 + s1, s1.location(), 4.34 + s2, s2.location()); 4.35 return; 4.36 } 4.37 } 4.38 } 4.39 } 4.40 4.41 + 4.42 + 4.43 /** Check that all static methods accessible from 'site' are 4.44 * mutually compatible (JLS 8.4.8). 4.45 * 4.46 @@ -2142,16 +2142,15 @@ 4.47 void checkHideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) { 4.48 ClashFilter cf = new ClashFilter(site); 4.49 //for each method m1 that is a member of 'site'... 4.50 - for (Scope.Entry e = types.membersClosure(site).lookup(sym.name, cf) ; 4.51 - e.scope != null ; e = e.next(cf)) { 4.52 + for (Symbol s : types.membersClosure(site).getElementsByName(sym.name, cf)) { 4.53 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as 4.54 //a member of 'site') and (ii) 'sym' has the same erasure as m1, issue an error 4.55 - if (!types.isSubSignature(sym.type, types.memberType(site, e.sym)) && 4.56 - types.hasSameArgs(e.sym.erasure(types), sym.erasure(types))) { 4.57 + if (!types.isSubSignature(sym.type, types.memberType(site, s)) && 4.58 + types.hasSameArgs(s.erasure(types), sym.erasure(types))) { 4.59 log.error(pos, 4.60 "name.clash.same.erasure.no.hide", 4.61 sym, sym.location(), 4.62 - e.sym, e.sym.location()); 4.63 + s, s.location()); 4.64 return; 4.65 } 4.66 }
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/tools/javac/scope/7017664/CompoundScopeTest.java Tue Feb 15 11:49:46 2011 +0000 5.3 @@ -0,0 +1,212 @@ 5.4 +/* 5.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. 5.11 + * 5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.15 + * version 2 for more details (a copy is included in the LICENSE file that 5.16 + * accompanied this code). 5.17 + * 5.18 + * You should have received a copy of the GNU General Public License version 5.19 + * 2 along with this work; if not, write to the Free Software Foundation, 5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.21 + * 5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.23 + * or visit www.oracle.com if you need additional information or have any 5.24 + * questions. 5.25 + */ 5.26 + 5.27 +/* 5.28 + * @test 5.29 + * @bug 7017664 5.30 + * @summary Basher for CompoundScopes 5.31 + */ 5.32 + 5.33 +import java.util.Random; 5.34 +import java.util.Map; 5.35 +import java.util.HashMap; 5.36 +import com.sun.tools.javac.util.*; 5.37 +import com.sun.tools.javac.code.*; 5.38 +import com.sun.tools.javac.code.Scope.*; 5.39 +import com.sun.tools.javac.code.Symbol.*; 5.40 +import com.sun.tools.javac.file.JavacFileManager; 5.41 + 5.42 +public class CompoundScopeTest { 5.43 + public static void main(String... args) throws Exception { 5.44 + new CompoundScopeTest().run(args); 5.45 + } 5.46 + 5.47 + static final int MAX_SYMBOLS_COUNT = 20; 5.48 + static final int PASSES = 10; 5.49 + 5.50 + void run(String... args) throws Exception { 5.51 + int count = PASSES; 5.52 + 5.53 + for (int i = 0; i < args.length; i++) { 5.54 + String arg = args[i]; 5.55 + if (arg.equals("-seed") && (i + 1 < args.length)) 5.56 + seed = Long.parseLong(args[++i]); 5.57 + else if(arg.equals("-tests") && (i + 1 < args.length)) 5.58 + count = Integer.parseInt(args[++i]); 5.59 + else 5.60 + throw new Exception("unknown arg: " + arg); 5.61 + } 5.62 + 5.63 + rgen = new Random(seed); 5.64 + 5.65 + for (int i = 0; i < count; i++) { 5.66 + Test t = new Test(); 5.67 + t.run(); 5.68 + } 5.69 + 5.70 + if (errors > 0) 5.71 + throw new Exception(errors + " errors found"); 5.72 + } 5.73 + 5.74 + /** 5.75 + * Write a message to stderr. 5.76 + */ 5.77 + void log(String msg) { 5.78 + System.err.println(msg); 5.79 + } 5.80 + 5.81 + /** 5.82 + * Write an error message to stderr. 5.83 + */ 5.84 + void error(String msg) { 5.85 + System.err.println("Error: " + msg); 5.86 + errors++; 5.87 + } 5.88 + 5.89 + Random rgen; 5.90 + long seed = 0; 5.91 + 5.92 + int errors; 5.93 + 5.94 + /** Class to encapsulate a test run. */ 5.95 + class Test { 5.96 + 5.97 + List<Symbol> elems = List.nil(); 5.98 + Map<Name, List<Symbol>> shadowedMap = new HashMap<Name, List<Symbol>>(); 5.99 + 5.100 + /** Run the test. */ 5.101 + void run() throws Exception { 5.102 + log ("starting test"); 5.103 + setup(); 5.104 + Scope[] scopes = { createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)), 5.105 + createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)), 5.106 + createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)) }; 5.107 + boolean[][] scopeNesting = { {false, true, false, true}, 5.108 + {false, true, true, true}, 5.109 + {false, false, true, true} }; 5.110 + /** 5.111 + * We want to generate (and check) the following compound scopes: 5.112 + * C1 = C(S1, S2, S3) 5.113 + * C2 = C((S1, S2), S3) 5.114 + * C3 = C(S1, (S2, S3)) 5.115 + * C3 = C(C(S1, S2, S3)) 5.116 + */ 5.117 + for (int i = 0 ; i < 4 ; i ++) { 5.118 + CompoundScope root = new CompoundScope(symtab.noSymbol); 5.119 + CompoundScope sub = new CompoundScope(symtab.noSymbol); 5.120 + boolean subAdded = false; 5.121 + for (int sc = 0 ; sc < 3 ; sc ++) { 5.122 + if (scopeNesting[sc][i]) { 5.123 + sub.addSubScope(scopes[sc]); 5.124 + if (!subAdded) { 5.125 + root.addSubScope(sub); 5.126 + subAdded = true; 5.127 + } 5.128 + } else { 5.129 + root.addSubScope(scopes[sc]); 5.130 + } 5.131 + } 5.132 + log("testing scope: " + root); 5.133 + checkElems(root); 5.134 + checkShadowed(root); 5.135 + } 5.136 + } 5.137 + 5.138 + /** 5.139 + * Create a scope containing a given number of synthetic symbols 5.140 + */ 5.141 + Scope createScope(int nelems) { 5.142 + Scope s = new Scope(symtab.noSymbol); 5.143 + for (int i = 0 ; i < nelems ; i++) { 5.144 + Symbol sym = new TypeSymbol(0, names.fromString("s" + i), null, null); 5.145 + s.enter(sym); 5.146 + elems = elems.prepend(sym); 5.147 + List<Symbol> shadowed = shadowedMap.get(sym.name); 5.148 + if (shadowed == null) { 5.149 + shadowed = List.nil(); 5.150 + } 5.151 + shadowedMap.put(sym.name, shadowed.prepend(sym)); 5.152 + } 5.153 + return s; 5.154 + } 5.155 + 5.156 + /** 5.157 + * Setup compiler context 5.158 + */ 5.159 + void setup() { 5.160 + log ("setup"); 5.161 + context = new Context(); 5.162 + JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab 5.163 + names = Names.instance(context); // Name.Table impls tied to an instance of Names 5.164 + symtab = Symtab.instance(context); 5.165 + } 5.166 + 5.167 + /** 5.168 + * Check that CompoundScope.getElements() correctly visits all symbols 5.169 + * in all subscopes (in the correct order) 5.170 + */ 5.171 + void checkElems(CompoundScope cs) { 5.172 + List<Symbol> allSymbols = elems; 5.173 + int count = 0; 5.174 + for (Symbol s : cs.getElements()) { 5.175 + checkSameSymbols(s, allSymbols.head); 5.176 + allSymbols = allSymbols.tail; 5.177 + count++; 5.178 + } 5.179 + if (count != elems.size()) { 5.180 + error("CompoundScope.getElements() did not returned enough symbols"); 5.181 + } 5.182 + } 5.183 + 5.184 + /** 5.185 + * Check that CompoundScope.getElements() correctly visits all symbols 5.186 + * with a given name in all subscopes (in the correct order) 5.187 + */ 5.188 + void checkShadowed(CompoundScope cs) { 5.189 + for (Map.Entry<Name, List<Symbol>> shadowedEntry : shadowedMap.entrySet()) { 5.190 + int count = 0; 5.191 + List<Symbol> shadowed = shadowedEntry.getValue(); 5.192 + Name name = shadowedEntry.getKey(); 5.193 + for (Symbol s : cs.getElementsByName(name)) { 5.194 + checkSameSymbols(s, shadowed.head); 5.195 + shadowed = shadowed.tail; 5.196 + count++; 5.197 + } 5.198 + if (count != shadowedEntry.getValue().size()) { 5.199 + error("CompoundScope.lookup() did not returned enough symbols for name " + name); 5.200 + } 5.201 + } 5.202 + } 5.203 + 5.204 + void checkSameSymbols(Symbol found, Symbol req) { 5.205 + if (found != req) { 5.206 + error("Symbol mismatch - found : " + found + ":" + found.hashCode() + "\n" + 5.207 + " required : " + req + ":" + req.hashCode()); 5.208 + } 5.209 + } 5.210 + 5.211 + Context context; 5.212 + Symtab symtab; 5.213 + Names names; 5.214 + } 5.215 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/test/tools/javac/scope/7017664/ImplementationCacheTest.java Tue Feb 15 11:49:46 2011 +0000 6.3 @@ -0,0 +1,129 @@ 6.4 +/* 6.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.7 + * 6.8 + * This code is free software; you can redistribute it and/or modify it 6.9 + * under the terms of the GNU General Public License version 2 only, as 6.10 + * published by the Free Software Foundation. 6.11 + * 6.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 6.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 6.15 + * version 2 for more details (a copy is included in the LICENSE file that 6.16 + * accompanied this code). 6.17 + * 6.18 + * You should have received a copy of the GNU General Public License version 6.19 + * 2 along with this work; if not, write to the Free Software Foundation, 6.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 6.21 + * 6.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 6.23 + * or visit www.oracle.com if you need additional information or have any 6.24 + * questions. 6.25 + */ 6.26 + 6.27 +/* 6.28 + * @test 6.29 + * @bug 7017664 6.30 + * @summary Basher for CompoundScopes 6.31 + */ 6.32 + 6.33 +import com.sun.source.util.JavacTask; 6.34 +import com.sun.tools.javac.code.Symbol; 6.35 +import com.sun.tools.javac.code.Types; 6.36 +import com.sun.tools.javac.file.JavacFileManager; 6.37 +import com.sun.tools.javac.util.Context; 6.38 + 6.39 +import com.sun.tools.javac.code.Symbol.*; 6.40 + 6.41 +import java.io.IOException; 6.42 +import java.net.URI; 6.43 +import java.util.Arrays; 6.44 +import java.util.List; 6.45 +import javax.lang.model.element.Element; 6.46 +import javax.tools.JavaCompiler; 6.47 +import javax.tools.JavaFileObject; 6.48 +import javax.tools.SimpleJavaFileObject; 6.49 +import javax.tools.ToolProvider; 6.50 + 6.51 +import static javax.tools.JavaFileObject.Kind; 6.52 + 6.53 +public class ImplementationCacheTest { 6.54 + 6.55 + static class SourceFile extends SimpleJavaFileObject { 6.56 + 6.57 + final String source = "interface I { void m(); }\n" + 6.58 + "class A implements I { public void m() {} }\n" + 6.59 + "class B extends A { }\n"; 6.60 + 6.61 + public SourceFile() { 6.62 + super(URI.create("test.java"), Kind.SOURCE); 6.63 + } 6.64 + 6.65 + public CharSequence getCharContent(boolean ignoreEncodingErrors) { 6.66 + return source; 6.67 + } 6.68 + } 6.69 + 6.70 + public static void main(String[] args) throws IOException { 6.71 + List<? extends JavaFileObject> files = Arrays.asList(new SourceFile()); 6.72 + JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); 6.73 + JavacTask ct = (JavacTask)tool.getTask(null, null, null, null, null, files); 6.74 + Context ctx = new Context(); 6.75 + JavacFileManager.preRegister(ctx); 6.76 + checkImplementationCache(ct.analyze(), Types.instance(ctx)); 6.77 + } 6.78 + 6.79 + static void checkImplementationCache(Iterable<? extends Element> elements, Types types) { 6.80 + if (types == null) { 6.81 + throw new AssertionError("problems initializing Types"); 6.82 + } 6.83 + 6.84 + Symbol a = null; 6.85 + Symbol b = null; 6.86 + Symbol i = null; 6.87 + 6.88 + for (Element e : elements) { 6.89 + if (e.getSimpleName().contentEquals("A")) { 6.90 + a = (Symbol)e; 6.91 + } else if (e.getSimpleName().contentEquals("B")) { 6.92 + b = (Symbol)e; 6.93 + } else if (e.getSimpleName().contentEquals("I")) { 6.94 + i = (Symbol)e; 6.95 + } 6.96 + } 6.97 + 6.98 + if (a == null || b == null || i == null) { 6.99 + throw new AssertionError("missing class"); 6.100 + } 6.101 + 6.102 + MethodSymbol I_m = null; 6.103 + 6.104 + for (Symbol sym : i.members().getElements()) { 6.105 + if (sym.name.contentEquals("m")) { 6.106 + I_m = (MethodSymbol)sym; 6.107 + } 6.108 + } 6.109 + 6.110 + if (I_m == null) { 6.111 + throw new AssertionError("missing method m() in scope of interface I"); 6.112 + } 6.113 + 6.114 + Symbol impl = I_m.implementation((TypeSymbol)b, types, true); 6.115 + 6.116 + if (impl == null || impl.owner != a) { 6.117 + throw new AssertionError("wrong implementation for m() in B"); 6.118 + } 6.119 + 6.120 + b.members().enter(I_m.clone(b)); 6.121 + 6.122 + Symbol newImpl = I_m.implementation((TypeSymbol)b, types, true); 6.123 + 6.124 + if (newImpl == impl) { 6.125 + throw new AssertionError("stale implementation for m() in B"); 6.126 + } 6.127 + 6.128 + if (newImpl == null || newImpl.owner != b) { 6.129 + throw new AssertionError("wrong implementation for m() in B"); 6.130 + } 6.131 + } 6.132 +}