StarImportTest.java revision 2739:9d2192f36e53
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 types = Types.instance(context); 139 int setupCount = rgen.nextInt(MAX_SETUP_COUNT); 140 for (int i = 0; i < setupCount; i++) { 141 switch (random(SetupKind.values())) { 142 case NAMES: 143 setupNames(); 144 break; 145 case PACKAGE: 146 setupPackage(); 147 break; 148 case CLASS: 149 setupClass(); 150 break; 151 } 152 } 153 } 154 155 /** 156 * Set up a random number of names. 157 */ 158 void setupNames() { 159 int count = rgen.nextInt(MAX_SETUP_NAME_COUNT); 160 log("setup: creating " + count + " new names"); 161 for (int i = 0; i < count; i++) { 162 names.fromString("n" + (++nextNameSerial)); 163 } 164 } 165 166 /** 167 * Set up a package containing a random number of member elements. 168 */ 169 void setupPackage() { 170 Name name = names.fromString("p" + (++nextPackageSerial)); 171 int count = rgen.nextInt(MAX_SETUP_PACKAGE_COUNT); 172 log("setup: creating package " + name + " with " + count + " entries"); 173 PackageSymbol p = new PackageSymbol(name, symtab.rootPackage); 174 p.members_field = WriteableScope.create(p); 175 for (int i = 0; i < count; i++) { 176 String outer = name + "c" + i; 177 String suffix = random(null, "$Entry", "$Entry2"); 178 ClassSymbol c1 = createClass(names.fromString(outer), p); 179// log("setup: created " + c1); 180 if (suffix != null) { 181 ClassSymbol c2 = createClass(names.fromString(outer + suffix), p); 182// log("setup: created " + c2); 183 } 184 } 185// log("package " + p, p.members_field); 186 packages.add(p); 187 imports.add(p); 188 } 189 190 /** 191 * Set up a class containing a random number of member elements. 192 */ 193 void setupClass() { 194 Name name = names.fromString("c" + (++nextClassSerial)); 195 int count = rgen.nextInt(MAX_SETUP_CLASS_COUNT); 196 log("setup: creating class " + name + " with " + count + " entries"); 197 ClassSymbol c = createClass(name, symtab.unnamedPackage); 198// log("setup: created " + c); 199 for (int i = 0; i < count; i++) { 200 ClassSymbol ic = createClass(names.fromString("Entry" + i), c); 201// log("setup: created " + ic); 202 } 203 classes.add(c); 204 imports.add(c); 205 } 206 207 /** 208 * Create a star-import scope and a model thereof, from the packages and 209 * classes created by setupPackages and setupClasses. 210 * @throws Exception for fatal errors, such as from reflection 211 */ 212 void createStarImportScope() throws Exception { 213 log ("createStarImportScope"); 214 PackageSymbol pkg = new PackageSymbol(names.fromString("pkg"), symtab.rootPackage); 215 216 starImportScope = new StarImportScope(pkg); 217 starImportModel = new Model(); 218 219 for (Symbol imp: imports) { 220 Scope members = imp.members(); 221// log("importAll", members); 222 starImportScope.importAll(types, members, new ImportFilter() { 223 @Override 224 public boolean accepts(Scope origin, Symbol t) { 225 return t.kind == TYP; 226 } 227 }, false); 228 229 for (Symbol sym : members.getSymbols()) { 230 starImportModel.enter(sym); 231 } 232 } 233 234// log("star-import scope", starImportScope); 235 starImportModel.check(starImportScope); 236 } 237 238 /** 239 * The core of the test. In a random order, move nested classes from 240 * the package in which they created to the class which should own them. 241 */ 242 void test() { 243 log ("test"); 244 List<ClassSymbol> nestedClasses = new LinkedList<ClassSymbol>(); 245 for (PackageSymbol p: packages) { 246 for (Symbol sym : p.members_field.getSymbols()) { 247 if (sym.name.toString().contains("$")) 248 nestedClasses.add((ClassSymbol) sym); 249 } 250 } 251 252 for (int i = nestedClasses.size(); i > 0; i--) { 253 // select a random nested class to move from package to class 254 ClassSymbol sym = nestedClasses.remove(rgen.nextInt(i)); 255 log("adjusting class " + sym); 256 257 // remove from star import model 258 starImportModel.remove(sym); 259 260 String s = sym.name.toString(); 261 int dollar = s.indexOf("$"); 262 263 // owner should be a package 264 assert (sym.owner.kind == PCK); 265 266 // determine new owner 267 Name outerName = names.fromString(s.substring(0, dollar)); 268// log(sym + " owner: " + sym.owner, sym.owner.members()); 269 ClassSymbol outer = (ClassSymbol)sym.owner.members().findFirst(outerName); 270// log("outer: " + outerName + " " + outer); 271 272 // remove from package 273 sym.owner.members().remove(sym); 274 275 // rename and insert into class 276 sym.name = names.fromString(s.substring(dollar + 1)); 277 outer.members().enter(sym); 278 sym.owner = outer; 279 280 // verify 281 starImportModel.check(starImportScope); 282 } 283 } 284 285 ClassSymbol createClass(Name name, Symbol owner) { 286 ClassSymbol sym = new ClassSymbol(0, name, owner); 287 sym.members_field = WriteableScope.create(sym); 288 if (owner != symtab.unnamedPackage) 289 owner.members().enter(sym); 290 return sym; 291 } 292 293 Context context; 294 Symtab symtab; 295 Names names; 296 Types types; 297 int nextNameSerial; 298 List<PackageSymbol> packages = new ArrayList<PackageSymbol>(); 299 int nextPackageSerial; 300 List<ClassSymbol> classes = new ArrayList<ClassSymbol>(); 301 List<Symbol> imports = new ArrayList<Symbol>(); 302 int nextClassSerial; 303 304 StarImportScope starImportScope; 305 Model starImportModel; 306 } 307 308 class Model { 309 private Map<Name, Set<Symbol>> map = new HashMap<Name, Set<Symbol>>(); 310 private Set<Symbol> bogus = new HashSet<Symbol>(); 311 312 void enter(Symbol sym) { 313 Set<Symbol> syms = map.get(sym.name); 314 if (syms == null) 315 map.put(sym.name, syms = new LinkedHashSet<Symbol>()); 316 syms.add(sym); 317 } 318 319 void remove(Symbol sym) { 320 Set<Symbol> syms = map.get(sym.name); 321 if (syms == null) 322 error("no entries for " + sym.name + " found in reference model"); 323 else { 324 boolean ok = syms.remove(sym); 325 if (ok) { 326// log(sym.name + "(" + sym + ") removed from reference model"); 327 } else { 328 error(sym.name + " not found in reference model"); 329 } 330 if (syms.isEmpty()) 331 map.remove(sym.name); 332 } 333 } 334 335 /** 336 * Check the contents of a scope 337 */ 338 void check(Scope scope) { 339 // First, check all entries in scope are in map 340 int bogusCount = 0; 341 for (Symbol sym : scope.getSymbols()) { 342 if (sym.owner != scope.getOrigin(sym).owner) { 343 if (bogus.contains(sym)) { 344 bogusCount++; 345 } else { 346 log("Warning: " + sym.name + ":" + sym + " appears to be bogus"); 347 bogus.add(sym); 348 } 349 } else { 350 Set<Symbol> syms = map.get(sym.name); 351 if (syms == null) { 352 error("check: no entries found for " + sym.name + ":" + sym + " in reference map"); 353 } else if (!syms.contains(sym)) { 354 error("check: symbol " + sym.name + ":" + sym + " not found in reference map"); 355 } 356 } 357 } 358 if (bogusCount > 0) { 359 log("Warning: " + bogusCount + " other bogus entries previously reported"); 360 } 361 362 // Second, check all entries in map are in scope 363 for (Map.Entry<Name,Set<Symbol>> me: map.entrySet()) { 364 Name name = me.getKey(); 365 if (scope.findFirst(name) == null) { 366 error("check: no entries found for " + name + " in scope"); 367 continue; 368 } 369 nextSym: 370 for (Symbol sym: me.getValue()) { 371 for (Symbol s : scope.getSymbolsByName(name)) { 372 if (sym == s) 373 continue nextSym; 374 } 375 error("check: symbol " + sym + " not found in scope"); 376 } 377 } 378 } 379 } 380} 381