diff options
author | Jay Arthanareeswaran | 2020-05-12 14:11:18 +0000 |
---|---|---|
committer | Jay Arthanareeswaran | 2020-05-14 02:28:34 +0000 |
commit | 9295bf84c9dbff60af20ec946d9d9cb0c37008df (patch) | |
tree | 632a5bf867e6e7daee88e1add569fd1023c44597 | |
parent | 53022ce4a0390470da9bbf2e286a2f79f50687fe (diff) | |
download | eclipse.jdt.core-9295bf84c9dbff60af20ec946d9d9cb0c37008df.tar.gz eclipse.jdt.core-9295bf84c9dbff60af20ec946d9d9cb0c37008df.tar.xz eclipse.jdt.core-9295bf84c9dbff60af20ec946d9d9cb0c37008df.zip |
expressions from Java 14
Change-Id: Ib9587a26209337d3abf033d1be176b8f4be99da2
Signed-off-by: Jay Arthanareeswaran <jarthana@in.ibm.com>
9 files changed, 298 insertions, 41 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java index 8b0005a744..4b629a8470 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java @@ -1097,6 +1097,7 @@ public void test011_problem_categories() { expectedProblemAttributes.put("UnqualifiedFieldAccess", new ProblemAttributes(CategorizedProblem.CAT_CODE_STYLE)); expectedProblemAttributes.put("UnreachableCatch", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("UnresolvedVariable", new ProblemAttributes(CategorizedProblem.CAT_MEMBER)); + expectedProblemAttributes.put("UnsafeCast", new ProblemAttributes(CategorizedProblem.CAT_TYPE)); expectedProblemAttributes.put("UnsafeElementTypeConversion", new ProblemAttributes(CategorizedProblem.CAT_UNCHECKED_RAW)); expectedProblemAttributes.put("UnsafeGenericArrayForVarargs", new ProblemAttributes(CategorizedProblem.CAT_UNCHECKED_RAW)); expectedProblemAttributes.put("UnsafeGenericCast", new ProblemAttributes(CategorizedProblem.CAT_UNCHECKED_RAW)); @@ -2122,6 +2123,7 @@ public void test012_compiler_problems_tuning() { expectedProblemAttributes.put("UnqualifiedFieldAccess", new ProblemAttributes(JavaCore.COMPILER_PB_UNQUALIFIED_FIELD_ACCESS)); expectedProblemAttributes.put("UnreachableCatch", SKIP); expectedProblemAttributes.put("UnresolvedVariable", SKIP); + expectedProblemAttributes.put("UnsafeCast", SKIP); expectedProblemAttributes.put("UnsafeElementTypeConversion", new ProblemAttributes(JavaCore.COMPILER_PB_UNCHECKED_TYPE_OPERATION)); expectedProblemAttributes.put("UnsafeGenericArrayForVarargs", new ProblemAttributes(JavaCore.COMPILER_PB_UNCHECKED_TYPE_OPERATION)); expectedProblemAttributes.put("UnsafeGenericCast", new ProblemAttributes(JavaCore.COMPILER_PB_UNCHECKED_TYPE_OPERATION)); diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java index 9e73da19fe..47beae1a92 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. + * Copyright (c) 2000, 2020 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -5400,10 +5400,12 @@ public class GenericTypeTest extends AbstractComparableTest { true, customOptions); } - public void _test0178a() { + public void test0178a() { if (this.complianceLevel < ClassFileConstants.JDK14) return; Map customOptions = getCompilerOptions(); + customOptions.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.ENABLED); + customOptions.put(CompilerOptions.OPTION_ReportPreviewFeatures, CompilerOptions.WARNING); this.runNegativeTest( new String[] { "X.java", @@ -5419,7 +5421,7 @@ public class GenericTypeTest extends AbstractComparableTest { " return t;\n" + " } else if (t instanceof T) {\n" + " return t;\n" + - " } else if (t instanceof X) {\n" + + " } else if (t instanceof X) { // this is allowed since Java 14 as preview feature\n" + " return t;\n" + " }\n" + " return null;\n" + @@ -5429,13 +5431,33 @@ public class GenericTypeTest extends AbstractComparableTest { "----------\n" + "1. ERROR in X.java (at line 5)\n" + " if (t instanceof X<T>) {\n" + - " ^^^^^^^^^^^^^^\n" + - "Type mismatch: cannot convert from T to X<T>\n" + + " ^\n" + + "Type T cannot be safely cast to X<T>\n" + "----------\n" + - "2. ERROR in X.java (at line 7)\n" + + "2. WARNING in X.java (at line 5)\n" + + " if (t instanceof X<T>) {\n" + + " ^\n" + + "You are using a preview language feature that may or may not be supported in a future release\n" + + "----------\n" + + "3. ERROR in X.java (at line 7)\n" + " } else if (t instanceof X<String>) {\n" + - " ^^^^^^^^^^^^^^\n" + - "Type mismatch: cannot convert from T to X<String>\n" + + " ^\n" + + "Type T cannot be safely cast to X<String>\n" + + "----------\n" + + "4. WARNING in X.java (at line 7)\n" + + " } else if (t instanceof X<String>) {\n" + + " ^\n" + + "You are using a preview language feature that may or may not be supported in a future release\n" + + "----------\n" + + "5. WARNING in X.java (at line 11)\n" + + " } else if (t instanceof T) {\n" + + " ^^^^^^^^^^^^^^\n" + + "The expression of type T is already an instance of type T\n" + + "----------\n" + + "6. WARNING in X.java (at line 11)\n" + + " } else if (t instanceof T) {\n" + + " ^\n" + + "You are using a preview language feature that may or may not be supported in a future release\n" + "----------\n", null, true, diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PatternMatching14Test.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PatternMatching14Test.java index 9dc03a4a46..016414f1df 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PatternMatching14Test.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/PatternMatching14Test.java @@ -24,7 +24,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { static { // TESTS_NUMBERS = new int [] { 40 }; // TESTS_RANGE = new int[] { 1, -1 }; -// TESTS_NAMES = new String[] { "test005" }; +// TESTS_NAMES = new String[] { "testBug562392" }; } public static Class<?> testClass() { @@ -2045,7 +2045,7 @@ public class PatternMatching14Test extends AbstractRegressionTest { compilerOptions); compilerOptions.put(CompilerOptions.OPTION_PreserveUnusedLocal, old); } - public void _testBug562392a() { + public void testBug562392a() { Map<String, String> compilerOptions = getCompilerOptions(true); runConformTest( new String[] { @@ -2067,11 +2067,12 @@ public class PatternMatching14Test extends AbstractRegressionTest { "true", compilerOptions); } - public void _testBug562392b() { + public void testBug562392b() { Map<String, String> compilerOptions = getCompilerOptions(true); runNegativeTest( new String[] { "X.java", + "@SuppressWarnings(\"preview\")\n" + "public class X<T> {\n" + " public boolean foo(Object obj) {\n" + " if (obj instanceof T) {\n" + @@ -2085,17 +2086,21 @@ public class PatternMatching14Test extends AbstractRegressionTest { "}\n", }, "----------\n" + - "1. ERROR in X.java (at line 3)\n" + + "1. ERROR in X.java (at line 4)\n" + " if (obj instanceof T) {\n" + - " ^^^^^^^^^^^^^^^^\n" + - "Type mismatch: cannot convert from Object to T\n" + + " ^^^\n" + + "Type Object cannot be safely cast to T\n" + "----------\n", - "", + "X.java:4: error: Object cannot be safely cast to T\n" + + " if (obj instanceof T) {\n" + + " ^\n" + + " where T is a type-variable:\n" + + " T extends Object declared in class X", null, true, compilerOptions); } - public void _testBug562392c() { + public void testBug562392c() { Map<String, String> compilerOptions = getCompilerOptions(true); runNegativeTest( new String[] { @@ -2116,15 +2121,19 @@ public class PatternMatching14Test extends AbstractRegressionTest { "----------\n" + "1. ERROR in X.java (at line 4)\n" + " if (obj instanceof T t) {\n" + - " ^^^^^^^^^^^^^^^^^^\n" + - "Type mismatch: cannot convert from Object to T\n" + + " ^^^\n" + + "Type Object cannot be safely cast to T\n" + "----------\n", - "", + "X.java:4: error: Object cannot be safely cast to T\n" + + " if (obj instanceof T t) {\n" + + " ^\n" + + " where T is a type-variable:\n" + + " T extends Object declared in class X", null, true, compilerOptions); } - public void _testBug562392d() { + public void testBug562392d() { Map<String, String> compilerOptions = getCompilerOptions(true); runConformTest( new String[] { @@ -2144,7 +2153,180 @@ public class PatternMatching14Test extends AbstractRegressionTest { }, "", compilerOptions); + } + public void testBug562392e() { + Map<String, String> compilerOptions = getCompilerOptions(true); + runNegativeTest( + new String[] { + "X.java", + "@SuppressWarnings(\"preview\")\n" + + "public class X<T> {\n" + + " public boolean foo(X<?> obj) {\n" + + " if (obj instanceof X<String> p) {\n" + + " return true;\n" + + " }\n" + + " return false;\n" + + " }\n" + + "}\n", + }, + "----------\n" + + "1. ERROR in X.java (at line 4)\n" + + " if (obj instanceof X<String> p) {\n" + + " ^^^\n" + + "Type X<capture#1-of ?> cannot be safely cast to X<String>\n" + + "----------\n", + "", + null, + true, + compilerOptions); + } + public void testBug562392f() { + Map<String, String> compilerOptions = getCompilerOptions(true); + runNegativeTest( + new String[] { + "X.java", + "class Outer<T> {\n" + + " static class Inner<T> {\n" + + " }\n" + + "}\n" + + "@SuppressWarnings({\"preview\", \"rawtypes\"})\n" + + "class X<T> {\n" + + " public boolean foo(Outer.Inner obj) {\n" + + " if (obj instanceof Outer<?> p) {\n" + + " return true;\n" + + " }\n" + + " return false;\n" + + " }\n" + + "}\n", + }, + "----------\n" + + "1. ERROR in X.java (at line 8)\n" + + " if (obj instanceof Outer<?> p) {\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Incompatible conditional operand types Outer.Inner and Outer<?>\n" + + "----------\n", + "", + null, + true, + compilerOptions); + } + public void testBug562392g() { + Map<String, String> compilerOptions = getCompilerOptions(true); + runConformTest( + new String[] { + "X.java", + "class Outer<T> {\n" + + " static class Inner<T> {\n" + + " }\n" + + "}\n" + + "@SuppressWarnings({\"preview\", \"rawtypes\"})\n" + + "class X<T> {\n" + + " public boolean foo(Object obj) {\n" + + " if (obj instanceof Outer.Inner<?> p) {\n" + + " return true;\n" + + " }\n" + + " return false;\n" + + " }\n" + + " public static void main(String argv[]) {\n" + + " Outer.Inner inn = new Outer.Inner();\n" + + " System.out.println(new X<String>().foo(inn));\n" + + " }\n" + + "}\n", + }, + "true", + compilerOptions); + } + public void testBug562392h() { + Map<String, String> compilerOptions = getCompilerOptions(true); + runNegativeTest( + new String[] { + "X.java", + "@SuppressWarnings({\"preview\", \"rawtypes\"})\n" + + "public class X<T> {\n" + + " public boolean foo(X[] obj) {\n" + + " if (obj instanceof Object[] p) {\n" + + " return true;\n" + + " }\n" + + " return false;\n" + + " }\n" + + " public static void main(String argv[]) {\n" + + " Object[] param = {new X()};\n" + + " System.out.println(new X<String>().foo(param));\n" + + " }\n" + + "}\n", + }, + "----------\n" + + "1. ERROR in X.java (at line 11)\n" + + " System.out.println(new X<String>().foo(param));\n" + + " ^^^\n" + + "The method foo(X[]) in the type X<String> is not applicable for the arguments (Object[])\n" + + "----------\n", + "", + null, + true, + compilerOptions); + } + public void testBug562392i() { + Map<String, String> compilerOptions = getCompilerOptions(true); + String backup = compilerOptions.get(CompilerOptions.OPTION_EnablePreviews); + compilerOptions.put(CompilerOptions.OPTION_EnablePreviews, CompilerOptions.DISABLED); + try { + runNegativeTest( + new String[] { + "Test.java", + "import java.util.ArrayList;\n" + + "import java.util.List;\n" + + "import java.util.function.Function;\n" + + "import java.util.function.UnaryOperator;\n" + + "@SuppressWarnings({\"preview\"})\n" + + "public class Test<T> {\n" + + " public boolean foo(Function<ArrayList<T>, ArrayList<T>> obj) {\n" + + " if (obj instanceof UnaryOperator<? extends List<T>>) {\n" + + " return false;\n" + + " }\n" + + " return true;\n" + + " }\n" + + "}\n", + }, + "----------\n" + + "1. ERROR in Test.java (at line 8)\n" + + " if (obj instanceof UnaryOperator<? extends List<T>>) {\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Cannot perform instanceof check against parameterized type UnaryOperator<? extends List<T>>. Use the form UnaryOperator<?> instead since further generic type information will be erased at runtime\n" + + "----------\n", + "", + null, + true, + compilerOptions); + } finally { + compilerOptions.put(CompilerOptions.OPTION_EnablePreviews, backup); } + } + public void testBug562392j() { + Map<String, String> compilerOptions = getCompilerOptions(true); + runConformTest( + new String[] { + "Test.java", + "import java.util.ArrayList;\n" + + "import java.util.List;\n" + + "import java.util.function.Function;\n" + + "import java.util.function.UnaryOperator;\n" + + "@SuppressWarnings({\"preview\", \"rawtypes\"})\n" + + "public class Test<T> {\n" + + " public boolean foo(Function<ArrayList<T>, ArrayList<T>> obj) {\n" + + " if (obj instanceof UnaryOperator<? extends List<T>>) {\n" + + " return false;\n" + + " }\n" + + " return true;\n" + + " }\n" + + " public static void main(String argv[]) {\n" + + " System.out.println(\"\");\n" + + " }\n" + + "}\n", + }, + "", + compilerOptions); + } public void test053() { Map<String, String> compilerOptions = getCompilerOptions(true); runConformTest( diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java index 393226d08e..e9f48d34db 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java @@ -702,6 +702,10 @@ void setSourceStart(int sourceStart); /** @since 3.5 */ int ComparingIdentical = Internal + 211; + /** @since 3.22 + * @noreference preview feature error */ + int UnsafeCast = TypeRelated + 212; + int UnmatchedBracket = Syntax + Internal + 220; int NoFieldOnBaseType = FieldRelated + 221; int InvalidExpressionAsStatement = Syntax + Internal + 222; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java index 22cde62aaa..35f1d8a40b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java @@ -99,14 +99,14 @@ public abstract class ASTNode implements TypeConstants, TypeIds { public final static int Bit4 = 0x8; // return type (operator) | first assignment to local (name ref,local decl) | undocumented empty block (block, type and method decl) public final static int Bit5 = 0x10; // value for return (expression) | has all method bodies (unit) | supertype ref (type ref) | resolved (field decl)| name ref (yield result value) public final static int Bit6 = 0x20; // depth (name ref, msg) | ignore need cast check (cast expression) | error in signature (method declaration/ initializer) | is recovered (annotation reference) - public final static int Bit7 = 0x40; // depth (name ref, msg) | operator (operator) | need runtime checkcast (cast expression) | label used (labelStatement) | needFreeReturn (AbstractMethodDeclaration) - public final static int Bit8 = 0x80; // depth (name ref, msg) | operator (operator) | unsafe cast (cast expression) | is default constructor (constructor declaration) | isElseStatementUnreachable (if statement) + public final static int Bit7 = 0x40; // depth (name ref, msg) | need runtime checkcast (cast expression) | label used (labelStatement) | needFreeReturn (AbstractMethodDeclaration) + public final static int Bit8 = 0x80; // depth (name ref, msg) | unsafe cast (cast expression) | is default constructor (constructor declaration) | isElseStatementUnreachable (if statement) public final static int Bit9 = 0x100; // depth (name ref, msg) | operator (operator) | is local type (type decl) | isThenStatementUnreachable (if statement) | can be static public final static int Bit10= 0x200; // depth (name ref, msg) | operator (operator) | is anonymous type (type decl) | is implicit constructor (constructor) public final static int Bit11 = 0x400; // depth (name ref, msg) | operator (operator) | is member type (type decl) public final static int Bit12 = 0x800; // depth (name ref, msg) | operator (operator) | has abstract methods (type decl) - public final static int Bit13 = 0x1000; // depth (name ref, msg) | is secondary type (type decl) - public final static int Bit14 = 0x2000; // strictly assigned (reference lhs) | discard enclosing instance (explicit constr call) | hasBeenGenerated (type decl) + public final static int Bit13 = 0x1000; // depth (name ref, msg) | operator (operator) | is secondary type (type decl) + public final static int Bit14 = 0x2000; // strictly assigned (reference lhs) | operator (operator) | discard enclosing instance (explicit constr call) | hasBeenGenerated (type decl) public final static int Bit15 = 0x4000; // is unnecessary cast (expression) | is varargs (type ref) | isSubRoutineEscaping (try statement) | superAccess (javadoc allocation expression/javadoc message send/javadoc return statement) public final static int Bit16 = 0x8000; // in javadoc comment (name ref, type ref, msg) public final static int Bit17 = 0x10000; // compound assigned (reference lhs) | unchecked (msg, alloc, explicit constr call) @@ -164,8 +164,8 @@ public abstract class ASTNode implements TypeConstants, TypeIds { // for operators public static final int ReturnTypeIDMASK = Bit1|Bit2|Bit3|Bit4; - public static final int OperatorSHIFT = 6; // Bit7 -> Bit12 - public static final int OperatorMASK = Bit7|Bit8|Bit9|Bit10|Bit11|Bit12; // 6 bits for operator ID + public static final int OperatorSHIFT = 8; // Bit9 -> Bit14 + public static final int OperatorMASK = Bit9|Bit10|Bit11|Bit12|Bit13|Bit14; // 6 bits for operator ID // for binary expressions public static final int IsReturnedValue = Bit5; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java index aad157f6c1..38fa4fccbe 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java @@ -396,10 +396,16 @@ private static boolean preventsUnlikelyTypeWarning(TypeBinding castedType, TypeB @Override public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) { + return CastExpression.checkUnsafeCast(this, scope, castType, expressionType, match, isNarrowing); +} +public static boolean checkUnsafeCast(Expression expression, Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) { + // In case of expression being a InstanceOfExpression, this.resolvedType is null + // hence use the type of RHS of the instanceof operator + TypeBinding resolvedType = expression.resolvedType != null ? expression.resolvedType : castType; if (TypeBinding.equalsEquals(match, castType)) { - if (!isNarrowing && TypeBinding.equalsEquals(match, this.resolvedType.leafComponentType()) // do not tag as unnecessary when recursing through upper bounds + if (!isNarrowing && TypeBinding.equalsEquals(match, resolvedType.leafComponentType()) // do not tag as unnecessary when recursing through upper bounds && !(expressionType.isParameterizedType() && expressionType.isProvablyDistinct(castType))) { - tagAsUnnecessaryCast(scope, castType); + expression.tagAsUnnecessaryCast(scope, castType); } return true; } @@ -414,7 +420,7 @@ public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding ex case Binding.PARAMETERIZED_TYPE : if (!castType.isReifiable()) { if (match == null) { // unrelated types - this.bits |= ASTNode.UnsafeCast; + expression.bits |= ASTNode.UnsafeCast; return true; } switch (match.kind()) { @@ -422,7 +428,7 @@ public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding ex if (isNarrowing) { // [JLS 5.5] T <: S if (expressionType.isRawType() || !expressionType.isEquivalentTo(match)) { - this.bits |= ASTNode.UnsafeCast; + expression.bits |= ASTNode.UnsafeCast; return true; } // [JLS 5.5] S has no subtype X != T, such that |X| == |T| @@ -433,7 +439,7 @@ public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding ex TypeBinding[] castArguments = paramCastType.arguments; int length = castArguments == null ? 0 : castArguments.length; if (paramMatch.arguments == null || length > paramMatch.arguments.length) { - this.bits |= ASTNode.UnsafeCast; + expression.bits |= ASTNode.UnsafeCast; } else if ((paramCastType.tagBits & (TagBits.HasDirectWildcard|TagBits.HasTypeVariable)) != 0) { // verify alternate cast type, substituting different type arguments nextAlternateArgument: for (int i = 0; i < length; i++) { @@ -451,7 +457,7 @@ public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding ex LookupEnvironment environment = scope.environment(); ParameterizedTypeBinding alternateCastType = environment.createParameterizedType((ReferenceBinding)castType.erasure(), alternateArguments, castType.enclosingType()); if (TypeBinding.equalsEquals(alternateCastType.findSuperTypeOriginatingFrom(expressionType), match)) { - this.bits |= ASTNode.UnsafeCast; + expression.bits |= ASTNode.UnsafeCast; break; } } @@ -460,18 +466,18 @@ public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding ex } else { // [JLS 5.5] T >: S if (!match.isEquivalentTo(castType)) { - this.bits |= ASTNode.UnsafeCast; + expression.bits |= ASTNode.UnsafeCast; return true; } } break; case Binding.RAW_TYPE : - this.bits |= ASTNode.UnsafeCast; // upcast since castType is known to be bound paramType + expression.bits |= ASTNode.UnsafeCast; // upcast since castType is known to be bound paramType return true; default : if (isNarrowing){ // match is not parameterized or raw, then any other subtype of match will erase to |T| - this.bits |= ASTNode.UnsafeCast; + expression.bits |= ASTNode.UnsafeCast; return true; } break; @@ -481,12 +487,12 @@ public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding ex case Binding.ARRAY_TYPE : TypeBinding leafType = castType.leafComponentType(); if (isNarrowing && (!leafType.isReifiable() || leafType.isTypeVariable())) { - this.bits |= ASTNode.UnsafeCast; + expression.bits |= ASTNode.UnsafeCast; return true; } break; case Binding.TYPE_PARAMETER : - this.bits |= ASTNode.UnsafeCast; + expression.bits |= ASTNode.UnsafeCast; return true; // (disabled) https://bugs.eclipse.org/bugs/show_bug.cgi?id=240807 // case Binding.TYPE : @@ -496,8 +502,8 @@ public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding ex // } // break; } - if (!isNarrowing && TypeBinding.equalsEquals(match, this.resolvedType.leafComponentType())) { // do not tag as unnecessary when recursing through upper bounds - tagAsUnnecessaryCast(scope, castType); + if (!isNarrowing && TypeBinding.equalsEquals(match, resolvedType.leafComponentType())) { // do not tag as unnecessary when recursing through upper bounds + expression.tagAsUnnecessaryCast(scope, castType); } return true; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java index 3ca65a79e0..4ce3b690b4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java @@ -26,9 +26,12 @@ package org.eclipse.jdt.internal.compiler.ast; import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.codegen.*; import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.impl.IrritantSet; import org.eclipse.jdt.internal.compiler.lookup.*; public class InstanceOfExpression extends OperatorExpression { @@ -176,7 +179,21 @@ public TypeBinding resolveType(BlockScope scope) { return null; if (!checkedType.isReifiable()) { - scope.problemReporter().illegalInstanceOfGenericType(checkedType, this); + CompilerOptions options = scope.compilerOptions(); + // If preview is disabled, report same as before, even at Java 14 + if (options.complianceLevel < ClassFileConstants.JDK14 || !options.enablePreviewFeatures) { + scope.problemReporter().illegalInstanceOfGenericType(checkedType, this); + } else { + if (options.isAnyEnabled(IrritantSet.PREVIEW)) { + scope.problemReporter().previewFeatureUsed(this.type.sourceStart, this.type.sourceEnd); + } + if (expressionType != TypeBinding.NULL) { + boolean isLegal = checkCastTypesCompatibility(scope, checkedType, expressionType, this.expression, true); + if (!isLegal || (this.bits & ASTNode.UnsafeCast) != 0) { + scope.problemReporter().unsafeCastInInstanceof(this.expression, checkedType, expressionType); + } + } + } } else if (checkedType.isValidBinding()) { // if not a valid binding, an error has already been reported for unresolved type if ((expressionType != TypeBinding.NULL && expressionType.isBaseType()) // disallow autoboxing @@ -187,10 +204,17 @@ public TypeBinding resolveType(BlockScope scope) { } return this.resolvedType = TypeBinding.BOOLEAN; } - +@Override +public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) { + if (!castType.isReifiable()) + return CastExpression.checkUnsafeCast(this, scope, castType, expressionType, match, isNarrowing); + else + return super.checkUnsafeCast(scope, castType, expressionType, match, isNarrowing); +} /** * @see org.eclipse.jdt.internal.compiler.ast.Expression#tagAsUnnecessaryCast(Scope,TypeBinding) */ + @Override public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) { // null is not instanceof Type, recognize direct scenario diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index 2ea0d3a4ec..dddb9efd6c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -8405,6 +8405,22 @@ public void typeCastError(CastExpression expression, TypeBinding leftType, TypeB expression.sourceStart, expression.sourceEnd); } +public void unsafeCastInInstanceof(Expression expression, TypeBinding leftType, TypeBinding rightType) { + String leftName = new String(leftType.readableName()); + String rightName = new String(rightType.readableName()); + String leftShortName = new String(leftType.shortReadableName()); + String rightShortName = new String(rightType.shortReadableName()); + if (leftShortName.equals(rightShortName)){ + leftShortName = leftName; + rightShortName = rightName; + } + this.handle( + IProblem.UnsafeCast, + new String[] { rightName, leftName }, + new String[] { rightShortName, leftShortName }, + expression.sourceStart, + expression.sourceEnd); +} public void typeCollidesWithEnclosingType(TypeDeclaration typeDecl) { String[] arguments = new String[] {new String(typeDecl.name)}; this.handle( diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties index 1518d0abb7..57a5e15a3a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties @@ -244,6 +244,7 @@ 209 = Syntax error on keyword "{0}"; {1} expected 210 = Syntax error on keyword "{0}", no accurate correction available 211 = Comparing identical expressions +212 = Type {0} cannot be safely cast to {1} 220 = Unmatched bracket 221 = The primitive type {0} of {1} does not have a field {2} |