diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/CastExpression.java index d4463f4554e..c6c6ebf3edd 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/CastExpression.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/ast/CastExpression.java @@ -430,24 +430,21 @@ public static boolean checkUnsafeCast(Expression expression, Scope scope, TypeBi ParameterizedTypeBinding paramCastType = (ParameterizedTypeBinding) castType; TypeBinding[] castArguments = paramCastType.arguments; int length = castArguments == null ? 0 : castArguments.length; - if ((paramCastType.tagBits & (TagBits.HasDirectWildcard|TagBits.HasTypeVariable)) != 0) { - // verify alternate cast type, substituting different type arguments - for (int i = 0; i < length; i++) { - if (castArguments[i].isUnboundWildcard()) - continue; - TypeBinding[] alternateArguments; - // need to clone for each iteration to avoid env paramtype cache interference - System.arraycopy(paramCastType.arguments, 0, alternateArguments = new TypeBinding[length], 0, length); - alternateArguments[i] = TypeBinding.equalsEquals(paramCastType.arguments[i], scope.getJavaLangObject()) ? scope.getJavaLangBoolean() : scope.getJavaLangObject(); - LookupEnvironment environment = scope.environment(); - ParameterizedTypeBinding alternateCastType = environment.createParameterizedType((ReferenceBinding)castType.erasure(), alternateArguments, castType.enclosingType()); - if (TypeBinding.equalsEquals(alternateCastType.findSuperTypeOriginatingFrom(expressionType), match)) { - expression.bits |= ASTNode.UnsafeCast; - break; - } + // verify alternate cast type, substituting different type arguments + for (int i = 0; i < length; i++) { + if (castArguments[i].isUnboundWildcard()) + continue; + TypeBinding[] alternateArguments; + // need to clone for each iteration to avoid env paramtype cache interference + System.arraycopy(paramCastType.arguments, 0, alternateArguments = new TypeBinding[length], 0, length); + alternateArguments[i] = TypeBinding.equalsEquals(paramCastType.arguments[i], scope.getJavaLangObject()) ? scope.getJavaLangBoolean() : scope.getJavaLangObject(); + LookupEnvironment environment = scope.environment(); + ParameterizedTypeBinding alternateCastType = environment.createParameterizedType((ReferenceBinding)castType.erasure(), alternateArguments, castType.enclosingType()); + if (TypeBinding.equalsEquals(alternateCastType.findSuperTypeOriginatingFrom(expressionType), match)) { + expression.bits |= ASTNode.UnsafeCast; + break; } } - // Type arguments added by subtypes of S and removed by supertypes of T don't need to be checked since the type arguments aren't specified by either S or T return true; } else { diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java index f6f0ddea86a..ceec296e917 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest.java @@ -6975,5 +6975,47 @@ public void testBugGH656_2() { "The method JavacWillAlsoError.someAbstractMethod() does not override the inherited method from MyAbstract since it is private to a different package\n" + "----------\n"); } +// https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1802 +// Unchecked casts go unreported with ECJ +public void testIssue1802() { + Runner runner = new Runner(); + runner.testFiles = + new String[] { + "X.java", + """ + class X { + void foo(I ix) { + A ay = (A) ix; + B bx = (B) ix; + } + } + class Y extends X {} + class Z extends X {} + + interface I { + } + + final class B implements I { + } + + + final class A implements I { + } + """ + }; + runner.expectedCompilerLog = + "----------\n" + + "1. WARNING in X.java (at line 3)\n" + + " A ay = (A) ix;\n" + + " ^^^^^^^^^\n" + + "Type safety: Unchecked cast from I to A\n" + + "----------\n" + + "2. WARNING in X.java (at line 4)\n" + + " B bx = (B) ix;\n" + + " ^^^^^^^^^\n" + + "Type safety: Unchecked cast from I to B\n" + + "----------\n"; + runner.runWarningTest(); +} } diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java index 3a370ec0f32..caab7826379 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchPatternTest.java @@ -8541,8 +8541,8 @@ public static void main(String[] args) { "42\n420\n4200"); } - public void testIssue3009_4() { // FIXME: this should not compile!!! - runConformTest( + public void testIssue3009_4() { + runNegativeTest( new String[] { "X.java", """ @@ -8572,7 +8572,12 @@ public static void main(String[] args) { } """ }, - "42\n420\n4200"); + "----------\n" + + "1. ERROR in X.java (at line 13)\r\n" + + " case H e -> 4200;\r\n" + + " ^^^^^^^^^^^^^^^\n" + + "Type J cannot be safely cast to H\n" + + "----------\n"); } public void testIssue3009_5() { @@ -8817,4 +8822,46 @@ public static void main(String[] args) { }, "42\n420"); } + + // https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1735 + // [Sealed types][Switch] Pattern switch - ECJ accepts code rejected by javac + public void testIssue1735() { + runNegativeTest( + new String[] { + "X.java", + """ + class X { + void foo(I ix) { + switch(ix) { + case A ay -> System.out.println(); + case B bx -> System.out.println(); + } + } + } + class Y extends X {} + class Z extends X {} + + sealed interface I permits A, B { + } + + final class B implements I { + } + + + final class A implements I { + } + """ + }, + "----------\n" + + "1. ERROR in X.java (at line 4)\n" + + " case A ay -> System.out.println();\n" + + " ^^^^^^^\n" + + "Type I cannot be safely cast to A\n" + + "----------\n" + + "2. ERROR in X.java (at line 5)\n" + + " case B bx -> System.out.println();\n" + + " ^^^^^^^\n" + + "Type I cannot be safely cast to B\n" + + "----------\n"); + } }