test/tools/javac/7118412/ShadowingTest.java

Wed, 13 Aug 2014 14:50:00 -0700

author
katleman
date
Wed, 13 Aug 2014 14:50:00 -0700
changeset 2549
0b6cc4ea670f
parent 0
959103a6100f
permissions
-rw-r--r--

Added tag jdk8u40-b01 for changeset bf89a471779d

     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 }

mercurial