Skip to content

Commit 72171c3

Browse files
committed
Make all existing tests run on JDK 21
This mostly affects pattern matching for switch and record patterns. Two tests which were working before for pattern matching for switch (preview 4), started to fail, so the corresponding code was commented out and eclipse-jdt/eclipse.jdt.core#1466 recorded. Signed-off-by: Alexander Kriegisch <[email protected]>
1 parent 99f426e commit 72171c3

File tree

6 files changed

+393
-488
lines changed

6 files changed

+393
-488
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import java.util.List;
2+
import java.util.Locale;
3+
4+
aspect SwitchPatternPreview3Aspect {
5+
Object around(Object o) : execution(* doSomethingWithObject(*)) && args(o) {
6+
System.out.println(switch (o) {
7+
case null -> "null";
8+
case Integer i -> String.format("int %d", i);
9+
case Long l -> String.format("long %d", l);
10+
case Double d -> String.format(Locale.ENGLISH, "double %f", d);
11+
case String s -> String.format("String %s", s);
12+
default -> o.toString();
13+
});
14+
return proceed(o);
15+
}
16+
17+
before(Shape s) : execution(* doSomethingWithShape(*)) && args(s) {
18+
System.out.println(switch (s) {
19+
case Circle c when (c.calculateArea() > 100) -> "Large circle";
20+
case Circle c -> "Small circle";
21+
default -> "Non-circle";
22+
});
23+
}
24+
25+
after(S s) : execution(* doSomethingWithSealedClass(*)) && args(s) {
26+
System.out.println(switch (s) {
27+
case A a -> "Sealed sub-class A";
28+
case B b -> "Sealed sub-class B";
29+
case C c -> "Sealed sub-record C";
30+
});
31+
}
32+
33+
Object around(Integer i): execution(* doSomethingWithInteger(*)) && args(i) {
34+
// This used to work in preview 4 (Java 20), but fails during runtime with
35+
// java.lang.IndexOutOfBoundsException: Index 4 out of bounds for length 4
36+
// in ECJ 3.36.0-SNAPSHOT with Java 21.
37+
// See:
38+
// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1466.
39+
//
40+
// TODO: Activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1466 is fixed.
41+
/*
42+
System.out.println(
43+
switch (i) {
44+
case null -> "value unavailable: " + i;
45+
case -1, 1 -> "absolute value 1: " + i;
46+
case Integer value when value > 0 -> "positive integer: " + i;
47+
default -> "other integer: " + i;
48+
}
49+
);
50+
*/
51+
return proceed(i);
52+
}
53+
}
54+
55+
class Shape {}
56+
class Rectangle extends Shape {}
57+
class Circle extends Shape {
58+
private final double radius;
59+
public Circle(double radius) { this.radius = radius; }
60+
double calculateArea() { return Math.PI * radius * radius; }
61+
}
62+
63+
sealed interface S permits A, B, C {}
64+
final class A implements S {}
65+
final class B implements S {}
66+
record C(int i) implements S {} // Implicitly final
67+
68+
class Application {
69+
public static void main(String[] args) {
70+
doSomethingWithObject(null);
71+
doSomethingWithObject(123);
72+
doSomethingWithObject(999L);
73+
doSomethingWithObject(12.34);
74+
doSomethingWithObject("foo");
75+
doSomethingWithObject(List.of(123, "foo", 999L, 12.34));
76+
77+
doSomethingWithShape(new Rectangle());
78+
doSomethingWithShape(new Circle(5));
79+
doSomethingWithShape(new Circle(6));
80+
81+
doSomethingWithSealedClass(new A());
82+
doSomethingWithSealedClass(new B());
83+
doSomethingWithSealedClass(new C(5));
84+
85+
doSomethingWithInteger(-1);
86+
doSomethingWithInteger(0);
87+
doSomethingWithInteger(42);
88+
doSomethingWithInteger(-99);
89+
doSomethingWithInteger(Integer.valueOf(123));
90+
doSomethingWithInteger(null);
91+
}
92+
93+
public static Object doSomethingWithObject(Object o) { return o; }
94+
public static void doSomethingWithSealedClass(S s) {}
95+
public static void doSomethingWithShape(Shape s) {}
96+
public static Object doSomethingWithInteger(Integer o) { return o; }
97+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import java.util.List;
2+
import java.util.Locale;
3+
4+
/**
5+
* Inspired by examples in https://openjdk.org/jeps/427
6+
*/
7+
public class SwitchPatternPreview4OK {
8+
public static void main(String[] args) {
9+
10+
System.out.println(formatterPatternSwitch(null));
11+
System.out.println(formatterPatternSwitch(123));
12+
System.out.println(formatterPatternSwitch(999L));
13+
System.out.println(formatterPatternSwitch(12.34));
14+
System.out.println(formatterPatternSwitch("foo"));
15+
System.out.println(formatterPatternSwitch(List.of(123, "foo", 999L, 12.34)));
16+
17+
System.out.println(testCircle(new Rectangle()));
18+
System.out.println(testCircle(new Circle(5)));
19+
System.out.println(testCircle(new Circle(6)));
20+
21+
System.out.println(testSealedCoverage(new A()));
22+
System.out.println(testSealedCoverage(new B()));
23+
System.out.println(testSealedCoverage(new C(5)));
24+
25+
// constantLabelMustAppearBeforePattern(-1);
26+
// constantLabelMustAppearBeforePattern(0);
27+
// constantLabelMustAppearBeforePattern(42);
28+
// constantLabelMustAppearBeforePattern(-99);
29+
// constantLabelMustAppearBeforePattern(Integer.valueOf(123));
30+
// constantLabelMustAppearBeforePattern(null);
31+
32+
// TODO: Activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1466 is fixed.
33+
/*
34+
constantLabelMustAppearBeforePatternInteger(-1);
35+
constantLabelMustAppearBeforePatternInteger(0);
36+
constantLabelMustAppearBeforePatternInteger(42);
37+
constantLabelMustAppearBeforePatternInteger(-99);
38+
constantLabelMustAppearBeforePatternInteger(Integer.valueOf(123));
39+
constantLabelMustAppearBeforePatternInteger(null);
40+
*/
41+
42+
System.out.println(testGenericSealedExhaustive(new E<Integer>()));
43+
}
44+
45+
static String formatterPatternSwitch(Object o) {
46+
return switch (o) {
47+
case null -> "null";
48+
case Integer i -> String.format("int %d", i);
49+
case Long l -> String.format("long %d", l);
50+
case Double d -> String.format(Locale.ENGLISH, "double %f", d);
51+
case String s -> String.format("String %s", s);
52+
default -> o.toString();
53+
};
54+
}
55+
56+
static class Shape {}
57+
static class Rectangle extends Shape {}
58+
static class Circle extends Shape {
59+
private final double radius;
60+
public Circle(double radius) { this.radius = radius; }
61+
double calculateArea() { return Math.PI * radius * radius; }
62+
}
63+
64+
static String testCircle(Shape s) {
65+
return switch (s) {
66+
case Circle c when (c.calculateArea() > 100) -> "Large circle";
67+
case Circle c -> "Small circle";
68+
default -> "Non-circle";
69+
};
70+
}
71+
72+
sealed interface S permits A, B, C {}
73+
final static class A implements S {}
74+
final static class B implements S {}
75+
static record C(int i) implements S {} // Implicitly final
76+
77+
static String testSealedCoverage(S s) {
78+
return switch (s) {
79+
case A a -> "Sealed sub-class A";
80+
case B b -> "Sealed sub-class B";
81+
case C c -> "Sealed sub-record C";
82+
};
83+
}
84+
85+
/**
86+
* According to an example from JEP 420, this should work, but it does not, neither with Javac nor ECJ.
87+
*
88+
* See:
89+
* https://openjdk.java.net/jeps/420#1b--Dominance-of-pattern-labels
90+
* https://bugs.openjdk.java.net/browse/JDK-8273326
91+
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=579355
92+
*
93+
* TODO: reactivate when implemented or move to preview 5 with Java 21, Eclipse 4.28.
94+
*/
95+
/*
96+
static String constantLabelMustAppearBeforePattern(Object o) {
97+
switch (o) {
98+
case null -> System.out.println("value unavailable: " + o);
99+
case -1, 1 -> System.out.println("special case:" + o);
100+
case Integer value when value > 0 -> System.out.println("positive integer: " + o);
101+
case Integer i -> System.out.println("other integer: " + o);
102+
default -> System.out.println("non-integer: " + o);
103+
}
104+
return o == null ? "null" : o.toString();
105+
}
106+
*/
107+
108+
/**
109+
* This used to work in preview 4 (Java 20), but fails during runtime with
110+
* java.lang.IndexOutOfBoundsException: Index 4 out of bounds for length 4
111+
* in ECJ 3.36.0-SNAPSHOT with Java 21.
112+
* See:
113+
* https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1466.
114+
*
115+
* TODO: Activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1466 is fixed.
116+
*/
117+
static String constantLabelMustAppearBeforePatternInteger(Integer i) {
118+
switch (i) {
119+
case null -> System.out.println("value unavailable: " + i);
120+
case -1, 1 -> System.out.println("absolute value 1: " + i);
121+
case Integer value when value > 0 -> System.out.println("positive integer: " + i);
122+
default -> System.out.println("other integer: " + i);
123+
}
124+
return i == null ? "null" : i.toString();
125+
}
126+
127+
static void nullCanAppearAfterConstantLabel(Integer i) {
128+
switch (i) {
129+
case -1, 1 -> System.out.println("absolute value 1: " + i);
130+
case null -> System.out.println("value unavailable: " + i);
131+
case Integer value when value > 0 -> System.out.println("positive integer: " + i);
132+
default -> System.out.println("other integer: " + i);
133+
}
134+
}
135+
136+
/**
137+
* According to an example from JEP 420, this should work with preview 2 (Java 18), and it does with Javac,
138+
* but not with ECJ for Java 18, 19 and 20.
139+
*
140+
* See:
141+
* https://openjdk.java.net/jeps/420#2--Exhaustiveness-of-switch-expressions-and-statements
142+
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=579360
143+
* https://github.com/eclipse-jdt/eclipse.jdt.core/issues/587
144+
*
145+
* TODO: reactivate when implemented or move to preview 5 with Java 21.
146+
*/
147+
sealed interface I<T> permits D, E {}
148+
final static class D<X> implements I<String> {}
149+
final static class E<Y> implements I<Y> {}
150+
151+
static int testGenericSealedExhaustive(I<Integer> i) {
152+
return switch (i) {
153+
// Exhaustive as no D case possible!
154+
case E<Integer> bi -> 42;
155+
};
156+
}
157+
}

tests/src/test/java/org/aspectj/systemtest/ajc1921/Ajc1921TestsJava.java

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package org.aspectj.systemtest.ajc1921;
99

1010
import junit.framework.Test;
11+
import org.aspectj.apache.bcel.Constants;
1112
import org.aspectj.testing.XMLBasedAjcTestCase;
1213
import org.aspectj.testing.XMLBasedAjcTestCaseForJava21OrLater;
1314

@@ -16,8 +17,78 @@
1617
*/
1718
public class Ajc1921TestsJava extends XMLBasedAjcTestCaseForJava21OrLater {
1819

19-
public void testDummyJava21() {
20-
//runTest("dummy Java 21");
20+
public void testSwitchPatternMatchingPreview4Java() {
21+
runTest("switch pattern matching preview 4 java");
22+
checkVersion("SwitchPatternPreview4OK", Constants.MAJOR_21, Constants.MINOR_21);
23+
}
24+
25+
public void testSwitchPatternMatchingPreview4Error() {
26+
runTest("switch pattern matching preview 4 error");
27+
}
28+
29+
public void testSwitchPatternMatchingPreview3Aspect() {
30+
runTest("switch pattern matching preview 3 aspect");
31+
checkVersion("SwitchPatternPreview3Aspect", Constants.MAJOR_21, Constants.MINOR_21);
32+
checkVersion("Application", Constants.MAJOR_21, Constants.MINOR_21);
33+
checkVersion("Shape", Constants.MAJOR_21, Constants.MINOR_21);
34+
checkVersion("S", Constants.MAJOR_21, Constants.MINOR_21);
35+
}
36+
37+
public void testSwitchPatternMatchingCaseLabelDominatedByPrecedingError() {
38+
runTest("switch pattern matching error");
39+
}
40+
41+
public void testSwitchPatternMatchingPreview3Error1() {
42+
runTest("switch pattern matching preview 3 error 1");
43+
}
44+
45+
public void testSwitchPatternMatchingPreview3Error2() {
46+
runTest("switch pattern matching preview 3 error 2");
47+
}
48+
49+
public void testRecordPatternsPreview1OK() {
50+
// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/450
51+
runTest("record patterns");
52+
}
53+
54+
public void testRecordPatternsPreview1Error() {
55+
// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/450 (fixed for preview 2 in Eclipse 2023-03, 4.27)
56+
runTest("record patterns error");
57+
checkVersion("RecordPatternsPreview1Error", Constants.MAJOR_21, Constants.MINOR_21);
58+
checkVersion("Box", Constants.MAJOR_21, Constants.MINOR_21);
59+
}
60+
61+
public void testRecordPatternsPreview1ExhaustivenessOK1() {
62+
// Falsely throws 'An enhanced switch statement should be exhaustive; a default label expected' twice,
63+
// see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455
64+
// TODO: Remove redundant default clauses when fixed upstream
65+
System.out.println("TODO: fully activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 has been fixed");
66+
runTest("record patterns exhaustiveness 1");
67+
}
68+
69+
public void testRecordPatternsPreview1Aspect() {
70+
runTest("record patterns aspect");
71+
}
72+
73+
public void testRecordPatternsPreview1ExhaustivenessAspect() {
74+
// Falsely throws 'An enhanced switch statement should be exhaustive; a default label expected' twice,
75+
// see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455
76+
// TODO: Remove redundant default clauses when fixed upstream
77+
System.out.println("TODO: fully activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 has been fixed");
78+
runTest("record patterns exhaustiveness aspect");
79+
}
80+
81+
public void testRecordPatternsPreview1ExhaustivenessError() {
82+
// See https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455
83+
runTest("record patterns exhaustiveness error");
84+
}
85+
86+
public void testRecordPatternsPreview1ExhaustivenessOK2() {
87+
// Falsely throws 'An enhanced switch statement should be exhaustive; a default label expected',
88+
// see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/398
89+
// TODO: activate when fixed
90+
System.out.println("TODO: activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/398 has been fixed");
91+
//runTest("record patterns exhaustiveness 2");
2192
}
2293

2394
public static Test suite() {

0 commit comments

Comments
 (0)