blob: c9594263c0bbfa4b634b38a246de06573817e55e [file] [log] [blame]
/*******************************************************************************
* 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");
}
}