test/tools/javac/7118412/ShadowingTest.java

Wed, 08 Oct 2014 14:16:40 -0700

author
asaha
date
Wed, 08 Oct 2014 14:16:40 -0700
changeset 2586
f5e5ca7505e2
parent 0
959103a6100f
permissions
-rw-r--r--

Merge

aoqi@0 1 /*
aoqi@0 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
aoqi@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
aoqi@0 4 *
aoqi@0 5 * This code is free software; you can redistribute it and/or modify it
aoqi@0 6 * under the terms of the GNU General Public License version 2 only, as
aoqi@0 7 * published by the Free Software Foundation.
aoqi@0 8 *
aoqi@0 9 * This code is distributed in the hope that it will be useful, but WITHOUT
aoqi@0 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
aoqi@0 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
aoqi@0 12 * version 2 for more details (a copy is included in the LICENSE file that
aoqi@0 13 * accompanied this code).
aoqi@0 14 *
aoqi@0 15 * You should have received a copy of the GNU General Public License version
aoqi@0 16 * 2 along with this work; if not, write to the Free Software Foundation,
aoqi@0 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
aoqi@0 18 *
aoqi@0 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
aoqi@0 20 * or visit www.oracle.com if you need additional information or have any
aoqi@0 21 * questions.
aoqi@0 22 */
aoqi@0 23
aoqi@0 24 /*
aoqi@0 25 * @test
aoqi@0 26 * @bug 7118412
aoqi@0 27 * @summary Shadowing of type-variables vs. member types
aoqi@0 28 */
aoqi@0 29 import java.io.File;
aoqi@0 30 import java.io.FileWriter;
aoqi@0 31 import java.io.IOException;
aoqi@0 32 import java.io.PrintWriter;
aoqi@0 33 import java.io.StringWriter;
aoqi@0 34
aoqi@0 35 public class ShadowingTest {
aoqi@0 36
aoqi@0 37 // We generate a method "test" that tries to call T.<something,
aoqi@0 38 // depending on the value of MethodCall>. This controls whether
aoqi@0 39 // "test" is static or not.
aoqi@0 40 private enum MethodContext {
aoqi@0 41 STATIC("static "),
aoqi@0 42 INSTANCE("");
aoqi@0 43
aoqi@0 44 public final String methodcontext;
aoqi@0 45
aoqi@0 46 MethodContext(final String methodcontext) {
aoqi@0 47 this.methodcontext = methodcontext;
aoqi@0 48 }
aoqi@0 49 }
aoqi@0 50
aoqi@0 51 // These control whether or not a type parameter, method type
aoqi@0 52 // parameter, or inner class get declared (and in the case of
aoqi@0 53 // inner classes, whether it's static or not.
aoqi@0 54
aoqi@0 55 private enum MethodTypeParameterDecl {
aoqi@0 56 NO(""),
aoqi@0 57 YES("<T extends Number> ");
aoqi@0 58
aoqi@0 59 public final String tyvar;
aoqi@0 60
aoqi@0 61 MethodTypeParameterDecl(final String tyvar) {
aoqi@0 62 this.tyvar = tyvar;
aoqi@0 63 }
aoqi@0 64 }
aoqi@0 65
aoqi@0 66 private enum InsideDef {
aoqi@0 67 NONE(""),
aoqi@0 68 STATIC("static class T { public void inner() {} }\n"),
aoqi@0 69 INSTANCE("class T { public void inner() {} }\n");
aoqi@0 70
aoqi@0 71 public final String instancedef;
aoqi@0 72
aoqi@0 73 InsideDef(final String instancedef) {
aoqi@0 74 this.instancedef = instancedef;
aoqi@0 75 }
aoqi@0 76 }
aoqi@0 77
aoqi@0 78 private enum TypeParameterDecl {
aoqi@0 79 NO(""),
aoqi@0 80 YES("<T extends Collection>");
aoqi@0 81
aoqi@0 82 public final String tyvar;
aoqi@0 83
aoqi@0 84 TypeParameterDecl(final String tyvar) {
aoqi@0 85 this.tyvar = tyvar;
aoqi@0 86 }
aoqi@0 87 }
aoqi@0 88
aoqi@0 89 // Represents what method we try to call. This is a way of
aoqi@0 90 // checking which T we're seeing.
aoqi@0 91 private enum MethodCall {
aoqi@0 92 // Method type variables extend Number, so we have intValue
aoqi@0 93 METHOD_TYPEVAR("intValue"),
aoqi@0 94 // The inner class declaration has a method called "inner"
aoqi@0 95 INNER_CLASS("inner"),
aoqi@0 96 // The class type variables extend Collection, so we call iterator
aoqi@0 97 TYPEVAR("iterator"),
aoqi@0 98 // The outer class declaration has a method called "outer"
aoqi@0 99 OUTER_CLASS("outer");
aoqi@0 100
aoqi@0 101 public final String methodcall;
aoqi@0 102
aoqi@0 103 MethodCall(final String methodcall) {
aoqi@0 104 this.methodcall = methodcall;
aoqi@0 105 }
aoqi@0 106
aoqi@0 107 }
aoqi@0 108
aoqi@0 109 public boolean succeeds(final MethodCall call,
aoqi@0 110 final MethodTypeParameterDecl mtyvar,
aoqi@0 111 final MethodContext ctx,
aoqi@0 112 final InsideDef inside,
aoqi@0 113 final TypeParameterDecl tyvar) {
aoqi@0 114 switch(call) {
aoqi@0 115 // We want to resolve to the method type variable
aoqi@0 116 case METHOD_TYPEVAR: switch(mtyvar) {
aoqi@0 117 // If the method type variable exists, then T will
aoqi@0 118 // resolve to it, and we'll have intValue.
aoqi@0 119 case YES: return true;
aoqi@0 120 // Otherwise, this cannot succeed.
aoqi@0 121 default: return false;
aoqi@0 122 }
aoqi@0 123 // We want to resolve to the inner class
aoqi@0 124 case INNER_CLASS: switch(mtyvar) {
aoqi@0 125 // The method type parameter will shadow the inner
aoqi@0 126 // class, so there can't be one.
aoqi@0 127 case NO: switch(ctx) {
aoqi@0 128 // If we're not static, then either one should succeed.
aoqi@0 129 case INSTANCE: switch(inside) {
aoqi@0 130 case INSTANCE:
aoqi@0 131 case STATIC:
aoqi@0 132 return true;
aoqi@0 133 default: return false;
aoqi@0 134 }
aoqi@0 135 case STATIC: switch(inside) {
aoqi@0 136 // If we are static, and the inner class is
aoqi@0 137 // static, then we also succeed, because we
aoqi@0 138 // can't see the type variable.
aoqi@0 139 case STATIC: return true;
aoqi@0 140 case INSTANCE: switch(tyvar) {
aoqi@0 141 // If we're calling from a non-static
aoqi@0 142 // context, there can't be a class type
aoqi@0 143 // variable, because that will shadow the
aoqi@0 144 // static inner class definition.
aoqi@0 145 case NO: return true;
aoqi@0 146 default: return false;
aoqi@0 147 }
aoqi@0 148 // If the inner class isn't declared, we can't
aoqi@0 149 // see it.
aoqi@0 150 default: return false;
aoqi@0 151 }
aoqi@0 152 // Can't get here.
aoqi@0 153 default: return false;
aoqi@0 154 }
aoqi@0 155 default: return false;
aoqi@0 156 }
aoqi@0 157 // We want to resolve to the class type parameter
aoqi@0 158 case TYPEVAR: switch(mtyvar) {
aoqi@0 159 // We can't have a method type parameter, as that would
aoqi@0 160 // shadow the class type parameter
aoqi@0 161 case NO: switch(ctx) {
aoqi@0 162 case INSTANCE: switch(inside) {
aoqi@0 163 // We have to be in an instance context. If
aoqi@0 164 // we're static, we can't see the type
aoqi@0 165 // variable.
aoqi@0 166 case NONE: switch(tyvar) {
aoqi@0 167 // Obviously, the type parameter has to be declared.
aoqi@0 168 case YES: return true;
aoqi@0 169 default: return false;
aoqi@0 170 }
aoqi@0 171 default: return false;
aoqi@0 172 }
aoqi@0 173 default: return false;
aoqi@0 174 }
aoqi@0 175 default: return false;
aoqi@0 176 }
aoqi@0 177 // We want to resolve to the outer class
aoqi@0 178 case OUTER_CLASS: switch(mtyvar) {
aoqi@0 179 case NO: switch(inside) {
aoqi@0 180 case NONE: switch(tyvar) {
aoqi@0 181 // Basically, nothing else can be declared, or
aoqi@0 182 // else we can't see it. Even if our context
aoqi@0 183 // is static, the compiler will complain if
aoqi@0 184 // non-static T's exist, because they will
aoqi@0 185 // shadow the outer class.
aoqi@0 186 case NO: return true;
aoqi@0 187 default: return false;
aoqi@0 188 }
aoqi@0 189 default: return false;
aoqi@0 190 }
aoqi@0 191 default: return false;
aoqi@0 192 }
aoqi@0 193 }
aoqi@0 194 return false;
aoqi@0 195 }
aoqi@0 196
aoqi@0 197 private static final File classesdir = new File("7118412");
aoqi@0 198
aoqi@0 199 private int errors = 0;
aoqi@0 200
aoqi@0 201 private int dirnum = 0;
aoqi@0 202
aoqi@0 203 private void doTest(final MethodTypeParameterDecl mtyvar,
aoqi@0 204 final TypeParameterDecl tyvar,
aoqi@0 205 final InsideDef insidedef, final MethodContext ctx,
aoqi@0 206 final MethodCall call)
aoqi@0 207 throws IOException {
aoqi@0 208 final String content = "import java.util.Collection;\n" +
aoqi@0 209 "class Test" + tyvar.tyvar + " {\n" +
aoqi@0 210 " " + insidedef.instancedef +
aoqi@0 211 " " + ctx.methodcontext + mtyvar.tyvar + "void test(T t) { t." +
aoqi@0 212 call.methodcall + "(); }\n" +
aoqi@0 213 "}\n" +
aoqi@0 214 "class T { void outer() {} }\n";
aoqi@0 215 final File dir = new File(classesdir, "" + dirnum);
aoqi@0 216 final File Test_java = writeFile(dir, "Test.java", content);
aoqi@0 217 dirnum++;
aoqi@0 218 if(succeeds(call, mtyvar, ctx, insidedef, tyvar)) {
aoqi@0 219 if(!assert_compile_succeed(Test_java))
aoqi@0 220 System.err.println("Failed file:\n" + content);
aoqi@0 221 }
aoqi@0 222 else {
aoqi@0 223 if(!assert_compile_fail(Test_java))
aoqi@0 224 System.err.println("Failed file:\n" + content);
aoqi@0 225 }
aoqi@0 226 }
aoqi@0 227
aoqi@0 228 private void run() throws Exception {
aoqi@0 229 classesdir.mkdir();
aoqi@0 230 for(MethodTypeParameterDecl mtyvar : MethodTypeParameterDecl.values())
aoqi@0 231 for(TypeParameterDecl tyvar : TypeParameterDecl.values())
aoqi@0 232 for(InsideDef insidedef : InsideDef.values())
aoqi@0 233 for(MethodContext ctx : MethodContext.values())
aoqi@0 234 for(MethodCall methodcall : MethodCall.values())
aoqi@0 235 doTest(mtyvar, tyvar, insidedef, ctx, methodcall);
aoqi@0 236 if (errors != 0)
aoqi@0 237 throw new Exception("ShadowingTest test failed with " +
aoqi@0 238 errors + " errors.");
aoqi@0 239 }
aoqi@0 240
aoqi@0 241 private boolean assert_compile_fail(final File file) {
aoqi@0 242 final String filename = file.getPath();
aoqi@0 243 final String[] args = { filename };
aoqi@0 244 final StringWriter sw = new StringWriter();
aoqi@0 245 final PrintWriter pw = new PrintWriter(sw);
aoqi@0 246 final int rc = com.sun.tools.javac.Main.compile(args, pw);
aoqi@0 247 pw.close();
aoqi@0 248 if (rc == 0) {
aoqi@0 249 System.err.println("Compilation of " + file.getName() +
aoqi@0 250 " didn't fail as expected.");
aoqi@0 251 errors++;
aoqi@0 252 return false;
aoqi@0 253 } else return true;
aoqi@0 254 }
aoqi@0 255
aoqi@0 256 private boolean assert_compile_succeed(final File file) {
aoqi@0 257 final String filename = file.getPath();
aoqi@0 258 final String[] args = { filename };
aoqi@0 259 final StringWriter sw = new StringWriter();
aoqi@0 260 final PrintWriter pw = new PrintWriter(sw);
aoqi@0 261 final int rc = com.sun.tools.javac.Main.compile(args, pw);
aoqi@0 262 pw.close();
aoqi@0 263 if (rc != 0) {
aoqi@0 264 System.err.println("Compilation of " + file.getName() +
aoqi@0 265 " didn't succeed as expected. Output:");
aoqi@0 266 System.err.println(sw.toString());
aoqi@0 267 errors++;
aoqi@0 268 return false;
aoqi@0 269 } else return true;
aoqi@0 270 }
aoqi@0 271
aoqi@0 272 private File writeFile(final File dir,
aoqi@0 273 final String path,
aoqi@0 274 final String body) throws IOException {
aoqi@0 275 final File f = new File(dir, path);
aoqi@0 276 f.getParentFile().mkdirs();
aoqi@0 277 final FileWriter out = new FileWriter(f);
aoqi@0 278 out.write(body);
aoqi@0 279 out.close();
aoqi@0 280 return f;
aoqi@0 281 }
aoqi@0 282
aoqi@0 283 public static void main(String... args) throws Exception {
aoqi@0 284 new ShadowingTest().run();
aoqi@0 285 }
aoqi@0 286
aoqi@0 287 }

mercurial