| /******************************************************************************* |
| * Copyright (c) 2005, 2016 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.core.tests.compiler.regression; |
| |
| import java.util.Map; |
| |
| import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; |
| |
| import junit.framework.Test; |
| |
| @SuppressWarnings({ "rawtypes" }) |
| public class ConditionalExpressionTest extends AbstractRegressionTest { |
| |
| public ConditionalExpressionTest(String name) { |
| super(name); |
| } |
| |
| // Static initializer to specify tests subset using TESTS_* static variables |
| // All specified tests which does not belong to the class are skipped... |
| static { |
| // TESTS_NAMES = new String[] { "test003" }; |
| // TESTS_NUMBERS = new int[] { 65 }; |
| // TESTS_RANGE = new int[] { 11, -1 }; |
| } |
| public static Test suite() { |
| return buildAllCompliancesTestSuite(testClass()); |
| } |
| |
| public static Class testClass() { |
| return ConditionalExpressionTest.class; |
| } |
| |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=100162 |
| public void test001() { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " final boolean isA = true;\n" + |
| " public static void main(String[] args) {\n" + |
| " X x = new X();\n" + |
| " System.out.print(x.isA ? \"SUCCESS\" : \"FAILURE\");\n" + |
| " }\n" + |
| "}", |
| }, |
| "SUCCESS" |
| ); |
| } |
| |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=107193 |
| public void test002() { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "class RecipeElement {\n" + |
| " public static final RecipeElement[] NO_CHILDREN= new RecipeElement[0]; \n" + |
| "}\n" + |
| "class Ingredient extends RecipeElement { }\n" + |
| "class X extends RecipeElement {\n" + |
| " private Ingredient[] fIngredients;\n" + |
| " public RecipeElement[] getChildren() {\n" + |
| " return fIngredients == null ? NO_CHILDREN : fIngredients;\n" + |
| " }\n" + |
| "}", |
| }, |
| "" |
| ); |
| } |
| |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=426078, Bug 426078 - [1.8] VerifyError when conditional expression passed as an argument |
| public void test003() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_5) |
| return; |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " boolean isOdd(boolean what) {\n" + |
| " return square(what ? new Integer(1) : new Integer(2)) % 2 == 1; // trouble here\n" + |
| " }\n" + |
| " <T> int square(int i) {\n" + |
| " return i * i;\n" + |
| " }\n" + |
| " public static void main(String argv[]) {\n" + |
| " System.out.println(new X().isOdd(true));\n" + |
| " }\n" + |
| "}\n", |
| }, |
| "true" |
| ); |
| } |
| |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=423685, - [1.8] poly conditional expression must not use lub |
| public void test004() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_5) |
| return; |
| if (this.complianceLevel < ClassFileConstants.JDK1_8) { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "class A{/**/}\n" + |
| "class B extends A {/**/}\n" + |
| "class G<T> {\n" + |
| " G<B> gb=null;\n" + |
| " G<? super A> gsa=null;\n" + |
| " G<? super B> l = (true)? gsa : gb;\n" + |
| "}\n" + |
| "public class X {\n" + |
| " public static void main(String[] args) {\n" + |
| " System.out.println(\"OK\");\n" + |
| " }\n" + |
| "}\n", |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 6)\n" + |
| " G<? super B> l = (true)? gsa : gb;\n" + |
| " ^^^^^^^^^^^^^^^^\n" + |
| "Type mismatch: cannot convert from G<capture#2-of ? extends Object> to G<? super B>\n" + |
| "----------\n" |
| ); |
| } else { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "class A{/**/}\n" + |
| "class B extends A {/**/}\n" + |
| "class G<T> {\n" + |
| " G<B> gb=null;\n" + |
| " G<? super A> gsa=null;\n" + |
| " G<? super B> l = (true)? gsa : gb;\n" + |
| "}\n" + |
| "public class X {\n" + |
| " public static void main(String[] args) {\n" + |
| " System.out.println(\"OK\");\n" + |
| " }\n" + |
| "}\n", |
| }, |
| "OK" |
| ); |
| } |
| } |
| |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=425181, - Cast expression in ternary operation reported as incompatible |
| public void test005() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_5) |
| return; |
| if (this.complianceLevel < ClassFileConstants.JDK1_8) { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void main(String args[]) {\n" + |
| " I<? super J> i = true ? (I<I>) null : (I<J>) null; // Type mismatch reported\n" + |
| " System.out.println(\"OK\");\n" + |
| " }\n" + |
| "}\n" + |
| "interface I<T> {}\n" + |
| "interface J<T> extends I<T> {}\n", |
| }, |
| "----------\n" + |
| "1. WARNING in X.java (at line 3)\n" + |
| " I<? super J> i = true ? (I<I>) null : (I<J>) null; // Type mismatch reported\n" + |
| " ^\n" + |
| "J is a raw type. References to generic type J<T> should be parameterized\n" + |
| "----------\n" + |
| "2. ERROR in X.java (at line 3)\n" + |
| " I<? super J> i = true ? (I<I>) null : (I<J>) null; // Type mismatch reported\n" + |
| " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + |
| "Type mismatch: cannot convert from I<capture#1-of ? extends I> to I<? super J>\n" + |
| "----------\n" + |
| "3. WARNING in X.java (at line 3)\n" + |
| " I<? super J> i = true ? (I<I>) null : (I<J>) null; // Type mismatch reported\n" + |
| " ^\n" + |
| "I is a raw type. References to generic type I<T> should be parameterized\n" + |
| "----------\n" + |
| "4. WARNING in X.java (at line 3)\n" + |
| " I<? super J> i = true ? (I<I>) null : (I<J>) null; // Type mismatch reported\n" + |
| " ^\n" + |
| "J is a raw type. References to generic type J<T> should be parameterized\n" + |
| "----------\n" |
| ); |
| } else { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public static void main(String args[]) {\n" + |
| " I<? super J> i = true ? (I<I>) null : (I<J>) null; // Type mismatch reported\n" + |
| " System.out.println(\"OK\");\n" + |
| " }\n" + |
| "}\n" + |
| "interface I<T> {}\n" + |
| "interface J<T> extends I<T> {}\n", |
| }, |
| "OK" |
| ); |
| } |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=426315, - [1.8][compiler] UnsupportedOperationException with conditional expression |
| public void test006() { |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " static int foo(Object x) {\n" + |
| " return 0;\n" + |
| " }\n" + |
| " static int foo(int e) { \n" + |
| " return 1; \n" + |
| " }\n" + |
| " public static void main(String args[]) {\n" + |
| " Object x = new Object();\n" + |
| " System.out.println(foo(true ? x : new int[0]) != 0);\n" + |
| " }\n" + |
| "}\n", |
| }, |
| "false" |
| ); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=426680, - [1.8][compiler] Incorrect handling of poly conditional leads to CCE |
| public void test007() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_8) |
| return; |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "interface BinaryOperation<T> {\n" + |
| " T operate(T x, T y);\n" + |
| "}\n" + |
| "class StringCatenation implements BinaryOperation<String> { \n" + |
| " public String operate(String x, String y) { return x + y; }\n" + |
| "}\n" + |
| "public class X {\n" + |
| " public static void main(String argv[]) {\n" + |
| " foo(false ? (a,b)->a+b :new StringCatenation());\n" + |
| " }\n" + |
| " static void foo(BinaryOperation<Integer> x) {\n" + |
| " x.operate(5, 15);\n" + |
| " }\n" + |
| "}\n", |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 9)\n" + |
| " foo(false ? (a,b)->a+b :new StringCatenation());\n" + |
| " ^^^\n" + |
| "The method foo(BinaryOperation<Integer>) in the type X is not applicable for the arguments ((false ? (<no type> a, <no type> b) -> (a + b) : new StringCatenation()))\n" + |
| "----------\n" + |
| "2. ERROR in X.java (at line 9)\n" + |
| " foo(false ? (a,b)->a+b :new StringCatenation());\n" + |
| " ^^^^^^^^^^^^^^^^^^^^^^\n" + |
| "Type mismatch: cannot convert from StringCatenation to BinaryOperation<Integer>\n" + |
| "----------\n" |
| ); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=426680, - [1.8][compiler] Incorrect handling of poly conditional leads to CCE |
| public void test008() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_8) |
| return; |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "interface BinaryOperation<T> {\n" + |
| " T operate(T x, T y);\n" + |
| "}\n" + |
| "class StringCatenation implements BinaryOperation<String> { \n" + |
| " public String operate(String x, String y) { return x + y; }\n" + |
| "}\n" + |
| "public class X {\n" + |
| " public static void main(String argv[]) {\n" + |
| " foo(false ? new StringCatenation() : (a,b)->a+b);\n" + |
| " }\n" + |
| " static void foo(BinaryOperation<Integer> x) {\n" + |
| " x.operate(5, 15);\n" + |
| " }\n" + |
| "}\n", |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 9)\n" + |
| " foo(false ? new StringCatenation() : (a,b)->a+b);\n" + |
| " ^^^\n" + |
| "The method foo(BinaryOperation<Integer>) in the type X is not applicable for the arguments ((false ? new StringCatenation() : (<no type> a, <no type> b) -> (a + b)))\n" + |
| "----------\n" + |
| "2. ERROR in X.java (at line 9)\n" + |
| " foo(false ? new StringCatenation() : (a,b)->a+b);\n" + |
| " ^^^^^^^^^^^^^^^^^^^^^^\n" + |
| "Type mismatch: cannot convert from StringCatenation to BinaryOperation<Integer>\n" + |
| "----------\n" |
| ); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=427207, - [1.8][bytecode] Runtime type problem: Instruction type does not match stack map |
| // Reference poly conditional in assignment context |
| public void test009() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_8) |
| return; |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "import java.util.function.Function;\n" + |
| "public class X {\n" + |
| " public static void main(String[] args) {\n" + |
| " System.out.println(test(1, X::intToSome));\n" + |
| " }\n" + |
| " static <T> Some test(T value, Function<T, Some> f) {\n" + |
| " return (value == null) ? new Nothing() : f.apply(value);\n" + |
| " }\n" + |
| " static SomeInt intToSome(int i) {\n" + |
| " return new SomeInt();\n" + |
| " }\n" + |
| " static abstract class Some {}\n" + |
| " static class SomeInt extends Some {\n" + |
| " public String toString() {\n" + |
| " return \"SomeInt instance\";\n" + |
| " }\n" + |
| " }\n" + |
| " static class Nothing extends Some {}\n" + |
| "}\n", |
| }, |
| "SomeInt instance"); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=427207, - [1.8][bytecode] Runtime type problem: Instruction type does not match stack map |
| // Reference poly conditional in poly invocation context |
| public void test010() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_8) |
| return; |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "import java.util.function.Function;\n" + |
| "public class X {\n" + |
| " public static void main(String[] args) {\n" + |
| " System.out.println(test(1, X::intToSome));\n" + |
| " }\n" + |
| " static <T> Some test(T value, Function<T, Some> f) {\n" + |
| " return id((value == null) ? new Nothing<>() : f.apply(value));\n" + |
| " }\n" + |
| " static <T> T id(T t) {\n" + |
| " return t;\n" + |
| " }\n" + |
| " static SomeInt intToSome(int i) {\n" + |
| " return new SomeInt();\n" + |
| " }\n" + |
| " static abstract class Some {}\n" + |
| " static class SomeInt extends Some {\n" + |
| " public String toString() {\n" + |
| " return \"SomeInt instance\";\n" + |
| " }\n" + |
| " }\n" + |
| " static class Nothing<T> extends Some {}\n" + |
| "}\n", |
| }, |
| "SomeInt instance"); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=427207, - [1.8][bytecode] Runtime type problem: Instruction type does not match stack map |
| // Reference poly conditional in assignment context, order reversed. |
| public void test011() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_8) |
| return; |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "import java.util.function.Function;\n" + |
| "public class X {\n" + |
| " public static void main(String[] args) {\n" + |
| " System.out.println(test(1, X::intToSome));\n" + |
| " }\n" + |
| " static <T> Some test(T value, Function<T, Some> f) {\n" + |
| " return (value == null) ? f.apply(value) : new Nothing();\n" + |
| " }\n" + |
| " static SomeInt intToSome(int i) {\n" + |
| " return new SomeInt();\n" + |
| " }\n" + |
| " static abstract class Some {}\n" + |
| " static class SomeInt extends Some {\n" + |
| " public String toString() {\n" + |
| " return \"SomeInt instance\";\n" + |
| " }\n" + |
| " }\n" + |
| " static class Nothing<T> extends Some {\n" + |
| " public String toString() {\n" + |
| " return \"Nothing instance\";\n" + |
| " }\n" + |
| " }\n" + |
| "}\n", |
| }, |
| "Nothing instance"); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=427207, - [1.8][bytecode] Runtime type problem: Instruction type does not match stack map |
| // Reference poly conditional in poly invocation context, order reversed. |
| public void test012() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_8) |
| return; |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "import java.util.function.Function;\n" + |
| "public class X {\n" + |
| " public static void main(String[] args) {\n" + |
| " System.out.println(test(1, X::intToSome));\n" + |
| " }\n" + |
| " static <T> Some test(T value, Function<T, Some> f) {\n" + |
| " return id((value == null) ? f.apply(value) : new Nothing<>());\n" + |
| " }\n" + |
| " static <T> T id(T t) {\n" + |
| " return t;\n" + |
| " }\n" + |
| " static SomeInt intToSome(int i) {\n" + |
| " return new SomeInt();\n" + |
| " }\n" + |
| " static abstract class Some {}\n" + |
| " static class SomeInt extends Some {\n" + |
| " public String toString() {\n" + |
| " return \"SomeInt instance\";\n" + |
| " }\n" + |
| " }\n" + |
| " static class Nothing<T> extends Some {\n" + |
| " public String toString() {\n" + |
| " return \"Nothing instance\";\n" + |
| " }\n" + |
| " }\n" + |
| "}\n", |
| }, |
| "Nothing instance"); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=427207, - [1.8][bytecode] Runtime type problem: Instruction type does not match stack map |
| // Reference poly conditional in poly invocation context, interface types |
| public void test013() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_8) |
| return; |
| this.runConformTest( |
| new String[] { |
| "X.java", |
| "import java.util.function.Function;\n" + |
| "public class X {\n" + |
| " public static void main(String[] args) {\n" + |
| " System.out.println(test(1, X::intToSome));\n" + |
| " }\n" + |
| " static <T> Some test(T value, Function<T, Some> f) {\n" + |
| " return id((value == null) ? new Nothing<>() : f.apply(value));\n" + |
| " }\n" + |
| " static <T> T id(T t) {\n" + |
| " return t;\n" + |
| " }\n" + |
| " static SomeInt intToSome(int i) {\n" + |
| " return new SomeInt();\n" + |
| " }\n" + |
| " static interface Some {}\n" + |
| " static class SomeInt implements Some {\n" + |
| " public String toString() {\n" + |
| " return \"SomeInt instance\";\n" + |
| " }\n" + |
| " }\n" + |
| " static class Nothing<T> implements Some {}\n" + |
| "}", |
| }, |
| "SomeInt instance"); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=427438, - NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode |
| public void test014() { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public X(Class clazz) {\n" + |
| " }\n" + |
| " public void error() {\n" + |
| " boolean test = false;\n" + |
| " int i = 1;\n" + |
| " new X(test ? (i == 2 ? D.class : E.class) : null);\n" + |
| " }\n" + |
| " public class D {\n" + |
| " }\n" + |
| " public class E {\n" + |
| " }\n" + |
| "}\n", |
| }, |
| this.complianceLevel < ClassFileConstants.JDK1_5 ? "" : |
| "----------\n" + |
| "1. WARNING in X.java (at line 2)\n" + |
| " public X(Class clazz) {\n" + |
| " ^^^^^\n" + |
| "Class is a raw type. References to generic type Class<T> should be parameterized\n" + |
| "----------\n"); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=427438, - NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode |
| public void test015() { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X {\n" + |
| " public X(Class clazz) {\n" + |
| " }\n" + |
| " public void error() {\n" + |
| " boolean test = false;\n" + |
| " int i = 1;\n" + |
| " new X(test ? null : (i == 2 ? D.class : E.class));\n" + |
| " }\n" + |
| " public class D {\n" + |
| " }\n" + |
| " public class E {\n" + |
| " }\n" + |
| "}\n", |
| }, |
| this.complianceLevel < ClassFileConstants.JDK1_5 ? "" : |
| "----------\n" + |
| "1. WARNING in X.java (at line 2)\n" + |
| " public X(Class clazz) {\n" + |
| " ^^^^^\n" + |
| "Class is a raw type. References to generic type Class<T> should be parameterized\n" + |
| "----------\n"); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=427625, - NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode |
| public void test427625() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_5) |
| return; |
| Map<String,String> options = getCompilerOptions(); |
| options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.IGNORE); |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "import java.util.Collection;\n" + |
| "import java.util.List;\n" + |
| "public class X {\n" + |
| " public void error(Collection<Object> c) {\n" + |
| " boolean b =true;\n" + |
| " c.add(b ? new Integer(1)\n" + |
| " : c==null ? null \n" + |
| " : c instanceof List ? Integer.valueOf(1) \n" + |
| " : o()); \n" + |
| " }\n" + |
| " public Object o() {\n" + |
| " return null;\n" + |
| " }\n" + |
| "}\n", |
| }, |
| "", |
| null, true, options); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=432487, NullPointerException during compilation using jdk1.8.0 |
| public void testBug432487() { |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "class Y {\n" + |
| " String f() {\n" + |
| " return \"\";\n" + |
| " }\n" + |
| "}\n" + |
| "public class X {\n" + |
| "void f(String x) {}\n" + |
| " void bar(Y y) {\n" + |
| " f(y.f2() == 1 ? null : y.f());\n" + |
| " }\n" + |
| "}", |
| }, |
| "----------\n" + |
| "1. ERROR in X.java (at line 9)\n" + |
| " f(y.f2() == 1 ? null : y.f());\n" + |
| " ^^\n" + |
| "The method f2() is undefined for the type Y\n" + |
| "----------\n"); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=437444#c113, - Error building JRE8 |
| public void test437444_c113() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_8) |
| return; |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X extends Y {\n" + |
| " public X(Z[] n) {\n" + |
| " super((n == null) ? null : n.clone());\n" + |
| " }\n" + |
| "}\n" + |
| "class Y {\n" + |
| " public Y(Z[] notifications) {\n" + |
| " }\n" + |
| "}\n" + |
| "interface Z {}\n", |
| }, |
| ""); |
| } |
| public void test437444_2() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_8) |
| return; |
| this.runNegativeTest( |
| new String[] { |
| "X.java", |
| "public class X extends Y {\n" + |
| " public X(int[] n) {\n" + |
| " super((n == null) ? null : n.clone());\n" + |
| " }\n" + |
| "}\n" + |
| "class Y {\n" + |
| " public Y(int[] notifications) {\n" + |
| " }\n" + |
| "}\n" + |
| "interface Z {}\n", |
| }, |
| ""); |
| } |
| // https://bugs.eclipse.org/bugs/show_bug.cgi?id=484425: [bytecode] Bad type on operand stack - compiler omitted instructions for unboxing null Boolean |
| public void test484425() { |
| if (this.complianceLevel < ClassFileConstants.JDK1_5) |
| return; |
| this.runConformTest( |
| new String[] { |
| "Main.java", |
| "public class Main {\n" + |
| " public static void main(String[] args) {\n" + |
| " try {\n" + |
| " if ((false) ? true: null);\n" + |
| " } catch(NullPointerException npe) {\n" + |
| " System.out.println(\"Success\");\n" + |
| " }\n" + |
| " }\n" + |
| "}\n" |
| }, |
| "Success"); |
| } |
| } |