Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2020-01-02 17:54:14 +0000
committerStephan Herrmann2020-01-26 14:21:23 +0000
commit26442c4da93bb37c148503ede232875b5244e58f (patch)
tree2eeec740f70b9bfb24237cc062a679b66a1b2184
parent7524d911155feb0decf44ddadea1a9585a4e3a97 (diff)
downloadeclipse.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
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java5
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java4
-rw-r--r--org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java228
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java38
-rw-r--r--org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/.classpath10
-rw-r--r--org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/.project17
-rw-r--r--org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/annots/java/util/stream/Stream.eea4
-rw-r--r--org.eclipse.jdt.core.tests.model/workspace/ExternalAnnotations18/Bug482242/src/test1/Test.java19
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java5
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java61
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java10
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java17
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

Back to the top