Wed, 21 Aug 2013 20:41:42 -0400
8023520: Add missing test for JDK-7118412
Summary: The test for JDK-7118412 was dropped from the changeset in a merging accident.
Reviewed-by: jjg
1 /*
2 * Copyright (c) 2013, 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 7118412
27 * @summary Shadowing of type-variables vs. member types
28 */
29 import java.io.File;
30 import java.io.FileWriter;
31 import java.io.IOException;
32 import java.io.PrintWriter;
33 import java.io.StringWriter;
35 public class ShadowingTest {
37 // We generate a method "test" that tries to call T.<something,
38 // depending on the value of MethodCall>. This controls whether
39 // "test" is static or not.
40 private enum MethodContext {
41 STATIC("static "),
42 INSTANCE("");
44 public final String methodcontext;
46 MethodContext(final String methodcontext) {
47 this.methodcontext = methodcontext;
48 }
49 }
51 // These control whether or not a type parameter, method type
52 // parameter, or inner class get declared (and in the case of
53 // inner classes, whether it's static or not.
55 private enum MethodTypeParameterDecl {
56 NO(""),
57 YES("<T extends Number> ");
59 public final String tyvar;
61 MethodTypeParameterDecl(final String tyvar) {
62 this.tyvar = tyvar;
63 }
64 }
66 private enum InsideDef {
67 NONE(""),
68 STATIC("static class T { public void inner() {} }\n"),
69 INSTANCE("class T { public void inner() {} }\n");
71 public final String instancedef;
73 InsideDef(final String instancedef) {
74 this.instancedef = instancedef;
75 }
76 }
78 private enum TypeParameterDecl {
79 NO(""),
80 YES("<T extends Collection>");
82 public final String tyvar;
84 TypeParameterDecl(final String tyvar) {
85 this.tyvar = tyvar;
86 }
87 }
89 // Represents what method we try to call. This is a way of
90 // checking which T we're seeing.
91 private enum MethodCall {
92 // Method type variables extend Number, so we have intValue
93 METHOD_TYPEVAR("intValue"),
94 // The inner class declaration has a method called "inner"
95 INNER_CLASS("inner"),
96 // The class type variables extend Collection, so we call iterator
97 TYPEVAR("iterator"),
98 // The outer class declaration has a method called "outer"
99 OUTER_CLASS("outer");
101 public final String methodcall;
103 MethodCall(final String methodcall) {
104 this.methodcall = methodcall;
105 }
107 }
109 public boolean succeeds(final MethodCall call,
110 final MethodTypeParameterDecl mtyvar,
111 final MethodContext ctx,
112 final InsideDef inside,
113 final TypeParameterDecl tyvar) {
114 switch(call) {
115 // We want to resolve to the method type variable
116 case METHOD_TYPEVAR: switch(mtyvar) {
117 // If the method type variable exists, then T will
118 // resolve to it, and we'll have intValue.
119 case YES: return true;
120 // Otherwise, this cannot succeed.
121 default: return false;
122 }
123 // We want to resolve to the inner class
124 case INNER_CLASS: switch(mtyvar) {
125 // The method type parameter will shadow the inner
126 // class, so there can't be one.
127 case NO: switch(ctx) {
128 // If we're not static, then either one should succeed.
129 case INSTANCE: switch(inside) {
130 case INSTANCE:
131 case STATIC:
132 return true;
133 default: return false;
134 }
135 case STATIC: switch(inside) {
136 // If we are static, and the inner class is
137 // static, then we also succeed, because we
138 // can't see the type variable.
139 case STATIC: return true;
140 case INSTANCE: switch(tyvar) {
141 // If we're calling from a non-static
142 // context, there can't be a class type
143 // variable, because that will shadow the
144 // static inner class definition.
145 case NO: return true;
146 default: return false;
147 }
148 // If the inner class isn't declared, we can't
149 // see it.
150 default: return false;
151 }
152 // Can't get here.
153 default: return false;
154 }
155 default: return false;
156 }
157 // We want to resolve to the class type parameter
158 case TYPEVAR: switch(mtyvar) {
159 // We can't have a method type parameter, as that would
160 // shadow the class type parameter
161 case NO: switch(ctx) {
162 case INSTANCE: switch(inside) {
163 // We have to be in an instance context. If
164 // we're static, we can't see the type
165 // variable.
166 case NONE: switch(tyvar) {
167 // Obviously, the type parameter has to be declared.
168 case YES: return true;
169 default: return false;
170 }
171 default: return false;
172 }
173 default: return false;
174 }
175 default: return false;
176 }
177 // We want to resolve to the outer class
178 case OUTER_CLASS: switch(mtyvar) {
179 case NO: switch(inside) {
180 case NONE: switch(tyvar) {
181 // Basically, nothing else can be declared, or
182 // else we can't see it. Even if our context
183 // is static, the compiler will complain if
184 // non-static T's exist, because they will
185 // shadow the outer class.
186 case NO: return true;
187 default: return false;
188 }
189 default: return false;
190 }
191 default: return false;
192 }
193 }
194 return false;
195 }
197 private static final File classesdir = new File("7118412");
199 private int errors = 0;
201 private int dirnum = 0;
203 private void doTest(final MethodTypeParameterDecl mtyvar,
204 final TypeParameterDecl tyvar,
205 final InsideDef insidedef, final MethodContext ctx,
206 final MethodCall call)
207 throws IOException {
208 final String content = "import java.util.Collection;\n" +
209 "class Test" + tyvar.tyvar + " {\n" +
210 " " + insidedef.instancedef +
211 " " + ctx.methodcontext + mtyvar.tyvar + "void test(T t) { t." +
212 call.methodcall + "(); }\n" +
213 "}\n" +
214 "class T { void outer() {} }\n";
215 final File dir = new File(classesdir, "" + dirnum);
216 final File Test_java = writeFile(dir, "Test.java", content);
217 dirnum++;
218 if(succeeds(call, mtyvar, ctx, insidedef, tyvar)) {
219 if(!assert_compile_succeed(Test_java))
220 System.err.println("Failed file:\n" + content);
221 }
222 else {
223 if(!assert_compile_fail(Test_java))
224 System.err.println("Failed file:\n" + content);
225 }
226 }
228 private void run() throws Exception {
229 classesdir.mkdir();
230 for(MethodTypeParameterDecl mtyvar : MethodTypeParameterDecl.values())
231 for(TypeParameterDecl tyvar : TypeParameterDecl.values())
232 for(InsideDef insidedef : InsideDef.values())
233 for(MethodContext ctx : MethodContext.values())
234 for(MethodCall methodcall : MethodCall.values())
235 doTest(mtyvar, tyvar, insidedef, ctx, methodcall);
236 if (errors != 0)
237 throw new Exception("ShadowingTest test failed with " +
238 errors + " errors.");
239 }
241 private boolean assert_compile_fail(final File file) {
242 final String filename = file.getPath();
243 final String[] args = { filename };
244 final StringWriter sw = new StringWriter();
245 final PrintWriter pw = new PrintWriter(sw);
246 final int rc = com.sun.tools.javac.Main.compile(args, pw);
247 pw.close();
248 if (rc == 0) {
249 System.err.println("Compilation of " + file.getName() +
250 " didn't fail as expected.");
251 errors++;
252 return false;
253 } else return true;
254 }
256 private boolean assert_compile_succeed(final File file) {
257 final String filename = file.getPath();
258 final String[] args = { filename };
259 final StringWriter sw = new StringWriter();
260 final PrintWriter pw = new PrintWriter(sw);
261 final int rc = com.sun.tools.javac.Main.compile(args, pw);
262 pw.close();
263 if (rc != 0) {
264 System.err.println("Compilation of " + file.getName() +
265 " didn't succeed as expected. Output:");
266 System.err.println(sw.toString());
267 errors++;
268 return false;
269 } else return true;
270 }
272 private File writeFile(final File dir,
273 final String path,
274 final String body) throws IOException {
275 final File f = new File(dir, path);
276 f.getParentFile().mkdirs();
277 final FileWriter out = new FileWriter(f);
278 out.write(body);
279 out.close();
280 return f;
281 }
283 public static void main(String... args) throws Exception {
284 new ShadowingTest().run();
285 }
287 }