Fri, 24 Apr 2020 03:58:51 +0100
Merge
1 /*
2 * Copyright (c) 2010, 2011, 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 */
24 /*
25 * @test
26 * @bug 7004029
27 * @summary Basher for star-import scopes
28 */
30 import java.lang.reflect.*;
31 import java.util.*;
32 import java.util.List;
33 import com.sun.tools.javac.util.*;
34 import com.sun.tools.javac.code.*;
35 import com.sun.tools.javac.code.Scope.*;
36 import com.sun.tools.javac.code.Symbol.*;
37 import com.sun.tools.javac.file.JavacFileManager;
38 import static com.sun.tools.javac.code.Kinds.*;
40 public class StarImportTest {
41 public static void main(String... args) throws Exception {
42 new StarImportTest().run(args);
43 }
45 void run(String... args) throws Exception {
46 int count = 1;
48 for (int i = 0; i < args.length; i++) {
49 String arg = args[i];
50 if (arg.equals("-seed") && (i + 1 < args.length))
51 seed = Long.parseLong(args[++i]);
52 else if(arg.equals("-tests") && (i + 1 < args.length))
53 count = Integer.parseInt(args[++i]);
54 else
55 throw new Exception("unknown arg: " + arg);
56 }
58 rgen = new Random(seed);
60 for (int i = 0; i < count; i++) {
61 Test t = new Test();
62 t.run();
63 }
65 if (errors > 0)
66 throw new Exception(errors + " errors found");
67 }
69 /**
70 * Select a random element from an array of choices.
71 */
72 <T> T random(T... choices) {
73 return choices[rgen.nextInt(choices.length)];
74 }
76 /**
77 * Write a message to stderr.
78 */
79 void log(String msg) {
80 System.err.println(msg);
81 }
83 /**
84 * Write a message to stderr, and dump a scope.
85 */
86 void log(String msg, Scope s) {
87 System.err.print(msg);
88 System.err.print(": ");
89 String sep = "(";
90 for (Scope.Entry se = s.elems; se != null; se = se.sibling) {
91 for (Scope.Entry e = se; e.sym != null; e = e.next()) {
92 System.err.print(sep + e.sym.name + ":" + e.sym);
93 sep = ",";
94 }
95 System.err.print(")");
96 sep = ", (";
97 }
98 System.err.println();
99 }
101 /**
102 * Write an error message to stderr.
103 */
104 void error(String msg) {
105 System.err.println("Error: " + msg);
106 errors++;
107 }
109 Random rgen;
110 long seed = 0;
112 int errors;
114 enum SetupKind { NAMES, PACKAGE, CLASS };
115 static final int MAX_SETUP_COUNT = 50;
116 static final int MAX_SETUP_NAME_COUNT = 20;
117 static final int MAX_SETUP_PACKAGE_COUNT = 20;
118 static final int MAX_SETUP_CLASS_COUNT = 20;
120 /** Class to encapsulate a test run. */
121 class Test {
122 /** Run the test. */
123 void run() throws Exception {
124 log ("starting test");
125 setup();
126 createStarImportScope();
127 test();
128 }
130 /**
131 * Setup env by creating pseudo-random collection of names, packages and classes.
132 */
133 void setup() {
134 log ("setup");
135 context = new Context();
136 JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab
137 names = Names.instance(context); // Name.Table impls tied to an instance of Names
138 symtab = Symtab.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 }
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 }
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 = new Scope(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 }
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 }
207 /**
208 * Create a star-import scope and a model therof, 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);
216 // if StarImportScope exists, use it, otherwise, for testing legacy code,
217 // fall back on ImportScope
218 Method importAll;
219 try {
220 Class<?> c = Class.forName("com.sun.tools.javac.code.Scope$StarImportScope");
221 Constructor ctor = c.getDeclaredConstructor(new Class[] { Symbol.class });
222 importAll = c.getDeclaredMethod("importAll", new Class[] { Scope.class });
223 starImportScope = (Scope) ctor.newInstance(new Object[] { pkg });
224 } catch (ClassNotFoundException e) {
225 starImportScope = new ImportScope(pkg);
226 importAll = null;
227 }
228 starImportModel = new Model();
230 for (Symbol imp: imports) {
231 Scope members = imp.members();
232 if (importAll != null) {
233 // log("importAll", members);
234 importAll.invoke(starImportScope, members);
235 } else {
236 Scope fromScope = members;
237 Scope toScope = starImportScope;
238 // The following lines are taken from MemberEnter.importAll,
239 // before the use of StarImportScope.importAll.
240 for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) {
241 if (e.sym.kind == TYP && !toScope.includes(e.sym))
242 toScope.enter(e.sym, fromScope);
243 }
244 }
246 for (Scope.Entry e = members.elems; e != null; e = e.sibling) {
247 starImportModel.enter(e.sym);
248 }
249 }
251 // log("star-import scope", starImportScope);
252 starImportModel.check(starImportScope);
253 }
255 /**
256 * The core of the test. In a random order, move nested classes from
257 * the package in which they created to the class which should own them.
258 */
259 void test() {
260 log ("test");
261 List<ClassSymbol> nestedClasses = new LinkedList<ClassSymbol>();
262 for (PackageSymbol p: packages) {
263 for (Scope.Entry se = p.members_field.elems; se != null; se = se.sibling) {
264 if (se.sym.name.toString().contains("$"))
265 nestedClasses.add((ClassSymbol) se.sym);
266 }
267 }
269 for (int i = nestedClasses.size(); i > 0; i--) {
270 // select a random nested class to move from package to class
271 ClassSymbol sym = nestedClasses.remove(rgen.nextInt(i));
272 log("adjusting class " + sym);
274 // remove from star import model
275 starImportModel.remove(sym);
277 String s = sym.name.toString();
278 int dollar = s.indexOf("$");
280 // owner should be a package
281 assert (sym.owner.kind == PCK);
283 // determine new owner
284 Name outerName = names.fromString(s.substring(0, dollar));
285 // log(sym + " owner: " + sym.owner, sym.owner.members());
286 Scope.Entry outerEntry = sym.owner.members().lookup(outerName);
287 ClassSymbol outer = (ClassSymbol) outerEntry.sym;
288 // log("outer: " + outerName + " " + outer);
290 // remove from package
291 sym.owner.members().remove(sym);
293 // rename and insert into class
294 sym.name = names.fromString(s.substring(dollar + 1));
295 outer.members().enter(sym);
296 sym.owner = outer;
298 // verify
299 starImportModel.check(starImportScope);
300 }
301 }
303 ClassSymbol createClass(Name name, Symbol owner) {
304 ClassSymbol sym = new ClassSymbol(0, name, owner);
305 sym.members_field = new Scope(sym);
306 if (owner != symtab.unnamedPackage)
307 owner.members().enter(sym);
308 return sym;
309 }
311 Context context;
312 Symtab symtab;
313 Names names;
314 int nextNameSerial;
315 List<PackageSymbol> packages = new ArrayList<PackageSymbol>();
316 int nextPackageSerial;
317 List<ClassSymbol> classes = new ArrayList<ClassSymbol>();
318 List<Symbol> imports = new ArrayList<Symbol>();
319 int nextClassSerial;
321 Scope starImportScope;
322 Model starImportModel;
323 }
325 class Model {
326 private Map<Name, Set<Symbol>> map = new HashMap<Name, Set<Symbol>>();
327 private Set<Symbol> bogus = new HashSet<Symbol>();
329 void enter(Symbol sym) {
330 Set<Symbol> syms = map.get(sym.name);
331 if (syms == null)
332 map.put(sym.name, syms = new LinkedHashSet<Symbol>());
333 syms.add(sym);
334 }
336 void remove(Symbol sym) {
337 Set<Symbol> syms = map.get(sym.name);
338 if (syms == null)
339 error("no entries for " + sym.name + " found in reference model");
340 else {
341 boolean ok = syms.remove(sym);
342 if (ok) {
343 // log(sym.name + "(" + sym + ") removed from reference model");
344 } else {
345 error(sym.name + " not found in reference model");
346 }
347 if (syms.isEmpty())
348 map.remove(sym.name);
349 }
350 }
352 /**
353 * Check the contents of a scope
354 */
355 void check(Scope scope) {
356 // First, check all entries in scope are in map
357 int bogusCount = 0;
358 for (Scope.Entry se = scope.elems; se != null; se = se.sibling) {
359 Symbol sym = se.sym;
360 if (sym.owner != se.scope.owner) {
361 if (bogus.contains(sym)) {
362 bogusCount++;
363 } else {
364 log("Warning: " + sym.name + ":" + sym + " appears to be bogus");
365 bogus.add(sym);
366 }
367 } else {
368 Set<Symbol> syms = map.get(sym.name);
369 if (syms == null) {
370 error("check: no entries found for " + sym.name + ":" + sym + " in reference map");
371 } else if (!syms.contains(sym)) {
372 error("check: symbol " + sym.name + ":" + sym + " not found in reference map");
373 }
374 }
375 }
376 if (bogusCount > 0) {
377 log("Warning: " + bogusCount + " other bogus entries previously reported");
378 }
380 // Second, check all entries in map are in scope
381 for (Map.Entry<Name,Set<Symbol>> me: map.entrySet()) {
382 Name name = me.getKey();
383 Scope.Entry se = scope.lookup(name);
384 assert (se != null);
385 if (se.sym == null) {
386 error("check: no entries found for " + name + " in scope");
387 continue;
388 }
389 nextSym:
390 for (Symbol sym: me.getValue()) {
391 for (Scope.Entry e = se; e.sym != null; e = e.next()) {
392 if (sym == e.sym)
393 continue nextSym;
394 }
395 error("check: symbol " + sym + " not found in scope");
396 }
397 }
398 }
399 }
400 }