diff options
author | Stephan Herrmann | 2020-01-02 17:54:14 +0000 |
---|---|---|
committer | Stephan Herrmann | 2020-01-26 14:21:23 +0000 |
commit | 26442c4da93bb37c148503ede232875b5244e58f (patch) | |
tree | 2eeec740f70b9bfb24237cc062a679b66a1b2184 | |
parent | 7524d911155feb0decf44ddadea1a9585a4e3a97 (diff) | |
download | eclipse.jdt.core-26442c4da93bb37c148503ede232875b5244e58f.tar.gz eclipse.jdt.core-26442c4da93bb37c148503ede232875b5244e58f.tar.xz eclipse.jdt.core-26442c4da93bb37c148503ede232875b5244e58f.zip |
Bug 482242 - [compiler][null] option to raise problems when unsafelyI20200126-1800
passing annotated parameterized types into unannotated code
Change-Id: Ifd22f01d180a41fc1e7e9f878bfa6060c354e11f
15 files changed, 384 insertions, 56 deletions
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java index 4bb46891c0..ecafbcb7e1 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.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 @@ -1020,7 +1020,8 @@ public void test012b(){ " <option key=\"org.eclipse.jdt.core.compiler.emulateJavacBug8031744\" value=\"enabled\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.generateClassFiles\" value=\"enabled\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.maxProblemPerUnit\" value=\"100\"/>\n" + - " <option key=\"org.eclipse.jdt.core.compiler.problem.APILeak\" value=\"warning\"/>\n" + + " <option key=\"org.eclipse.jdt.core.compiler.problem.APILeak\" value=\"warning\"/>\n" + + " <option key=\"org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated\" value=\"info\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.annotationSuperInterface\" value=\"warning\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.assertIdentifier\" value=\"warning\"/>\n" + " <option key=\"org.eclipse.jdt.core.compiler.problem.autoboxing\" value=\"ignore\"/>\n" + diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java index 658c2e1e77..7cbe5d7796 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java @@ -8289,7 +8289,7 @@ public void testBug459967_Enum_values() { ? " @NonNull MyEnum[] getValues() {\n" : - " MyEnum @NonNull[] getValues() {\n" + " @NonNull MyEnum @NonNull[] getValues() {\n" )+ " return MyEnum.values();\n" + " }\n" + @@ -8325,7 +8325,7 @@ public void testBug459967_Enum_values_binary() { ? " @NonNull MyEnum[] getValues() {\n" : - " MyEnum @NonNull[] getValues() {\n" + " @NonNull MyEnum @NonNull[] getValues() {\n" )+ " return MyEnum.values();\n" + " }\n" + diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java index 1f67c69eaf..19c069027b 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2019 GK Software AG and others. + * Copyright (c) 2012, 2020 GK Software AG and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -827,6 +827,8 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { // issue from https://bugs.eclipse.org/bugs/show_bug.cgi?id=403216#c7 public void testBug403216_2() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED, JavaCore.IGNORE); runConformTestWithLibs( new String[] { "X.java", @@ -839,7 +841,7 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { " }\n" + "}\n" }, - getCompilerOptions(), + options, ""); } @@ -1451,7 +1453,7 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { "3. ERROR in Y1.java (at line 11)\n" + " x.wildcard1(new ArrayList<@NonNull X1>()); // incompatible\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'List<@Nullable ? extends X1>\' but this expression has type \'ArrayList<@NonNull X1>\', corresponding supertype is \'List<@NonNull X1>\'\n" + + "Null type mismatch (type annotations): required \'List<@Nullable ? extends X1>\' but this expression has type \'@NonNull ArrayList<@NonNull X1>\', corresponding supertype is \'List<@NonNull X1>\'\n" + "----------\n"); } @@ -1531,7 +1533,7 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { "3. ERROR in Y1.java (at line 11)\n" + " x.wildcard1(new ArrayList<p.@NonNull X1>()); // incompatible\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'List<@Nullable ? extends X1>\' but this expression has type \'ArrayList<@NonNull X1>\', corresponding supertype is \'List<@NonNull X1>\'\n" + + "Null type mismatch (type annotations): required \'List<@Nullable ? extends X1>\' but this expression has type \'@NonNull ArrayList<@NonNull X1>\', corresponding supertype is \'List<@NonNull X1>\'\n" + "----------\n"); } @@ -1829,6 +1831,8 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { // types with null annotations on details (type parameter) are compatible to types lacking the annotation public void testCompatibility2() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED, JavaCore.IGNORE); runConformTestWithLibs( new String[] { "X.java", @@ -1857,7 +1861,7 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { + " void takeAny(List<String> any) {}\n" + "}\n" }, - getCompilerOptions(), + options, ""); } @@ -3124,7 +3128,7 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { "1. WARNING in X.java (at line 8)\n" + " List<@NonNull ? extends @NonNull String> ls = new ArrayList<String>();\n" + " ^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type safety (type annotations): The expression of type \'ArrayList<String>\' needs unchecked conversion to conform to \'List<@NonNull ? extends @NonNull String>\', corresponding supertype is 'List<String>'\n" + + "Null type safety (type annotations): The expression of type \'@NonNull ArrayList<String>\' needs unchecked conversion to conform to \'List<@NonNull ? extends @NonNull String>\', corresponding supertype is 'List<String>'\n" + "----------\n" + "2. ERROR in X.java (at line 9)\n" + " ls.add(null);\n" + @@ -3255,7 +3259,12 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { "}\n" }, getCompilerOptions(), - ""); + "----------\n" + + "1. INFO in X.java (at line 9)\n" + + " X<String> x = new Y();\n" + + " ^^^^^^^\n" + + "Null type safety (type annotations): The expression of type '@NonNull Y' needs unchecked conversion to conform to 'X<String>', corresponding supertype is 'X<@NonNull String>'\n" + + "----------\n"); } public void testBug416181() { @@ -3317,7 +3326,7 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { "1. WARNING in X.java (at line 9)\n" + " X<@Nullable String> xs = new X<String>();\n" + " ^^^^^^^^^^^^^^^\n" + - "Null type safety (type annotations): The expression of type \'X<String>\' needs unchecked conversion to conform to \'X<@Nullable String>\'\n" + + "Null type safety (type annotations): The expression of type \'@NonNull X<String>\' needs unchecked conversion to conform to \'X<@Nullable String>\'\n" + "----------\n" + "2. ERROR in X.java (at line 10)\n" + " xs.foo(null);\n" + @@ -3363,7 +3372,7 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { "1. WARNING in X.java (at line 10)\n" + " X<@Nullable String> xs = new X<String>();\n" + " ^^^^^^^^^^^^^^^\n" + - "Null type safety (type annotations): The expression of type \'X<String>\' needs unchecked conversion to conform to \'X<@Nullable String>\'\n" + + "Null type safety (type annotations): The expression of type \'@NonNull X<String>\' needs unchecked conversion to conform to \'X<@Nullable String>\'\n" + "----------\n" + "2. ERROR in X.java (at line 12)\n" + " xs.foo(null);\n" + @@ -3466,7 +3475,7 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { "2. WARNING in X.java (at line 10)\n" + " s.foo(new ArrayList<String>()); // (1)\n" + " ^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type safety (type annotations): The expression of type \'ArrayList<String>\' needs unchecked conversion to conform to \'@NonNull List<@NonNull String>\', corresponding supertype is 'List<String>'\n" + + "Null type safety (type annotations): The expression of type \'@NonNull ArrayList<String>\' needs unchecked conversion to conform to \'@NonNull List<@NonNull String>\', corresponding supertype is 'List<String>'\n" + "----------\n" + "3. ERROR in X.java (at line 11)\n" + " s.foo(null); // (2)\n" + @@ -3667,12 +3676,17 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { " ^^^^\n" + "Null type mismatch: required \'@NonNull String\' but the provided value is null\n" + "----------\n" + - "2. ERROR in X.java (at line 7)\n" + + "2. INFO in X.java (at line 7)\n" + + " @NonNull String @NonNull [][] s2 = new @NonNull String [] @NonNull [] { null, { null} }; // problem at both nulls\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Null type safety (type annotations): The expression of type \'@NonNull String [] @NonNull[]\' needs unchecked conversion to conform to \'@NonNull String @NonNull[] []\'\n" + + "----------\n" + + "3. ERROR in X.java (at line 7)\n" + " @NonNull String @NonNull [][] s2 = new @NonNull String [] @NonNull [] { null, { null} }; // problem at both nulls\n" + " ^^^^\n" + "Null type mismatch: required \'@NonNull String @NonNull[]\' but the provided value is null\n" + "----------\n" + - "3. ERROR in X.java (at line 7)\n" + + "4. ERROR in X.java (at line 7)\n" + " @NonNull String @NonNull [][] s2 = new @NonNull String [] @NonNull [] { null, { null} }; // problem at both nulls\n" + " ^^^^\n" + "Null type mismatch: required \'@NonNull String\' but the provided value is null\n" + @@ -3682,6 +3696,8 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { // https://bugs.eclipse.org/417758 - [1.8][null] Null safety compromise during array creation. // three-dim array with annotations on dimensions, also assignment has a problem public void testArray3() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED, JavaCore.WARNING); runNegativeTestWithLibs( new String[] { "X.java", @@ -3694,7 +3710,7 @@ public class NullTypeAnnotationTest extends AbstractNullAnnotationTest { " }\n" + "}" }, - getCompilerOptions(), + options, "----------\n" + "1. WARNING in X.java (at line 6)\n" + " @NonNull String [][] @NonNull [] s = new @NonNull String []@NonNull [][] { null, { {null}, null/*ok*/ } };\n" + @@ -4710,7 +4726,7 @@ public void testBug429403() { "1. ERROR in X.java (at line 5)\n" + " List<@NonNull Person> l = new ArrayList<@Nullable Person>();}\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'List<@NonNull Person>\' but this expression has type \'ArrayList<@Nullable Person>\', corresponding supertype is \'List<@Nullable Person>\'\n" + + "Null type mismatch (type annotations): required \'List<@NonNull Person>\' but this expression has type \'@NonNull ArrayList<@Nullable Person>\', corresponding supertype is \'List<@Nullable Person>\'\n" + "----------\n"); } public void testBug430219() { @@ -4777,7 +4793,7 @@ public void testDefault01() { "2. ERROR in X.java (at line 7)\n" + " return new ArrayList<@Nullable Number>(); // ERR\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'List<@NonNull Number>\' but this expression has type \'ArrayList<@Nullable Number>\', corresponding supertype is \'List<@Nullable Number>\'\n" + + "Null type mismatch (type annotations): required \'List<@NonNull Number>\' but this expression has type \'@NonNull ArrayList<@Nullable Number>\', corresponding supertype is \'List<@Nullable Number>\'\n" + "----------\n" + "3. ERROR in X.java (at line 10)\n" + " in.add(null); // ERR\n" + @@ -4787,7 +4803,7 @@ public void testDefault01() { "4. ERROR in X.java (at line 11)\n" + " return new ArrayList<java.lang.@Nullable Number>(); // ERR\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'List<@NonNull Number>\' but this expression has type \'ArrayList<@Nullable Number>\', corresponding supertype is \'List<@Nullable Number>\'\n" + + "Null type mismatch (type annotations): required \'List<@NonNull Number>\' but this expression has type \'@NonNull ArrayList<@Nullable Number>\', corresponding supertype is \'List<@Nullable Number>\'\n" + "----------\n"); } @@ -4823,7 +4839,7 @@ public void testDefault01b() { "3. ERROR in X.java (at line 8)\n" + " return new ArrayList<@Nullable T>(); // NOK, cannot assume nullable for T in List<T>\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'List<T>\' but this expression has type \'ArrayList<@Nullable T>\', corresponding supertype is \'List<@Nullable T>\'\n" + + "Null type mismatch (type annotations): required \'List<T>\' but this expression has type \'@NonNull ArrayList<@Nullable T>\', corresponding supertype is \'List<@Nullable T>\'\n" + "----------\n"); } @@ -5129,7 +5145,7 @@ public void testDefault07() { "4. ERROR in X.java (at line 13)\n" + " @NonNull Number nnn = inner.process(Integer.valueOf(3), new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'List<? extends @NonNull Number>\' but this expression has type \'ArrayList<@Nullable Integer>\', corresponding supertype is \'List<@Nullable Integer>\'\n" + + "Null type mismatch (type annotations): required \'List<? extends @NonNull Number>\' but this expression has type \'@NonNull ArrayList<@Nullable Integer>\', corresponding supertype is \'List<@Nullable Integer>\'\n" + "----------\n"); } @@ -5170,7 +5186,7 @@ public void testDefault01_bin() { "1. ERROR in Y.java (at line 5)\n" + " x.test1(new ArrayList<@Nullable Number>()) // ERR at arg\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'List<@NonNull Number>\' but this expression has type \'ArrayList<@Nullable Number>\', corresponding supertype is \'List<@Nullable Number>\'\n" + + "Null type mismatch (type annotations): required \'List<@NonNull Number>\' but this expression has type \'@NonNull ArrayList<@Nullable Number>\', corresponding supertype is \'List<@Nullable Number>\'\n" + "----------\n" + "2. ERROR in Y.java (at line 6)\n" + " .add(null); // ERR\n" + @@ -5410,7 +5426,7 @@ public void testDefault07_bin() { "2. ERROR in Y.java (at line 5)\n" + " @NonNull Number nnn = inner.process(Integer.valueOf(3), new ArrayList<@Nullable Integer>()); // WARN on 1. arg; ERR on 2. arg\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'List<? extends @NonNull Number>\' but this expression has type \'ArrayList<@Nullable Integer>\', corresponding supertype is \'List<@Nullable Integer>\'\n" + + "Null type mismatch (type annotations): required \'List<? extends @NonNull Number>\' but this expression has type \'@NonNull ArrayList<@Nullable Integer>\', corresponding supertype is \'List<@Nullable Integer>\'\n" + "----------\n"); } public void testBug431269() { @@ -6620,7 +6636,12 @@ public void testBug439298_comment3() { "}\n" }, getCompilerOptions(), - ""); + "----------\n" + + "1. INFO in Extract.java (at line 9)\n" + + " return new R<@NonNull A>(null);\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Null type safety (type annotations): The expression of type '@NonNull R<@NonNull A>' needs unchecked conversion to conform to 'R<A>'\n" + + "----------\n"); } public void testBug439298_comment4() { runConformTestWithLibs( @@ -8160,7 +8181,7 @@ public void testBug448709_allocationExpression1() { "1. ERROR in X.java (at line 8)\n" + " return zork(new FI<>());\n" + " ^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'F0<@NonNull String>\' but this expression has type \'FI<@Nullable String>\', corresponding supertype is \'F0<@Nullable String>\'\n" + + "Null type mismatch (type annotations): required \'F0<@NonNull String>\' but this expression has type \'@NonNull FI<@Nullable String>\', corresponding supertype is \'F0<@Nullable String>\'\n" + "----------\n"); } public void testBug448709_allocationExpression2() { @@ -11983,7 +12004,7 @@ public void testBug485988nonnull() { "12. WARNING in nonnull\\WildcardNonNullTest.java (at line 81)\n" + " g(new A<T2>());\n" + " ^^^^^^^^^^^\n" + - "Null type safety (type annotations): The expression of type \'A<T2>\' needs unchecked conversion to conform to \'@NonNull A<@NonNull T2>\'\n" + + "Null type safety (type annotations): The expression of type \'@NonNull A<T2>\' needs unchecked conversion to conform to \'@NonNull A<@NonNull T2>\'\n" + "----------\n" + "13. ERROR in nonnull\\WildcardNonNullTest.java (at line 81)\n" + " g(new A<T2>());\n" + @@ -11998,7 +12019,7 @@ public void testBug485988nonnull() { "15. ERROR in nonnull\\WildcardNonNullTest.java (at line 87)\n" + " g(new A<@Nullable T2>());\n" + " ^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'@NonNull A<@NonNull T2>\' but this expression has type \'A<@Nullable T2>\'\n" + + "Null type mismatch (type annotations): required \'@NonNull A<@NonNull T2>\' but this expression has type \'@NonNull A<@Nullable T2>\'\n" + "----------\n" + "16. ERROR in nonnull\\WildcardNonNullTest.java (at line 87)\n" + " g(new A<@Nullable T2>());\n" + @@ -12162,7 +12183,7 @@ public void testBug485988nullable() { "12. WARNING in nullable\\WildcardNullableTest.java (at line 81)\n" + " g(new A<T2>());\n" + " ^^^^^^^^^^^\n" + - "Null type safety (type annotations): The expression of type \'A<T2>\' needs unchecked conversion to conform to \'@NonNull A<@Nullable T2>\'\n" + + "Null type safety (type annotations): The expression of type \'@NonNull A<T2>\' needs unchecked conversion to conform to \'@NonNull A<@Nullable T2>\'\n" + "----------\n" + "13. ERROR in nullable\\WildcardNullableTest.java (at line 81)\n" + " g(new A<T2>());\n" + @@ -12177,7 +12198,7 @@ public void testBug485988nullable() { "15. ERROR in nullable\\WildcardNullableTest.java (at line 84)\n" + " g(new A<@NonNull T2>());\n" + " ^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'@NonNull A<@Nullable T2>\' but this expression has type \'A<@NonNull T2>\'\n" + + "Null type mismatch (type annotations): required \'@NonNull A<@Nullable T2>\' but this expression has type \'@NonNull A<@NonNull T2>\'\n" + "----------\n" + "16. ERROR in nullable\\WildcardNullableTest.java (at line 84)\n" + " g(new A<@NonNull T2>());\n" + @@ -13378,6 +13399,8 @@ public void testBug502112b() { ); } public void testBug484926locals() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED, JavaCore.IGNORE); runNegativeTestWithLibs( new String[] { "test/NNBDOnLocalOrField.java", @@ -13410,12 +13433,12 @@ public void testBug484926locals() { " }\n" + "}\n" }, - getCompilerOptions(), + options, "----------\n" + "1. ERROR in test\\NNBDOnLocalOrField.java (at line 16)\n" + " AtomicReference<String> x2 = new AtomicReference<@NonNull String>(), x3=new AtomicReference<@Nullable String>();\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'AtomicReference<@NonNull String>\' but this expression has type \'AtomicReference<@Nullable String>\'\n" + + "Null type mismatch (type annotations): required \'AtomicReference<@NonNull String>\' but this expression has type \'@NonNull AtomicReference<@Nullable String>\'\n" + "----------\n" + "2. ERROR in test\\NNBDOnLocalOrField.java (at line 21)\n" + " x1.set(null);\n" + @@ -13435,6 +13458,8 @@ public void testBug484926locals() { ); } public void testBug484926fields() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED, JavaCore.IGNORE); runNegativeTestWithLibs( new String[] { "test/NNBDOnLocalOrField.java", @@ -13467,12 +13492,12 @@ public void testBug484926fields() { " }\n" + "}\n" }, - getCompilerOptions(), + options, "----------\n" + "1. ERROR in test\\NNBDOnLocalOrField.java (at line 15)\n" + " AtomicReference<String> x2 = new AtomicReference<@NonNull String>(), x3=new AtomicReference<@Nullable String>();\n" + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + - "Null type mismatch (type annotations): required \'@NonNull AtomicReference<@NonNull String>\' but this expression has type \'AtomicReference<@Nullable String>\'\n" + + "Null type mismatch (type annotations): required \'@NonNull AtomicReference<@NonNull String>\' but this expression has type \'@NonNull AtomicReference<@Nullable String>\'\n" + "----------\n" + "2. ERROR in test\\NNBDOnLocalOrField.java (at line 21)\n" + " x1.set(null);\n" + @@ -17818,4 +17843,147 @@ public void testBug499714() { "Potential null pointer access: The method get() may return null\n" + "----------\n"); } +public void testBug482242_simple() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED, JavaCore.ERROR); + runNegativeTestWithLibs( + new String[] { + "Test.java", + "import java.util.*;\n" + + "import org.eclipse.jdt.annotation.*;\n" + + "public class Test {\n" + + " static void dangerous(List<String> list) {\n" + + " list.add(null);\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " List<@NonNull String> l = new ArrayList<>();\n" + + " dangerous(l);\n" + + " for (String string : l)\n" + + " System.out.println(string.toLowerCase());\n" + + " }\n" + + "}\n" + }, + options, + "----------\n" + + "1. ERROR in Test.java (at line 9)\n" + + " dangerous(l);\n" + + " ^\n" + + "Null type safety (type annotations): The expression of type \'List<@NonNull String>\' needs unchecked conversion to conform to \'List<String>\'\n" + + "----------\n"); +} +public void testBug482242_intermediate() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED, JavaCore.ERROR); + runNegativeTestWithLibs( + new String[] { + "Test.java", + "import java.util.*;\n" + + "import org.eclipse.jdt.annotation.*;\n" + + "\n" + + "public class Test {\n" + + " public static void main(String[] args) {\n" + + " ArrayList<@NonNull String> list = new ArrayList<>();\n" + + " collect(list, null);\n" + + " for (String s : list)\n" + + " System.out.println(s.toUpperCase());\n" + + " }\n" + + " static void collect(List<@NonNull String> list, String string) {\n" + + " list.add(string); // (1)\n" + + " insert(list, string); // (2)\n" + + " }\n" + + " static void insert(List<? super String> l, String s) {\n" + + " l.add(s);\n" + + " }\n" + + "}\n" + }, + options, + "----------\n" + + "1. WARNING in Test.java (at line 12)\n" + + " list.add(string); // (1)\n" + + " ^^^^^^\n" + + "Null type safety (type annotations): The expression of type \'String\' needs unchecked conversion to conform to \'@NonNull String\'\n" + + "----------\n" + + "2. ERROR in Test.java (at line 13)\n" + + " insert(list, string); // (2)\n" + + " ^^^^\n" + + "Null type safety (type annotations): The expression of type \'List<@NonNull String>\' needs unchecked conversion to conform to \'List<? super String>\'\n" + + "----------\n"); +} +public void testBug482242_annotatedTypeVariable() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED, JavaCore.ERROR); + runNegativeTestWithLibs( + new String[] { + "Test.java", + "import org.eclipse.jdt.annotation.*;\n" + + "\n" + + "interface List<T extends @NonNull Object> {\n" + + " void add(T elem);" + + "}\n" + + "public class Test {\n" + + " public static void test(List<@NonNull String> list) {\n" + + " collect(list, null);\n" + + " }\n" + + " static void collect(List<@NonNull String> list, String string) {\n" + + " insert(list, string);\n" + + " }\n" + + " static void insert(List<? super String> l, String s) {\n" + // type error at declaration site, no need to signal at the call site + " l.add(s);\n" + + " }\n" + + "}\n" + }, + options, + "----------\n" + + "1. ERROR in Test.java (at line 12)\n" + + " static void insert(List<? super String> l, String s) {\n" + + " ^^^^^^^^^^^^^^\n" + + "Null constraint mismatch: The type \'? super String\' is not a valid substitute for the type parameter \'T extends @NonNull Object\'\n" + + "----------\n" + + "2. WARNING in Test.java (at line 13)\n" + + " l.add(s);\n" + + " ^\n" + + "Null type safety (type annotations): The expression of type \'String\' needs unchecked conversion to conform to \'capture#of ? super String\'\n" + + "----------\n"); +} +public void testBug482242_boundedWildcard() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED, JavaCore.ERROR); + runNegativeTestWithLibs( + new String[] { + "Test.java", + "import org.eclipse.jdt.annotation.*;\n" + + "\n" + + "interface List<T extends @NonNull Object> {\n" + + " void add(T elem);" + + "}\n" + + "public class Test {\n" + + " public static void test(List<@NonNull String> list) {\n" + + " collect(list, null);\n" + + " }\n" + + " static void collect(List<@NonNull String> list, String string) {\n" + + " insert(list, string);\n" + + " }\n" + + " static void insert(List<? super @Nullable String> l, String s) {\n" + + " l.add(s);\n" + + " }\n" + + "}\n" + }, + options, + "----------\n" + + "1. ERROR in Test.java (at line 10)\n" + + " insert(list, string);\n" + + " ^^^^\n" + + "Null type mismatch (type annotations): required \'List<? super @Nullable String>\' but this expression has type \'List<@NonNull String>\'\n" + + "----------\n" + + "2. ERROR in Test.java (at line 12)\n" + + " static void insert(List<? super @Nullable String> l, String s) {\n" + + " ^^^^^^^^^^^^^^^^^^^^^^^^\n" + + "Null constraint mismatch: The type \'? super @Nullable String\' is not a valid substitute for the type parameter \'T extends @NonNull Object\'\n" + + "----------\n" + + "3. WARNING in Test.java (at line 13)\n" + + " l.add(s);\n" + + " ^\n" + + "Null type safety (type annotations): The expression of type \'String\' needs unchecked conversion to conform to \'capture#of ? super @Nullable String\'\n" + + "----------\n"); +} } diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java index b205d76307..4970f51c7b 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java @@ -2359,7 +2359,7 @@ public class ExternalAnnotations18Test extends ModifyingResourceTests { } } - @SuppressWarnings("deprecation") + @SuppressWarnings("deprecation") public void testBug508955() throws CoreException, IOException { myCreateJavaProject("TestLibs"); addLibraryWithExternalAnnotations(this.project, "lib1.jar", "annots", @@ -2624,4 +2624,40 @@ public class ExternalAnnotations18Test extends ModifyingResourceTests { CompilationUnit reconciled = cu.reconcile(getJSL9(), true, null, new NullProgressMonitor()); assertNoProblems(reconciled.getProblems()); } + + @SuppressWarnings("deprecation") + public void testBug482242() throws CoreException, IOException { + try { + String projectName = "Bug482242"; + setupJavaProject(projectName, true, true); + this .project.setOption(JavaCore.COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED, JavaCore.WARNING); + addEeaToVariableEntry("JCL18_FULL", "/"+projectName+"/annots"); + IPackageFragment fragment = this.project.getPackageFragmentRoots()[0].createPackageFragment("test1", true, null); + ICompilationUnit unit = fragment.getCompilationUnit("Test.java").getWorkingCopy(new NullProgressMonitor()); + CompilationUnit reconciled = unit.reconcile(AST.JLS8, true, null, new NullProgressMonitor()); + IProblem[] problems = reconciled.getProblems(); + assertProblems(problems, + new String[] { + "Pb(955) Null type safety (type annotations): The expression of type 'Collector<@NonNull String,capture#of ?,Set<@NonNull String>>' " + + "needs unchecked conversion to conform to 'Collector<? super String,Object,Set<@NonNull String>>'", + }, + new int[] {11}, + new int[] { ProblemSeverities.Warning }); + + this.project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null); + IMarker[] markers = this.project.getProject().findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE); + sortMarkers(markers); + assertMarkers("Markers after full build", + "Null type safety (type annotations): The expression of type 'Collector<@NonNull String,capture#of ?,Set<@NonNull String>>' needs unchecked conversion to conform to 'Collector<? super String,Object,Set<@NonNull String>>'", + markers); + int[] severities = new int[] { IMarker.SEVERITY_WARNING }; + for (int i = 0; i < markers.length; i++) { + IMarker marker = markers[i]; + assertEquals("severity of "+marker.getAttribute(IMarker.MESSAGE), + severities[i], marker.getAttribute(IMarker.SEVERITY)); + } + } finally { + deleteProject("Bug500024"); + } + } } diff --git a/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/.classpath b/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/.classpath new file mode 100644 index 0000000000..3dfabed655 --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/.classpath @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="var" path="JCL18_LIB"> + <attributes> + <attribute name="annotationpath" value="annots"/> + </attributes> + </classpathentry> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/.project b/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/.project new file mode 100644 index 0000000000..1cf4df7e7a --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>Bug482242</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/annots/java/util/stream/Stream.eea b/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/annots/java/util/stream/Stream.eea new file mode 100644 index 0000000000..d311f09519 --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/annots/java/util/stream/Stream.eea @@ -0,0 +1,4 @@ +class java/util/stream/Stream +collect + <R:Ljava/lang/Object;A:Ljava/lang/Object;>(Ljava/util/stream/Collector<-TT;TA;TR;>;)TR; + <R:Ljava/lang/Object;A:Ljava/lang/Object;>(Ljava/util/stream/Collector<-TT;TA;TR;>;)T1R; diff --git a/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/src/test1/Test.java b/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/src/test1/Test.java new file mode 100644 index 0000000000..8135abb174 --- /dev/null +++ b/org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/src/test1/Test.java @@ -0,0 +1,19 @@ +package test1; + +import java.util.Collections; +import java.util.Set; +import java.util.stream.Collectors; + +import org.eclipse.jdt.annotation.NonNull; + +public class Test { + static Set<@NonNull String> test1(Set<String> args) { + @NonNull Set<@NonNull String> mapped = args.stream().collect(Collectors.toSet()); + return mapped; + } + public static void main(String[] args) { + Set<String> set = Collections.singleton(null); + for (@NonNull String s : test1(set)) + System.out.println(s.toUpperCase()); + } +} diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java index 3e53caeae7..250daf1f39 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.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 @@ -517,12 +517,13 @@ public TypeBinding resolveType(BlockScope scope) { } if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(this.binding, scope); - if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) { + if (scope.environment().usesNullTypeAnnotations()) { if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) { TypeVariableBinding[] typeVariables = this.binding.original().typeVariables(); for (int i = 0; i < this.typeArguments.length; i++) this.typeArguments[i].checkNullConstraints(scope, (ParameterizedGenericMethodBinding) this.binding, typeVariables, i); } + this.resolvedType = scope.environment().createAnnotatedType(this.resolvedType, new AnnotationBinding[] {scope.environment().getNonNullAnnotation()}); } } if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8 && diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java index bf6658821b..2be11efa14 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013, 2019 GK Software AG and others. + * Copyright (c) 2013, 2020 GK Software AG and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -101,6 +101,8 @@ public class NullAnnotationMatching { LEGACY_WARNING, /** Need unchecked conversion from unannotated to annotated. */ UNCHECKED, + /** Need unchecked conversion to pass type with annotated type arguments into unannotated code. */ + UNCHECKED_TO_UNANNOTATED, /** Definite nullity mismatch. */ MISMATCH; @@ -127,10 +129,11 @@ public class NullAnnotationMatching { this.nullStatus = nullStatus; } - public boolean isAnyMismatch() { return this.severity.isAnyMismatch(); } - public boolean isUnchecked() { return this.severity == Severity.UNCHECKED; } - public boolean isDefiniteMismatch() { return this.severity == Severity.MISMATCH; } - public boolean wantToReport() { return this.severity == Severity.LEGACY_WARNING; } + public boolean isAnyMismatch() { return this.severity.isAnyMismatch(); } + public boolean isUnchecked() { return this.severity == Severity.UNCHECKED || this.severity == Severity.UNCHECKED_TO_UNANNOTATED; } + public boolean isAnnotatedToUnannotated() { return this.severity == Severity.UNCHECKED_TO_UNANNOTATED; } + public boolean isDefiniteMismatch() { return this.severity == Severity.MISMATCH; } + public boolean wantToReport() { return this.severity == Severity.LEGACY_WARNING; } public boolean isPotentiallyNullMismatch() { return !isDefiniteMismatch() && this.nullStatus != -1 && (this.nullStatus & FlowInfo.POTENTIALLY_NULL) != 0; @@ -228,6 +231,7 @@ public class NullAnnotationMatching { try { Severity severity = Severity.OK; TypeBinding superTypeHint = null; + TypeBinding originalRequiredType = requiredType; NullAnnotationMatching okStatus = NullAnnotationMatching.NULL_ANNOTATIONS_OK; if (areSameTypes(requiredType, providedType, providedSubstitute)) { if ((requiredType.tagBits & TagBits.AnnotationNonNull) != 0) @@ -288,7 +292,7 @@ public class NullAnnotationMatching { } else { if (i > 0) currentNullStatus = -1; // don't use beyond the outermost dimension - Severity dimSeverity = computeNullProblemSeverity(requiredBits, providedBits, currentNullStatus, i == 0 ? mode : mode.toDetail(), false); + Severity dimSeverity = computeNullProblemSeverity(requiredBits, providedBits, currentNullStatus, i == 0 ? mode : mode.toDetail(), null); if (i > 0 && dimSeverity == Severity.UNCHECKED && providedExpression instanceof ArrayAllocationExpression && providedBits == 0 && requiredBits != 0) @@ -322,11 +326,14 @@ public class NullAnnotationMatching { // at toplevel (having a nullStatus) nullable matches all } else { long providedBits = providedNullTagBits(providedType); - Severity s = computeNullProblemSeverity(requiredBits, providedBits, nullStatus, mode, requiredType.isTypeVariable()); + Severity s = computeNullProblemSeverity(requiredBits, providedBits, nullStatus, mode, originalRequiredType); if (s.isAnyMismatch() && requiredType.isWildcard() && requiredBits != 0) { if (((WildcardBinding) requiredType).determineNullBitsFromDeclaration(null, null) == 0) { - // wildcard has its nullBits from the type variable: avoid redundant warning. - s = Severity.OK; + TypeVariableBinding typeVariable = ((WildcardBinding) requiredType).typeVariable(); + if ((typeVariable.tagBits & TagBits.AnnotationNullMASK) != 0) { + // wildcard has its nullBits from the type variable + s = Severity.OK; // is already reported as illegal substitution + } } } severity = severity.max(s); @@ -433,6 +440,19 @@ public class NullAnnotationMatching { return validNullTagBits(tagBits); if (type.isWildcard()) { + WildcardBinding wildcardBinding = (WildcardBinding) type; + TypeBinding bound = wildcardBinding.bound; + tagBits = bound != null ? bound.tagBits & TagBits.AnnotationNullMASK : 0; + switch (wildcardBinding.boundKind) { + case Wildcard.SUPER: + if (tagBits == TagBits.AnnotationNullable) + return TagBits.AnnotationNullable; // type cannot require @NonNull + break; + case Wildcard.EXTENDS: + if (tagBits == TagBits.AnnotationNonNull) + return tagBits; + break; + } return TagBits.AnnotationNullMASK; } @@ -544,29 +564,44 @@ public class NullAnnotationMatching { * @param providedBits null tagBits of the provided type * @param nullStatus -1 means: don't use, other values see constants in FlowInfo * @param mode check mode (see {@link CheckMode}) - * @param requiredIsTypeVariable is the required type a type variable (possibly: "free type variable")? + * @param requiredType the required type, used, e.g., to check if it is a type variable (possibly: "free type variable")? * @return see {@link #severity} for interpretation of values */ - private static Severity computeNullProblemSeverity(long requiredBits, long providedBits, int nullStatus, CheckMode mode, boolean requiredIsTypeVariable) { + private static Severity computeNullProblemSeverity(long requiredBits, long providedBits, int nullStatus, CheckMode mode, TypeBinding requiredType) { if (requiredBits == providedBits) return Severity.OK; if (requiredBits == 0) { switch (mode) { + case EXACT: + if (providedBits == TagBits.AnnotationNonNull && !(requiredType instanceof TypeVariableBinding)) + return Severity.UNCHECKED_TO_UNANNOTATED; + return Severity.OK; case COMPATIBLE: case BOUND_CHECK: case BOUND_SUPER_CHECK: - case EXACT: return Severity.OK; case OVERRIDE_RETURN: if (providedBits == TagBits.AnnotationNonNull) return Severity.OK; // covariant redefinition to nonnull is good - if (!requiredIsTypeVariable) + if (!(requiredType instanceof TypeVariableBinding)) return Severity.OK; // refining an unconstrained non-TVB return to nullable is also legal return Severity.UNCHECKED; case OVERRIDE: return Severity.UNCHECKED; // warn about dropped annotation } } else if (requiredBits == TagBits.AnnotationNullMASK) { + if (mode == CheckMode.EXACT && providedBits == TagBits.AnnotationNonNull) { + if (requiredType instanceof WildcardBinding) { + WildcardBinding wildcard = (WildcardBinding) requiredType; + // passing '@NonNull X' into '? super Y' risks pollution with null + if (wildcard.boundKind == Wildcard.SUPER && providedBits == TagBits.AnnotationNonNull) { + TypeBinding bound = wildcard.bound; + if (bound != null && (bound.tagBits & TagBits.AnnotationNullMASK) != 0) + return Severity.OK; // when the wildcard is annotated via its bound, there is not annotated->unannotated conversion + return Severity.UNCHECKED_TO_UNANNOTATED; + } + } + } return Severity.OK; // OK since LHS accepts either } else if (requiredBits == TagBits.AnnotationNonNull) { switch (mode) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java index 2dd1101d27..90d434fc32 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.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 @@ -49,6 +49,7 @@ import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; @@ -305,12 +306,15 @@ public class QualifiedAllocationExpression extends AllocationExpression { final CompilerOptions compilerOptions = scope.compilerOptions(); if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(this.binding, scope); - if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) { + if (scope.environment().usesNullTypeAnnotations()) { if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) { TypeVariableBinding[] typeVariables = this.binding.original().typeVariables(); for (int i = 0; i < this.typeArguments.length; i++) this.typeArguments[i].checkNullConstraints(scope, (ParameterizedGenericMethodBinding) this.binding, typeVariables, i); } + if (this.resolvedType.isValidBinding()) { + this.resolvedType = scope.environment().createAnnotatedType(this.resolvedType, new AnnotationBinding[] {scope.environment().getNonNullAnnotation()}); + } } } if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8 && diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java index d3954dfd37..90008c6e9d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java @@ -194,6 +194,7 @@ public class CompilerOptions { public static final String OPTION_ReportNonnullParameterAnnotationDropped = "org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped"; //$NON-NLS-1$ public static final String OPTION_PessimisticNullAnalysisForFreeTypeVariables = "org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables"; //$NON-NLS-1$ public static final String OPTION_ReportNonNullTypeVariableFromLegacyInvocation = "org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation"; //$NON-NLS-1$ + public static final String OPTION_ReportAnnotatedTypeArgumentToUnannotated = "org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated"; //$NON-NLS-1$ public static final String OPTION_ReportUnlikelyCollectionMethodArgumentType = "org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType"; //$NON-NLS-1$ public static final String OPTION_ReportUnlikelyCollectionMethodArgumentTypeStrict = "org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict"; //$NON-NLS-1$ @@ -347,6 +348,7 @@ public class CompilerOptions { public static final int UnstableAutoModuleName = IrritantSet.GROUP2 | ASTNode.Bit26; public static final int PreviewFeatureUsed = IrritantSet.GROUP2 | ASTNode.Bit27; public static final int SuppressWarningsNotAnalysed = IrritantSet.GROUP2 | ASTNode.Bit28; + public static final int AnnotatedTypeArgumentToUnannotated = IrritantSet.GROUP2 | ASTNode.Bit29; // Severity level for handlers @@ -771,6 +773,8 @@ public class CompilerOptions { return OPTION_PessimisticNullAnalysisForFreeTypeVariables; case NonNullTypeVariableFromLegacyInvocation: return OPTION_ReportNonNullTypeVariableFromLegacyInvocation; + case AnnotatedTypeArgumentToUnannotated: + return OPTION_ReportAnnotatedTypeArgumentToUnannotated; case UnlikelyCollectionMethodArgumentType: return OPTION_ReportUnlikelyCollectionMethodArgumentType; case UnlikelyEqualsArgumentType: @@ -1020,6 +1024,7 @@ public class CompilerOptions { OPTION_ReportUnusedTypeParameter, OPTION_InheritNullAnnotations, OPTION_ReportNonnullParameterAnnotationDropped, + OPTION_ReportAnnotatedTypeArgumentToUnannotated, OPTION_ReportUnlikelyCollectionMethodArgumentType, OPTION_ReportUnlikelyEqualsArgumentType, OPTION_ReportAPILeak, @@ -1101,6 +1106,7 @@ public class CompilerOptions { case NonnullParameterAnnotationDropped: case PessimisticNullAnalysisForFreeTypeVariables: case NonNullTypeVariableFromLegacyInvocation: + case AnnotatedTypeArgumentToUnannotated: return "null"; //$NON-NLS-1$ case FallthroughCase : return "fallthrough"; //$NON-NLS-1$ @@ -1372,6 +1378,7 @@ public class CompilerOptions { optionsMap.put(OPTION_ReportUninternedIdentityComparison, this.complainOnUninternedIdentityComparison ? ENABLED : DISABLED); optionsMap.put(OPTION_PessimisticNullAnalysisForFreeTypeVariables, getSeverityString(PessimisticNullAnalysisForFreeTypeVariables)); optionsMap.put(OPTION_ReportNonNullTypeVariableFromLegacyInvocation, getSeverityString(NonNullTypeVariableFromLegacyInvocation)); + optionsMap.put(OPTION_ReportAnnotatedTypeArgumentToUnannotated, getSeverityString(AnnotatedTypeArgumentToUnannotated)); optionsMap.put(OPTION_ReportUnlikelyCollectionMethodArgumentType, getSeverityString(UnlikelyCollectionMethodArgumentType)); optionsMap.put(OPTION_ReportUnlikelyCollectionMethodArgumentTypeStrict, this.reportUnlikelyCollectionMethodArgumentTypeStrict ? ENABLED : DISABLED); optionsMap.put(OPTION_ReportUnlikelyEqualsArgumentType, getSeverityString(UnlikelyEqualsArgumentType)); @@ -1949,6 +1956,7 @@ public class CompilerOptions { this.inheritNullAnnotations = ENABLED.equals(optionValue); } if ((optionValue = optionsMap.get(OPTION_ReportNonnullParameterAnnotationDropped)) != null) updateSeverity(NonnullParameterAnnotationDropped, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportAnnotatedTypeArgumentToUnannotated)) != null) updateSeverity(AnnotatedTypeArgumentToUnannotated, optionValue); if ((optionValue = optionsMap.get(OPTION_PessimisticNullAnalysisForFreeTypeVariables)) != null) updateSeverity(PessimisticNullAnalysisForFreeTypeVariables, optionValue); if (getSeverity(PessimisticNullAnalysisForFreeTypeVariables) == ProblemSeverities.Ignore) { this.pessimisticNullAnalysisForFreeTypeVariablesEnabled = false; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java index 72ae67a1fc..69c40b762c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java @@ -86,7 +86,8 @@ public class IrritantSet { // group-2 infos enabled by default .set( CompilerOptions.UnlikelyEqualsArgumentType - | CompilerOptions.SuppressWarningsNotAnalysed); + | CompilerOptions.SuppressWarningsNotAnalysed + | CompilerOptions.AnnotatedTypeArgumentToUnannotated); COMPILER_DEFAULT_WARNINGS // group-0 warnings enabled by default @@ -158,7 +159,8 @@ public class IrritantSet { .set(CompilerOptions.NonnullParameterAnnotationDropped) .set(CompilerOptions.MissingNonNullByDefaultAnnotation) .set(CompilerOptions.PessimisticNullAnalysisForFreeTypeVariables) - .set(CompilerOptions.NonNullTypeVariableFromLegacyInvocation); + .set(CompilerOptions.NonNullTypeVariableFromLegacyInvocation) + .set(CompilerOptions.AnnotatedTypeArgumentToUnannotated); RESTRICTION.set(CompilerOptions.DiscouragedReference); STATIC_ACCESS.set(CompilerOptions.NonStaticAccessToStatic); 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 6932f0aa86..3021f41f8c 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 @@ -10592,6 +10592,12 @@ public void arrayReferencePotentialNullReference(ArrayReference arrayReference) public void nullityMismatchingTypeAnnotation(Expression expression, TypeBinding providedType, TypeBinding requiredType, NullAnnotationMatching status) { if (providedType == requiredType) return; //$IDENTITY-COMPARISON$ + int severity = -1; + if (status.isAnnotatedToUnannotated()) { + severity = this.options.getSeverity(CompilerOptions.AnnotatedTypeArgumentToUnannotated); + if (severity == ProblemSeverities.Ignore) + return; + } // try to improve nonnull vs. null: if (providedType.id == TypeIds.T_null || status.nullStatus == FlowInfo.NULL) { nullityMismatchIsNull(expression, requiredType); @@ -10655,7 +10661,9 @@ public void nullityMismatchingTypeAnnotation(Expression expression, TypeBinding arguments = new String[] { requiredName, providedName }; shortArguments = new String[] { requiredNameShort, providedNameShort }; } - this.handle(problemId, arguments, shortArguments, expression.sourceStart, expression.sourceEnd); + if (severity == -1) + severity = computeSeverity(problemId); + this.handle(problemId, arguments, shortArguments, severity, expression.sourceStart, expression.sourceEnd); } public void nullityMismatchTypeArgument(TypeBinding typeVariable, TypeBinding typeArgument, ASTNode location) { diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java index 3b56560176..dc32bf4bb6 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java @@ -2070,7 +2070,22 @@ public final class JavaCore extends Plugin { * @category CompilerOptionID */ public static final String COMPILER_PB_NONNULL_TYPEVAR_FROM_LEGACY_INVOCATION = JavaCore.PLUGIN_ID+".compiler.problem.nonnullTypeVariableFromLegacyInvocation"; //$NON-NLS-1$ - + /** + * Compiler option ID: Reporting Unsafe Conversion To Unannotated Type Argument. + * <p>When enabled, the compiler will issue an error, warning or info when a value of a parameterized type + * with annotated type arguments is assigned to a variable / bound to a method argument, where the corresponding + * type argument is unannotated.</p> + * <p>This situation is problematic because it will enable using the less-annotated type to manipulate the given + * objects in ways that may violate contracts of the more-annotated type.</p> + * <dl> + * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated"</code></dd> + * <dt>Possible values:</dt><dd><code>{ "error", "warning", "info", "ignore" }</code></dd> + * <dt>Default:</dt><dd><code>"info"</code></dd> + * </dl> + * @since 3.21 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED = JavaCore.PLUGIN_ID+".compiler.problem.annotatedTypeArgumentToUnannotated"; //$NON-NLS-1$ /** * Compiler option ID: Setting Source Compatibility Mode. * <p>Specify whether which source level compatibility is used. From 1.4 on, <code>'assert'</code> is a keyword |