CompoundScopeTest.java revision 981:671bb63f3ed5
1/*
2 * Copyright (c) 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 */
23
24/*
25 * @test
26 * @bug 7017664 7036906
27 * @summary Basher for CompoundScopes
28 */
29
30import java.util.Random;
31import java.util.Map;
32import java.util.HashMap;
33import com.sun.tools.javac.util.*;
34import com.sun.tools.javac.code.*;
35import com.sun.tools.javac.code.Scope.*;
36import com.sun.tools.javac.code.Symbol.*;
37import com.sun.tools.javac.file.JavacFileManager;
38
39public class CompoundScopeTest {
40    public static void main(String... args) throws Exception {
41        new CompoundScopeTest().run(args);
42    }
43
44    static final int MAX_SYMBOLS_COUNT = 20;
45    static final int PASSES = 10;
46
47    void run(String... args) throws Exception {
48        int count = PASSES;
49
50        for (int i = 0; i < args.length; i++) {
51            String arg = args[i];
52            if (arg.equals("-seed") && (i + 1 < args.length))
53                seed = Long.parseLong(args[++i]);
54            else if(arg.equals("-tests") && (i + 1 < args.length))
55                count = Integer.parseInt(args[++i]);
56            else
57                throw new Exception("unknown arg: " + arg);
58        }
59
60        rgen = new Random(seed);
61
62        for (int i = 0; i < count; i++) {
63            Test t = new Test();
64            t.run();
65        }
66
67        if (errors > 0)
68            throw new Exception(errors + " errors found");
69    }
70
71    /**
72     * Write a message to stderr.
73     */
74    void log(String msg) {
75        System.err.println(msg);
76    }
77
78    /**
79     * Write an error message to stderr.
80     */
81    void error(String msg) {
82        System.err.println("Error: " + msg);
83        errors++;
84    }
85
86    Random rgen;
87    long seed = 0;
88
89    int errors;
90
91    /** Class to encapsulate a test run. */
92    class Test {
93
94        List<Symbol> elems = List.nil();
95        Map<Name, List<Symbol>> shadowedMap = new HashMap<Name, List<Symbol>>();
96
97        /** Run the test. */
98        void run() throws Exception {
99            log ("starting test");
100            setup();
101            Scope[] scopes = { createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)),
102                               createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)),
103                               createScope(rgen.nextInt(MAX_SYMBOLS_COUNT)) };
104            boolean[][] scopeNesting = { {false, true, false, true},
105                                   {false, true, true, true},
106                                   {false, false, true, true} };
107            /**
108             * We want to generate (and check) the following compound scopes:
109             * C1 = C(S1, S2, S3)
110             * C2 = C((S1, S2), S3)
111             * C3 = C(S1, (S2, S3))
112             * C3 = C(C(S1, S2, S3))
113             */
114            for (int i = 0 ; i < 4 ; i ++) {
115                CompoundScope root = new CompoundScope(symtab.noSymbol);
116                CompoundScope sub = new CompoundScope(symtab.noSymbol);
117                boolean subAdded = false;
118                for (int sc = 0 ; sc < 3 ; sc ++) {
119                    if (scopeNesting[sc][i]) {
120                        sub.addSubScope(scopes[sc]);
121                        if (!subAdded) {
122                            root.addSubScope(sub);
123                            subAdded = true;
124                        }
125                    } else {
126                        root.addSubScope(scopes[sc]);
127                    }
128                }
129                log("testing scope: " + root);
130                checkElems(root, null);
131                checkElems(root, new OddFilter());
132                checkShadowed(root, null);
133                checkShadowed(root, new OddFilter());
134            }
135        }
136
137        class OddFilter implements Filter<Symbol> {
138            public boolean accepts(Symbol s) {
139                Name numPart = s.name.subName(1, s.name.length());
140                return Integer.parseInt(numPart.toString()) % 2 != 0;
141            }
142        }
143
144        /**
145         * Create a scope containing a given number of synthetic symbols
146         */
147        Scope createScope(int nelems) {
148            Scope s = new Scope(symtab.noSymbol);
149            for (int i = 0 ; i < nelems ; i++) {
150                Symbol sym = new TypeSymbol(0, names.fromString("s" + i), null, null);
151                s.enter(sym);
152                elems = elems.prepend(sym);
153                List<Symbol> shadowed = shadowedMap.get(sym.name);
154                if (shadowed == null) {
155                    shadowed = List.nil();
156                }
157                shadowedMap.put(sym.name, shadowed.prepend(sym));
158            }
159            return s;
160        }
161
162        /**
163         * Setup compiler context
164         */
165        void setup() {
166            log ("setup");
167            context = new Context();
168            JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab
169            names = Names.instance(context);       // Name.Table impls tied to an instance of Names
170            symtab = Symtab.instance(context);
171        }
172
173        /**
174         * Check that CompoundScope.getElements() correctly visits all symbols
175         * in all subscopes (in the correct order)
176         */
177        void checkElems(CompoundScope cs, Filter<Symbol> sf) {
178            int count = 0;
179            ListBuffer<Symbol> found = ListBuffer.lb();
180            List<Symbol> allSymbols = sf == null ?
181                    elems :
182                    filter(elems, sf);
183            int expectedCount = allSymbols.length();
184            for (Symbol s : sf == null ? cs.getElements() : cs.getElements(sf)) {
185                checkSameSymbols(s, allSymbols.head);
186                allSymbols = allSymbols.tail;
187                found.append(s);
188                count++;
189            }
190            if (count != expectedCount) {
191                error("CompoundScope.getElements() did not returned enough symbols");
192            }
193        }
194
195        /**
196         * Check that CompoundScope.getElements() correctly visits all symbols
197         * with a given name in all subscopes (in the correct order)
198         */
199        void checkShadowed(CompoundScope cs, Filter<Symbol> sf) {
200            for (Map.Entry<Name, List<Symbol>> shadowedEntry : shadowedMap.entrySet()) {
201                int count = 0;
202                List<Symbol> shadowed = sf == null ?
203                    shadowedEntry.getValue() :
204                    filter(shadowedEntry.getValue(), sf);
205                int expectedCount = shadowed.length();
206                Name name = shadowedEntry.getKey();
207                for (Symbol s : sf == null ? cs.getElementsByName(name) : cs.getElementsByName(name, sf)) {
208                    checkSameSymbols(s, shadowed.head);
209                    shadowed = shadowed.tail;
210                    count++;
211                }
212                if (count != expectedCount) {
213                    error("CompoundScope.lookup() did not returned enough symbols for name " + name);
214                }
215            }
216        }
217
218        List<Symbol> filter(List<Symbol> elems, Filter<Symbol> sf) {
219            ListBuffer<Symbol> res = ListBuffer.lb();
220            for (Symbol s : elems) {
221                if (sf.accepts(s)) {
222                    res.append(s);
223                }
224            }
225            return res.toList();
226        }
227
228        void checkSameSymbols(Symbol found, Symbol req) {
229            if (found != req) {
230                error("Symbol mismatch - found    : " + found + ":" + found.hashCode() + "\n" +
231                      "                  required : " + req + ":" + req.hashCode());
232            }
233        }
234
235        Context context;
236        Symtab symtab;
237        Names names;
238    }
239}
240