Update to a8944173670c6319cce2438add6b3e87f478a46c from jdt.core
- includes fixing some patch-mistakes
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
index 4fde541..78a3e35 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
@@ -23,6 +23,7 @@
* bug 382353 - [1.8][compiler] Implementation property modifiers should be accepted on default methods.
* bug 382347 - [1.8][compiler] Compiler accepts incorrect default method inheritance
* bug 388281 - [compiler][null] inheritance of null annotations as an option
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.core.tests.compiler.regression;
@@ -371,6 +372,7 @@
expectedProblemAttributes.put("ArgumentTypeNotFound", DEPRECATED);
expectedProblemAttributes.put("ArgumentTypeNotVisible", DEPRECATED);
expectedProblemAttributes.put("ArrayConstantsOnlyInArrayInitializers", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
+ expectedProblemAttributes.put("ArrayReferencePotentialNullReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("ArrayReferenceRequired", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
expectedProblemAttributes.put("AssignmentHasNoEffect", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("AssignmentToMultiCatchParameter", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
@@ -422,6 +424,7 @@
expectedProblemAttributes.put("DeadCode", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("DefaultMethodNotBelow18", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
expectedProblemAttributes.put("DefaultMethodOverridesObjectMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
+ expectedProblemAttributes.put("DereferencingNullableExpression", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("DiamondNotBelow17", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("DirectInvocationOfAbstractMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
expectedProblemAttributes.put("DisallowedTargetForAnnotation", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
@@ -780,6 +783,8 @@
expectedProblemAttributes.put("NullLocalVariableComparisonYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("NullLocalVariableInstanceofYieldsFalse", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("NullLocalVariableReference", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
+ expectedProblemAttributes.put("NullityMismatchingTypeAnnotation", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
+ expectedProblemAttributes.put("NullityMismatchingTypeAnnotationUnchecked", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("NullSourceString", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
expectedProblemAttributes.put("NumericValueOutOfRange", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
expectedProblemAttributes.put("ObjectCannotBeGeneric", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
@@ -1182,6 +1187,7 @@
expectedProblemAttributes.put("ArgumentTypeNotFound", SKIP);
expectedProblemAttributes.put("ArgumentTypeNotVisible", SKIP);
expectedProblemAttributes.put("ArrayConstantsOnlyInArrayInitializers", SKIP);
+ expectedProblemAttributes.put("ArrayReferencePotentialNullReference", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE));
expectedProblemAttributes.put("ArrayReferenceRequired", SKIP);
expectedProblemAttributes.put("AssignmentHasNoEffect", new ProblemAttributes(JavaCore.COMPILER_PB_NO_EFFECT_ASSIGNMENT));
expectedProblemAttributes.put("AssignmentToMultiCatchParameter", SKIP);
@@ -1233,6 +1239,7 @@
expectedProblemAttributes.put("DeadCode", new ProblemAttributes(JavaCore.COMPILER_PB_DEAD_CODE));
expectedProblemAttributes.put("DefaultMethodNotBelow18", SKIP);
expectedProblemAttributes.put("DefaultMethodOverridesObjectMethod", SKIP);
+ expectedProblemAttributes.put("DereferencingNullableExpression", new ProblemAttributes(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE));
expectedProblemAttributes.put("DiamondNotBelow17", SKIP);
expectedProblemAttributes.put("DirectInvocationOfAbstractMethod", SKIP);
expectedProblemAttributes.put("DisallowedTargetForAnnotation", SKIP);
@@ -1588,6 +1595,8 @@
expectedProblemAttributes.put("NotVisibleField", SKIP);
expectedProblemAttributes.put("NotVisibleMethod", SKIP);
expectedProblemAttributes.put("NotVisibleType", SKIP);
+ expectedProblemAttributes.put("NullityMismatchingTypeAnnotation", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION));
+ expectedProblemAttributes.put("NullityMismatchingTypeAnnotationUnchecked", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_UNCHECKED_CONVERSION));
expectedProblemAttributes.put("NullLocalVariableComparisonYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("NullLocalVariableInstanceofYieldsFalse", new ProblemAttributes(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK));
expectedProblemAttributes.put("NullLocalVariableReference", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_REFERENCE));
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GrammarCoverageTests308.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GrammarCoverageTests308.java
index 39cb314..a7c87e0 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GrammarCoverageTests308.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GrammarCoverageTests308.java
@@ -1482,24 +1482,24 @@
"----------\n" +
"4. ERROR in X.java (at line 4)\n" +
" Object q = (@Marker java. @Marker util. @Marker List<@Marker String> []) null;\n" +
+ " ^^^^^^^\n" +
+ "Syntax error, type annotations are illegal here\n" +
+ "----------\n" +
+ "5. ERROR in X.java (at line 4)\n" +
+ " Object q = (@Marker java. @Marker util. @Marker List<@Marker String> []) null;\n" +
" ^^^^^^\n" +
"Marker cannot be resolved to a type\n" +
"----------\n" +
- "5. ERROR in X.java (at line 4)\n" +
+ "6. ERROR in X.java (at line 4)\n" +
" Object q = (@Marker java. @Marker util. @Marker List<@Marker String> []) null;\n" +
" ^^^^^^^\n" +
"Syntax error, type annotations are illegal here\n" +
"----------\n" +
- "6. ERROR in X.java (at line 4)\n" +
+ "7. ERROR in X.java (at line 4)\n" +
" Object q = (@Marker java. @Marker util. @Marker List<@Marker String> []) null;\n" +
" ^^^^^^\n" +
"Marker cannot be resolved to a type\n" +
"----------\n" +
- "7. ERROR in X.java (at line 4)\n" +
- " Object q = (@Marker java. @Marker util. @Marker List<@Marker String> []) null;\n" +
- " ^^^^^^^\n" +
- "Syntax error, type annotations are illegal here\n" +
- "----------\n" +
"8. ERROR in X.java (at line 4)\n" +
" Object q = (@Marker java. @Marker util. @Marker List<@Marker String> []) null;\n" +
" ^^^^^^\n" +
@@ -1513,7 +1513,7 @@
"10. ERROR in X.java (at line 5)\n" +
" Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" +
" ^^^^^^^\n" +
- "Type annotations are not allowed on type names used to access static members\n" +
+ "Syntax error, type annotations are illegal here\n" +
"----------\n" +
"11. ERROR in X.java (at line 5)\n" +
" Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" +
@@ -1535,10 +1535,10 @@
" ^^^^^^\n" +
"Marker cannot be resolved to a type\n" +
"----------\n" +
- "15. ERROR in X.java (at line 5)\n" +
- " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" +
- " ^^^^^^^\n" +
- "Syntax error, type annotations are illegal here\n" +
+ "15. ERROR in X.java (at line 5)\n" +
+ " Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" +
+ " ^^^^^^^\n" +
+ "Type annotations are not allowed on type names used to access static members\n" +
"----------\n" +
"16. ERROR in X.java (at line 5)\n" +
" Object r = (@Marker java. @Marker util.@Marker Map<@Marker String, @Marker String>.@Marker Entry @Marker []) null;\n" +
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java
index 7452605..283bac7 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NegativeTypeAnnotationTest.java
@@ -2350,7 +2350,7 @@
"public class X { \n " +
" Object o1 = (@Marker java.lang.Integer) null; // 1. Right.\n" +
" Object o2 = (java. @Marker lang.Integer) null; // 2. Wrong.\n" +
- " Object o3 = (java.lang. @Marker Integer) null; // 3. Wrong.\n" +
+ " Object o3 = (java.lang. @Marker Integer) null; // 3. Legal.\n" +
" public void foo(java. @Marker lang.Integer arg) {}\n" +
" public void bar(java.lang. @Marker Integer arg) {}\n" +
" public void foobar(@Marker java.lang.Integer arg) {}\n" +
@@ -2374,25 +2374,20 @@
"}\n"
},
"----------\n" +
- "1. ERROR in X.java (at line 5)\n" +
- " Object o2 = (java. @Marker lang.Integer) null; // 2. Wrong.\n" +
- " ^^^^^^^\n" +
+ "1. ERROR in X.java (at line 4)\n" +
+ " Object o1 = (@Marker java.lang.Integer) null; // 1. Right.\n" +
+ " ^^^^^^^\n" +
"Syntax error, type annotations are illegal here\n" +
"----------\n" +
- "2. ERROR in X.java (at line 6)\n" +
- " Object o3 = (java.lang. @Marker Integer) null; // 3. Wrong.\n" +
- " ^^^^^^^\n" +
+ "2. ERROR in X.java (at line 5)\n" +
+ " Object o2 = (java. @Marker lang.Integer) null; // 2. Wrong.\n" +
+ " ^^^^^^^\n" +
"Syntax error, type annotations are illegal here\n" +
"----------\n" +
"3. ERROR in X.java (at line 7)\n" +
" public void foo(java. @Marker lang.Integer arg) {}\n" +
" ^^^^^^^\n" +
"Syntax error, type annotations are illegal here\n" +
- "----------\n" +
- "4. ERROR in X.java (at line 8)\n" +
- " public void bar(java.lang. @Marker Integer arg) {}\n" +
- " ^^^^^^^\n" +
- "Syntax error, type annotations are illegal here\n" +
"----------\n");
}
public void test0390882a() {
@@ -2402,8 +2397,8 @@
"import java.lang.annotation.Target;\n" +
"import static java.lang.annotation.ElementType.*;\n" +
"public class X { \n " +
- " Object o1 = (java. @Marker @Annot lang.Integer) null; // 2. Wrong.\n" +
- " Object o2 = (java.lang. @Marker @Annot Integer) null; // 3. Wrong.\n" +
+ " Object o1 = (java. @Marker @Annot lang.Integer) null; // 1. Wrong.\n" +
+ " Object o2 = (java.lang. @Marker @Annot Integer) null; // 2. Legal\n" +
" Object o3 = (java.@lang lang) null; // 3. Wrong.\n" +
"}\n" +
"@Target(TYPE_USE)\n" +
@@ -2428,16 +2423,11 @@
},
"----------\n" +
"1. ERROR in X.java (at line 4)\n" +
- " Object o1 = (java. @Marker @Annot lang.Integer) null; // 2. Wrong.\n" +
+ " Object o1 = (java. @Marker @Annot lang.Integer) null; // 1. Wrong.\n" +
" ^^^^^^^^^^^^^^\n" +
"Syntax error, type annotations are illegal here\n" +
"----------\n" +
- "2. ERROR in X.java (at line 5)\n" +
- " Object o2 = (java.lang. @Marker @Annot Integer) null; // 3. Wrong.\n" +
- " ^^^^^^^^^^^^^^\n" +
- "Syntax error, type annotations are illegal here\n" +
- "----------\n" +
- "3. ERROR in X.java (at line 6)\n" +
+ "2. ERROR in X.java (at line 6)\n" +
" Object o3 = (java.@lang lang) null; // 3. Wrong.\n" +
" ^^^^^^^^^^^^^^^\n" +
"java.lang cannot be resolved to a type\n" +
@@ -2450,10 +2440,11 @@
"import java.lang.annotation.Target;\n" +
"import static java.lang.annotation.ElementType.*;\n" +
"public class X { \n " +
- " Object o1 = (java.util.@Marker @Annot List<String>) null; // 1. Wrong.\n" +
- " Object o2 = (java.lang.@Marker @Annot Integer[]) null; // 2. Wrong.\n" +
- " Object o3 = (java.util.@Marker @Annot List<String>[]) null; // 3. Wrong.\n" +
- " Object o4 = (java.lang.Integer @Marker []) null; // 4. Right.\n" +
+ " Object o1 = (@Marker @Annot java.util.List<String>) null; // 1. Wrong.\n" +
+ " Object o2 = (java. @Marker @Annot lang.Integer[]) null; // 2. Wrong.\n" +
+ " Object o3 = (@Marker @Annot java.util.List<String>[]) null; // 3. Wrong.\n" +
+ " Object o4 = (java.util.List<String> @Marker @Annot []) null; // 4. Right.\n" +
+ " Object o5 = (java.lang.Integer @Marker @Annot []) null; // 5. Right.\n" +
"}\n" +
"@Target(TYPE_USE)\n" +
"@interface Marker {}\n" +
@@ -2477,18 +2468,18 @@
},
"----------\n" +
"1. ERROR in X.java (at line 4)\n" +
- " Object o1 = (java.util.@Marker @Annot List<String>) null; // 1. Wrong.\n" +
- " ^^^^^^^^^^^^^^\n" +
+ " Object o1 = (@Marker @Annot java.util.List<String>) null; // 1. Wrong.\n" +
+ " ^^^^^^^^^^^^^^\n" +
"Syntax error, type annotations are illegal here\n" +
"----------\n" +
"2. ERROR in X.java (at line 5)\n" +
- " Object o2 = (java.lang.@Marker @Annot Integer[]) null; // 2. Wrong.\n" +
- " ^^^^^^^^^^^^^^\n" +
+ " Object o2 = (java. @Marker @Annot lang.Integer[]) null; // 2. Wrong.\n" +
+ " ^^^^^^^^^^^^^^\n" +
"Syntax error, type annotations are illegal here\n" +
"----------\n" +
"3. ERROR in X.java (at line 6)\n" +
- " Object o3 = (java.util.@Marker @Annot List<String>[]) null; // 3. Wrong.\n" +
- " ^^^^^^^^^^^^^^\n" +
+ " Object o3 = (@Marker @Annot java.util.List<String>[]) null; // 3. Wrong.\n" +
+ " ^^^^^^^^^^^^^^\n" +
"Syntax error, type annotations are illegal here\n" +
"----------\n");
}
@@ -2547,7 +2538,7 @@
"4. ERROR in A.java (at line 7)\n" +
" Object o2 = (@Marker p.@Marker A.@Marker B.@Marker C) null;\n" +
" ^^^^^^^\n" +
- "Type annotations are not allowed on type names used to access static members\n" +
+ "Syntax error, type annotations are illegal here\n" +
"----------\n" +
"5. WARNING in A.java (at line 7)\n" +
" Object o2 = (@Marker p.@Marker A.@Marker B.@Marker C) null;\n" +
@@ -2557,7 +2548,7 @@
"6. ERROR in A.java (at line 7)\n" +
" Object o2 = (@Marker p.@Marker A.@Marker B.@Marker C) null;\n" +
" ^^^^^^^\n" +
- "Syntax error, type annotations are illegal here\n" +
+ "Type annotations are not allowed on type names used to access static members\n" +
"----------\n" +
"7. ERROR in A.java (at line 7)\n" +
" Object o2 = (@Marker p.@Marker A.@Marker B.@Marker C) null;\n" +
@@ -2606,12 +2597,12 @@
"1. ERROR in A.java (at line 6)\n" +
" Object o1 = (@Marker p.@Marker A.@Marker B.@Marker C[]) null;\n" +
" ^^^^^^^\n" +
- "Type annotations are not allowed on type names used to access static members\n" +
+ "Syntax error, type annotations are illegal here\n" +
"----------\n" +
"2. ERROR in A.java (at line 6)\n" +
" Object o1 = (@Marker p.@Marker A.@Marker B.@Marker C[]) null;\n" +
" ^^^^^^^\n" +
- "Syntax error, type annotations are illegal here\n" +
+ "Type annotations are not allowed on type names used to access static members\n" +
"----------\n" +
"3. ERROR in A.java (at line 6)\n" +
" Object o1 = (@Marker p.@Marker A.@Marker B.@Marker C[]) null;\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 4d40987..030d647 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
@@ -84,7 +84,7 @@
" System.out.print(l.get(0).toString()); // problem: retrieved element can be null\n" +
" l.add(null);\n" +
" }\n" +
- " void bar(java.util.List<@Nullable java.lang.Object> l) {\n" +
+ " void bar(java.util.List<@Nullable Object> l) {\n" +
" System.out.print(l.get(1).toString()); // problem: retrieved element can be null\n" +
" l.add(null);\n" +
" }\n" +
@@ -133,7 +133,7 @@
" System.out.print(l.get(0).toString()); // problem: retrieved element can be null\n" +
" l.add(null);\n" +
" }\n" +
- " void bar(java.util.List<@Dummy @Nullable java.lang.Object> l) {\n" +
+ " void bar(java.util.List<@Dummy @Nullable Object> l) {\n" +
" System.out.print(l.get(1).toString()); // problem: retrieved element can be null\n" +
" l.add(null);\n" +
" }\n" +
@@ -175,7 +175,7 @@
" System.out.print(l.get(0).toString()); // problem: l may be null\n" +
" l.add(null); // problem: cannot insert 'null' into this list\n" +
" }\n" +
- " void bar(@Nullable java.util.List<@NonNull java.lang.Object> l) {\n" +
+ " void bar(@Nullable List<@NonNull Object> l) {\n" +
" System.out.print(l.get(0).toString()); // problem: l may be null\n" +
" l.add(0, null); // problem: cannot insert 'null' into this list\n" +
" }\n" +
@@ -376,7 +376,7 @@
"1. ERROR in B.java (at line 4)\n" +
" ai.foo(null); // problems: ai can be null, arg must not be null\n" +
" ^^\n" +
- "Potential null pointer access: The variable ai may be null at this location\n" +
+ "Potential null pointer access: this expression has a '@Nullable' type\n" +
"----------\n" +
"2. ERROR in B.java (at line 4)\n" +
" ai.foo(null); // problems: ai can be null, arg must not be null\n" +
@@ -409,4 +409,394 @@
"Missing2 cannot be resolved to a type\n" +
"----------\n");
}
+
+ // bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
+ // annotation on leaf type in 1-dim array
+ public void testArrayType_01() {
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_NULLABLE_ANNOTATION_NAME, "org.foo.Nullable");
+ customOptions.put(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "org.foo.NonNull");
+ runNegativeTest(
+ new String[] {
+ ELEMENT_TYPE_JAVA,
+ ELEMENT_TYPE_SOURCE,
+ CUSTOM_NULLABLE_NAME,
+ CUSTOM_NULLABLE_CONTENT_JSR308,
+ CUSTOM_NONNULL_NAME,
+ CUSTOM_NONNULL_CONTENT_JSR308,
+ "Wrapper.java",
+ "public class Wrapper<T> {\n" +
+ " T content;" +
+ " public T content() { return content; }\n" +
+ "}\n",
+ "A.java",
+ "import org.foo.*;\n" +
+ "public class A {\n" +
+// Using Wrapper is a workaround until bug 391331 is fixed (to force the interesting annotation to be consumed as a type annotation):
+ " void bar(Wrapper<@NonNull String[]> realStrings, Wrapper<@Nullable String[]> maybeStrings) {\n" +
+ " System.out.println(realStrings.content()[0].toUpperCase()); // no problem\n" +
+ " realStrings.content()[0] = null; // problem: cannot assign null as @NonNull element\n" +
+ " System.out.println(maybeStrings.content()[0].toUpperCase()); // problem: element can be null\n" +
+ " maybeStrings.content()[0] = null; // no problem\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in A.java (at line 5)\n" +
+ " realStrings.content()[0] = null; // problem: cannot assign null as @NonNull element\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Null type mismatch: required \'@NonNull String\' but the provided value is null\n" +
+ "----------\n" +
+ "2. ERROR in A.java (at line 6)\n" +
+ " System.out.println(maybeStrings.content()[0].toUpperCase()); // problem: element can be null\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Potential null pointer access: array element may be null\n" +
+ "----------\n",
+ null,
+ true, /* shouldFlush*/
+ customOptions);
+ }
+
+ // bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
+ // annotation on leaf type in 2-dim array
+ public void testArrayType_02() {
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_NULLABLE_ANNOTATION_NAME, "org.foo.Nullable");
+ customOptions.put(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "org.foo.NonNull");
+ runNegativeTest(
+ new String[] {
+ ELEMENT_TYPE_JAVA,
+ ELEMENT_TYPE_SOURCE,
+ CUSTOM_NULLABLE_NAME,
+ CUSTOM_NULLABLE_CONTENT_JSR308,
+ CUSTOM_NONNULL_NAME,
+ CUSTOM_NONNULL_CONTENT_JSR308,
+ "Wrapper.java",
+ "public class Wrapper<T> {\n" +
+ " T content;" +
+ " public T content() { return content; }\n" +
+ "}\n",
+ "A.java",
+ "import org.foo.*;\n" +
+ "public class A {\n" +
+// Using Wrapper is a workaround until bug 391331 is fixed (to force the interesting annotation to be consumed as a type annotation):
+ " void bar(Wrapper<@NonNull String[][]> realStrings, Wrapper<@Nullable String[][]> maybeStrings) {\n" +
+ " System.out.println(realStrings.content()[0][0].toUpperCase()); // no problem\n" +
+ " realStrings.content()[0][0] = null; // problem: cannot assign null as @NonNull element\n" +
+ " System.out.println(maybeStrings.content()[0][0].toUpperCase()); // problem: element can be null\n" +
+ " maybeStrings.content()[0][0] = null; // no problem\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in A.java (at line 5)\n" +
+ " realStrings.content()[0][0] = null; // problem: cannot assign null as @NonNull element\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Null type mismatch: required \'@NonNull String\' but the provided value is null\n" +
+ "----------\n" +
+ "2. ERROR in A.java (at line 6)\n" +
+ " System.out.println(maybeStrings.content()[0][0].toUpperCase()); // problem: element can be null\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Potential null pointer access: array element may be null\n" +
+ "----------\n",
+ null,
+ true, /* shouldFlush*/
+ customOptions);
+ }
+
+ // bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
+ // annotation on array type (1-dim array)
+ public void testArrayType_03() {
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_NULLABLE_ANNOTATION_NAME, "org.foo.Nullable");
+ customOptions.put(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "org.foo.NonNull");
+ runNegativeTest(
+ new String[] {
+ ELEMENT_TYPE_JAVA,
+ ELEMENT_TYPE_SOURCE,
+ CUSTOM_NULLABLE_NAME,
+ CUSTOM_NULLABLE_CONTENT_JSR308,
+ CUSTOM_NONNULL_NAME,
+ CUSTOM_NONNULL_CONTENT_JSR308,
+ "A.java",
+ "import org.foo.*;\n" +
+ "public class A {\n" +
+ " void array(String @NonNull[] realStringArray, String @Nullable[] maybeStringArray) {\n" +
+ " @NonNull Object array;\n" +
+ " array = realStringArray; // no problem\n" +
+ " realStringArray = null; // problem: cannot assign null as @NonNull array\n" +
+ " array = maybeStringArray; // problem: array can be null\n" +
+ " maybeStringArray = null; // no problem\n" +
+ " }\n" +
+ " void leaf(String @NonNull[] realStringArray, String @Nullable[] maybeStringArray) {\n" +
+ " @NonNull String string;\n" +
+ " string = realStringArray[0]; // problem: unchecked conversion\n" +
+ " realStringArray[0] = null; // no problem\n" +
+ " string = maybeStringArray[0]; // problems: indexing nullable array & unchecked conversion\n" +
+ " maybeStringArray[0] = null; // problem: indexing nullable array\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in A.java (at line 7)\n" +
+ " array = maybeStringArray; // problem: array can be null\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "Null type mismatch: required \'@NonNull Object\' but the provided value is inferred as @Nullable\n" +
+ "----------\n" +
+ "2. WARNING in A.java (at line 12)\n" +
+ " string = realStringArray[0]; // problem: unchecked conversion\n" +
+ " ^^^^^^^^^^^^^^^^^^\n" +
+ "Null type safety: The expression of type String needs unchecked conversion to conform to \'@NonNull String\'\n" +
+ "----------\n" +
+ "3. ERROR in A.java (at line 14)\n" +
+ " string = maybeStringArray[0]; // problems: indexing nullable array & unchecked conversion\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "Potential null pointer access: this expression has a '@Nullable' type\n" +
+ "----------\n" +
+ "4. WARNING in A.java (at line 14)\n" +
+ " string = maybeStringArray[0]; // problems: indexing nullable array & unchecked conversion\n" +
+ " ^^^^^^^^^^^^^^^^^^^\n" +
+ "Null type safety: The expression of type String needs unchecked conversion to conform to \'@NonNull String\'\n" +
+ "----------\n" +
+ "5. ERROR in A.java (at line 15)\n" +
+ " maybeStringArray[0] = null; // problem: indexing nullable array\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "Potential null pointer access: this expression has a '@Nullable' type\n" +
+ "----------\n",
+ null,
+ true, /* shouldFlush*/
+ customOptions);
+ }
+
+ // bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
+ // annotation on intermediate type in 2-dim array
+ public void testArrayType_04() {
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_NULLABLE_ANNOTATION_NAME, "org.foo.Nullable");
+ customOptions.put(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "org.foo.NonNull");
+ runNegativeTest(
+ new String[] {
+ ELEMENT_TYPE_JAVA,
+ ELEMENT_TYPE_SOURCE,
+ CUSTOM_NULLABLE_NAME,
+ CUSTOM_NULLABLE_CONTENT_JSR308,
+ CUSTOM_NONNULL_NAME,
+ CUSTOM_NONNULL_CONTENT_JSR308,
+ "A.java",
+ "import org.foo.*;\n" +
+ "public class A {\n" +
+ " void outer(String [] @NonNull[] realArrays, String [] @Nullable[] maybeArrays) {\n" +
+ " @NonNull Object array;\n" +
+ " array = realArrays; // problem: unchecked conversion\n" +
+ " realArrays = null; // no problem, outer array is unspecified\n" +
+ " array = maybeArrays; // problem: unchecked conversion\n" +
+ " maybeArrays = null; // no problem\n" +
+ " }\n" +
+ " void inner(String [] @NonNull[] realArrays, String [] @Nullable[] maybeArrays) {\n" +
+ " @NonNull Object array;\n" +
+ " array = realArrays[0]; // no problem\n" +
+ " realArrays[0] = null; // problem: cannot assign null to @NonNull array\n" +
+ " array = maybeArrays[0]; // problem: element can be null\n" +
+ " maybeArrays[0] = null; // no problem\n" +
+ " }\n" +
+ " void leaf(String [] @NonNull[] realArrays, String [] @Nullable[] maybeArrays) {\n" +
+ " @NonNull Object array;\n" +
+ " array = realArrays[0][0]; // problem: unchecked conversion\n" +
+ " realArrays[0][0] = null; // no problem, element type is unspecified\n" +
+ " array = maybeArrays[0][0]; // problems: indexing nullable array & unchecked conversion\n" +
+ " maybeArrays[0][0] = null; // problem: indexing nullable array\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. WARNING in A.java (at line 5)\n" +
+ " array = realArrays; // problem: unchecked conversion\n" +
+ " ^^^^^^^^^^\n" +
+ "Null type safety: The expression of type String[][] needs unchecked conversion to conform to \'@NonNull Object\'\n" +
+ "----------\n" +
+ "2. WARNING in A.java (at line 7)\n" +
+ " array = maybeArrays; // problem: unchecked conversion\n" +
+ " ^^^^^^^^^^^\n" +
+ "Null type safety: The expression of type String[][] needs unchecked conversion to conform to \'@NonNull Object\'\n" +
+ "----------\n" +
+ "3. ERROR in A.java (at line 13)\n" +
+ " realArrays[0] = null; // problem: cannot assign null to @NonNull array\n" +
+ " ^^^^^^^^^^^^^\n" +
+ "Null type mismatch: required \'String @NonNull[]\' but the provided value is null\n" +
+ "----------\n" +
+ "4. ERROR in A.java (at line 14)\n" +
+ " array = maybeArrays[0]; // problem: element can be null\n" +
+ " ^^^^^^^^^^^^^^\n" +
+ "Null type mismatch: required '@NonNull Object' but the provided value is inferred as @Nullable\n" +
+ "----------\n" +
+ "5. WARNING in A.java (at line 19)\n" +
+ " array = realArrays[0][0]; // problem: unchecked conversion\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "Null type safety: The expression of type String needs unchecked conversion to conform to \'@NonNull Object\'\n" +
+ "----------\n" +
+ "6. ERROR in A.java (at line 21)\n" +
+ " array = maybeArrays[0][0]; // problems: indexing nullable array & unchecked conversion\n" +
+ " ^^^^^^^^^^^^^^\n" +
+ "Potential null pointer access: array element may be null\n" +
+ "----------\n" +
+ "7. WARNING in A.java (at line 21)\n" +
+ " array = maybeArrays[0][0]; // problems: indexing nullable array & unchecked conversion\n" +
+ " ^^^^^^^^^^^^^^^^^\n" +
+ "Null type safety: The expression of type String needs unchecked conversion to conform to \'@NonNull Object\'\n" +
+ "----------\n" +
+ "8. ERROR in A.java (at line 22)\n" +
+ " maybeArrays[0][0] = null; // problem: indexing nullable array\n" +
+ " ^^^^^^^^^^^^^^\n" +
+ "Potential null pointer access: array element may be null\n" +
+ "----------\n",
+ null,
+ true, /* shouldFlush*/
+ customOptions);
+ }
+
+ // bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
+ // mismatches against outer array type, test display of type annotation in error messages
+ public void testArrayType_05() {
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_NULLABLE_ANNOTATION_NAME, "org.foo.Nullable");
+ customOptions.put(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "org.foo.NonNull");
+ runNegativeTest(
+ new String[] {
+ ELEMENT_TYPE_JAVA,
+ ELEMENT_TYPE_SOURCE,
+ CUSTOM_NULLABLE_NAME,
+ CUSTOM_NULLABLE_CONTENT_JSR308,
+ CUSTOM_NONNULL_NAME,
+ CUSTOM_NONNULL_CONTENT_JSR308,
+ "A.java",
+ "import org.foo.*;\n" +
+ "public class A {\n" +
+ " void outer(String @NonNull[] @NonNull[] realArrays, String @NonNull[] @Nullable[] maybeArrays, String @Nullable[][] unknownArrays) {\n" +
+ " realArrays[0] = maybeArrays[0]; // problem: inner array can be null\n" +
+ " realArrays[0] = unknownArrays[0]; // problems: inner array is unspecified, outer can be null\n" +
+ " }\n" +
+ " void oneDim(String @Nullable[] maybeStrings, String[] unknownStrings) {\n" +
+ " String @NonNull[] s = maybeStrings;\n" +
+ " s = unknownStrings;\n" +
+ " consume(maybeStrings);\n" +
+ " consume(unknownStrings);\n" +
+ " }\n" +
+ " void consume(String @NonNull[] s) {};\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in A.java (at line 4)\n" +
+ " realArrays[0] = maybeArrays[0]; // problem: inner array can be null\n" +
+ " ^^^^^^^^^^^^^\n" +
+ "Null type mismatch: required \'String @NonNull[]\' but the provided value is inferred as @Nullable\n" +
+ "----------\n" +
+ "2. WARNING in A.java (at line 5)\n" +
+ " realArrays[0] = unknownArrays[0]; // problems: inner array is unspecified, outer can be null\n" +
+ " ^^^^^^^^^^^^^\n" +
+ "Null type safety: The expression of type String[] needs unchecked conversion to conform to \'String @NonNull[]\'\n" +
+ "----------\n" +
+ "3. ERROR in A.java (at line 5)\n" +
+ " realArrays[0] = unknownArrays[0]; // problems: inner array is unspecified, outer can be null\n" +
+ " ^^^^^^^^^^^^^\n" +
+ "Potential null pointer access: this expression has a \'@Nullable\' type\n" +
+ "----------\n" +
+ "4. ERROR in A.java (at line 8)\n" +
+ " String @NonNull[] s = maybeStrings;\n" +
+ " ^^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): required \'String @NonNull[]\' but this expression has type \'String @Nullable[]\'\n" +
+ "----------\n" +
+ "5. WARNING in A.java (at line 9)\n" +
+ " s = unknownStrings;\n" +
+ " ^^^^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): the expression of type \'String[]\' needs unchecked conversion to conform to \'String @NonNull[]\'\n" +
+ "----------\n" +
+ "6. ERROR in A.java (at line 10)\n" +
+ " consume(maybeStrings);\n" +
+ " ^^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): required \'String @NonNull[]\' but this expression has type \'String @Nullable[]\'\n" +
+ "----------\n" +
+ "7. WARNING in A.java (at line 11)\n" +
+ " consume(unknownStrings);\n" +
+ " ^^^^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): the expression of type \'String[]\' needs unchecked conversion to conform to \'String @NonNull[]\'\n" +
+ "----------\n",
+ null,
+ true, /* shouldFlush*/
+ customOptions);
+ }
+
+ // bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
+ // more compiler messages
+ public void testArrayType_10() {
+ Map customOptions = getCompilerOptions();
+ customOptions.put(JavaCore.COMPILER_NULLABLE_ANNOTATION_NAME, "org.foo.Nullable");
+ customOptions.put(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, "org.foo.NonNull");
+ runNegativeTest(
+ new String[] {
+ ELEMENT_TYPE_JAVA,
+ ELEMENT_TYPE_SOURCE,
+ CUSTOM_NULLABLE_NAME,
+ CUSTOM_NULLABLE_CONTENT_JSR308,
+ CUSTOM_NONNULL_NAME,
+ CUSTOM_NONNULL_CONTENT_JSR308,
+ "A.java",
+ "import org.foo.*;\n" +
+ "public class A {\n" +
+ " void outer(String @NonNull[] @NonNull[] realArrays, String @NonNull[] @Nullable[] maybeArrays, String @Nullable[][] unknownArrays, String @NonNull[][] mixedArrays) {\n" +
+ " realArrays = maybeArrays; // problem on inner dimension!\n" +
+ " realArrays = unknownArrays; // problems on both dimensions\n" +
+ " maybeArrays = realArrays; // problem on inner dimension\n" +
+ " unknownArrays = maybeArrays; // problsm on outer dimension\n" +
+ " realArrays = mixedArrays; // problem on inner\n" +
+ " maybeArrays = mixedArrays; // problem on inner\n" +
+ " consume(maybeArrays, mixedArrays, maybeArrays);\n" +
+ " }\n" +
+ " void consume(String @NonNull[] @NonNull[] realStrings, String @NonNull[] @Nullable[] maybeArrays, String @Nullable[][] unknownArrays) {\n" +
+ " }\n" +
+ "}\n"},
+ "----------\n" +
+ "1. ERROR in A.java (at line 4)\n" +
+ " realArrays = maybeArrays; // problem on inner dimension!\n" +
+ " ^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): required \'String @NonNull[] @NonNull[]\' but this expression has type \'String @NonNull[] @Nullable[]\'\n" +
+ "----------\n" +
+ "2. ERROR in A.java (at line 5)\n" +
+ " realArrays = unknownArrays; // problems on both dimensions\n" +
+ " ^^^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): required \'String @NonNull[] @NonNull[]\' but this expression has type \'String @Nullable[] []\'\n" +
+ "----------\n" +
+ "3. ERROR in A.java (at line 6)\n" +
+ " maybeArrays = realArrays; // problem on inner dimension\n" +
+ " ^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): required \'String @NonNull[] @Nullable[]\' but this expression has type \'String @NonNull[] @NonNull[]\'\n" +
+ "----------\n" +
+ "4. ERROR in A.java (at line 7)\n" +
+ " unknownArrays = maybeArrays; // problsm on outer dimension\n" +
+ " ^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): required \'String @Nullable[] []\' but this expression has type \'String @NonNull[] @Nullable[]\'\n" +
+ "----------\n" +
+ "5. WARNING in A.java (at line 8)\n" +
+ " realArrays = mixedArrays; // problem on inner\n" +
+ " ^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): the expression of type \'String @NonNull[] []\' needs unchecked conversion to conform to \'String @NonNull[] @NonNull[]\'\n" +
+ "----------\n" +
+ "6. WARNING in A.java (at line 9)\n" +
+ " maybeArrays = mixedArrays; // problem on inner\n" +
+ " ^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): the expression of type \'String @NonNull[] []\' needs unchecked conversion to conform to \'String @NonNull[] @Nullable[]\'\n" +
+ "----------\n" +
+ "7. ERROR in A.java (at line 10)\n" +
+ " consume(maybeArrays, mixedArrays, maybeArrays);\n" +
+ " ^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): required \'String @NonNull[] @NonNull[]\' but this expression has type \'String @NonNull[] @Nullable[]\'\n" +
+ "----------\n" +
+ "8. WARNING in A.java (at line 10)\n" +
+ " consume(maybeArrays, mixedArrays, maybeArrays);\n" +
+ " ^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): the expression of type \'String @NonNull[] []\' needs unchecked conversion to conform to \'String @NonNull[] @Nullable[]\'\n" +
+ "----------\n" +
+ "9. ERROR in A.java (at line 10)\n" +
+ " consume(maybeArrays, mixedArrays, maybeArrays);\n" +
+ " ^^^^^^^^^^^\n" +
+ "Null type mismatch (type annotations): required \'String @Nullable[] []\' but this expression has type \'String @NonNull[] @Nullable[]\'\n" +
+ "----------\n",
+ null,
+ true, /* shouldFlush*/
+ customOptions);
+ }
}
diff --git a/org.eclipse.jdt.core.tests.model/JCL/converterJclMin1.8.jar b/org.eclipse.jdt.core.tests.model/JCL/converterJclMin1.8.jar
new file mode 100644
index 0000000..3ac44e9
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/JCL/converterJclMin1.8.jar
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/JCL/converterJclMin1.8src.zip b/org.eclipse.jdt.core.tests.model/JCL/converterJclMin1.8src.zip
new file mode 100644
index 0000000..50607ff
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/JCL/converterJclMin1.8src.zip
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/JCL/jclMin1.8.jar b/org.eclipse.jdt.core.tests.model/JCL/jclMin1.8.jar
new file mode 100644
index 0000000..2b78416
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/JCL/jclMin1.8.jar
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/JCL/jclMin1.8src.zip b/org.eclipse.jdt.core.tests.model/JCL/jclMin1.8src.zip
new file mode 100644
index 0000000..0757f3a
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/JCL/jclMin1.8src.zip
Binary files differ
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava8Tests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava8Tests.java
index e2798de..c77fcd0 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava8Tests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava8Tests.java
@@ -11,6 +11,8 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Stephan Herrmann - Contribution for
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.core.tests;
@@ -31,6 +33,7 @@
import org.eclipse.jdt.core.tests.compiler.regression.GrammarCoverageTests308;
import org.eclipse.jdt.core.tests.compiler.regression.NegativeLambdaExpressionsTest;
import org.eclipse.jdt.core.tests.compiler.regression.NegativeTypeAnnotationTest;
+import org.eclipse.jdt.core.tests.compiler.regression.NullTypeAnnotationTest;
import org.eclipse.jdt.core.tests.dom.ASTConverter15JLS8Test;
import org.eclipse.jdt.core.tests.dom.ASTConverterAST8Test;
import org.eclipse.jdt.core.tests.dom.ASTConverterBugsTestJLS8;
@@ -52,7 +55,8 @@
ReferenceExpressionSyntaxTest.class,
DefaultMethodsTest.class,
ComplianceDiagnoseTest.class,
- GrammarCoverageTests308.class
+ GrammarCoverageTests308.class,
+ NullTypeAnnotationTest.class
};
}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
index fd3c570..8fea5b7 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
@@ -995,11 +995,10 @@
/* no need to take action if not inside completed identifiers */
if ((index = indexOfAssistIdentifier(true)) < 0) {
-// orig: FIXME
+/* orig:
return super.getTypeReference(dim);
-// :giro */
-// OT PREVIOUS:
-// return super.getUnannotatedTypeReference(dim, liftingTypeAllowed);
+ :giro */
+ return super.getTypeReference(dim, liftingTypeAllowed);
// SH}
}
int length = this.identifierLengthStack[this.identifierLengthPtr];
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
index 0cc18be..b0a1846 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -159,6 +159,10 @@
* InheritedDefaultMethodConflictsWithOtherInherited
* ConflictingNullAnnotations
* ConflictingInheritedNullAnnotations
+ * ArrayReferencePotentialNullReference
+ * DereferencingNullableExpression
+ * NullityMismatchingTypeAnnotation
+ * NullityMismatchingTypeAnnotationUnchecked
*******************************************************************************/
package org.eclipse.jdt.core.compiler;
@@ -1554,6 +1558,15 @@
/** @since 3.9 */
int ConflictingInheritedNullAnnotations = MethodRelated + 940;
+ /** @since 3.9 */
+ int ArrayReferencePotentialNullReference = Internal + 951;
+ /** @since 3.9 */
+ int DereferencingNullableExpression = Internal + 952;
+ /** @since 3.9 */
+ int NullityMismatchingTypeAnnotation = Internal + 953;
+ /** @since 3.9 */
+ int NullityMismatchingTypeAnnotationUnchecked = Internal + 954;
+
// Java 8 work
/** @since 3.9 */
int IllegalModifiersForElidedType = Internal + 1001;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java
index 55d4cac..24e87d4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java
@@ -5,10 +5,15 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - Contribution for
* bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null"
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -19,6 +24,7 @@
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
@@ -40,12 +46,19 @@
if (assignment.expression == null) {
return analyseCode(currentScope, flowContext, flowInfo);
}
- return assignment
+ flowInfo = assignment
.expression
.analyseCode(
currentScope,
flowContext,
analyseCode(currentScope, flowContext, flowInfo).unconditionalInits());
+ if ((this.resolvedType.tagBits & TagBits.AnnotationNonNull) != 0) {
+ int nullStatus = assignment.expression.nullStatus(flowInfo);
+ if (nullStatus != FlowInfo.NON_NULL) {
+ currentScope.problemReporter().nullityMismatch(this, assignment.expression.resolvedType, this.resolvedType, nullStatus, currentScope.environment().getNonNullAnnotationName());
+ }
+ }
+ return flowInfo;
}
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
@@ -57,6 +70,14 @@
return flowInfo;
}
+public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
+ if ((this.resolvedType.tagBits & TagBits.AnnotationNullable) != 0) {
+ scope.problemReporter().arrayReferencePotentialNullReference(this);
+ } else {
+ super.checkNPE(scope, flowContext, flowInfo);
+ }
+}
+
public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) {
int pc = codeStream.position;
this.receiver.generateCode(currentScope, codeStream, true);
@@ -167,10 +188,6 @@
codeStream.arrayAtPut(this.resolvedType.id, false);
}
-public int nullStatus(FlowInfo flowInfo) {
- return FlowInfo.UNKNOWN;
-}
-
public StringBuffer printExpression(int indent, StringBuffer output) {
this.receiver.printExpression(0, output).append('[');
return this.position.printExpression(0, output).append(']');
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
index 8d122c9..8a74c00 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
@@ -6,6 +6,10 @@
* http://www.eclipse.org/legal/epl-v10.html
* $Id: Expression.java 23404 2010-02-03 14:10:22Z stephan $
*
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
* Contributors:
* IBM Corporation - initial API and implementation
* Fraunhofer FIRST - extended API and implementation
@@ -13,6 +17,7 @@
* Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for
* bug 292478 - Report potentially null across variable assignment
* bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null"
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -712,6 +717,16 @@
* @param flowInfo the upstream flow info; caveat: may get modified
*/
public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
+ if (this.resolvedType != null) {
+ if ((this.resolvedType.tagBits & TagBits.AnnotationNonNull) != 0) {
+ return; // no danger
+ } else if ((this.resolvedType.tagBits & TagBits.AnnotationNullable) != 0) {
+ scope.problemReporter().dereferencingNullableExpression(this, scope.environment());
+ return; // danger is definite.
+ // stopping analysis at this point requires that the above error is not suppressable
+ // unless suppressing all null warnings (otherwise we'd miss a stronger warning below).
+ }
+ }
LocalVariableBinding local = localVariableBinding();
if (local != null &&
(local.type.tagBits & TagBits.IsBaseType) == 0) {
@@ -1054,7 +1069,7 @@
if (/* (this.bits & IsNonNull) != 0 || */
this.constant != null && this.constant != Constant.NotAConstant)
- return FlowInfo.NON_NULL; // constant expression cannot be null
+ return FlowInfo.NON_NULL; // constant expression cannot be null
LocalVariableBinding local = localVariableBinding();
if (local != null)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
index 8f31fc5..0fa52d3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
@@ -6,6 +6,10 @@
* http://www.eclipse.org/legal/epl-v10.html
* $Id: MessageSend.java 23405 2010-02-03 17:02:18Z stephan $
*
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
* Contributors:
* IBM Corporation - initial API and implementation
* Nick Teryaev - fix for bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=40752)
@@ -22,6 +26,7 @@
* bug 379784 - [compiler] "Method can be static" is not getting reported
* bug 379834 - Wrong "method can be static" in presence of qualified super and different staticness of nested super class.
* bug 388281 - [compiler][null] inheritance of null annotations as an option
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -291,9 +296,10 @@
}
// SH}
public void checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
- super.checkNPE(scope, flowContext, flowInfo);
- if ((nullStatus(flowInfo) & FlowInfo.POTENTIALLY_NULL) != 0)
+ if ((nullStatus(flowInfo) & FlowInfo.POTENTIALLY_NULL) != 0) // note that flowInfo is not used inside nullStatus(..)
scope.problemReporter().messageSendPotentialNullReference(this.binding, this);
+ else
+ super.checkNPE(scope, flowContext, flowInfo);
}
/**
* @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
index 799d2a2..6824d55 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
@@ -235,7 +235,7 @@
: scope.environment().convertToParameterizedType(qualifyingType);
}
} else {
- rejectAnnotationsOnStaticMemberQualififer(scope, currentType, packageBinding, i);
+ rejectAnnotationsOnStaticMemberQualififer(scope, currentType, i);
if (typeIsConsistent && currentType.isStatic()
&& (qualifyingType.isParameterizedTypeWithActualArguments() || qualifyingType.isGenericType())) {
scope.problemReporter().staticMemberOfParameterizedType(this, scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifyingType), i);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
index 57c1c8c..f3f6680 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
@@ -150,7 +150,7 @@
if (packageBinding == null || this.annotations == null) return;
int i = packageBinding.compoundName.length;
- for (int j = i; j > 0; j--) {
+ for (int j = 0; j < i; j++) {
Annotation[] qualifierAnnot = this.annotations[j];
if (qualifierAnnot != null && qualifierAnnot.length > 0) {
scope.problemReporter().misplacedTypeAnnotations(qualifierAnnot[0], qualifierAnnot[qualifierAnnot.length - 1]);
@@ -159,7 +159,7 @@
}
}
- protected void rejectAnnotationsOnStaticMemberQualififer(Scope scope, ReferenceBinding currentType, PackageBinding packageBinding, int tokenIndex) {
+ protected void rejectAnnotationsOnStaticMemberQualififer(Scope scope, ReferenceBinding currentType, int tokenIndex) {
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=385137
if (this.annotations != null && currentType.isMemberType() && currentType.isStatic()) {
Annotation[] qualifierAnnot = this.annotations[tokenIndex - 1];
@@ -167,14 +167,6 @@
scope.problemReporter().illegalTypeAnnotationsInStaticMemberAccess(qualifierAnnot[0],
qualifierAnnot[qualifierAnnot.length - 1]);
}
- // For the case: @Marker p.X.StaticNestedType, where 'p' is a package and 'X' is a class
- if (packageBinding != null && packageBinding.compoundName.length == (tokenIndex - 1)) {
- qualifierAnnot = this.annotations[0];
- if (qualifierAnnot != null) {
- scope.problemReporter().illegalTypeAnnotationsInStaticMemberAccess(qualifierAnnot[0],
- qualifierAnnot[qualifierAnnot.length - 1]);
- }
- }
}
}
@@ -244,7 +236,7 @@
return null;
ReferenceBinding currentType = (ReferenceBinding) this.resolvedType;
if (qualifiedType != null) {
- rejectAnnotationsOnStaticMemberQualififer(scope, currentType, packageBinding, i);
+ rejectAnnotationsOnStaticMemberQualififer(scope, currentType, i);
ReferenceBinding enclosingType = currentType.enclosingType();
if (enclosingType != null && enclosingType.erasure() != qualifiedType.erasure()) {
qualifiedType = enclosingType; // inherited member type, leave it associated with its enclosing rather than subtype
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
index ee157de..d228167 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
@@ -4,13 +4,18 @@
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
- * $Id: Reference.java 23404 2010-02-03 14:10:22Z stephan $
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
- * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 185682 - Increment/decrement operators mark local variables as read
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended API and implementation
+ * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for
+ * bug 185682 - Increment/decrement operators mark local variables as read
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -27,6 +32,7 @@
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.objectteams.otdt.internal.core.compiler.model.TeamModel;
@@ -115,6 +121,16 @@
public abstract void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired);
+public int nullStatus(FlowInfo flowInfo) {
+ if (this.resolvedType != null) {
+ if ((this.resolvedType.tagBits & TagBits.AnnotationNonNull) != 0)
+ return FlowInfo.NON_NULL;
+ else if ((this.resolvedType.tagBits & TagBits.AnnotationNullable) != 0)
+ return FlowInfo.POTENTIALLY_NULL;
+ }
+ return FlowInfo.UNKNOWN;
+}
+
/* report if a private field is only read from a 'special operator',
* i.e., in a postIncrement expression or a compound assignment,
* where the information is never flowing out off the field. */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
index 9f79f10..f2c21f5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
@@ -4,7 +4,10 @@
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
- * $Id: Statement.java 23404 2010-02-03 14:10:22Z stephan $
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
@@ -18,12 +21,15 @@
* bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK
* bug 370930 - NonNull annotation not considered for enhanced for loops
* bug 365859 - [compiler][null] distinguish warnings based on flow analysis vs. null annotations
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.objectteams.otdt.core.compiler.IOTConstants;
@@ -79,35 +85,57 @@
protected void analyseArguments(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, MethodBinding methodBinding, Expression[] arguments)
{
// compare actual null-status against parameter annotations of the called method:
- if (arguments != null && methodBinding.parameterNonNullness != null) {
-
- // check if varargs need special treatment:
+ if (arguments != null) {
+ CompilerOptions compilerOptions = currentScope.compilerOptions();
+ boolean considerTypeAnnotations = compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8
+ && compilerOptions.isAnnotationBasedNullAnalysisEnabled;
+ boolean hasJDK15NullAnnotations = methodBinding.parameterNonNullness != null;
int numParamsToCheck = methodBinding.parameters.length;
- boolean passThrough = false;
- if (methodBinding.isVarargs()) {
- int varArgPos = numParamsToCheck-1;
- // this if-block essentially copied from generateArguments(..):
- if (numParamsToCheck == arguments.length) {
- TypeBinding varArgsType = methodBinding.parameters[varArgPos];
- TypeBinding lastType = arguments[varArgPos].resolvedType;
- if (lastType == TypeBinding.NULL
- || (varArgsType.dimensions() == lastType.dimensions()
- && lastType.isCompatibleWith(varArgsType)))
- passThrough = true; // pass directly as-is
+ if (considerTypeAnnotations || hasJDK15NullAnnotations) {
+ // check if varargs need special treatment:
+ boolean passThrough = false;
+ if (methodBinding.isVarargs()) {
+ int varArgPos = numParamsToCheck-1;
+ // this if-block essentially copied from generateArguments(..):
+ if (numParamsToCheck == arguments.length) {
+ TypeBinding varArgsType = methodBinding.parameters[varArgPos];
+ TypeBinding lastType = arguments[varArgPos].resolvedType;
+ if (lastType == TypeBinding.NULL
+ || (varArgsType.dimensions() == lastType.dimensions()
+ && lastType.isCompatibleWith(varArgsType)))
+ passThrough = true; // pass directly as-is
+ }
+ if (!passThrough)
+ numParamsToCheck--; // with non-passthrough varargs last param is fed from individual args -> don't check
}
- if (!passThrough)
- numParamsToCheck--; // with non-passthrough varargs last param is fed from individual args -> don't check
}
-
- for (int i = 0; i < numParamsToCheck; i++) {
- if (methodBinding.parameterNonNullness[i] == Boolean.TRUE) {
+ if (considerTypeAnnotations) {
+ for (int i=0; i<numParamsToCheck; i++) {
TypeBinding expectedType = methodBinding.parameters[i];
Expression argument = arguments[i];
- int nullStatus = argument.nullStatus(flowInfo); // slight loss of precision: should also use the null info from the receiver.
- if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided
- flowContext.recordNullityMismatch(currentScope, argument, argument.resolvedType, expectedType, nullStatus);
+ // prefer check based on type annotations:
+ int severity = findNullTypeAnnotationMismatch(expectedType, argument.resolvedType);
+ if (severity > 0) {
+ // immediate reporting:
+ currentScope.problemReporter().nullityMismatchingTypeAnnotation(argument, argument.resolvedType, expectedType, severity==1, currentScope.environment());
+ // next check flow-based null status against null JDK15-style annotations:
+ } else if (hasJDK15NullAnnotations && methodBinding.parameterNonNullness[i] == Boolean.TRUE) {
+ int nullStatus = argument.nullStatus(flowInfo); // slight loss of precision: should also use the null info from the receiver.
+ if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided
+ flowContext.recordNullityMismatch(currentScope, argument, argument.resolvedType, expectedType, nullStatus);
+ }
}
- }
+ } else if (hasJDK15NullAnnotations) {
+ for (int i = 0; i < numParamsToCheck; i++) {
+ if (methodBinding.parameterNonNullness[i] == Boolean.TRUE) {
+ TypeBinding expectedType = methodBinding.parameters[i];
+ Expression argument = arguments[i];
+ int nullStatus = argument.nullStatus(flowInfo); // slight loss of precision: should also use the null info from the receiver.
+ if (nullStatus != FlowInfo.NON_NULL) // if required non-null is not provided
+ flowContext.recordNullityMismatch(currentScope, argument, argument.resolvedType, expectedType, nullStatus);
+ }
+ }
+ }
}
}
@@ -116,10 +144,13 @@
LocalVariableBinding local, int nullStatus, Expression expression, TypeBinding providedType)
{
if (local != null) {
+ int severity = 0;
if ((local.tagBits & TagBits.AnnotationNonNull) != 0
&& nullStatus != FlowInfo.NON_NULL) {
flowContext.recordNullityMismatch(currentScope, expression, providedType, local.type, nullStatus);
return FlowInfo.NON_NULL;
+ } else if ((severity = findNullTypeAnnotationMismatch(local.type, providedType)) > 0) {
+ currentScope.problemReporter().nullityMismatchingTypeAnnotation(expression, providedType, local.type, severity==1, currentScope.environment());
} else if ((local.tagBits & TagBits.AnnotationNullable) != 0
&& nullStatus == FlowInfo.UNKNOWN) { // provided a legacy type?
return FlowInfo.POTENTIALLY_NULL; // -> use more specific info from the annotation
@@ -127,7 +158,33 @@
}
return nullStatus;
}
-
+protected int findNullTypeAnnotationMismatch(TypeBinding requiredType, TypeBinding providedType) {
+ int severity = 0;
+ if (requiredType instanceof ArrayBinding) {
+ long[] requiredDimsTagBits = ((ArrayBinding)requiredType).nullTagBitsPerDimension;
+ if (requiredDimsTagBits != null) {
+ int dims = requiredType.dimensions();
+ if (requiredType.dimensions() == providedType.dimensions()) {
+ long[] providedDimsTagBits = ((ArrayBinding)providedType).nullTagBitsPerDimension;
+ if (providedDimsTagBits == null) {
+ severity = 1; // required is annotated, provided not, need unchecked conversion
+ } else {
+ for (int i=0; i<dims; i++) {
+ long requiredBits = requiredDimsTagBits[i] & TagBits.AnnotationNullMASK;
+ long providedBits = providedDimsTagBits[i] & TagBits.AnnotationNullMASK;
+ if (requiredBits != 0 && requiredBits != providedBits) {
+ if (providedBits == 0)
+ severity = 1; // need unchecked conversion regarding type detail
+ else
+ return 2; // mismatching annotations
+ }
+ }
+ }
+ }
+ }
+ }
+ return severity;
+}
/**
* INTERNAL USE ONLY.
* This is used to redirect inter-statements jumps.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
index 7f8ac4f..67298e9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
@@ -15,6 +15,7 @@
* Technical University Berlin - extended API and implementation
* Stephan Herrmann - Contribution for
* bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;
@@ -535,13 +536,15 @@
&& scope.compilerOptions().getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore) {
scope.problemReporter().rawTypeReference(this, type);
}
- resolveAnnotations(scope);
-
if (hasError) {
- // do not store the computed type, keep the problem type instead
+ resolveAnnotations(scope);
return type;
+ } else {
+ // store the computed type only if no error, otherwise keep the problem type instead
+ this.resolvedType = type;
+ resolveAnnotations(scope);
+ return this.resolvedType; // pick up value that may have been changed in resolveAnnotations(..)
}
- return this.resolvedType = type;
}
//{ObjectTeams: alternative strategies for resolving:
@@ -685,11 +688,27 @@
if (this.annotations != null || annotationsOnDimensions != null) {
BlockScope resolutionScope = Scope.typeAnnotationsResolutionScope(scope);
if (resolutionScope != null) {
+ long[] tagBitsPerDimension = null;
+ int dimensions = this.dimensions();
+ boolean shouldAnalyzeArrayNullAnnotations = scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled && this instanceof ArrayTypeReference;
if (this.annotations != null) {
int annotationsLevels = this.annotations.length;
for (int i = 0; i < annotationsLevels; i++) {
- if (this.annotations[i] != null) {
- resolveAnnotations(resolutionScope, this.annotations[i], new Annotation.TypeUseBinding(isWildcard() ? Binding.TYPE_PARAMETER : Binding.TYPE_USE));
+ Annotation[] currentAnnotations = this.annotations[i];
+ if (currentAnnotations != null) {
+ resolveAnnotations(resolutionScope, currentAnnotations, new Annotation.TypeUseBinding(isWildcard() ? Binding.TYPE_PARAMETER : Binding.TYPE_USE));
+ if (shouldAnalyzeArrayNullAnnotations) {
+ int len = currentAnnotations.length;
+ for (int j=0; j<len; j++) {
+ Binding recipient = currentAnnotations[j].recipient;
+ if (recipient instanceof Annotation.TypeUseBinding) {
+ if (tagBitsPerDimension == null)
+ tagBitsPerDimension = new long[dimensions+1]; // each dimension plus leaf component type at last position
+ // @NonNull Foo [][][] means the leaf component type is @NonNull:
+ tagBitsPerDimension[dimensions] = ((Annotation.TypeUseBinding)recipient).tagBits & TagBits.AnnotationNullMASK;
+ }
+ }
+ }
}
}
}
@@ -699,9 +718,25 @@
Annotation [] dimensionAnnotations = annotationsOnDimensions[i];
if (dimensionAnnotations != null) {
resolveAnnotations(resolutionScope, dimensionAnnotations, new Annotation.TypeUseBinding(Binding.TYPE_USE));
+ if (shouldAnalyzeArrayNullAnnotations) {
+ int len = dimensionAnnotations.length;
+ for (int j=0; j<len; j++) {
+ Binding recipient = dimensionAnnotations[j].recipient;
+ if (recipient instanceof Annotation.TypeUseBinding) {
+ if (tagBitsPerDimension == null)
+ tagBitsPerDimension = new long[dimensions+1];
+ tagBitsPerDimension[i] = ((Annotation.TypeUseBinding)recipient).tagBits & TagBits.AnnotationNullMASK;
+ }
+ }
+ }
}
}
}
+ if (tagBitsPerDimension != null && this.resolvedType.isValidBinding()) {
+ // TODO(stephan): wouldn't it be more efficient to store the array bindings inside the type binding rather than the environment?
+ // cf. LocalTypeBinding.createArrayType()
+ this.resolvedType = scope.environment().createArrayType(this.resolvedType.leafComponentType(), dimensions, tagBitsPerDimension);
+ }
}
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
index 16b3854..be06999 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
@@ -1,13 +1,19 @@
/*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
* Contributors:
* IBM Corporation - initial API and implementation
* Technical University Berlin - extended API and implementation
+ * Stephan Herrmann - Contribution for
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -29,7 +35,15 @@
char[] constantPoolName;
char[] genericTypeSignature;
+ // One bitset for each dimension plus one more for the leaf component type at position 'dimensions',
+ // possible bits are TagBits.AnnotationNonNull and TagBits.AnnotationNullable
+ // (only ever set when CompilerOptions.isAnnotationBasedNullAnalysisEnabled == true):
+ public long[] nullTagBitsPerDimension;
+
public ArrayBinding(TypeBinding type, int dimensions, LookupEnvironment environment) {
+ this(type, dimensions, environment, null);
+}
+public ArrayBinding(TypeBinding type, int dimensions, LookupEnvironment environment, long[] nullTagBitsPerDimension) {
this.tagBits |= TagBits.IsArrayType;
this.leafComponentType = type;
this.dimensions = dimensions;
@@ -38,6 +52,11 @@
((UnresolvedReferenceBinding) type).addWrapper(this, environment);
else
this.tagBits |= type.tagBits & (TagBits.HasTypeVariable | TagBits.HasDirectWildcard | TagBits.HasMissingType | TagBits.ContainsNestedTypeReferences);
+
+ if (nullTagBitsPerDimension != null) {
+ this.tagBits |= nullTagBitsPerDimension[0]; // outer-most dimension
+ this.nullTagBitsPerDimension = nullTagBitsPerDimension;
+ }
}
public TypeBinding closestMatch() {
@@ -130,8 +149,17 @@
*/
public TypeBinding elementsType() {
- if (this.dimensions == 1) return this.leafComponentType;
- return this.environment.createArrayType(this.leafComponentType, this.dimensions - 1);
+ long[] nullTagBitsSub = null;
+ if (this.nullTagBitsPerDimension != null) {
+ int len = this.nullTagBitsPerDimension.length-1;
+ System.arraycopy(this.nullTagBitsPerDimension, 1, nullTagBitsSub = new long[len], 0, len);
+ }
+ if (this.dimensions == 1) {
+ if (nullTagBitsSub != null && nullTagBitsSub[0] != 0L && this.leafComponentType instanceof ReferenceBinding)
+ return this.environment.createParameterizedType((ReferenceBinding) this.leafComponentType, null, nullTagBitsSub[0], null);
+ return this.leafComponentType;
+ }
+ return this.environment.createArrayType(this.leafComponentType, this.dimensions - 1, nullTagBitsSub);
}
/**
* @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#erasure()
@@ -222,6 +250,35 @@
return this.leafComponentType;
}
+public char[] nullAnnotatedReadableName(LookupEnvironment env, boolean shortNames) /* java.lang.Object @o.e.j.a.NonNull[] */ {
+ if (this.nullTagBitsPerDimension == null)
+ return shortNames ? shortReadableName() : readableName();
+ char[][] brackets = new char[this.dimensions][];
+ for (int i = 0; i < this.dimensions; i++) {
+ if ((this.nullTagBitsPerDimension[i] & TagBits.AnnotationNullMASK) != 0) {
+ char[][] fqAnnotationName;
+ if ((this.nullTagBitsPerDimension[i] & TagBits.AnnotationNonNull) != 0)
+ fqAnnotationName = env.getNonNullAnnotationName();
+ else
+ fqAnnotationName = env.getNullableAnnotationName();
+ char[] annotationName = shortNames
+ ? fqAnnotationName[fqAnnotationName.length-1]
+ : CharOperation.concatWith(fqAnnotationName, '.');
+ brackets[i] = new char[annotationName.length+3];
+ brackets[i][0] = '@';
+ System.arraycopy(annotationName, 0, brackets[i], 1, annotationName.length);
+ brackets[i][annotationName.length+1] = '[';
+ brackets[i][annotationName.length+2] = ']';
+ } else {
+ brackets[i] = new char[]{'[', ']'};
+ }
+ }
+ char[] leafTypeName = shortNames ? this.leafComponentType.shortReadableName() : this.leafComponentType.readableName();
+ return CharOperation.concat(leafTypeName,
+ CharOperation.concatWith(brackets, ' '),
+ ' ');
+}
+
/* API
* Answer the problem id associated with the receiver.
* NoError if the receiver is a valid binding.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
index 65fecfa..6dd21eb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
@@ -18,10 +18,12 @@
* bug 186342 - [compiler][null] Using annotations for null checking
* bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults
* bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -823,6 +825,9 @@
* Used to guarantee array type identity.
*/
public ArrayBinding createArrayType(TypeBinding leafComponentType, int dimensionCount) {
+ return createArrayType(leafComponentType, dimensionCount, null);
+}
+public ArrayBinding createArrayType(TypeBinding leafComponentType, int dimensionCount, long[] nullTagBitsPerDimension) {
if (leafComponentType instanceof LocalTypeBinding) // cache local type arrays with the local type itself
return ((LocalTypeBinding) leafComponentType).createArrayType(dimensionCount, this);
@@ -847,8 +852,9 @@
while (++index < length) {
ArrayBinding currentBinding = arrayBindings[index];
if (currentBinding == null) // no matching array, but space left
- return arrayBindings[index] = new ArrayBinding(leafComponentType, dimensionCount, this);
- if (currentBinding.leafComponentType == leafComponentType)
+ return arrayBindings[index] = new ArrayBinding(leafComponentType, dimensionCount, this, nullTagBitsPerDimension);
+ if (currentBinding.leafComponentType == leafComponentType
+ && (nullTagBitsPerDimension == null || Arrays.equals(currentBinding.nullTagBitsPerDimension, nullTagBitsPerDimension)))
return currentBinding;
}
@@ -858,7 +864,7 @@
(arrayBindings = new ArrayBinding[length * 2]), 0,
length);
this.uniqueArrayBindings[dimIndex] = arrayBindings;
- return arrayBindings[length] = new ArrayBinding(leafComponentType, dimensionCount, this);
+ return arrayBindings[length] = new ArrayBinding(leafComponentType, dimensionCount, this, nullTagBitsPerDimension);
}
public BinaryTypeBinding createBinaryTypeFrom(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
return createBinaryTypeFrom(binaryType, packageBinding, true, accessRestriction);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index 9f54faf..5ad6d96 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -5,6 +5,10 @@
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
+ *
* Contributors:
* IBM Corporation - initial API and implementation
* Fraunhofer FIRST - extended API and implementation
@@ -16,6 +20,7 @@
* bug 358903 - Filter practically unimportant resource leak warnings
* bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults
* bug 388281 - [compiler][null] inheritance of null annotations as an option
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -1789,6 +1794,24 @@
return Binding.NO_METHODS;
}
+public char[] nullAnnotatedReadableName(LookupEnvironment env, boolean shortNames) /* java.lang.Object @o.e.j.a.NonNull[] */ {
+ char[] typeName = shortNames ? shortReadableName() : readableName();
+ if ((this.tagBits & TagBits.AnnotationNullMASK) == 0)
+ return typeName;
+ char[][] fqAnnotationName;
+ if ((this.tagBits & TagBits.AnnotationNonNull) != 0)
+ fqAnnotationName = env.getNonNullAnnotationName();
+ else
+ fqAnnotationName = env.getNullableAnnotationName();
+ char[] annotationName = shortNames
+ ? fqAnnotationName[fqAnnotationName.length-1]
+ : CharOperation.concatWith(fqAnnotationName, '.');
+ char[] prefix = new char[annotationName.length+1];
+ prefix[0] = '@';
+ System.arraycopy(annotationName, 0, prefix, 1, annotationName.length);
+ return CharOperation.concat(prefix, typeName, ' ');
+}
+
public final ReferenceBinding outermostEnclosingType() {
ReferenceBinding current = this;
while (true) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
index b45fb89..bceeae0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
@@ -4,13 +4,18 @@
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
- * $Id: TypeBinding.java 23405 2010-02-03 17:02:18Z stephan $
+ *
+ * This is an implementation of an early-draft specification developed under the Java
+ * Community Process (JCP) and is made available for testing and evaluation purposes
+ * only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* IBM Corporation - initial API and implementation
- * Stephen Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 317046
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended API and implementation
+ * Stephen Herrmann <stephan@cs.tu-berlin.de> - Contributions for
+ * bug 317046 - Exception during debugging when hover mouse over a field
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -1215,6 +1220,14 @@
return false;
}
+/** Answer a readable name (for error reporting) that includes nullness type annotations. */
+public char[] nullAnnotatedReadableName(LookupEnvironment env, boolean shortNames) /* e.g.: java.lang.Object @o.e.j.a.NonNull[] */ {
+ if (shortNames)
+ return shortReadableName();
+ else
+ return readableName();
+}
+
/**
* Returns the orignal generic type instantiated by the receiver type, or itself if not.
* This is similar to erasure process, except it doesn't erase type variable, wildcard, intersection types etc...
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
index 1d3767f..35d751f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
@@ -9146,19 +9146,19 @@
consumeTypeArgument();
break;
- case 737 : if (DEBUG) { System.out.println("TypeAnchor ::= AT Name"); } //$NON-NLS-1$
+ case 737 : if (DEBUG) { System.out.println("TypeAnchor ::= ATOT Name"); } //$NON-NLS-1$
consumeTypeAnchor(false);
break;
- case 738 : if (DEBUG) { System.out.println("TypeAnchor ::= AT base"); } //$NON-NLS-1$
+ case 738 : if (DEBUG) { System.out.println("TypeAnchor ::= ATOT base"); } //$NON-NLS-1$
consumeTypeAnchor(true);
break;
- case 739 : if (DEBUG) { System.out.println("TypeAnchor ::= AT this"); } //$NON-NLS-1$
+ case 739 : if (DEBUG) { System.out.println("TypeAnchor ::= ATOT this"); } //$NON-NLS-1$
skipThisAnchor();
break;
- case 740 : if (DEBUG) { System.out.println("TypeAnchor ::= AT Name DOT base"); } //$NON-NLS-1$
+ case 740 : if (DEBUG) { System.out.println("TypeAnchor ::= ATOT Name DOT base"); } //$NON-NLS-1$
consumeQualifiedBaseTypeAnchor();
break;
@@ -13039,7 +13039,7 @@
int stackTopState = this.stack[stackTop]; // single cell non write through "alternate stack" - the automaton's stack pointer either stays fixed during this manoeuvre or monotonically decreases.
int highWaterMark = stackTop;
- if (token != TokenNameAT) {
+ if (token != TokenNameAT && token != TokenNameATOT) {
token = token == TokenNameLPAREN ? TokenNameBeginLambda : TokenNameBeginTypeArguments;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java
index 3909b0d..a3a5a46 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java
@@ -23,19 +23,19 @@
public interface ParserBasicInformation {
public final static int
- ERROR_SYMBOL = 136,
+ ERROR_SYMBOL = 137,
MAX_NAME_LENGTH = 41,
NUM_STATES = 1313,
- NT_OFFSET = 136,
+ NT_OFFSET = 137,
SCOPE_UBOUND = 354,
SCOPE_SIZE = 355,
LA_STATE_OFFSET = 17809,
MAX_LA = 1,
NUM_RULES = 935,
- NUM_TERMINALS = 136,
+ NUM_TERMINALS = 137,
NUM_NON_TERMINALS = 417,
- NUM_SYMBOLS = 553,
+ NUM_SYMBOLS = 554,
START_STATE = 1185,
EOFT_SYMBOL = 65,
EOLT_SYMBOL = 65,
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 eb561d3..87c90f3 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
@@ -27,6 +27,7 @@
* bug 382353 - [1.8][compiler] Implementation property modifiers should be accepted on default methods.
* bug 382347 - [1.8][compiler] Compiler accepts incorrect default method inheritance
* bug 388281 - [compiler][null] inheritance of null annotations as an option
+ * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.problem;
@@ -119,6 +120,7 @@
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.MemberTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
@@ -368,6 +370,8 @@
case IProblem.PotentialNullLocalVariableReference:
case IProblem.PotentialNullMessageSendReference:
+ case IProblem.ArrayReferencePotentialNullReference:
+ case IProblem.DereferencingNullableExpression:
return CompilerOptions.PotentialNullReference;
case IProblem.RedundantLocalVariableNullAssignment:
@@ -391,11 +395,13 @@
case IProblem.CannotImplementIncompatibleNullness:
case IProblem.ConflictingNullAnnotations:
case IProblem.ConflictingInheritedNullAnnotations:
+ case IProblem.NullityMismatchingTypeAnnotation:
return CompilerOptions.NullSpecViolation;
case IProblem.RequiredNonNullButProvidedPotentialNull:
return CompilerOptions.NullAnnotationInferenceConflict;
case IProblem.RequiredNonNullButProvidedUnknown:
+ case IProblem.NullityMismatchingTypeAnnotationUnchecked:
return CompilerOptions.NullUncheckedConversion;
case IProblem.RedundantNullAnnotation:
case IProblem.RedundantNullDefaultAnnotation:
@@ -9160,12 +9166,10 @@
public void nullityMismatchIsNull(Expression expression, TypeBinding requiredType, char[][] annotationName) {
int problemId = IProblem.RequiredNonNullButProvidedNull;
String[] arguments = new String[] {
- String.valueOf(CharOperation.concatWith(annotationName, '.')),
- String.valueOf(requiredType.readableName())
+ annotatedTypeName(requiredType, annotationName)
};
String[] argumentsShort = new String[] {
- String.valueOf(annotationName[annotationName.length-1]),
- String.valueOf(requiredType.shortReadableName())
+ shortAnnotatedTypeName(requiredType, annotationName)
};
this.handle(problemId, arguments, argumentsShort, expression.sourceStart, expression.sourceEnd);
}
@@ -9173,13 +9177,11 @@
int problemId = IProblem.RequiredNonNullButProvidedSpecdNullable;
char[][] nullableName = this.options.nullableAnnotationName;
String[] arguments = new String[] {
- String.valueOf(CharOperation.concatWith(annotationName, '.')),
- String.valueOf(requiredType.readableName()),
+ annotatedTypeName(requiredType, annotationName),
String.valueOf(CharOperation.concatWith(nullableName, '.'))
};
String[] argumentsShort = new String[] {
- String.valueOf(annotationName[annotationName.length-1]),
- String.valueOf(requiredType.shortReadableName()),
+ shortAnnotatedTypeName(requiredType, annotationName),
String.valueOf(nullableName[nullableName.length-1])
};
this.handle(problemId, arguments, argumentsShort, expression.sourceStart, expression.sourceEnd);
@@ -9188,13 +9190,11 @@
int problemId = IProblem.RequiredNonNullButProvidedPotentialNull;
char[][] nullableName = this.options.nullableAnnotationName;
String[] arguments = new String[] {
- String.valueOf(CharOperation.concatWith(annotationName, '.')),
- String.valueOf(requiredType.readableName()),
+ annotatedTypeName(requiredType, annotationName),
String.valueOf(CharOperation.concatWith(nullableName, '.'))
};
String[] argumentsShort = new String[] {
- String.valueOf(annotationName[annotationName.length-1]),
- String.valueOf(requiredType.shortReadableName()),
+ shortAnnotatedTypeName(requiredType, annotationName),
String.valueOf(nullableName[nullableName.length-1])
};
this.handle(problemId, arguments, argumentsShort, expression.sourceStart, expression.sourceEnd);
@@ -9203,13 +9203,11 @@
int problemId = IProblem.RequiredNonNullButProvidedUnknown;
String[] arguments = new String[] {
String.valueOf(providedType.readableName()),
- String.valueOf(CharOperation.concatWith(annotationName, '.')),
- String.valueOf(requiredType.readableName())
+ annotatedTypeName(requiredType, annotationName)
};
String[] argumentsShort = new String[] {
String.valueOf(providedType.shortReadableName()),
- String.valueOf(annotationName[annotationName.length-1]),
- String.valueOf(requiredType.shortReadableName())
+ shortAnnotatedTypeName(requiredType, annotationName)
};
this.handle(problemId, arguments, argumentsShort, expression.sourceStart, expression.sourceEnd);
}
@@ -13005,6 +13003,50 @@
type.sourceEnd);
}
+private String annotatedTypeName(TypeBinding type, char[][] annotationName) {
+ int dims = 0;
+ if (type instanceof ArrayBinding && ((ArrayBinding)type).nullTagBitsPerDimension != null) {
+ dims = type.dimensions();
+ type = type.leafComponentType();
+ }
+ char[] typeName = type.readableName();
+ char[] annotationDisplayName = CharOperation.concatWith(annotationName, '.');
+ return internalAnnotatedTypeName(annotationDisplayName, typeName, dims);
+}
+private String shortAnnotatedTypeName(TypeBinding type, char[][] annotationName) {
+ int dims = 0;
+ if (type instanceof ArrayBinding && ((ArrayBinding)type).nullTagBitsPerDimension != null) {
+ // if type has annotations on dimensions show the annotation on the outer most dimension:
+ dims = type.dimensions();
+ type = type.leafComponentType();
+ }
+ char[] typeName = type.shortReadableName();
+ char[] annotationDisplayName = annotationName[annotationName.length-1];
+ return internalAnnotatedTypeName(annotationDisplayName, typeName, dims);
+}
+
+String internalAnnotatedTypeName(char[] annotationName, char[] typeName, int dims) {
+ char[] fullName;
+ if (dims > 0) {
+ int plainLen = annotationName.length+typeName.length+2; // adding '@' and ' ' ...
+ fullName = new char[plainLen+(2*dims)]; // ... and []*
+ System.arraycopy(typeName, 0, fullName, 0, typeName.length);
+ fullName[typeName.length] = ' ';
+ fullName[typeName.length+1] = '@';
+ System.arraycopy(annotationName, 0, fullName, typeName.length+2, annotationName.length);
+ for (int i=0; i<dims; i++) {
+ fullName[plainLen+i] = '[';
+ fullName[plainLen+i+1] = ']';
+ }
+ } else {
+ fullName = new char[annotationName.length+typeName.length+2]; // adding '@' and ' '
+ fullName[0] = '@';
+ System.arraycopy(annotationName, 0, fullName, 1, annotationName.length);
+ fullName[annotationName.length+1] = ' ';
+ System.arraycopy(typeName, 0, fullName, annotationName.length+2, typeName.length);
+ }
+ return String.valueOf(fullName);
+}
private Annotation findAnnotation(Annotation[] annotations, int typeId) {
if (annotations != null) {
// should have a @NonNull/@Nullable annotation, search for it:
@@ -13057,4 +13099,38 @@
argument.declarationSourceStart,
argument.declarationSourceEnd);
}
+
+public void arrayReferencePotentialNullReference(ArrayReference arrayReference) {
+ // TODO(stephan): merge with other expressions
+ this.handle(IProblem.ArrayReferencePotentialNullReference, NoArgument, NoArgument, arrayReference.sourceStart, arrayReference.sourceEnd);
+
+}
+public void nullityMismatchingTypeAnnotation(Expression expression, TypeBinding providedType, TypeBinding requiredType,
+ boolean uncheckedConversion, LookupEnvironment env)
+{
+ String[] arguments = new String[] {
+ String.valueOf(requiredType.nullAnnotatedReadableName(env, false)),
+ String.valueOf(providedType.nullAnnotatedReadableName(env, false))
+ };
+ String[] shortArguments = new String[] {
+ String.valueOf(requiredType.nullAnnotatedReadableName(env, true)),
+ String.valueOf(providedType.nullAnnotatedReadableName(env, true))
+ };
+ this.handle(
+ uncheckedConversion ? IProblem.NullityMismatchingTypeAnnotationUnchecked : IProblem.NullityMismatchingTypeAnnotation,
+ arguments, shortArguments, expression.sourceStart, expression.sourceEnd);
+}
+public void dereferencingNullableExpression(Expression expression, LookupEnvironment env) {
+ if (expression instanceof MessageSend) {
+ MessageSend send = (MessageSend) expression;
+ messageSendPotentialNullReference(send.binding, send);
+ return;
+ }
+ char[][] nullableName = env.getNullableAnnotationName();
+ char[] nullableShort = nullableName[nullableName.length-1];
+ String[] arguments = { String.valueOf(nullableShort) };
+ // TODO(stephan): more sophisticated handling for various kinds of expressions
+ this.handle(IProblem.DereferencingNullableExpression, arguments, arguments, expression.sourceStart, expression.sourceEnd);
+
+}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index 43d77eb..c30428e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -26,6 +26,7 @@
# bug 382353 - [1.8][compiler] Implementation property modifiers should be accepted on default methods.
# bug 382347 - [1.8][compiler] Compiler accepts incorrect default method inheritance
# bug 388281 - [compiler][null] inheritance of null annotations as an option
+# bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
###############################################################################
0 = {0}
1 = super cannot be used in java.lang.Object
@@ -695,9 +696,9 @@
890 = Cannot switch on an enum value for source level below 1.5. Only convertible int values are permitted
### NULL ANNOTATIONS
-910 = Null type mismatch: required ''@{0} {1}'' but the provided value is null
-911 = Null type mismatch: required ''@{0} {1}'' but the provided value is inferred as @{2}
-912 = Null type safety: The expression of type {0} needs unchecked conversion to conform to ''@{1} {2}''
+910 = Null type mismatch: required ''{0}'' but the provided value is null
+911 = Null type mismatch: required ''{0}'' but the provided value is inferred as @{1}
+912 = Null type safety: The expression of type {0} needs unchecked conversion to conform to ''{1}''
913 = A default nullness annotation has not been specified for the package {0}
914 = The return type is incompatible with the @{1} return from {0}
915 = Illegal redefinition of parameter {0}, inherited method from {1} declares this parameter as @{2}
@@ -717,10 +718,14 @@
930 = A default nullness annotation has not been specified for the type {0}
931 = Redundant null check: The variable {0} is specified as @{1}
932 = Null comparison always yields false: The variable {0} is specified as @{1}
-933 = Null type mismatch: required ''@{0} {1}'' but the provided value is specified as @{2}
+933 = Null type mismatch: required ''{0}'' but the provided value is specified as @{1}
939 = The default ''@{0}'' conflicts with the inherited ''@{1}'' annotation in the overridden method from {2}
940 = Conflict between inherited null annotations ''@{0}'' declared in {1} versus ''@{2}'' declared in {3}
+951 = Potential null pointer access: array element may be null
+952 = Potential null pointer access: this expression has a ''@{0}'' type
+953 = Null type mismatch (type annotations): required ''{0}'' but this expression has type ''{1}''
+954 = Null type mismatch (type annotations): the expression of type ''{1}'' needs unchecked conversion to conform to ''{0}''
// Java 8
1001 = Syntax error, modifiers and annotations are not allowed for the lambda parameter {0} as its type is elided