From 72171c3724100618bf2c733316d23ff7578eeaa1 Mon Sep 17 00:00:00 2001 From: Alexander Kriegisch Date: Thu, 5 Oct 2023 11:29:04 +0700 Subject: [PATCH] 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 https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1466 recorded. Signed-off-by: Alexander Kriegisch --- .../java21/SwitchPatternPreview3Aspect.aj | 97 +++++ .../java21/SwitchPatternPreview4OK.java | 157 +++++++ .../systemtest/ajc1921/Ajc1921TestsJava.java | 75 +++- .../systemtest/ajc1921/Bugs1921Tests.java | 73 +--- .../ajc1921/Java21PreviewFeaturesTests.java | 75 +--- .../aspectj/systemtest/ajc1921/ajc1921.xml | 404 +++--------------- 6 files changed, 393 insertions(+), 488 deletions(-) create mode 100644 tests/features1921/java21/SwitchPatternPreview3Aspect.aj create mode 100644 tests/features1921/java21/SwitchPatternPreview4OK.java diff --git a/tests/features1921/java21/SwitchPatternPreview3Aspect.aj b/tests/features1921/java21/SwitchPatternPreview3Aspect.aj new file mode 100644 index 000000000..cab9a2bcd --- /dev/null +++ b/tests/features1921/java21/SwitchPatternPreview3Aspect.aj @@ -0,0 +1,97 @@ +import java.util.List; +import java.util.Locale; + +aspect SwitchPatternPreview3Aspect { + Object around(Object o) : execution(* doSomethingWithObject(*)) && args(o) { + System.out.println(switch (o) { + case null -> "null"; + case Integer i -> String.format("int %d", i); + case Long l -> String.format("long %d", l); + case Double d -> String.format(Locale.ENGLISH, "double %f", d); + case String s -> String.format("String %s", s); + default -> o.toString(); + }); + return proceed(o); + } + + before(Shape s) : execution(* doSomethingWithShape(*)) && args(s) { + System.out.println(switch (s) { + case Circle c when (c.calculateArea() > 100) -> "Large circle"; + case Circle c -> "Small circle"; + default -> "Non-circle"; + }); + } + + after(S s) : execution(* doSomethingWithSealedClass(*)) && args(s) { + System.out.println(switch (s) { + case A a -> "Sealed sub-class A"; + case B b -> "Sealed sub-class B"; + case C c -> "Sealed sub-record C"; + }); + } + + Object around(Integer i): execution(* doSomethingWithInteger(*)) && args(i) { + // This used to work in preview 4 (Java 20), but fails during runtime with + // java.lang.IndexOutOfBoundsException: Index 4 out of bounds for length 4 + // in ECJ 3.36.0-SNAPSHOT with Java 21. + // See: + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1466. + // + // TODO: Activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1466 is fixed. + /* + System.out.println( + switch (i) { + case null -> "value unavailable: " + i; + case -1, 1 -> "absolute value 1: " + i; + case Integer value when value > 0 -> "positive integer: " + i; + default -> "other integer: " + i; + } + ); + */ + return proceed(i); + } +} + +class Shape {} +class Rectangle extends Shape {} +class Circle extends Shape { + private final double radius; + public Circle(double radius) { this.radius = radius; } + double calculateArea() { return Math.PI * radius * radius; } +} + +sealed interface S permits A, B, C {} +final class A implements S {} +final class B implements S {} +record C(int i) implements S {} // Implicitly final + +class Application { + public static void main(String[] args) { + doSomethingWithObject(null); + doSomethingWithObject(123); + doSomethingWithObject(999L); + doSomethingWithObject(12.34); + doSomethingWithObject("foo"); + doSomethingWithObject(List.of(123, "foo", 999L, 12.34)); + + doSomethingWithShape(new Rectangle()); + doSomethingWithShape(new Circle(5)); + doSomethingWithShape(new Circle(6)); + + doSomethingWithSealedClass(new A()); + doSomethingWithSealedClass(new B()); + doSomethingWithSealedClass(new C(5)); + + doSomethingWithInteger(-1); + doSomethingWithInteger(0); + doSomethingWithInteger(42); + doSomethingWithInteger(-99); + doSomethingWithInteger(Integer.valueOf(123)); + doSomethingWithInteger(null); + } + + public static Object doSomethingWithObject(Object o) { return o; } + public static void doSomethingWithSealedClass(S s) {} + public static void doSomethingWithShape(Shape s) {} + public static Object doSomethingWithInteger(Integer o) { return o; } +} diff --git a/tests/features1921/java21/SwitchPatternPreview4OK.java b/tests/features1921/java21/SwitchPatternPreview4OK.java new file mode 100644 index 000000000..c9caf7eca --- /dev/null +++ b/tests/features1921/java21/SwitchPatternPreview4OK.java @@ -0,0 +1,157 @@ +import java.util.List; +import java.util.Locale; + +/** + * Inspired by examples in https://openjdk.org/jeps/427 + */ +public class SwitchPatternPreview4OK { + public static void main(String[] args) { + + System.out.println(formatterPatternSwitch(null)); + System.out.println(formatterPatternSwitch(123)); + System.out.println(formatterPatternSwitch(999L)); + System.out.println(formatterPatternSwitch(12.34)); + System.out.println(formatterPatternSwitch("foo")); + System.out.println(formatterPatternSwitch(List.of(123, "foo", 999L, 12.34))); + + System.out.println(testCircle(new Rectangle())); + System.out.println(testCircle(new Circle(5))); + System.out.println(testCircle(new Circle(6))); + + System.out.println(testSealedCoverage(new A())); + System.out.println(testSealedCoverage(new B())); + System.out.println(testSealedCoverage(new C(5))); + +// constantLabelMustAppearBeforePattern(-1); +// constantLabelMustAppearBeforePattern(0); +// constantLabelMustAppearBeforePattern(42); +// constantLabelMustAppearBeforePattern(-99); +// constantLabelMustAppearBeforePattern(Integer.valueOf(123)); +// constantLabelMustAppearBeforePattern(null); + + // TODO: Activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1466 is fixed. + /* + constantLabelMustAppearBeforePatternInteger(-1); + constantLabelMustAppearBeforePatternInteger(0); + constantLabelMustAppearBeforePatternInteger(42); + constantLabelMustAppearBeforePatternInteger(-99); + constantLabelMustAppearBeforePatternInteger(Integer.valueOf(123)); + constantLabelMustAppearBeforePatternInteger(null); + */ + + System.out.println(testGenericSealedExhaustive(new E())); + } + + static String formatterPatternSwitch(Object o) { + return switch (o) { + case null -> "null"; + case Integer i -> String.format("int %d", i); + case Long l -> String.format("long %d", l); + case Double d -> String.format(Locale.ENGLISH, "double %f", d); + case String s -> String.format("String %s", s); + default -> o.toString(); + }; + } + + static class Shape {} + static class Rectangle extends Shape {} + static class Circle extends Shape { + private final double radius; + public Circle(double radius) { this.radius = radius; } + double calculateArea() { return Math.PI * radius * radius; } + } + + static String testCircle(Shape s) { + return switch (s) { + case Circle c when (c.calculateArea() > 100) -> "Large circle"; + case Circle c -> "Small circle"; + default -> "Non-circle"; + }; + } + + sealed interface S permits A, B, C {} + final static class A implements S {} + final static class B implements S {} + static record C(int i) implements S {} // Implicitly final + + static String testSealedCoverage(S s) { + return switch (s) { + case A a -> "Sealed sub-class A"; + case B b -> "Sealed sub-class B"; + case C c -> "Sealed sub-record C"; + }; + } + + /** + * According to an example from JEP 420, this should work, but it does not, neither with Javac nor ECJ. + * + * See: + * https://openjdk.java.net/jeps/420#1b--Dominance-of-pattern-labels + * https://bugs.openjdk.java.net/browse/JDK-8273326 + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=579355 + * + * TODO: reactivate when implemented or move to preview 5 with Java 21, Eclipse 4.28. + */ +/* + static String constantLabelMustAppearBeforePattern(Object o) { + switch (o) { + case null -> System.out.println("value unavailable: " + o); + case -1, 1 -> System.out.println("special case:" + o); + case Integer value when value > 0 -> System.out.println("positive integer: " + o); + case Integer i -> System.out.println("other integer: " + o); + default -> System.out.println("non-integer: " + o); + } + return o == null ? "null" : o.toString(); + } +*/ + + /** + * This used to work in preview 4 (Java 20), but fails during runtime with + * java.lang.IndexOutOfBoundsException: Index 4 out of bounds for length 4 + * in ECJ 3.36.0-SNAPSHOT with Java 21. + * See: + * https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1466. + * + * TODO: Activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1466 is fixed. + */ + static String constantLabelMustAppearBeforePatternInteger(Integer i) { + switch (i) { + case null -> System.out.println("value unavailable: " + i); + case -1, 1 -> System.out.println("absolute value 1: " + i); + case Integer value when value > 0 -> System.out.println("positive integer: " + i); + default -> System.out.println("other integer: " + i); + } + return i == null ? "null" : i.toString(); + } + + static void nullCanAppearAfterConstantLabel(Integer i) { + switch (i) { + case -1, 1 -> System.out.println("absolute value 1: " + i); + case null -> System.out.println("value unavailable: " + i); + case Integer value when value > 0 -> System.out.println("positive integer: " + i); + default -> System.out.println("other integer: " + i); + } + } + + /** + * According to an example from JEP 420, this should work with preview 2 (Java 18), and it does with Javac, + * but not with ECJ for Java 18, 19 and 20. + * + * See: + * https://openjdk.java.net/jeps/420#2--Exhaustiveness-of-switch-expressions-and-statements + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=579360 + * https://github.com/eclipse-jdt/eclipse.jdt.core/issues/587 + * + * TODO: reactivate when implemented or move to preview 5 with Java 21. + */ + sealed interface I permits D, E {} + final static class D implements I {} + final static class E implements I {} + + static int testGenericSealedExhaustive(I i) { + return switch (i) { + // Exhaustive as no D case possible! + case E bi -> 42; + }; + } +} diff --git a/tests/src/test/java/org/aspectj/systemtest/ajc1921/Ajc1921TestsJava.java b/tests/src/test/java/org/aspectj/systemtest/ajc1921/Ajc1921TestsJava.java index e7d3b9596..20efe1723 100644 --- a/tests/src/test/java/org/aspectj/systemtest/ajc1921/Ajc1921TestsJava.java +++ b/tests/src/test/java/org/aspectj/systemtest/ajc1921/Ajc1921TestsJava.java @@ -8,6 +8,7 @@ package org.aspectj.systemtest.ajc1921; import junit.framework.Test; +import org.aspectj.apache.bcel.Constants; import org.aspectj.testing.XMLBasedAjcTestCase; import org.aspectj.testing.XMLBasedAjcTestCaseForJava21OrLater; @@ -16,8 +17,78 @@ import org.aspectj.testing.XMLBasedAjcTestCaseForJava21OrLater; */ public class Ajc1921TestsJava extends XMLBasedAjcTestCaseForJava21OrLater { - public void testDummyJava21() { - //runTest("dummy Java 21"); + public void testSwitchPatternMatchingPreview4Java() { + runTest("switch pattern matching preview 4 java"); + checkVersion("SwitchPatternPreview4OK", Constants.MAJOR_21, Constants.MINOR_21); + } + + public void testSwitchPatternMatchingPreview4Error() { + runTest("switch pattern matching preview 4 error"); + } + + public void testSwitchPatternMatchingPreview3Aspect() { + runTest("switch pattern matching preview 3 aspect"); + checkVersion("SwitchPatternPreview3Aspect", Constants.MAJOR_21, Constants.MINOR_21); + checkVersion("Application", Constants.MAJOR_21, Constants.MINOR_21); + checkVersion("Shape", Constants.MAJOR_21, Constants.MINOR_21); + checkVersion("S", Constants.MAJOR_21, Constants.MINOR_21); + } + + public void testSwitchPatternMatchingCaseLabelDominatedByPrecedingError() { + runTest("switch pattern matching error"); + } + + public void testSwitchPatternMatchingPreview3Error1() { + runTest("switch pattern matching preview 3 error 1"); + } + + public void testSwitchPatternMatchingPreview3Error2() { + runTest("switch pattern matching preview 3 error 2"); + } + + public void testRecordPatternsPreview1OK() { + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/450 + runTest("record patterns"); + } + + public void testRecordPatternsPreview1Error() { + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/450 (fixed for preview 2 in Eclipse 2023-03, 4.27) + runTest("record patterns error"); + checkVersion("RecordPatternsPreview1Error", Constants.MAJOR_21, Constants.MINOR_21); + checkVersion("Box", Constants.MAJOR_21, Constants.MINOR_21); + } + + public void testRecordPatternsPreview1ExhaustivenessOK1() { + // Falsely throws 'An enhanced switch statement should be exhaustive; a default label expected' twice, + // see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 + // TODO: Remove redundant default clauses when fixed upstream + System.out.println("TODO: fully activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 has been fixed"); + runTest("record patterns exhaustiveness 1"); + } + + public void testRecordPatternsPreview1Aspect() { + runTest("record patterns aspect"); + } + + public void testRecordPatternsPreview1ExhaustivenessAspect() { + // Falsely throws 'An enhanced switch statement should be exhaustive; a default label expected' twice, + // see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 + // TODO: Remove redundant default clauses when fixed upstream + System.out.println("TODO: fully activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 has been fixed"); + runTest("record patterns exhaustiveness aspect"); + } + + public void testRecordPatternsPreview1ExhaustivenessError() { + // See https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 + runTest("record patterns exhaustiveness error"); + } + + public void testRecordPatternsPreview1ExhaustivenessOK2() { + // Falsely throws 'An enhanced switch statement should be exhaustive; a default label expected', + // see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/398 + // TODO: activate when fixed + System.out.println("TODO: activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/398 has been fixed"); + //runTest("record patterns exhaustiveness 2"); } public static Test suite() { diff --git a/tests/src/test/java/org/aspectj/systemtest/ajc1921/Bugs1921Tests.java b/tests/src/test/java/org/aspectj/systemtest/ajc1921/Bugs1921Tests.java index 3c11149d3..113731a4f 100644 --- a/tests/src/test/java/org/aspectj/systemtest/ajc1921/Bugs1921Tests.java +++ b/tests/src/test/java/org/aspectj/systemtest/ajc1921/Bugs1921Tests.java @@ -15,77 +15,8 @@ import org.aspectj.testing.XMLBasedAjcTestCase; */ public class Bugs1921Tests extends XMLBasedAjcTestCase { - public void testSwitchWith_Integer_MAX_VALUE() { - runTest("switch with Integer.MAX_VALUE case"); - } - - public void testParenthesisedExpressionWithAjKeyword() { - runTest("parenthesised expression with AspectJ keyword"); - } - - public void testInterfaceInnerAspectImplicitlyStatic() { - runTest("inner aspect of interface is implicitly static"); - } - - public void testExactArrayTypeMatchCompiledTogether() { - runTest("exact array type matching, aspect compiled together with target class"); - } - - public void testExactArrayTypeMatchCompiledSeparately() { - runTest("exact array type matching, aspect compiled separately from target class"); - } - - public void testFuzzyArrayTypeMatchCompiledTogether() { - runTest("fuzzy array type matching, aspect compiled together with target class"); - } - - public void testFuzzyArrayTypeMatchCompiledSeparately() { - runTest("fuzzy array type matching, aspect compiled separately from target class"); - } - - public void test_GitHub_214() { - runTest("ArrayIndexOutOfBoundsException with Xlint unorderedAdviceAtShadow=warning"); - } - - /** - * Add correct annotations to multiple ITD methods with the same name and same number of arguments, i.e. copy the - * annotations correctly from the aspect into the target class instead of falsely always copying the annotations (if - * any) from the first ITD method found. - *

- * See GitHub issue 246. - */ - public void test_GitHub_246() { - runTest("add correct annotations to multiple ITD methods with the same name and same number of arguments"); - } - - /** - * Make sure to create one {@code ajc$inlineAccessMethod} for identically named (overloaded) private aspect methods. - *

- * See GitHub issue 250. - */ - public void test_GitHub_250() { - runTest("correctly handle overloaded private methods in aspects"); - } - - /** - * If one generic method overrides another one with a narrower return type, avoid matching bridge methods. - *

- * See Spring GitHub issue 27761. - *

- * This test uses an ASM-modified class file reproducing the problem seen in Spring in plain AspectJ. Before the - * bugfix, it fails with "advice defined in RepositoryAspect has not been applied [Xlint:adviceDidNotMatch]". - */ - public void test_Spring_GitHub_27761() { - runTest("do not match bridge methods"); - } - - /** - * In 1.9.20, a regression bug occurred, matching negated types like '!void' and '!String' incorrectly. - *

- * See GitHub issue 257. - */ - public void test_GitHub_257() { - runTest("handle negated type patterns correctly"); + public void testDummy() { + //runTest("dummy"); } public static Test suite() { diff --git a/tests/src/test/java/org/aspectj/systemtest/ajc1921/Java21PreviewFeaturesTests.java b/tests/src/test/java/org/aspectj/systemtest/ajc1921/Java21PreviewFeaturesTests.java index 1088aac63..4b4de845d 100644 --- a/tests/src/test/java/org/aspectj/systemtest/ajc1921/Java21PreviewFeaturesTests.java +++ b/tests/src/test/java/org/aspectj/systemtest/ajc1921/Java21PreviewFeaturesTests.java @@ -8,7 +8,6 @@ package org.aspectj.systemtest.ajc1921; import junit.framework.Test; -import org.aspectj.apache.bcel.Constants; import org.aspectj.testing.XMLBasedAjcTestCase; import org.aspectj.testing.XMLBasedAjcTestCaseForJava21Only; @@ -17,78 +16,8 @@ import org.aspectj.testing.XMLBasedAjcTestCaseForJava21Only; */ public class Java21PreviewFeaturesTests extends XMLBasedAjcTestCaseForJava21Only { - public void testSwitchPatternMatchingPreview4Java() { - runTest("switch pattern matching preview 4 java"); - checkVersion("SwitchPatternPreview4OK", Constants.MAJOR_21, Constants.PREVIEW_MINOR_VERSION); - } - - public void testSwitchPatternMatchingPreview4Error() { - runTest("switch pattern matching preview 4 error"); - } - - public void testSwitchPatternMatchingPreview3Aspect() { - runTest("switch pattern matching preview 3 aspect"); - checkVersion("SwitchPatternPreview3Aspect", Constants.MAJOR_21, Constants.PREVIEW_MINOR_VERSION); - checkVersion("Application", Constants.MAJOR_21, Constants.PREVIEW_MINOR_VERSION); - checkVersion("Shape", Constants.MAJOR_21, Constants.PREVIEW_MINOR_VERSION); - checkVersion("S", Constants.MAJOR_21, Constants.PREVIEW_MINOR_VERSION); - } - - public void testSwitchPatternMatchingCaseLabelDominatedByPrecedingError() { - runTest("switch pattern matching error"); - } - - public void testSwitchPatternMatchingPreview3Error1() { - runTest("switch pattern matching preview 3 error 1"); - } - - public void testSwitchPatternMatchingPreview3Error2() { - runTest("switch pattern matching preview 3 error 2"); - } - - public void testRecordPatternsPreview1OK() { - // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/450 - runTest("record patterns"); - } - - public void testRecordPatternsPreview1Error() { - // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/450 (fixed for preview 2 in Eclipse 2023-03, 4.27) - runTest("record patterns error"); - checkVersion("RecordPatternsPreview1Error", Constants.MAJOR_21, Constants.PREVIEW_MINOR_VERSION); - checkVersion("Box", Constants.MAJOR_21, Constants.PREVIEW_MINOR_VERSION); - } - - public void testRecordPatternsPreview1ExhaustivenessOK1() { - // Falsely throws 'An enhanced switch statement should be exhaustive; a default label expected' twice, - // see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 - // TODO: Remove redundant default clauses when fixed upstream - System.out.println("TODO: fully activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 has been fixed"); - runTest("record patterns exhaustiveness 1"); - } - - public void testRecordPatternsPreview1Aspect() { - runTest("record patterns aspect"); - } - - public void testRecordPatternsPreview1ExhaustivenessAspect() { - // Falsely throws 'An enhanced switch statement should be exhaustive; a default label expected' twice, - // see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 - // TODO: Remove redundant default clauses when fixed upstream - System.out.println("TODO: fully activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 has been fixed"); - runTest("record patterns exhaustiveness aspect"); - } - - public void testRecordPatternsPreview1ExhaustivenessError() { - // See https://github.com/eclipse-jdt/eclipse.jdt.core/issues/455 - runTest("record patterns exhaustiveness error"); - } - - public void testRecordPatternsPreview1ExhaustivenessOK2() { - // Falsely throws 'An enhanced switch statement should be exhaustive; a default label expected', - // see https://github.com/eclipse-jdt/eclipse.jdt.core/issues/398 - // TODO: activate when fixed - System.out.println("TODO: activate when https://github.com/eclipse-jdt/eclipse.jdt.core/issues/398 has been fixed"); - //runTest("record patterns exhaustiveness 2"); + public void testDummyPreviewJava21() { + //runTest("dummy preview Java 21"); } public static Test suite() { diff --git a/tests/src/test/resources/org/aspectj/systemtest/ajc1921/ajc1921.xml b/tests/src/test/resources/org/aspectj/systemtest/ajc1921/ajc1921.xml index 1199bb03a..73f2bdf5b 100644 --- a/tests/src/test/resources/org/aspectj/systemtest/ajc1921/ajc1921.xml +++ b/tests/src/test/resources/org/aspectj/systemtest/ajc1921/ajc1921.xml @@ -1,19 +1,31 @@ - - - - + + + + @@ -28,28 +40,32 @@ + + + - + - + - - - - + + + + @@ -63,55 +79,58 @@ + + - + - + - + - - - + + + - + - + - + - + - + - + - + @@ -119,10 +138,10 @@ - + - - + + @@ -130,11 +149,11 @@ - + - + - + @@ -143,10 +162,10 @@ - + - - + + @@ -159,320 +178,21 @@ - + - + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- 2.39.5