test/tools/javac/scope/StarImportTest.java

Mon, 07 Feb 2011 18:10:13 +0000

author
mcimadamore
date
Mon, 07 Feb 2011 18:10:13 +0000
changeset 858
96d4226bdd60
parent 767
7e3e9f6d013f
child 962
0ff2bbd38f10
permissions
-rw-r--r--

7007615: java_util/generics/phase2/NameClashTest02 fails since jdk7/pit/b123.
Summary: override clash algorithm is not implemented correctly
Reviewed-by: jjg

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

mercurial