1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/test/tools/javac/scope/StarImportTest.java Wed Apr 27 01:34:52 2016 +0800 1.3 @@ -0,0 +1,400 @@ 1.4 +/* 1.5 + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + */ 1.26 + 1.27 +/* 1.28 + * @test 1.29 + * @bug 7004029 1.30 + * @summary Basher for star-import scopes 1.31 + */ 1.32 + 1.33 +import java.lang.reflect.*; 1.34 +import java.util.*; 1.35 +import java.util.List; 1.36 +import com.sun.tools.javac.util.*; 1.37 +import com.sun.tools.javac.code.*; 1.38 +import com.sun.tools.javac.code.Scope.*; 1.39 +import com.sun.tools.javac.code.Symbol.*; 1.40 +import com.sun.tools.javac.file.JavacFileManager; 1.41 +import static com.sun.tools.javac.code.Kinds.*; 1.42 + 1.43 +public class StarImportTest { 1.44 + public static void main(String... args) throws Exception { 1.45 + new StarImportTest().run(args); 1.46 + } 1.47 + 1.48 + void run(String... args) throws Exception { 1.49 + int count = 1; 1.50 + 1.51 + for (int i = 0; i < args.length; i++) { 1.52 + String arg = args[i]; 1.53 + if (arg.equals("-seed") && (i + 1 < args.length)) 1.54 + seed = Long.parseLong(args[++i]); 1.55 + else if(arg.equals("-tests") && (i + 1 < args.length)) 1.56 + count = Integer.parseInt(args[++i]); 1.57 + else 1.58 + throw new Exception("unknown arg: " + arg); 1.59 + } 1.60 + 1.61 + rgen = new Random(seed); 1.62 + 1.63 + for (int i = 0; i < count; i++) { 1.64 + Test t = new Test(); 1.65 + t.run(); 1.66 + } 1.67 + 1.68 + if (errors > 0) 1.69 + throw new Exception(errors + " errors found"); 1.70 + } 1.71 + 1.72 + /** 1.73 + * Select a random element from an array of choices. 1.74 + */ 1.75 + <T> T random(T... choices) { 1.76 + return choices[rgen.nextInt(choices.length)]; 1.77 + } 1.78 + 1.79 + /** 1.80 + * Write a message to stderr. 1.81 + */ 1.82 + void log(String msg) { 1.83 + System.err.println(msg); 1.84 + } 1.85 + 1.86 + /** 1.87 + * Write a message to stderr, and dump a scope. 1.88 + */ 1.89 + void log(String msg, Scope s) { 1.90 + System.err.print(msg); 1.91 + System.err.print(": "); 1.92 + String sep = "("; 1.93 + for (Scope.Entry se = s.elems; se != null; se = se.sibling) { 1.94 + for (Scope.Entry e = se; e.sym != null; e = e.next()) { 1.95 + System.err.print(sep + e.sym.name + ":" + e.sym); 1.96 + sep = ","; 1.97 + } 1.98 + System.err.print(")"); 1.99 + sep = ", ("; 1.100 + } 1.101 + System.err.println(); 1.102 + } 1.103 + 1.104 + /** 1.105 + * Write an error message to stderr. 1.106 + */ 1.107 + void error(String msg) { 1.108 + System.err.println("Error: " + msg); 1.109 + errors++; 1.110 + } 1.111 + 1.112 + Random rgen; 1.113 + long seed = 0; 1.114 + 1.115 + int errors; 1.116 + 1.117 + enum SetupKind { NAMES, PACKAGE, CLASS }; 1.118 + static final int MAX_SETUP_COUNT = 50; 1.119 + static final int MAX_SETUP_NAME_COUNT = 20; 1.120 + static final int MAX_SETUP_PACKAGE_COUNT = 20; 1.121 + static final int MAX_SETUP_CLASS_COUNT = 20; 1.122 + 1.123 + /** Class to encapsulate a test run. */ 1.124 + class Test { 1.125 + /** Run the test. */ 1.126 + void run() throws Exception { 1.127 + log ("starting test"); 1.128 + setup(); 1.129 + createStarImportScope(); 1.130 + test(); 1.131 + } 1.132 + 1.133 + /** 1.134 + * Setup env by creating pseudo-random collection of names, packages and classes. 1.135 + */ 1.136 + void setup() { 1.137 + log ("setup"); 1.138 + context = new Context(); 1.139 + JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab 1.140 + names = Names.instance(context); // Name.Table impls tied to an instance of Names 1.141 + symtab = Symtab.instance(context); 1.142 + int setupCount = rgen.nextInt(MAX_SETUP_COUNT); 1.143 + for (int i = 0; i < setupCount; i++) { 1.144 + switch (random(SetupKind.values())) { 1.145 + case NAMES: 1.146 + setupNames(); 1.147 + break; 1.148 + case PACKAGE: 1.149 + setupPackage(); 1.150 + break; 1.151 + case CLASS: 1.152 + setupClass(); 1.153 + break; 1.154 + } 1.155 + } 1.156 + } 1.157 + 1.158 + /** 1.159 + * Set up a random number of names. 1.160 + */ 1.161 + void setupNames() { 1.162 + int count = rgen.nextInt(MAX_SETUP_NAME_COUNT); 1.163 + log("setup: creating " + count + " new names"); 1.164 + for (int i = 0; i < count; i++) { 1.165 + names.fromString("n" + (++nextNameSerial)); 1.166 + } 1.167 + } 1.168 + 1.169 + /** 1.170 + * Set up a package containing a random number of member elements. 1.171 + */ 1.172 + void setupPackage() { 1.173 + Name name = names.fromString("p" + (++nextPackageSerial)); 1.174 + int count = rgen.nextInt(MAX_SETUP_PACKAGE_COUNT); 1.175 + log("setup: creating package " + name + " with " + count + " entries"); 1.176 + PackageSymbol p = new PackageSymbol(name, symtab.rootPackage); 1.177 + p.members_field = new Scope(p); 1.178 + for (int i = 0; i < count; i++) { 1.179 + String outer = name + "c" + i; 1.180 + String suffix = random(null, "$Entry", "$Entry2"); 1.181 + ClassSymbol c1 = createClass(names.fromString(outer), p); 1.182 +// log("setup: created " + c1); 1.183 + if (suffix != null) { 1.184 + ClassSymbol c2 = createClass(names.fromString(outer + suffix), p); 1.185 +// log("setup: created " + c2); 1.186 + } 1.187 + } 1.188 +// log("package " + p, p.members_field); 1.189 + packages.add(p); 1.190 + imports.add(p); 1.191 + } 1.192 + 1.193 + /** 1.194 + * Set up a class containing a random number of member elements. 1.195 + */ 1.196 + void setupClass() { 1.197 + Name name = names.fromString("c" + (++nextClassSerial)); 1.198 + int count = rgen.nextInt(MAX_SETUP_CLASS_COUNT); 1.199 + log("setup: creating class " + name + " with " + count + " entries"); 1.200 + ClassSymbol c = createClass(name, symtab.unnamedPackage); 1.201 +// log("setup: created " + c); 1.202 + for (int i = 0; i < count; i++) { 1.203 + ClassSymbol ic = createClass(names.fromString("Entry" + i), c); 1.204 +// log("setup: created " + ic); 1.205 + } 1.206 + classes.add(c); 1.207 + imports.add(c); 1.208 + } 1.209 + 1.210 + /** 1.211 + * Create a star-import scope and a model therof, from the packages and 1.212 + * classes created by setupPackages and setupClasses. 1.213 + * @throws Exception for fatal errors, such as from reflection 1.214 + */ 1.215 + void createStarImportScope() throws Exception { 1.216 + log ("createStarImportScope"); 1.217 + PackageSymbol pkg = new PackageSymbol(names.fromString("pkg"), symtab.rootPackage); 1.218 + 1.219 + // if StarImportScope exists, use it, otherwise, for testing legacy code, 1.220 + // fall back on ImportScope 1.221 + Method importAll; 1.222 + try { 1.223 + Class<?> c = Class.forName("com.sun.tools.javac.code.Scope$StarImportScope"); 1.224 + Constructor ctor = c.getDeclaredConstructor(new Class[] { Symbol.class }); 1.225 + importAll = c.getDeclaredMethod("importAll", new Class[] { Scope.class }); 1.226 + starImportScope = (Scope) ctor.newInstance(new Object[] { pkg }); 1.227 + } catch (ClassNotFoundException e) { 1.228 + starImportScope = new ImportScope(pkg); 1.229 + importAll = null; 1.230 + } 1.231 + starImportModel = new Model(); 1.232 + 1.233 + for (Symbol imp: imports) { 1.234 + Scope members = imp.members(); 1.235 + if (importAll != null) { 1.236 +// log("importAll", members); 1.237 + importAll.invoke(starImportScope, members); 1.238 + } else { 1.239 + Scope fromScope = members; 1.240 + Scope toScope = starImportScope; 1.241 + // The following lines are taken from MemberEnter.importAll, 1.242 + // before the use of StarImportScope.importAll. 1.243 + for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) { 1.244 + if (e.sym.kind == TYP && !toScope.includes(e.sym)) 1.245 + toScope.enter(e.sym, fromScope); 1.246 + } 1.247 + } 1.248 + 1.249 + for (Scope.Entry e = members.elems; e != null; e = e.sibling) { 1.250 + starImportModel.enter(e.sym); 1.251 + } 1.252 + } 1.253 + 1.254 +// log("star-import scope", starImportScope); 1.255 + starImportModel.check(starImportScope); 1.256 + } 1.257 + 1.258 + /** 1.259 + * The core of the test. In a random order, move nested classes from 1.260 + * the package in which they created to the class which should own them. 1.261 + */ 1.262 + void test() { 1.263 + log ("test"); 1.264 + List<ClassSymbol> nestedClasses = new LinkedList<ClassSymbol>(); 1.265 + for (PackageSymbol p: packages) { 1.266 + for (Scope.Entry se = p.members_field.elems; se != null; se = se.sibling) { 1.267 + if (se.sym.name.toString().contains("$")) 1.268 + nestedClasses.add((ClassSymbol) se.sym); 1.269 + } 1.270 + } 1.271 + 1.272 + for (int i = nestedClasses.size(); i > 0; i--) { 1.273 + // select a random nested class to move from package to class 1.274 + ClassSymbol sym = nestedClasses.remove(rgen.nextInt(i)); 1.275 + log("adjusting class " + sym); 1.276 + 1.277 + // remove from star import model 1.278 + starImportModel.remove(sym); 1.279 + 1.280 + String s = sym.name.toString(); 1.281 + int dollar = s.indexOf("$"); 1.282 + 1.283 + // owner should be a package 1.284 + assert (sym.owner.kind == PCK); 1.285 + 1.286 + // determine new owner 1.287 + Name outerName = names.fromString(s.substring(0, dollar)); 1.288 +// log(sym + " owner: " + sym.owner, sym.owner.members()); 1.289 + Scope.Entry outerEntry = sym.owner.members().lookup(outerName); 1.290 + ClassSymbol outer = (ClassSymbol) outerEntry.sym; 1.291 +// log("outer: " + outerName + " " + outer); 1.292 + 1.293 + // remove from package 1.294 + sym.owner.members().remove(sym); 1.295 + 1.296 + // rename and insert into class 1.297 + sym.name = names.fromString(s.substring(dollar + 1)); 1.298 + outer.members().enter(sym); 1.299 + sym.owner = outer; 1.300 + 1.301 + // verify 1.302 + starImportModel.check(starImportScope); 1.303 + } 1.304 + } 1.305 + 1.306 + ClassSymbol createClass(Name name, Symbol owner) { 1.307 + ClassSymbol sym = new ClassSymbol(0, name, owner); 1.308 + sym.members_field = new Scope(sym); 1.309 + if (owner != symtab.unnamedPackage) 1.310 + owner.members().enter(sym); 1.311 + return sym; 1.312 + } 1.313 + 1.314 + Context context; 1.315 + Symtab symtab; 1.316 + Names names; 1.317 + int nextNameSerial; 1.318 + List<PackageSymbol> packages = new ArrayList<PackageSymbol>(); 1.319 + int nextPackageSerial; 1.320 + List<ClassSymbol> classes = new ArrayList<ClassSymbol>(); 1.321 + List<Symbol> imports = new ArrayList<Symbol>(); 1.322 + int nextClassSerial; 1.323 + 1.324 + Scope starImportScope; 1.325 + Model starImportModel; 1.326 + } 1.327 + 1.328 + class Model { 1.329 + private Map<Name, Set<Symbol>> map = new HashMap<Name, Set<Symbol>>(); 1.330 + private Set<Symbol> bogus = new HashSet<Symbol>(); 1.331 + 1.332 + void enter(Symbol sym) { 1.333 + Set<Symbol> syms = map.get(sym.name); 1.334 + if (syms == null) 1.335 + map.put(sym.name, syms = new LinkedHashSet<Symbol>()); 1.336 + syms.add(sym); 1.337 + } 1.338 + 1.339 + void remove(Symbol sym) { 1.340 + Set<Symbol> syms = map.get(sym.name); 1.341 + if (syms == null) 1.342 + error("no entries for " + sym.name + " found in reference model"); 1.343 + else { 1.344 + boolean ok = syms.remove(sym); 1.345 + if (ok) { 1.346 +// log(sym.name + "(" + sym + ") removed from reference model"); 1.347 + } else { 1.348 + error(sym.name + " not found in reference model"); 1.349 + } 1.350 + if (syms.isEmpty()) 1.351 + map.remove(sym.name); 1.352 + } 1.353 + } 1.354 + 1.355 + /** 1.356 + * Check the contents of a scope 1.357 + */ 1.358 + void check(Scope scope) { 1.359 + // First, check all entries in scope are in map 1.360 + int bogusCount = 0; 1.361 + for (Scope.Entry se = scope.elems; se != null; se = se.sibling) { 1.362 + Symbol sym = se.sym; 1.363 + if (sym.owner != se.scope.owner) { 1.364 + if (bogus.contains(sym)) { 1.365 + bogusCount++; 1.366 + } else { 1.367 + log("Warning: " + sym.name + ":" + sym + " appears to be bogus"); 1.368 + bogus.add(sym); 1.369 + } 1.370 + } else { 1.371 + Set<Symbol> syms = map.get(sym.name); 1.372 + if (syms == null) { 1.373 + error("check: no entries found for " + sym.name + ":" + sym + " in reference map"); 1.374 + } else if (!syms.contains(sym)) { 1.375 + error("check: symbol " + sym.name + ":" + sym + " not found in reference map"); 1.376 + } 1.377 + } 1.378 + } 1.379 + if (bogusCount > 0) { 1.380 + log("Warning: " + bogusCount + " other bogus entries previously reported"); 1.381 + } 1.382 + 1.383 + // Second, check all entries in map are in scope 1.384 + for (Map.Entry<Name,Set<Symbol>> me: map.entrySet()) { 1.385 + Name name = me.getKey(); 1.386 + Scope.Entry se = scope.lookup(name); 1.387 + assert (se != null); 1.388 + if (se.sym == null) { 1.389 + error("check: no entries found for " + name + " in scope"); 1.390 + continue; 1.391 + } 1.392 + nextSym: 1.393 + for (Symbol sym: me.getValue()) { 1.394 + for (Scope.Entry e = se; e.sym != null; e = e.next()) { 1.395 + if (sym == e.sym) 1.396 + continue nextSym; 1.397 + } 1.398 + error("check: symbol " + sym + " not found in scope"); 1.399 + } 1.400 + } 1.401 + } 1.402 + } 1.403 +}