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 8013357
  27  * @summary javac should correctly enforce binary comparison rules.
  28  */
  29 import com.sun.tools.javac.code.Type;
  30 import com.sun.tools.javac.code.Type.*;
  31 import com.sun.tools.javac.code.Symbol.*;
  32 import java.io.*;
  33 import java.lang.reflect.Array;
  34 import java.util.EnumSet;
  35 
  36 public class TestComparisons {
  37 
  38     private int errors = 0;
  39     private int testnum = 0;
  40 
  41     static final File testdir = new File("8013357");
  42 
  43     private enum CompareType {
  44         BYTE_PRIM("byte"),
  45         SHORT_PRIM("short"),
  46         CHAR_PRIM("char"),
  47         INTEGER_PRIM("int"),
  48         LONG_PRIM("long"),
  49         FLOAT_PRIM("float"),
  50         DOUBLE_PRIM("double"),
  51         BOOLEAN_PRIM("boolean"),
  52 
  53         BYTE("Byte"),
  54         SHORT("Short"),
  55         CHAR("Character"),
  56         INTEGER("Integer"),
  57         LONG("Long"),
  58         FLOAT("Float"),
  59         DOUBLE("Double"),
  60         BOOLEAN("Boolean"),
  61 
  62         BYTE_SUPER("List<? super Byte>", true),
  63         SHORT_SUPER("List<? super Short>", true),
  64         CHAR_SUPER("List<? super Character>", true),
  65         INTEGER_SUPER("List<? super Integer>", true),
  66         LONG_SUPER("List<? super Long>", true),
  67         FLOAT_SUPER("List<? super Float>", true),
  68         DOUBLE_SUPER("List<? super Double>", true),
  69         BOOLEAN_SUPER("List<? super Boolean>", true),
  70 
  71         OBJECT("Object"),
  72         NUMBER("Number"),
  73         STRING("String");
  74 
  75         public final boolean isList;
  76         public final String name;
  77 
  78         private CompareType(final String name, final boolean isList) {
  79             this.isList = isList;
  80             this.name = name;
  81         }
  82 
  83         private CompareType(final String name) {
  84             this(name, false);
  85         }
  86     }
  87 
  88     // The integers here refer to which subsection of JLS 15.21 is in
  89     // effect.  0 means no comparison is allowed.
  90     private static final int truthtab[][] = {
  91         // byte, comparable to itself, any numeric type, or any boxed
  92         // numeric type.
  93         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
  94           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
  95           0, 0, 0, 0, 0, 0, 0, 0, // Captures
  96           0, 0, 0                 // Reference types
  97         },
  98         // short, comparable to itself, any numeric type, or any boxed
  99         // numeric type.
 100         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 101           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
 102           0, 0, 0, 0, 0, 0, 0, 0, // Captures
 103           0, 0, 0                 // Reference types
 104         },
 105         // char, comparable to itself, any numeric type, or any boxed
 106         // numeric type.
 107         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 108           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
 109           0, 0, 0, 0, 0, 0, 0, 0, // Captures
 110           0, 0, 0                 // Reference types
 111         },
 112         // int, comparable to itself, any numeric type, or any boxed
 113         // numeric type.
 114         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 115           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
 116           0, 0, 0, 0, 0, 0, 0, 0, // Captures
 117           0, 0, 0                 // Reference types
 118         },
 119         // long, comparable to itself, any numeric type, or any boxed
 120         // numeric type.
 121         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 122           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
 123           0, 0, 0, 0, 0, 0, 0, 0, // Captures
 124           0, 0, 0                 // Reference types
 125         },
 126         // float, comparable to itself, any numeric type, or any boxed
 127         // numeric type.
 128         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 129           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
 130           0, 0, 0, 0, 0, 0, 0, 0, // Captures
 131           0, 0, 0                 // Reference types
 132         },
 133         // double, comparable to itself, any numeric type, or any boxed
 134         // numeric type.
 135         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 136           1, 1, 1, 1, 1, 1, 1, 0, // Boxed primitives
 137           0, 0, 0, 0, 0, 0, 0, 0, // Captures
 138           0, 0, 0                 // Reference types
 139         },
 140         // boolean, comparable only to itself and Boolean.
 141         { 0, 0, 0, 0, 0, 0, 0, 2, // Primitives
 142           0, 0, 0, 0, 0, 0, 0, 2, // Boxed primitives
 143           0, 0, 0, 0, 0, 0, 0, 0, // Captures
 144           0, 0, 0                 // Reference types
 145         },
 146         // Byte, comparable to itself, Number, Object, any numeric primitive,
 147         // and any captures.
 148         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 149           3, 0, 0, 0, 0, 0, 0, 0, // Boxed primitives
 150           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 151           3, 3, 0                 // Reference types
 152         },
 153         // Short, comparable to itself, Number, Object, any numeric primitive,
 154         // and any captures.
 155         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 156           0, 3, 0, 0, 0, 0, 0, 0, // Boxed primitives
 157           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 158           3, 3, 0                 // Reference types
 159         },
 160         // Character, comparable to itself, Object, any numeric primitive,
 161         // and any captures.
 162         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 163           0, 0, 3, 0, 0, 0, 0, 0, // Boxed primitives
 164           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 165           3, 0, 0                 // Reference types
 166         },
 167         // Int, comparable to itself, Number, Object, any numeric primitive,
 168         // and any captures.
 169         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 170           0, 0, 0, 3, 0, 0, 0, 0, // Boxed primitives
 171           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 172           3, 3, 0                 // Reference types
 173         },
 174         // Long, comparable to itself, Number, Object, any numeric primitive,
 175         // and any captures.
 176         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 177           0, 0, 0, 0, 3, 0, 0, 0, // Boxed primitives
 178           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 179           3, 3, 0                 // Reference types
 180         },
 181         // Float, comparable to itself, Number, Object, any numeric primitive,
 182         // and any captures.
 183         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 184           0, 0, 0, 0, 0, 3, 0, 0, // Boxed primitives
 185           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 186           3, 3, 0                 // Reference types
 187         },
 188         // Double, comparable to itself, Number, Object, any numeric primitive,
 189         // and any captures.
 190         { 1, 1, 1, 1, 1, 1, 1, 0, // Primitives
 191           0, 0, 0, 0, 0, 0, 3, 0, // Boxed primitives
 192           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 193           3, 3, 0                 // Reference types
 194         },
 195         // Boolean, to itself, any capture, Object, and boolean.
 196         { 0, 0, 0, 0, 0, 0, 0, 2, // Primitives
 197           0, 0, 0, 0, 0, 0, 0, 2, // Boxed primitives
 198           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 199           3, 0, 0                 // Reference types
 200         },
 201         // Byte supertype wildcard, comparable to any reference type.
 202         // and any captures.
 203         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
 204           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
 205           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 206           3, 3, 3                 // Reference types
 207         },
 208         // Short supertype wildcard, comparable to any reference type.
 209         // and any captures.
 210         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
 211           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
 212           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 213           3, 3, 3                 // Reference types
 214         },
 215         // Character supertype wildcard, comparable to any reference type.
 216         // and any captures.
 217         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
 218           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
 219           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 220           3, 3, 3                 // Reference types
 221         },
 222         // Integer supertype wildcard, comparable to any reference type.
 223         // and any captures.
 224         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
 225           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
 226           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 227           3, 3, 3                 // Reference types
 228         },
 229         // Long supertype wildcard, comparable to any reference type.
 230         // and any captures.
 231         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
 232           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
 233           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 234           3, 3, 3                 // Reference types
 235         },
 236         // Float supertype wildcard, comparable to any reference type.
 237         // and any captures.
 238         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
 239           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
 240           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 241           3, 3, 3                 // Reference types
 242         },
 243         // Double supertype wildcard, comparable to any reference type.
 244         // and any captures.
 245         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
 246           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
 247           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 248           3, 3, 3                 // Reference types
 249         },
 250         // Boolean supertype wildcard, comparable to any reference type.
 251         // and any captures.
 252         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
 253           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
 254           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 255           3, 3, 3                 // Reference types
 256         },
 257         // Object, comparable to any reference type.
 258         // and any captures.
 259         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
 260           3, 3, 3, 3, 3, 3, 3, 3, // Boxed primitives
 261           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 262           3, 3, 3                 // Reference types
 263         },
 264         // Number, comparable to Object, any of its subclasses.
 265         // and any captures.
 266         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
 267           3, 3, 0, 3, 3, 3, 3, 0, // Boxed primitives
 268           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 269           3, 3, 0                 // Reference types
 270         },
 271         // String supertype wildcard, comparable to any reference type.
 272         // and any captures.
 273         { 0, 0, 0, 0, 0, 0, 0, 0, // Primitives
 274           0, 0, 0, 0, 0, 0, 0, 0, // Boxed primitives
 275           3, 3, 3, 3, 3, 3, 3, 3, // Captures
 276           3, 0, 3                 // Reference types
 277         }
 278     };
 279 
 280     private void assert_compile_fail(final File file, final String body) {
 281         final String filename = file.getPath();
 282         final String[] args = { filename };
 283         final StringWriter sw = new StringWriter();
 284         final PrintWriter pw = new PrintWriter(sw);
 285         final int rc = com.sun.tools.javac.Main.compile(args, pw);
 286         pw.close();
 287         if (rc == 0) {
 288             System.err.println("Compilation of " + file.getName() +
 289                                " didn't fail as expected.\nFile:\n" +
 290                                body + "\nOutput:\n" + sw.toString());
 291             errors++;
 292         }
 293     }
 294 
 295     private void assert_compile_succeed(final File file, final String body) {
 296         final String filename = file.getPath();
 297         final String[] args = { filename };
 298         final StringWriter sw = new StringWriter();
 299         final PrintWriter pw = new PrintWriter(sw);
 300         final int rc = com.sun.tools.javac.Main.compile(args, pw);
 301         pw.close();
 302         if (rc != 0) {
 303             System.err.println("Compilation of " + file.getName() +
 304                                " didn't succeed as expected.\nFile:\n" +
 305                                body + "\nOutput:\n" +
 306                                sw.toString());
 307             errors++;
 308         }
 309     }
 310 
 311     private String makeBody(final int num,
 312                             final CompareType left,
 313                             final CompareType right) {
 314         return "import java.util.List;\n" +
 315             "public class Test" + num + " {\n" +
 316             "    public boolean test(" + left.name +
 317             " left, " + right.name + " right) {\n" +
 318             "        return left" + (left.isList ? ".get(0)" : "") +
 319             " == right" + (right.isList ? ".get(0)" : "") + ";\n" +
 320             "    }\n" +
 321             "}\n";
 322     }
 323 
 324     private File writeFile(final String filename,
 325                            final String body)
 326         throws IOException {
 327         final File f = new File(testdir, filename);
 328         f.getParentFile().mkdirs();
 329         final FileWriter out = new FileWriter(f);
 330         out.write(body);
 331         out.close();
 332         return f;
 333     }
 334 
 335     private void test(final CompareType left, final CompareType right)
 336         throws IOException {
 337         final int num = testnum++;
 338         final String filename = "Test" + num + ".java";
 339         final String body = makeBody(num, left, right);
 340         final File file = writeFile(filename, body);
 341         if (truthtab[left.ordinal()][right.ordinal()] != 0)
 342             assert_compile_succeed(file, body);
 343         else
 344             assert_compile_fail(file, body);
 345     }
 346 
 347     void run() throws Exception {
 348         testdir.mkdir();
 349 
 350         for(CompareType left : CompareType.values())
 351             for(CompareType right : CompareType.values())
 352                 test(left, right);
 353 
 354         if (errors != 0)
 355             throw new Exception("ObjectZeroCompare test failed with " +
 356                                 errors + " errors.");
 357     }
 358 
 359     public static void main(String... args) throws Exception {
 360         new TestComparisons().run();
 361     }
 362 }