diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java index fc21f6d..5916344 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java @@ -1972,6 +1972,69 @@ "Type mismatch: required \'@NonNull Object\' but the provided value can be null\n" + "----------\n"); } +//same as test_default_nullness_003b, but default-induced annotations are combined with explicit ones (not null related) +public void test_default_nullness_003b() { + Map customOptions = getCompilerOptions(); + runConformTestWithLibs( + new String[] { + "p1/Annot.java", + "package p1;\n" + + "import static java.lang.annotation.ElementType.*;\n" + + "import java.lang.annotation.*;\n" + + "@Retention(RetentionPolicy.CLASS)\n" + + "@Target({METHOD,PARAMETER})\n" + + "public @interface Annot {}\n", + "p1/X.java", + "package p1;\n" + + "import org.eclipse.jdt.annotation.*;\n" + + "@NonNullByDefault\n" + + "public class X {\n" + + " protected @Annot Object getObject(@Annot @Nullable Object o) {\n" + + " return new Object();\n" + + " }\n" + + " protected @Annot void bar(@Annot Object o2) { }\n" + // parameter is nonnull per type default + "}\n", + "p2/package-info.java", + "@org.eclipse.jdt.annotation.NonNullByDefault\n" + + "package p2;\n", + }, + customOptions, + ""); + // check if default is visible from package-info.class. + runNegativeTestWithLibs( + false, // don't flush + new String[] { + "p2/Y.java", + "package p2;\n" + + "import org.eclipse.jdt.annotation.*;\n" + + "public class Y extends p1.X {\n" + + " @Override\n" + + " protected @Nullable Object getObject(@Nullable Object o) {\n" + // can't override inherited default nonnull + " bar(o);\n" + // parameter is nonnull in super class's .class file + " accept(o);\n" + + " return o;\n" + + " }\n" + + " void accept(@p1.Annot Object a) {}\n" + // governed by package level default + "}\n" + }, + customOptions, + "----------\n" + + "1. ERROR in p2\\Y.java (at line 5)\n" + + " protected @Nullable Object getObject(@Nullable Object o) {\n" + + " ^^^^^^^^^^^^^^^^\n" + + "The return type is incompatible with the @NonNull return from X.getObject(Object)\n" + + "----------\n" + + "2. ERROR in p2\\Y.java (at line 6)\n" + + " bar(o);\n" + + " ^\n" + + "Type mismatch: required \'@NonNull Object\' but the provided value can be null\n" + + "----------\n" + + "3. ERROR in p2\\Y.java (at line 7)\n" + + " accept(o);\n" + + " ^\n" + + "Type mismatch: required \'@NonNull Object\' but the provided value can be null\n" + + "----------\n"); +} // don't apply type-level default to non-reference type public void test_default_nullness_004() { Map customOptions = getCompilerOptions(); @@ -2193,6 +2256,42 @@ "The nullness annotation is redundant with a default that applies to this location\n" + "----------\n"); } +// package-info declares nonnull-by-default +// special compile order due to import of type from that package +// cf. https://bugs.eclipse.org/bugs/show_bug.cgi?id=186342#add_comment +public void test_default_nullness_011() { + runNegativeTestWithLibs( + new String[] { + "Main.java", + "import p1.C;\n" + + "public class Main {\n" + + " void test(@org.eclipse.jdt.annotation.NonNull Object o) {\n" + + " o = null;\n" + + " new C(null);\n" + + " }\n" + + "}\n", + "p1/C.java", + "package p1;\n" + + "@org.eclipse.jdt.annotation.NonNullByDefault\n" + + "public class C {\n" + + " public C (Object o) {}\n" + + "}\n", + "p1/package-info.java", + "@org.eclipse.jdt.annotation.NonNullByDefault\n" + + "package p1;\n" + }, + "----------\n" + + "1. ERROR in Main.java (at line 4)\n" + + " o = null;\n" + + " ^^^^\n" + + "Type mismatch: required \'@NonNull Object\' but the provided value is null\n" + + "----------\n" + + "2. ERROR in Main.java (at line 5)\n" + + " new C(null);\n" + + " ^^^^\n" + + "Type mismatch: required \'@NonNull Object\' but the provided value is null\n" + + "----------\n"); +} // a nonnull variable is dereferenced in a loop public void test_nonnull_var_in_constrol_structure_1() { Map customOptions = getCompilerOptions(); 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 659ef81..f4b99d8 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 @@ -1133,9 +1133,7 @@ boolean tolerateMissing = this.mayTolerateMissingType; this.mayTolerateMissingType = true; try { - int id = nullAnnotation.id; nullAnnotation = BinaryTypeBinding.resolveType(nullAnnotation, this, false); - nullAnnotation.id = id; } finally { this.mayTolerateMissingType = tolerateMissing; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java index 8d7c02d..330d65e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java @@ -267,15 +267,18 @@ if (this.environment.nullableAnnotationPackage == this && CharOperation.equals(type.compoundName, this.environment.getNullableAnnotationName())) { type.id = TypeIds.T_ConfiguredAnnotationNullable; - this.environment.nullableAnnotationPackage = null; // don't check again + if (!(type instanceof UnresolvedReferenceBinding)) // unresolved will need to check back for the resolved type + this.environment.nullableAnnotationPackage = null; // don't check again } else if (this.environment.nonnullAnnotationPackage == this && CharOperation.equals(type.compoundName, this.environment.getNonNullAnnotationName())) { type.id = TypeIds.T_ConfiguredAnnotationNonNull; - this.environment.nonnullAnnotationPackage = null; // don't check again + if (!(type instanceof UnresolvedReferenceBinding)) // unresolved will need to check back for the resolved type + this.environment.nonnullAnnotationPackage = null; // don't check again } else if (this.environment.nonnullByDefaultAnnotationPackage == this && CharOperation.equals(type.compoundName, this.environment.getNonNullByDefaultAnnotationName())) { type.id = TypeIds.T_ConfiguredAnnotationNonNullByDefault; - this.environment.nonnullByDefaultAnnotationPackage = null; // don't check again + if (!(type instanceof UnresolvedReferenceBinding)) // unresolved will need to check back for the resolved type + this.environment.nonnullByDefaultAnnotationPackage = null; // don't check again } }