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  */
  23 
  24 /*
  25  * @test
  26  * @bug 7118412
  27  * @summary javac should generate method parameters correctly.
  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;
  34 
  35 public class ShadowingTest {
  36 
  37     enum MethodCall {
  38         INNER("inner"),
  39         TYPEVAR("iterator"),
  40         OUTER("outer");
  41 
  42         public final String methodcall;
  43 
  44         MethodCall(final String methodcall) {
  45             this.methodcall = methodcall;
  46         }
  47 
  48         public boolean succeeds(final MethodContext ctx,
  49                                 final InsideDef inside,
  50                                 final TyVar tyvar) {
  51             switch(this) {
  52             case INNER: switch(ctx) {
  53                 case STATIC: switch(inside) {
  54                     case INSTANCE:
  55                     case STATIC:
  56                         return true;
  57                     default: return false;
  58                     }
  59                 case INSTANCE: switch(inside) {
  60                     case INSTANCE:
  61                     case STATIC: return true;
  62                     default: return false;
  63                     }
  64                 }
  65             case TYPEVAR: switch(ctx) {
  66                 case INSTANCE: switch(inside) {
  67                     case NONE: switch(tyvar) {
  68                         case YES: return true;
  69                         default: return false;
  70                         }
  71                     default: return false;
  72                     }
  73                 default: return false;
  74                 }
  75             case OUTER: switch(inside) {
  76                 case NONE: switch(tyvar) {
  77                     case NO: return true;
  78                     default: return false;
  79                     }
  80                 default: return false;
  81                 }
  82             }
  83             return false;
  84         }
  85     }
  86 
  87     enum MethodContext {
  88         STATIC("static "),
  89         INSTANCE("");
  90 
  91         public final String methodcontext;
  92 
  93         MethodContext(final String methodcontext) {
  94             this.methodcontext = methodcontext;
  95         }
  96     }
  97 
  98     enum InsideDef {
  99         NONE(""),
 100         STATIC("static class T { public void inner() {} }\n"),
 101         INSTANCE("class T { public void inner() {} }\n");
 102 
 103         public final String instancedef;
 104 
 105         InsideDef(final String instancedef) {
 106             this.instancedef = instancedef;
 107         }
 108     }
 109 
 110     enum TyVar {
 111         NO(""),
 112         YES("<T extends Collection>");
 113 
 114         public final String tyvar;
 115 
 116         TyVar(final String tyvar) {
 117             this.tyvar = tyvar;
 118         }
 119     }
 120 
 121     static final File classesdir = new File("7118412");
 122 
 123     private int errors = 0;
 124 
 125     public static void main(String... args) throws Exception {
 126         new ShadowingTest().run();
 127     }
 128 
 129     int dirnum = 0;
 130 
 131     private void doTest(final TyVar tyvar, final InsideDef insidedef,
 132                         final MethodContext ctx, final MethodCall call)
 133         throws IOException {
 134         final String content = "import java.util.Collection;\n" +
 135             "class Test" + tyvar.tyvar + " {\n" +
 136             "  " + insidedef.instancedef +
 137             "  " + ctx.methodcontext + "void test(T t) { t." +
 138             call.methodcall + "(); }\n" +
 139             "}\n" +
 140             "class T { void outer() {} }\n";
 141         final File dir = new File(classesdir, "" + dirnum);
 142         final File Test_java = writeFile(dir, "Test.java", content);
 143         dirnum++;
 144         if(call.succeeds(ctx, insidedef, tyvar)) {
 145             if(!assert_compile_succeed(Test_java))
 146                 System.err.println("Failed file:\n" + content);
 147         }
 148         else {
 149             if(!assert_compile_fail(Test_java))
 150                 System.err.println("Failed file:\n" + content);
 151         }
 152     }
 153 
 154     void run() throws Exception {
 155         classesdir.mkdir();
 156         for(TyVar tyvar : TyVar.values())
 157             for(InsideDef insidedef : InsideDef.values())
 158                 for(MethodContext ctx : MethodContext.values())
 159                     for(MethodCall methodcall : MethodCall.values())
 160                         doTest(tyvar, insidedef, ctx, methodcall);
 161         if (errors != 0)
 162             throw new Exception("ShadowingTest test failed with " +
 163                                 errors + " errors.");
 164     }
 165 
 166     boolean assert_compile_fail(final File file) {
 167         final String filename = file.getPath();
 168         final String[] args = { filename };
 169         final StringWriter sw = new StringWriter();
 170         final PrintWriter pw = new PrintWriter(sw);
 171         final int rc = com.sun.tools.javac.Main.compile(args, pw);
 172         pw.close();
 173         if (rc == 0) {
 174             System.err.println("Compilation of " + file.getName() +
 175                                " didn't fail as expected.");
 176             errors++;
 177             return false;
 178         } else return true;
 179     }
 180 
 181     boolean assert_compile_succeed(final File file) {
 182         final String filename = file.getPath();
 183         final String[] args = { filename };
 184         final StringWriter sw = new StringWriter();
 185         final PrintWriter pw = new PrintWriter(sw);
 186         final int rc = com.sun.tools.javac.Main.compile(args, pw);
 187         pw.close();
 188         if (rc != 0) {
 189             System.err.println("Compilation of " + file.getName() +
 190                                " didn't succeed as expected.  Output:");
 191             System.err.println(sw.toString());
 192             errors++;
 193             return false;
 194         } else return true;
 195     }
 196 
 197     File writeFile(final File dir,
 198                    final String path,
 199                    final String body) throws IOException {
 200         final File f = new File(dir, path);
 201         f.getParentFile().mkdirs();
 202         final FileWriter out = new FileWriter(f);
 203         out.write(body);
 204         out.close();
 205         return f;
 206     }
 207 }