StarImportTest.java revision 2673:bf8500822576
1/* 2 * Copyright (c) 2010, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 7004029 27 * @summary Basher for star-import scopes 28 */ 29 30import java.util.*; 31import java.util.List; 32 33import com.sun.tools.javac.code.*; 34import com.sun.tools.javac.code.Scope.ImportFilter; 35import com.sun.tools.javac.code.Scope.StarImportScope; 36import com.sun.tools.javac.code.Scope.WriteableScope; 37import com.sun.tools.javac.code.Symbol.*; 38import com.sun.tools.javac.file.JavacFileManager; 39import com.sun.tools.javac.util.*; 40 41import static com.sun.tools.javac.code.Kinds.Kind.*; 42 43public class StarImportTest { 44 public static void main(String... args) throws Exception { 45 new StarImportTest().run(args); 46 } 47 48 void run(String... args) throws Exception { 49 int count = 1; 50 51 for (int i = 0; i < args.length; i++) { 52 String arg = args[i]; 53 if (arg.equals("-seed") && (i + 1 < args.length)) 54 seed = Long.parseLong(args[++i]); 55 else if(arg.equals("-tests") && (i + 1 < args.length)) 56 count = Integer.parseInt(args[++i]); 57 else 58 throw new Exception("unknown arg: " + arg); 59 } 60 61 rgen = new Random(seed); 62 63 for (int i = 0; i < count; i++) { 64 Test t = new Test(); 65 t.run(); 66 } 67 68 if (errors > 0) 69 throw new Exception(errors + " errors found"); 70 } 71 72 /** 73 * Select a random element from an array of choices. 74 */ 75 <T> T random(T... choices) { 76 return choices[rgen.nextInt(choices.length)]; 77 } 78 79 /** 80 * Write a message to stderr. 81 */ 82 void log(String msg) { 83 System.err.println(msg); 84 } 85 86 /** 87 * Write a message to stderr, and dump a scope. 88 */ 89 void log(String msg, Scope s) { 90 System.err.print(msg); 91 System.err.print(": "); 92 String sep = "("; 93 for (Symbol sym : s.getSymbols()) { 94 System.err.print(sep + sym.name + ":" + sym); 95 sep = ","; 96 } 97 System.err.println(); 98 } 99 100 /** 101 * Write an error message to stderr. 102 */ 103 void error(String msg) { 104 System.err.println("Error: " + msg); 105 errors++; 106 } 107 108 Random rgen; 109 long seed = 0; 110 111 int errors; 112 113 enum SetupKind { NAMES, PACKAGE, CLASS }; 114 static final int MAX_SETUP_COUNT = 50; 115 static final int MAX_SETUP_NAME_COUNT = 20; 116 static final int MAX_SETUP_PACKAGE_COUNT = 20; 117 static final int MAX_SETUP_CLASS_COUNT = 20; 118 119 /** Class to encapsulate a test run. */ 120 class Test { 121 /** Run the test. */ 122 void run() throws Exception { 123 log ("starting test"); 124 setup(); 125 createStarImportScope(); 126 test(); 127 } 128 129 /** 130 * Setup env by creating pseudo-random collection of names, packages and classes. 131 */ 132 void setup() { 133 log ("setup"); 134 context = new Context(); 135 JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab 136 names = Names.instance(context); // Name.Table impls tied to an instance of Names 137 symtab = Symtab.instance(context); 138 int setupCount = rgen.nextInt(MAX_SETUP_COUNT); 139 for (int i = 0; i < setupCount; i++) { 140 switch (random(SetupKind.values())) { 141 case NAMES: 142 setupNames(); 143 break; 144 case PACKAGE: 145 setupPackage(); 146 break; 147 case CLASS: 148 setupClass(); 149 break; 150 } 151 } 152 } 153 154 /** 155 * Set up a random number of names. 156 */ 157 void setupNames() { 158 int count = rgen.nextInt(MAX_SETUP_NAME_COUNT); 159 log("setup: creating " + count + " new names"); 160 for (int i = 0; i < count; i++) { 161 names.fromString("n" + (++nextNameSerial)); 162 } 163 } 164 165 /** 166 * Set up a package containing a random number of member elements. 167 */ 168 void setupPackage() { 169 Name name = names.fromString("p" + (++nextPackageSerial)); 170 int count = rgen.nextInt(MAX_SETUP_PACKAGE_COUNT); 171 log("setup: creating package " + name + " with " + count + " entries"); 172 PackageSymbol p = new PackageSymbol(name, symtab.rootPackage); 173 p.members_field = WriteableScope.create(p); 174 for (int i = 0; i < count; i++) { 175 String outer = name + "c" + i; 176 String suffix = random(null, "$Entry", "$Entry2"); 177 ClassSymbol c1 = createClass(names.fromString(outer), p); 178// log("setup: created " + c1); 179 if (suffix != null) { 180 ClassSymbol c2 = createClass(names.fromString(outer + suffix), p); 181// log("setup: created " + c2); 182 } 183 } 184// log("package " + p, p.members_field); 185 packages.add(p); 186 imports.add(p); 187 } 188 189 /** 190 * Set up a class containing a random number of member elements. 191 */ 192 void setupClass() { 193 Name name = names.fromString("c" + (++nextClassSerial)); 194 int count = rgen.nextInt(MAX_SETUP_CLASS_COUNT); 195 log("setup: creating class " + name + " with " + count + " entries"); 196 ClassSymbol c = createClass(name, symtab.unnamedPackage); 197// log("setup: created " + c); 198 for (int i = 0; i < count; i++) { 199 ClassSymbol ic = createClass(names.fromString("Entry" + i), c); 200// log("setup: created " + ic); 201 } 202 classes.add(c); 203 imports.add(c); 204 } 205 206 /** 207 * Create a star-import scope and a model therof, from the packages and 208 * classes created by setupPackages and setupClasses. 209 * @throws Exception for fatal errors, such as from reflection 210 */ 211 void createStarImportScope() throws Exception { 212 log ("createStarImportScope"); 213 PackageSymbol pkg = new PackageSymbol(names.fromString("pkg"), symtab.rootPackage); 214 215 starImportScope = new StarImportScope(pkg); 216 starImportModel = new Model(); 217 218 for (Symbol imp: imports) { 219 Scope members = imp.members(); 220// log("importAll", members); 221 starImportScope.importAll(members, members, new ImportFilter() { 222 @Override 223 public boolean accepts(Scope origin, Symbol t) { 224 return t.kind == TYP; 225 } 226 }, false); 227 228 for (Symbol sym : members.getSymbols()) { 229 starImportModel.enter(sym); 230 } 231 } 232 233// log("star-import scope", starImportScope); 234 starImportModel.check(starImportScope); 235 } 236 237 /** 238 * The core of the test. In a random order, move nested classes from 239 * the package in which they created to the class which should own them. 240 */ 241 void test() { 242 log ("test"); 243 List<ClassSymbol> nestedClasses = new LinkedList<ClassSymbol>(); 244 for (PackageSymbol p: packages) { 245 for (Symbol sym : p.members_field.getSymbols()) { 246 if (sym.name.toString().contains("$")) 247 nestedClasses.add((ClassSymbol) sym); 248 } 249 } 250 251 for (int i = nestedClasses.size(); i > 0; i--) { 252 // select a random nested class to move from package to class 253 ClassSymbol sym = nestedClasses.remove(rgen.nextInt(i)); 254 log("adjusting class " + sym); 255 256 // remove from star import model 257 starImportModel.remove(sym); 258 259 String s = sym.name.toString(); 260 int dollar = s.indexOf("$"); 261 262 // owner should be a package 263 assert (sym.owner.kind == PCK); 264 265 // determine new owner 266 Name outerName = names.fromString(s.substring(0, dollar)); 267// log(sym + " owner: " + sym.owner, sym.owner.members()); 268 ClassSymbol outer = (ClassSymbol)sym.owner.members().findFirst(outerName); 269// log("outer: " + outerName + " " + outer); 270 271 // remove from package 272 sym.owner.members().remove(sym); 273 274 // rename and insert into class 275 sym.name = names.fromString(s.substring(dollar + 1)); 276 outer.members().enter(sym); 277 sym.owner = outer; 278 279 // verify 280 starImportModel.check(starImportScope); 281 } 282 } 283 284 ClassSymbol createClass(Name name, Symbol owner) { 285 ClassSymbol sym = new ClassSymbol(0, name, owner); 286 sym.members_field = WriteableScope.create(sym); 287 if (owner != symtab.unnamedPackage) 288 owner.members().enter(sym); 289 return sym; 290 } 291 292 Context context; 293 Symtab symtab; 294 Names names; 295 int nextNameSerial; 296 List<PackageSymbol> packages = new ArrayList<PackageSymbol>(); 297 int nextPackageSerial; 298 List<ClassSymbol> classes = new ArrayList<ClassSymbol>(); 299 List<Symbol> imports = new ArrayList<Symbol>(); 300 int nextClassSerial; 301 302 StarImportScope starImportScope; 303 Model starImportModel; 304 } 305 306 class Model { 307 private Map<Name, Set<Symbol>> map = new HashMap<Name, Set<Symbol>>(); 308 private Set<Symbol> bogus = new HashSet<Symbol>(); 309 310 void enter(Symbol sym) { 311 Set<Symbol> syms = map.get(sym.name); 312 if (syms == null) 313 map.put(sym.name, syms = new LinkedHashSet<Symbol>()); 314 syms.add(sym); 315 } 316 317 void remove(Symbol sym) { 318 Set<Symbol> syms = map.get(sym.name); 319 if (syms == null) 320 error("no entries for " + sym.name + " found in reference model"); 321 else { 322 boolean ok = syms.remove(sym); 323 if (ok) { 324// log(sym.name + "(" + sym + ") removed from reference model"); 325 } else { 326 error(sym.name + " not found in reference model"); 327 } 328 if (syms.isEmpty()) 329 map.remove(sym.name); 330 } 331 } 332 333 /** 334 * Check the contents of a scope 335 */ 336 void check(Scope scope) { 337 // First, check all entries in scope are in map 338 int bogusCount = 0; 339 for (Symbol sym : scope.getSymbols()) { 340 if (sym.owner != scope.getOrigin(sym).owner) { 341 if (bogus.contains(sym)) { 342 bogusCount++; 343 } else { 344 log("Warning: " + sym.name + ":" + sym + " appears to be bogus"); 345 bogus.add(sym); 346 } 347 } else { 348 Set<Symbol> syms = map.get(sym.name); 349 if (syms == null) { 350 error("check: no entries found for " + sym.name + ":" + sym + " in reference map"); 351 } else if (!syms.contains(sym)) { 352 error("check: symbol " + sym.name + ":" + sym + " not found in reference map"); 353 } 354 } 355 } 356 if (bogusCount > 0) { 357 log("Warning: " + bogusCount + " other bogus entries previously reported"); 358 } 359 360 // Second, check all entries in map are in scope 361 for (Map.Entry<Name,Set<Symbol>> me: map.entrySet()) { 362 Name name = me.getKey(); 363 if (scope.findFirst(name) == null) { 364 error("check: no entries found for " + name + " in scope"); 365 continue; 366 } 367 nextSym: 368 for (Symbol sym: me.getValue()) { 369 for (Symbol s : scope.getSymbolsByName(name)) { 370 if (sym == s) 371 continue nextSym; 372 } 373 error("check: symbol " + sym + " not found in scope"); 374 } 375 } 376 } 377 } 378} 379