Bug 446442 - [1.8] merge null annotations from super methods
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 b6c4cc8..98ea5fd 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
@@ -35,6 +35,7 @@
* Bug 430150 - [1.8][null] stricter checking against type variables
* Bug 439516 - [1.8][null] NonNullByDefault wrongly applied to implicit type bound of binary type
* Bug 438467 - [compiler][null] Better error position for "The method _ cannot implement the corresponding method _ due to incompatible nullness constraints"
+ * Bug 446442 - [1.8] merge null annotations from super methods
* Jesper S Moller - Contributions for
* bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
* bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
@@ -432,9 +433,10 @@
expectedProblemAttributes.put("ContainerAnnotationTypeHasShorterRetention", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("ContainerAnnotationTypeHasWrongValueType", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
expectedProblemAttributes.put("ContainerAnnotationTypeMustHaveValue", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
- expectedProblemAttributes.put("ContradictoryNullAnnotations", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
- expectedProblemAttributes.put("ContradictoryNullAnnotationsOnBound", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
- expectedProblemAttributes.put("ContradictoryNullAnnotationsInferred", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
+ expectedProblemAttributes.put("ContradictoryNullAnnotations", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
+ expectedProblemAttributes.put("ContradictoryNullAnnotationsOnBound", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
+ expectedProblemAttributes.put("ContradictoryNullAnnotationsInferred", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
+ expectedProblemAttributes.put("ContradictoryNullAnnotationsInferredFunctionType", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("ComparingIdentical", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
expectedProblemAttributes.put("ConflictingImport", new ProblemAttributes(CategorizedProblem.CAT_IMPORT));
expectedProblemAttributes.put("ConflictingNullAnnotations", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
@@ -1264,9 +1266,10 @@
expectedProblemAttributes.put("ContainerAnnotationTypeHasShorterRetention", SKIP);
expectedProblemAttributes.put("ContainerAnnotationTypeHasWrongValueType", SKIP);
expectedProblemAttributes.put("ContainerAnnotationTypeMustHaveValue", SKIP);
- expectedProblemAttributes.put("ContradictoryNullAnnotations", SKIP);
- expectedProblemAttributes.put("ContradictoryNullAnnotationsOnBound", SKIP);
- expectedProblemAttributes.put("ContradictoryNullAnnotationsInferred", SKIP);
+ expectedProblemAttributes.put("ContradictoryNullAnnotations", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION));
+ expectedProblemAttributes.put("ContradictoryNullAnnotationsOnBound", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION));
+ expectedProblemAttributes.put("ContradictoryNullAnnotationsInferred", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION));
+ expectedProblemAttributes.put("ContradictoryNullAnnotationsInferredFunctionType", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION));
expectedProblemAttributes.put("ConstructorVarargsArgumentNeedCast", new ProblemAttributes(JavaCore.COMPILER_PB_VARARGS_ARGUMENT_NEED_CAST));
expectedProblemAttributes.put("CorruptedSignature", SKIP);
expectedProblemAttributes.put("DanglingReference", SKIP);
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 923c96f..564c6c5 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
@@ -6960,4 +6960,342 @@
"Contradictory null annotations: method was inferred as \'@NonNull @Nullable String a(@NonNull @Nullable String)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
"----------\n");
}
+public void testBug446442_comment2a() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "Test.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface Foo<T, N extends Number> {\n" +
+ " void m(@NonNull N arg2);\n" +
+ "\n" +
+ " void m(@Nullable T arg1);\n" +
+ "}\n" +
+ "\n" +
+ "interface Baz extends Foo<Integer, Integer> {}\n" +
+ "\n" +
+ "class Impl implements Baz {\n" +
+ " public void m(@NonNull Integer i) {}\n" +
+ "}\n" +
+ "\n" +
+ "public class Test {\n" +
+ " Baz baz= x -> {\n" +
+ " x= null;\n" +
+ " }; \n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in Test.java (at line 11)\n" +
+ " public void m(@NonNull Integer i) {}\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "Illegal redefinition of parameter i, inherited method from Foo<Integer,Integer> declares this parameter as @Nullable\n" +
+ "----------\n");
+}
+// swapped order of method declarations
+public void testBug446442_comment2b() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "Test.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface Foo<T, N extends Number> {\n" +
+ " void m(@Nullable T arg1);\n" +
+ "\n" +
+ " void m(@NonNull N arg2);\n" +
+ "}\n" +
+ "\n" +
+ "interface Baz extends Foo<Integer, Integer> {}\n" +
+ "\n" +
+ "class Impl implements Baz {\n" +
+ " public void m(@NonNull Integer i) {}\n" +
+ "}\n" +
+ "\n" +
+ "public class Test {\n" +
+ " Baz baz= x -> {\n" +
+ " x= null;\n" +
+ " }; \n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in Test.java (at line 11)\n" +
+ " public void m(@NonNull Integer i) {}\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "Illegal redefinition of parameter i, inherited method from Foo<Integer,Integer> declares this parameter as @Nullable\n" +
+ "----------\n");
+}
+// inherit from two different supers
+public void testBug446442_comment2c() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "Test.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface Foo0<T, N extends Number> {\n" +
+ " void m(@Nullable T arg1);\n" +
+ "}\n" +
+ "\n" +
+ "interface Foo1<T, N extends Number> {\n" +
+ " void m(@NonNull N arg2);\n" +
+ "}\n" +
+ "\n" +
+ "interface Baz extends Foo1<Integer, Integer>, Foo0<Integer, Integer> {}\n" +
+ "\n" +
+ "class Impl implements Baz {\n" +
+ " public void m(@NonNull Integer i) {}\n" +
+ "}\n" +
+ "\n" +
+ "public class Test {\n" +
+ " Baz baz= x -> {\n" +
+ " x= null;\n" +
+ " }; \n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in Test.java (at line 13)\n" +
+ " public void m(@NonNull Integer i) {}\n" +
+ " ^^^^^^^^^^^^^^^^\n" +
+ "Illegal redefinition of parameter i, inherited method from Foo0<Integer,Integer> declares this parameter as @Nullable\n" +
+ "----------\n");
+}
+// merging @NonNull & unannotated in arg-position must answer unannotated
+public void testBug446442_2a() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "Test.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface Foo<T, N extends Number> {\n" +
+ " void m(@NonNull N arg2);\n" +
+ "\n" +
+ " void m(T arg1);\n" +
+ "}\n" +
+ "\n" +
+ "interface Baz extends Foo<Integer, Integer> {}\n" +
+ "\n" +
+ "public class Test {\n" +
+ " Baz baz= x -> {\n" +
+ " @NonNull Object o = x;\n" +
+ " }; \n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. WARNING in Test.java (at line 12)\n" +
+ " @NonNull Object o = x;\n" +
+ " ^\n" +
+ "Null type safety (type annotations): The expression of type \'Integer\' needs unchecked conversion to conform to \'@NonNull Object\'\n" +
+ "----------\n");
+}
+// merging @NonNull & unannotated in arg-position must answer unannotated - swapped order
+public void testBug446442_2b() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "Test.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface Foo<T, N extends Number> {\n" +
+ " void m(T arg1);\n" +
+ "\n" +
+ " void m(@NonNull N arg2);\n" +
+ "}\n" +
+ "\n" +
+ "interface Baz extends Foo<Integer, Integer> {}\n" +
+ "\n" +
+ "public class Test {\n" +
+ " Baz baz= x -> {\n" +
+ " @NonNull Object o = x;\n" +
+ " }; \n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. WARNING in Test.java (at line 12)\n" +
+ " @NonNull Object o = x;\n" +
+ " ^\n" +
+ "Null type safety (type annotations): The expression of type \'Integer\' needs unchecked conversion to conform to \'@NonNull Object\'\n" +
+ "----------\n");
+}
+// using inherited implementation to fulfill both contracts
+public void testBug446442_3() {
+ runConformTestWithLibs(
+ new String[] {
+ "Test.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface Foo<T, N extends Number> {\n" +
+ " void m(@NonNull N arg2);\n" +
+ "\n" +
+ " void m(T arg1);\n" +
+ "}\n" +
+ "\n" +
+ "interface Baz extends Foo<Integer, Integer> {}\n" +
+ "class Impl {\n" +
+ " public void m(Integer a) {}\n" +
+ "}\n" +
+ "class BazImpl extends Impl implements Baz {}\n" +
+ "\n" +
+ "public class Test {\n" +
+ " void test(BazImpl b) {\n" +
+ " b.m(null);\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "");
+}
+// unsuccessful attempt to trigger use of MostSpecificExceptionMethodBinding
+public void testBug446442_4() {
+ runConformTestWithLibs(
+ new String[] {
+ "Test.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface Foo<T, N extends Number> {\n" +
+ " abstract void m(@NonNull N arg2) throws Exception;\n" +
+ "\n" +
+ " default void m(T arg1) throws java.io.IOException {}\n" +
+ "}\n" +
+ "\n" +
+ "interface Baz extends Foo<Integer, Integer> {}\n" +
+ "abstract class Impl {\n" +
+ " public void m(Integer a) throws java.io.IOException {}\n" +
+ "}\n" +
+ "class BazImpl extends Impl implements Baz {}\n" +
+ "\n" +
+ "public class Test {\n" +
+ " void test(BazImpl b) throws java.io.IOException {\n" +
+ " b.m(null);\n" +
+ " }\n" +
+ "}\n"
+ },
+ getCompilerOptions(),
+ "");
+}
+// annotated return types
+public void testBug446442_5() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "Test.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "interface Foo<T, N extends Number> {\n" +
+ " T m(T t);\n" +
+ "\n" +
+ " @NonNull N m(N n);\n" +
+ "}\n" +
+ "\n" +
+ "interface Baz extends Foo<Integer, Integer> {}\n" +
+ "\n" +
+ "class Impl implements Baz {\n" +
+ " public Integer m(Integer i) { return new Integer(0); }\n" +
+ "}\n" +
+ "\n" +
+ "public class Test {\n" +
+ " Baz baz= x -> null;\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in Test.java (at line 11)\n" +
+ " public Integer m(Integer i) { return new Integer(0); }\n" +
+ " ^^^^^^^\n" +
+ "The return type is incompatible with \'@NonNull Integer\' returned from Foo<Integer,Integer>.m(Integer) (mismatching null constraints)\n" +
+ "----------\n" +
+ "2. ERROR in Test.java (at line 15)\n" +
+ " Baz baz= x -> null;\n" +
+ " ^^^^\n" +
+ "Null type mismatch: required \'@NonNull Integer\' but the provided value is null\n" +
+ "----------\n");
+}
+// conflicting annotations on type arguments
+public void testBug446442_6a() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "Test.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "import java.util.*;\n" +
+ "interface Foo<T,C1 extends Collection<T>, C2 extends List<T>> {\n" +
+ " void m(C1 a1);\n" +
+ "\n" +
+ " void m(C2 a2);\n" +
+ "}\n" +
+ "\n" +
+ "interface Baz extends Foo<Integer, ArrayList<@NonNull Integer>, ArrayList<@Nullable Integer>> {}\n" +
+ "\n" +
+ "class Impl implements Baz {\n" +
+ " public void m(ArrayList<@NonNull Integer> i) {} // contradictory type cannot be implemented\n" +
+ "}\n" +
+ "\n" +
+ "public class Test {\n" +
+ " Baz baz= x -> { // contradictory type cannot be used as SAM\n" +
+ " x.add(null); // contradictory type cause errors at call sites\n" +
+ " }; \n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in Test.java (at line 12)\n" +
+ " public void m(ArrayList<@NonNull Integer> i) {} // contradictory type cannot be implemented\n" +
+ " ^^^^^^^^^\n" +
+ "Illegal redefinition of parameter i, inherited method from Foo<Integer,ArrayList<Integer>,ArrayList<Integer>> declares this parameter as \'ArrayList<@Nullable Integer>\' (mismatching null constraints)\n" +
+ "----------\n" +
+ "2. ERROR in Test.java (at line 16)\n" +
+ " Baz baz= x -> { // contradictory type cannot be used as SAM\n" +
+ " x.add(null); // contradictory type cause errors at call sites\n" +
+ " }; \n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Contradictory null annotations: function type was inferred as \'void (ArrayList<@NonNull @Nullable Integer>)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "----------\n" +
+ "3. ERROR in Test.java (at line 17)\n" +
+ " x.add(null); // contradictory type cause errors at call sites\n" +
+ " ^^^^^^^^^^^\n" +
+ "Contradictory null annotations: method was inferred as \'boolean add(@NonNull @Nullable Integer)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "----------\n");
+}
+// swapped order of method declarations + added return type
+public void testBug446442_6b() {
+ runNegativeTestWithLibs(
+ new String[] {
+ "Test.java",
+ "import org.eclipse.jdt.annotation.*;\n" +
+ "import java.util.*;\n" +
+ "interface Foo<T,C1 extends Collection<T>, C2 extends List<T>> {\n" +
+ " C2 m(C2 a2);\n" +
+ "\n" +
+ " C1 m(C1 a1);\n" +
+ "}\n" +
+ "\n" +
+ "interface Baz extends Foo<Integer, ArrayList<@NonNull Integer>, ArrayList<@Nullable Integer>> {}\n" +
+ "\n" +
+ "class Impl implements Baz {\n" +
+ " public ArrayList<@NonNull Integer> m(ArrayList<@Nullable Integer> i) { return i; }\n" +
+ "}\n" +
+ "\n" +
+ "public class Test {\n" +
+ " Baz baz= x -> {\n" +
+ " x.add(null);\n" +
+ " x.get(0);\n" +
+ " return x;\n" +
+ " };\n" +
+ "}\n"
+ },
+ "----------\n" +
+ "1. ERROR in Test.java (at line 12)\n" +
+ " public ArrayList<@NonNull Integer> m(ArrayList<@Nullable Integer> i) { return i; }\n" +
+ " ^^^^^^^^^\n" +
+ "The return type is incompatible with \'ArrayList<@Nullable Integer>\' returned from Foo<Integer,ArrayList<Integer>,ArrayList<Integer>>.m(ArrayList<Integer>) (mismatching null constraints)\n" +
+ "----------\n" +
+ "2. ERROR in Test.java (at line 12)\n" +
+ " public ArrayList<@NonNull Integer> m(ArrayList<@Nullable Integer> i) { return i; }\n" +
+ " ^^^^^^^^^\n" +
+ "Illegal redefinition of parameter i, inherited method from Foo<Integer,ArrayList<Integer>,ArrayList<Integer>> declares this parameter as \'ArrayList<@NonNull Integer>\' (mismatching null constraints)\n" +
+ "----------\n" +
+ "3. ERROR in Test.java (at line 16)\n" +
+ " Baz baz= x -> {\n" +
+ " x.add(null);\n" +
+ " x.get(0);\n" +
+ " return x;\n" +
+ " };\n" +
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
+ "Contradictory null annotations: function type was inferred as \'ArrayList<@NonNull @Nullable Integer> (ArrayList<@NonNull @Nullable Integer>)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "----------\n" +
+ "4. ERROR in Test.java (at line 17)\n" +
+ " x.add(null);\n" +
+ " ^^^^^^^^^^^\n" +
+ "Contradictory null annotations: method was inferred as \'boolean add(@NonNull @Nullable Integer)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "----------\n" +
+ "5. ERROR in Test.java (at line 18)\n" +
+ " x.get(0);\n" +
+ " ^^^^^^^^\n" +
+ "Contradictory null annotations: method was inferred as \'@NonNull @Nullable Integer get(int)\', but only one of \'@NonNull\' and \'@Nullable\' can be effective at any location\n" +
+ "----------\n");
+}
}
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 1b27d3c..d1df0cd 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
@@ -194,6 +194,7 @@
* NullityMismatchAgainstFreeTypeVariable
* ImplicitObjectBoundNoNullDefault
* IllegalParameterNullityRedefinition
+ * ContradictoryNullAnnotationsInferredFunctionType
* Jesper S Moller - added the following constants
* TargetTypeNotAFunctionalInterface
* OuterLocalMustBeEffectivelyFinal
@@ -1798,6 +1799,8 @@
int ImplicitObjectBoundNoNullDefault = 971;
/** @since 3.11 */
int IllegalParameterNullityRedefinition = MethodRelated + 972;
+ /** @since 3.11 */
+ int ContradictoryNullAnnotationsInferredFunctionType = MethodRelated + 973;
// Java 8 work
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
index 5dd8d3b..6564b8a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
@@ -32,6 +32,7 @@
* Bug 440143 - [1.8][null] one more case of contradictory null annotations regarding type variables
* Bug 441693 - [1.8][null] Bogus warning for type argument annotated with @NonNull
* Bug 434483 - [1.8][compiler][inference] Type inference not picked up with method reference
+ * Bug 446442 - [1.8] merge null annotations from super methods
* Jesper S Moller - Contributions for
* bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
* bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
@@ -947,7 +948,7 @@
AnnotationBinding [] se8Annotations = null;
int se8count = 0;
long se8nullBits = 0;
- Annotation se8NullAnnotation = null;
+ Annotation se8NullAnnotation = null; // just any involved annotation so we have a location for error reporting
int firstSE8 = -1;
for (int i = 0, length = annotations.length; i < length; i++) {
AnnotationBinding annotation = annotations[i].getCompilerAnnotation();
@@ -970,10 +971,10 @@
se8Annotations[se8count++] = annotation;
}
if (annotationType.id == TypeIds.T_ConfiguredAnnotationNonNull) {
- se8nullBits = TagBits.AnnotationNonNull;
+ se8nullBits |= TagBits.AnnotationNonNull;
se8NullAnnotation = annotations[i];
} else if (annotationType.id == TypeIds.T_ConfiguredAnnotationNullable) {
- se8nullBits = TagBits.AnnotationNullable;
+ se8nullBits |= TagBits.AnnotationNullable;
se8NullAnnotation = annotations[i];
}
}
@@ -1038,13 +1039,14 @@
// for arrays: @T X[] SE7 associates @T to the type, but in SE8 it affects the leaf component type
long prevNullBits = existingType.leafComponentType().tagBits & TagBits.AnnotationNullMASK;
- if (se8nullBits != 0 && prevNullBits != se8nullBits && ((prevNullBits | se8nullBits) == TagBits.AnnotationNullMASK)) {
- if (existingType instanceof TypeVariableBinding) {
- // let type-use annotations override annotations on the type parameter declaration
- existingType = existingType.withoutToplevelNullAnnotation();
- } else {
- scope.problemReporter().contradictoryNullAnnotations(se8NullAnnotation);
+ if ((prevNullBits | se8nullBits) == TagBits.AnnotationNullMASK) { // contradiction after merge?
+ if (!(existingType instanceof TypeVariableBinding)) { // let type-use annotations override annotations on the type parameter declaration
+ if (prevNullBits != TagBits.AnnotationNullMASK && se8nullBits != TagBits.AnnotationNullMASK) { // conflict caused by the merge?
+ scope.problemReporter().contradictoryNullAnnotations(se8NullAnnotation);
+ }
+ se8Annotations = Binding.NO_ANNOTATIONS;
}
+ existingType = existingType.withoutToplevelNullAnnotation();
}
TypeBinding oldLeafType = (unionRef == null) ? existingType.leafComponentType() : unionRef.resolvedType;
AnnotationBinding [][] goodies = new AnnotationBinding[typeRef.getAnnotatableLevels()][];
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
index 4f992eb..8cd39d8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
@@ -19,6 +19,7 @@
* Bug 424403 - [1.8][compiler] Generic method call with method reference argument fails to resolve properly.
* Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280)
* Bug 428352 - [1.8][compiler] Resolution errors don't always surface
+ * Bug 446442 - [1.8] merge null annotations from super methods
* Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
* Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas
*******************************************************************************/
@@ -179,6 +180,8 @@
this.descriptor = sam;
if (kosherDescriptor(blockScope, sam, true)) {
+ if (blockScope.environment().globalOptions.isAnnotationBasedNullAnalysisEnabled)
+ NullAnnotationMatching.checkForContradictions(sam, this, blockScope);
return this.resolvedType = this.expectedType;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java
index be01e6f..1a979f7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java
@@ -13,11 +13,13 @@
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding;
import org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
@@ -418,8 +420,8 @@
* After a method has substituted type parameters, check if this resulted in any contradictory null annotations.
* Problems are either reported directly (if scope != null) or by returning a ProblemMethodBinding.
*/
- public static MethodBinding checkForContraditions(
- final MethodBinding method, final InvocationSite invocationSite, final Scope scope) {
+ public static MethodBinding checkForContradictions(
+ final MethodBinding method, final Object location, final Scope scope) {
class SearchContradictions extends TypeBindingVisitor {
ReferenceBinding typeWithContradiction;
@@ -441,19 +443,27 @@
}
}
+ int start = 0, end = 0;
+ if (location instanceof InvocationSite) {
+ start = ((InvocationSite) location).sourceStart();
+ end = ((InvocationSite) location).sourceEnd();
+ } else if (location instanceof ASTNode) {
+ start = ((ASTNode) location).sourceStart;
+ end = ((ASTNode) location).sourceEnd;
+ }
SearchContradictions searchContradiction = new SearchContradictions();
TypeBindingVisitor.visit(searchContradiction, method.returnType);
if (searchContradiction.typeWithContradiction != null) {
if (scope == null)
return new ProblemMethodBinding(method, method.selector, method.parameters, ProblemReasons.ContradictoryNullAnnotations);
- scope.problemReporter().contradictoryNullAnnotationsInferred(method, invocationSite);
+ scope.problemReporter().contradictoryNullAnnotationsInferred(method, start, end, location instanceof FunctionalExpression);
// note: if needed, we might want to update the method by removing the contradictory annotations??
return method;
}
Expression[] arguments = null;
- if (invocationSite instanceof Invocation)
- arguments = ((Invocation)invocationSite).arguments();
+ if (location instanceof Invocation)
+ arguments = ((Invocation)location).arguments();
for (int i = 0; i < method.parameters.length; i++) {
TypeBindingVisitor.visit(searchContradiction, method.parameters[i]);
if (searchContradiction.typeWithContradiction != null) {
@@ -462,10 +472,53 @@
if (arguments != null && i < arguments.length)
scope.problemReporter().contradictoryNullAnnotationsInferred(method, arguments[i]);
else
- scope.problemReporter().contradictoryNullAnnotationsInferred(method, invocationSite);
+ scope.problemReporter().contradictoryNullAnnotationsInferred(method, start, end, location instanceof FunctionalExpression);
return method;
}
}
return method;
}
+
+ public static TypeBinding strongerType(TypeBinding type1, TypeBinding type2, LookupEnvironment environment) {
+ if ((type1.tagBits & TagBits.AnnotationNonNull) != 0)
+ return mergeTypeAnnotations(type1, type2, true, environment);
+ return mergeTypeAnnotations(type2, type1, true, environment); // don't bother to distinguish unannotated vs. @Nullable, since both can accept null
+ }
+
+ public static TypeBinding[] weakerTypes(TypeBinding[] parameters1, TypeBinding[] parameters2, LookupEnvironment environment) {
+ TypeBinding[] newParameters = new TypeBinding[parameters1.length];
+ for (int i = 0; i < newParameters.length; i++) {
+ long tagBits1 = parameters1[i].tagBits;
+ long tagBits2 = parameters2[i].tagBits;
+ if ((tagBits1 & TagBits.AnnotationNullable) != 0)
+ newParameters[i] = mergeTypeAnnotations(parameters1[i], parameters2[i], true, environment); // @Nullable must be preserved
+ else if ((tagBits2 & TagBits.AnnotationNullable) != 0)
+ newParameters[i] = mergeTypeAnnotations(parameters2[i], parameters1[i], true, environment); // @Nullable must be preserved
+ else if ((tagBits1 & TagBits.AnnotationNonNull) == 0)
+ newParameters[i] = mergeTypeAnnotations(parameters1[i], parameters2[i], true, environment); // unannotated must be preserved
+ else
+ newParameters[i] = mergeTypeAnnotations(parameters2[i], parameters1[i], true, environment); // either unannotated, or both are @NonNull
+ }
+ return newParameters;
+ }
+ private static TypeBinding mergeTypeAnnotations(TypeBinding type, TypeBinding otherType, boolean top, LookupEnvironment environment) {
+ TypeBinding mainType = type;
+ if (!top) {
+ // for all but the top level type superimpose other's type annotation onto type
+ AnnotationBinding[] otherAnnotations = otherType.getTypeAnnotations();
+ if (otherAnnotations != Binding.NO_ANNOTATIONS)
+ mainType = environment.createAnnotatedType(type, otherAnnotations);
+ }
+ if (mainType instanceof ParameterizedTypeBinding && otherType instanceof ParameterizedTypeBinding) {
+ ParameterizedTypeBinding ptb = (ParameterizedTypeBinding) type, otherPTB = (ParameterizedTypeBinding) otherType;
+ TypeBinding[] typeArguments = ptb.arguments;
+ TypeBinding[] otherTypeArguments = otherPTB.arguments;
+ TypeBinding[] newTypeArguments = new TypeBinding[typeArguments.length];
+ for (int i = 0; i < typeArguments.length; i++) {
+ newTypeArguments[i] = mergeTypeAnnotations(typeArguments[i], otherTypeArguments[i], false, environment);
+ }
+ return environment.createParameterizedType(ptb.genericType(), newTypeArguments, ptb.enclosingType());
+ }
+ return mainType;
+ }
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
index 36e08a6..80370ea 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
@@ -112,7 +112,7 @@
// recurse to prepare currentSuper
checkImplicitNullAnnotations(currentSuper, null, false, scope); // TODO (stephan) complain=true if currentSuper is source method??
}
- checkNullSpecInheritance(currentMethod, srcMethod, needToApplyReturnNonNullDefault, needToApplyParameterNonNullDefault, complain, currentSuper, scope, inheritedNonNullnessInfos);
+ checkNullSpecInheritance(currentMethod, srcMethod, needToApplyReturnNonNullDefault, needToApplyParameterNonNullDefault, complain, currentSuper, null, scope, inheritedNonNullnessInfos);
needToApplyNonNullDefault = false;
}
@@ -192,16 +192,18 @@
{
MethodBinding [] ifcMethods = superType.getMethods(selector, suggestedParameterLength);
int length = ifcMethods.length;
+ boolean added = false;
for (int i=0; i<length; i++) {
MethodBinding currentMethod = ifcMethods[i];
if (currentMethod.isStatic())
continue;
if (MethodVerifier.doesMethodOverride(original, currentMethod, this.environment)) {
result.add(currentMethod);
- return; // at most one method is overridden from any supertype
+ added = true; // when overriding one or more methods from superType don't traverse to transitive superTypes
}
}
- findAllOverriddenMethods(original, selector, suggestedParameterLength, superType, ifcsSeen, result);
+ if (!added)
+ findAllOverriddenMethods(original, selector, suggestedParameterLength, superType, ifcsSeen, result);
}
/**
@@ -213,6 +215,7 @@
* @param shouldComplain should we report any errors found?
* (see also comment about flows into this method, below).
* @param inheritedMethod one overridden method from a super type
+ * @param allInheritedMethods look here to see if nonnull-unannotated conflict already exists in one super type
* @param scope provides context for error reporting etc.
* @param inheritedNonNullnessInfos if non-null, this array of non-null elements is used for
* interim recording of nullness information from inheritedMethod rather than prematurely updating currentMethod.
@@ -220,7 +223,7 @@
*/
void checkNullSpecInheritance(MethodBinding currentMethod, AbstractMethodDeclaration srcMethod,
boolean hasReturnNonNullDefault, boolean hasParameterNonNullDefault, boolean shouldComplain,
- MethodBinding inheritedMethod, Scope scope, InheritedNonNullnessInfo[] inheritedNonNullnessInfos)
+ MethodBinding inheritedMethod, MethodBinding[] allInheritedMethods, Scope scope, InheritedNonNullnessInfo[] inheritedNonNullnessInfos)
{
// Note that basically two different flows lead into this method:
// (1) during MethodVerifyer15.checkMethods() we want to report errors (against srcMethod or against the current type)
@@ -324,6 +327,7 @@
else if (currentMethod.parameterNonNullness != null)
length = currentMethod.parameterNonNullness.length;
+ parameterLoop:
for (int i = 0; i < length; i++) {
if (currentMethod.parameters[i].isBaseType()) continue;
@@ -404,6 +408,12 @@
continue;
} else if (inheritedNonNullNess == Boolean.TRUE) {
// not strictly a conflict, but a configurable warning is given anyway:
+ if (allInheritedMethods != null) {
+ // avoid this optional warning if the conflict already existed in one supertype (merging of two methods into one?)
+ for (MethodBinding one : allInheritedMethods)
+ if (TypeBinding.equalsEquals(inheritedMethod.declaringClass, one.declaringClass) && getParameterNonNullness(one, i, useTypeAnnotations) != Boolean.TRUE)
+ continue parameterLoop;
+ }
scope.problemReporter().parameterLackingNonnullAnnotation(
currentArgument,
inheritedMethod.declaringClass,
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
index 359f71e..905fdf8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
@@ -28,6 +28,7 @@
* Bug 390889 - [1.8][compiler] Evaluate options to support 1.7- projects against 1.8 JRE.
* Bug 440773 - [1.8][null]DefaultLocation.RETURN_TYPE erroneously affects method parameters in @NonNullByDefault
* Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
+ * Bug 446442 - [1.8] merge null annotations from super methods
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -103,7 +104,7 @@
this.type.addSyntheticBridgeMethod(originalInherited, concreteMethod.original());
}
if (analyseNullAnnotations && !concreteMethod.isStatic() && !abstractMethod.isStatic()) {
- checkNullSpecInheritance(concreteMethod, srcMethod, hasReturnNonNullDefault, hasParameterNonNullDefault, true, abstractMethod, this.type.scope, null);
+ checkNullSpecInheritance(concreteMethod, srcMethod, hasReturnNonNullDefault, hasParameterNonNullDefault, true, abstractMethod, abstractMethods, this.type.scope, null);
}
}
}
@@ -400,12 +401,12 @@
boolean hasParameterNonNullDefault = currentMethod.hasNonNullDefaultFor(Binding.DefaultLocationParameter, useTypeAnnotations);
for (int i = length; --i >= 0;)
if (!currentMethod.isStatic() && !methods[i].isStatic())
- checkNullSpecInheritance(currentMethod, srcMethod, hasReturnNonNullDefault, hasParameterNonNullDefault, true, methods[i], this.type.scope, null);
+ checkNullSpecInheritance(currentMethod, srcMethod, hasReturnNonNullDefault, hasParameterNonNullDefault, true, methods[i], methods, this.type.scope, null);
}
}
void checkNullSpecInheritance(MethodBinding currentMethod, AbstractMethodDeclaration srcMethod,
- boolean hasReturnNonNullDefault, boolean hasParameterNonNullDefault, boolean complain, MethodBinding inheritedMethod, Scope scope, InheritedNonNullnessInfo[] inheritedNonNullnessInfos)
+ boolean hasReturnNonNullDefault, boolean hasParameterNonNullDefault, boolean complain, MethodBinding inheritedMethod, MethodBinding[] allInherited, Scope scope, InheritedNonNullnessInfo[] inheritedNonNullnessInfos)
{
complain &= !currentMethod.isConstructor();
if (!hasReturnNonNullDefault && !hasParameterNonNullDefault && !complain && !this.environment.globalOptions.inheritNullAnnotations) {
@@ -419,7 +420,7 @@
{
this.buddyImplicitNullAnnotationsVerifier.checkImplicitNullAnnotations(currentMethod, srcMethod, complain, scope);
}
- super.checkNullSpecInheritance(currentMethod, srcMethod, hasReturnNonNullDefault, hasParameterNonNullDefault, complain, inheritedMethod, scope, inheritedNonNullnessInfos);
+ super.checkNullSpecInheritance(currentMethod, srcMethod, hasReturnNonNullDefault, hasParameterNonNullDefault, complain, inheritedMethod, allInherited, scope, inheritedNonNullnessInfos);
}
void reportRawReferences() {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
index 11c7909..4168962 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
@@ -21,6 +21,7 @@
* Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
* Bug 434602 - Possible error with inferred null annotations leading to contradictory null annotations
* Bug 434483 - [1.8][compiler][inference] Type inference not picked up with method reference
+ * Bug 446442 - [1.8] merge null annotations from super methods
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -239,7 +240,7 @@
}
if (invocationTypeInferred) {
if (compilerOptions.isAnnotationBasedNullAnalysisEnabled)
- NullAnnotationMatching.checkForContraditions(methodSubstitute, invocationSite, scope);
+ NullAnnotationMatching.checkForContradictions(methodSubstitute, invocationSite, scope);
MethodBinding problemMethod = methodSubstitute.boundCheck18(scope, arguments);
if (problemMethod != null) {
return problemMethod;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
index b158d42..1c82ac8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
@@ -686,7 +686,7 @@
// substitute methods, so as to get updated declaring class at least
parameterizedMethods[i] = createParameterizedMethod(originalMethods[i]);
if (useNullTypeAnnotations)
- parameterizedMethods[i] = NullAnnotationMatching.checkForContraditions(parameterizedMethods[i], null, null);
+ parameterizedMethods[i] = NullAnnotationMatching.checkForContradictions(parameterizedMethods[i], null, null);
}
if (this.methods == null) {
MethodBinding[] temp = new MethodBinding[length];
@@ -967,7 +967,7 @@
// substitute all methods, so as to get updated declaring class at least
parameterizedMethods[i] = createParameterizedMethod(originalMethods[i]);
if (useNullTypeAnnotations)
- parameterizedMethods[i] = NullAnnotationMatching.checkForContraditions(parameterizedMethods[i], null, null);
+ parameterizedMethods[i] = NullAnnotationMatching.checkForContradictions(parameterizedMethods[i], null, null);
}
this.methods = parameterizedMethods;
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 36ae9ab..61cb9f9 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
@@ -33,6 +33,7 @@
* Bug 431581 - Eclipse compiles what it should not
* Bug 440759 - [1.8][null] @NonNullByDefault should never affect wildcards and uses of a type variable
* Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression
+ * Bug 446442 - [1.8] merge null annotations from super methods
* Jesper S Moller - Contributions for
* bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
* bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
@@ -46,6 +47,7 @@
import org.eclipse.jdt.core.compiler.InvalidInputException;
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
@@ -1984,11 +1986,14 @@
final LookupEnvironment environment = scope.environment();
boolean genericMethodSeen = false;
int length = methods.length;
+ boolean analyseNullAnnotations = environment.globalOptions.isAnnotationBasedNullAnalysisEnabled;
next:for (int i = length - 1; i >= 0; --i) {
MethodBinding method = methods[i], otherMethod = null;
if (method.typeVariables != Binding.NO_TYPE_VARIABLES)
genericMethodSeen = true;
+ TypeBinding returnType = method.returnType;
+ TypeBinding[] parameters = method.parameters;
for (int j = 0; j < length; j++) {
if (i == j) continue;
otherMethod = methods[j];
@@ -2001,7 +2006,11 @@
continue next;
}
if (!MethodVerifier.isSubstituteParameterSubsignature(method, otherMethod, environment) || !MethodVerifier.areReturnTypesCompatible(method, otherMethod, environment))
- continue next;
+ continue next;
+ if (analyseNullAnnotations) {
+ returnType = NullAnnotationMatching.strongerType(returnType, otherMethod.returnType, environment);
+ parameters = NullAnnotationMatching.weakerTypes(parameters, otherMethod.parameters, environment);
+ }
}
// If we reach here, we found a method that is override equivalent with every other method and is also return type substitutable. Compute kosher exceptions now ...
ReferenceBinding [] exceptions = new ReferenceBinding[0];
@@ -2067,8 +2076,8 @@
}
this.singleAbstractMethod[index] = new MethodBinding(theAbstractMethod.modifiers | ClassFileConstants.AccSynthetic,
theAbstractMethod.selector,
- theAbstractMethod.returnType,
- theAbstractMethod.parameters,
+ returnType,
+ parameters,
exceptions,
theAbstractMethod.declaringClass);
this.singleAbstractMethod[index].typeVariables = theAbstractMethod.typeVariables;
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 99be8dc..634f423 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
@@ -54,6 +54,7 @@
* Bug 438467 - [compiler][null] Better error position for "The method _ cannot implement the corresponding method _ due to incompatible nullness constraints"
* Bug 439298 - [null] "Missing code implementation in the compiler" when using @NonNullByDefault in package-info.java
* Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
+ * Bug 446442 - [1.8] merge null annotations from super methods
* Jesper S Moller <jesper@selskabet.org> - Contributions for
* bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
* bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
@@ -406,6 +407,10 @@
case IProblem.UninitializedNonNullFieldHintMissingDefault:
case IProblem.ReferenceExpressionParameterNullityMismatch:
case IProblem.ReferenceExpressionReturnNullRedef:
+ case IProblem.ContradictoryNullAnnotations:
+ case IProblem.ContradictoryNullAnnotationsOnBound:
+ case IProblem.ContradictoryNullAnnotationsInferred:
+ case IProblem.ContradictoryNullAnnotationsInferredFunctionType:
return CompilerOptions.NullSpecViolation;
case IProblem.ParameterLackingNonNullAnnotation:
@@ -4295,7 +4300,7 @@
return;
case ProblemReasons.ContradictoryNullAnnotations:
problemMethod = (ProblemMethodBinding) method;
- contradictoryNullAnnotationsInferred(problemMethod.closestMatch, (ASTNode)messageSend);
+ contradictoryNullAnnotationsInferred(problemMethod.closestMatch, messageSend);
return;
case ProblemReasons.NoError : // 0
default :
@@ -9566,12 +9571,9 @@
}
public void contradictoryNullAnnotationsInferred(MethodBinding inferredMethod, ASTNode location) {
- contradictoryNullAnnotationsInferred(inferredMethod, location.sourceStart, location.sourceEnd);
+ contradictoryNullAnnotationsInferred(inferredMethod, location.sourceStart, location.sourceEnd, false);
}
-public void contradictoryNullAnnotationsInferred(MethodBinding inferredMethod, InvocationSite location) {
- contradictoryNullAnnotationsInferred(inferredMethod, location.sourceStart(), location.sourceEnd());
-}
-public void contradictoryNullAnnotationsInferred(MethodBinding inferredMethod, int sourceStart, int sourceEnd) {
+public void contradictoryNullAnnotationsInferred(MethodBinding inferredMethod, int sourceStart, int sourceEnd, boolean isFunctionalExpression) {
// when this error is triggered we can safely assume that both annotations have been configured
char[][] nonNullAnnotationName = this.options.nonNullAnnotationName;
char[][] nullableAnnotationName = this.options.nullableAnnotationName;
@@ -9589,7 +9591,9 @@
new String(inferredMethod.selector),
typesAsString(inferredMethod, true, true)
};
- this.handle(IProblem.ContradictoryNullAnnotationsInferred, arguments, shortArguments, sourceStart, sourceEnd);
+ this.handle(
+ isFunctionalExpression ? IProblem.ContradictoryNullAnnotationsInferredFunctionType : IProblem.ContradictoryNullAnnotationsInferred,
+ arguments, shortArguments, sourceStart, sourceEnd);
}
public void contradictoryNullAnnotationsOnBounds(Annotation annotation, long previousTagBit) {
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 ee7ee45..2cacfa0 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
@@ -828,6 +828,7 @@
970 = Null type mismatch (type annotations): required ''{0}'' but this expression has type ''{1}'', where ''{0}'' is a free type variable
971 = The explicit type bound 'Object' is not affected by the nullness default for DefaultLocation.TYPE_BOUND.
972 = Illegal redefinition of parameter {0}, inherited method from {1} declares this parameter as ''{2}'' (mismatching null constraints)
+973 = Contradictory null annotations: function type was inferred as ''{2} ({4})'', but only one of ''@{0}'' and ''@{1}'' can be effective at any location
# Java 8
1001 = Syntax error, modifiers and annotations are not allowed for the lambda parameter {0} as its type is elided