diff options
Diffstat (limited to 'org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java')
| -rw-r--r-- | org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java | 489 |
1 files changed, 483 insertions, 6 deletions
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 13e77704ba..8b5a4d6b6d 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 @@ -53,7 +53,7 @@ public NullAnnotationTest(String name) { // Static initializer to specify tests subset using TESTS_* static variables // All specified tests which do not belong to the class are skipped... static { -// TESTS_NAMES = new String[] { "testBug385626" }; +// TESTS_NAMES = new String[] { "testBug388281_08" }; // TESTS_NUMBERS = new int[] { 561 }; // TESTS_RANGE = new int[] { 1, 2049 }; } @@ -4277,9 +4277,11 @@ public void test_nullable_field_3m() { } // access to a nullable field - dereference after check // https://bugs.eclipse.org/bugs/show_bug.cgi?id=331649 -public void _test_nullable_field_4() { +public void test_nullable_field_4() { // currently no flow analysis for fields is implemented, - // but the direct sequence of null-check + dereference could perhaps be supported as a special case + // but the direct sequence of null-check + dereference is be optionally supported as a special case + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_PB_SYNTACTIC_NULL_ANALYSIS_FOR_FIELDS, JavaCore.ENABLED); runNegativeTestWithLibs( new String[] { "X.java", @@ -4289,6 +4291,8 @@ public void _test_nullable_field_4() { " public String oString() {\n" + " if (this.o != null)\n" + " return this.o.toString();\n" + // silent after check + " if (o != null)\n" + + " return o.toString();\n" + // silent after check " return \"\";\n" + " }\n" + " public String oString2() {\n" + @@ -4301,14 +4305,14 @@ public void _test_nullable_field_4() { " }\n" + "}\n" }, - null /*customOptions*/, + options /*customOptions*/, "----------\n" + - "1. ERROR in X.java (at line 10)\n" + + "1. ERROR in X.java (at line 12)\n" + " String local = o.toString();\n" + " ^\n" + "Potential null pointer access: The field o is declared as @Nullable\n" + "----------\n" + - "2. ERROR in X.java (at line 13)\n" + + "2. ERROR in X.java (at line 15)\n" + " return this.o.toString(); // warn here\n" + " ^\n" + "Potential null pointer access: The field o is declared as @Nullable\n" + @@ -5061,4 +5065,477 @@ public void testBug385626_2() { null,//options ""); } + +/* Content of Test388281.jar used in the following tests: + +// === package i (explicit annotations): === +package i; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; +public interface I { + @NonNull Object m1(@Nullable Object a1); + @Nullable String m2(@NonNull Object a2); + Object m1(@Nullable Object o1, Object o2); +} + +// === package i2 with package-info.java (default annot, canceled in one type): === +@org.eclipse.jdt.annotation.NonNullByDefault +package i2; + +package i2; +public interface I2 { + Object m1(Object a1); + String m2(Object a2); +} + +package i2; +public interface II extends i.I { + String m1(Object o1, Object o2); +} + +package i2; +import org.eclipse.jdt.annotation.NonNullByDefault; +@NonNullByDefault(false) +public interface I2A { + Object m1(Object a1); + String m2(Object a2); +} + +// === package c (no null annotations): === +package c; +public class C1 implements i.I { + public Object m1(Object a1) { + System.out.println(a1.toString()); // (1) + return null; // (2) + } + public String m2(Object a2) { + System.out.println(a2.toString()); + return null; + } + public Object m1(Object o1, Object o2) { + return null; + } +} + +package c; +public class C2 implements i2.I2 { + public Object m1(Object a1) { + return a1; + } + public String m2(Object a2) { + return a2.toString(); + } +} + */ +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281 +// Test whether null annotations from a super interface are respected +// Class and its super interface both read from binary +public void testBug388281_01() { + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar"; + String[] libs = new String[this.LIBS.length + 1]; + System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length); + libs[this.LIBS.length] = path; + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED); + runNegativeTest( + new String[] { + "Client.java", + "import c.C1;\n" + + "public class Client {\n" + + " void test(C1 c) {\n" + + " String s = c.m2(null); // (3)\n" + + " System.out.println(s.toUpperCase()); // (4)\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in Client.java (at line 4)\n" + + " String s = c.m2(null); // (3)\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + + "----------\n" + + "2. ERROR in Client.java (at line 5)\n" + + " System.out.println(s.toUpperCase()); // (4)\n" + + " ^\n" + + "Potential null pointer access: The variable s may be null at this location\n" + + "----------\n", + libs, + true /* shouldFlush*/, + options); +} + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281 +// Test whether null annotations from a super interface are respected +// Class from source, its supers (class + super interface) from binary +public void testBug388281_02() { + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar"; + String[] libs = new String[this.LIBS.length + 1]; + System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length); + libs[this.LIBS.length] = path; + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED); + runNegativeTest( + new String[] { + "ctest/C.java", + "package ctest;\n" + + "public class C extends c.C1 {\n" + + " @Override\n" + + " public Object m1(Object a1) {\n" + + " System.out.println(a1.toString()); // (1)\n" + + " return null; // (2)\n" + + " }\n" + + " @Override\n" + + " public String m2(Object a2) {\n" + + " System.out.println(a2.toString());\n" + + " return null;\n" + + " }\n" + + "}\n", + "Client.java", + "import ctest.C;\n" + + "public class Client {\n" + + " void test(C c) {\n" + + " String s = c.m2(null); // (3)\n" + + " System.out.println(s.toUpperCase()); // (4)\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in ctest\\C.java (at line 5)\n" + + " System.out.println(a1.toString()); // (1)\n" + + " ^^\n" + + "Potential null pointer access: The variable a1 may be null at this location\n" + + "----------\n" + + "2. ERROR in ctest\\C.java (at line 6)\n" + + " return null; // (2)\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + + "----------\n" + + "----------\n" + + "1. ERROR in Client.java (at line 4)\n" + + " String s = c.m2(null); // (3)\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + + "----------\n" + + "2. ERROR in Client.java (at line 5)\n" + + " System.out.println(s.toUpperCase()); // (4)\n" + + " ^\n" + + "Potential null pointer access: The variable s may be null at this location\n" + + "----------\n", + libs, + true /* shouldFlush*/, + options); +} + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281 +// Test whether null annotations from a super interface trigger an error against the overriding implementation +// Class from source, its super interface from binary +public void testBug388281_03() { + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar"; + String[] libs = new String[this.LIBS.length + 1]; + System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length); + libs[this.LIBS.length] = path; + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED); + runNegativeTest( + new String[] { + "ctest/C.java", + "package ctest;\n" + + "public class C implements i.I {\n" + + " public Object m1(Object a1) {\n" + + " System.out.println(a1.toString()); // (1)\n" + + " return null; // (2)\n" + + " }\n" + + " public String m2(Object a2) {\n" + + " System.out.println(a2.toString());\n" + + " return null;\n" + + " }\n" + + " public Object m1(Object a1, Object a2) {\n" + + " System.out.println(a1.toString()); // (3)\n" + + " return null;\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in ctest\\C.java (at line 4)\n" + + " System.out.println(a1.toString()); // (1)\n" + + " ^^\n" + + "Potential null pointer access: The variable a1 may be null at this location\n" + + "----------\n" + + "2. ERROR in ctest\\C.java (at line 5)\n" + + " return null; // (2)\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + + "----------\n" + + "3. ERROR in ctest\\C.java (at line 12)\n" + + " System.out.println(a1.toString()); // (3)\n" + + " ^^\n" + + "Potential null pointer access: The variable a1 may be null at this location\n" + + "----------\n", + libs, + true /* shouldFlush*/, + options); +} + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281 +// Do inherit even if one parameter/return is annotated +// also features some basic overloading +public void testBug388281_04() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED); + runNegativeTestWithLibs( + true /* shouldFlush*/, + new String[] { + "i/I.java", + "package i;\n" + + "import org.eclipse.jdt.annotation.*;\n" + + "public interface I {\n" + + " @NonNull Object m1(@NonNull Object s1, @Nullable String s2);\n" + + " @Nullable Object m1(@Nullable String s1, @NonNull Object s2);\n" + + "}\n", + "ctest/C.java", + "package ctest;\n" + + "import org.eclipse.jdt.annotation.*;\n" + + "public class C implements i.I {\n" + + " public Object m1(@Nullable Object o1, String s2) {\n" + + " System.out.println(s2.toString()); // (1)\n" + + " return null; // (2)\n" + + " }\n" + + " public @NonNull Object m1(String s1, Object o2) {\n" + + " System.out.println(s1.toString()); // (3)\n" + + " return new Object();\n" + + " }\n" + + "}\n" + }, + options, + "----------\n" + + "1. ERROR in ctest\\C.java (at line 5)\n" + + " System.out.println(s2.toString()); // (1)\n" + + " ^^\n" + + "Potential null pointer access: The variable s2 may be null at this location\n" + + "----------\n" + + "2. ERROR in ctest\\C.java (at line 6)\n" + + " return null; // (2)\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + + "----------\n" + + "3. ERROR in ctest\\C.java (at line 9)\n" + + " System.out.println(s1.toString()); // (3)\n" + + " ^^\n" + + "Potential null pointer access: The variable s1 may be null at this location\n" + + "----------\n"); +} + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281 +// Test whether null annotations from a super interface trigger an error against the overriding implementation +// Class from source, its super interface from binary +// Super interface subject to package level @NonNullByDefault +public void testBug388281_05() { + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar"; + String[] libs = new String[this.LIBS.length + 1]; + System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length); + libs[this.LIBS.length] = path; + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED); + runNegativeTest( + new String[] { + "ctest/C.java", + "package ctest;\n" + + "public class C implements i2.I2 {\n" + + " public Object m1(Object a1) {\n" + + " System.out.println(a1.toString()); // silent\n" + + " return null; // (1)\n" + + " }\n" + + " public String m2(Object a2) {\n" + + " System.out.println(a2.toString());\n" + + " return null; // (2)\n" + + " }\n" + + "}\n", + "Client.java", + "import ctest.C;\n" + + "public class Client {\n" + + " void test(C c) {\n" + + " String s = c.m2(null); // (3)\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in ctest\\C.java (at line 5)\n" + + " return null; // (1)\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + + "----------\n" + + "2. ERROR in ctest\\C.java (at line 9)\n" + + " return null; // (2)\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull String\' but the provided value is null\n" + + "----------\n" + + "----------\n" + + "1. ERROR in Client.java (at line 4)\n" + + " String s = c.m2(null); // (3)\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + + "----------\n", + libs, + true /* shouldFlush*/, + options); +} + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281 +// Conflicting annotations from several indirect super interfaces must be detected +public void testBug388281_06() { + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar"; + String[] libs = new String[this.LIBS.length + 1]; + System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length); + libs[this.LIBS.length] = path; + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED); + runNegativeTest( + new String[] { + "ctest/C.java", + "package ctest;\n" + + "public class C extends c.C2 implements i2.I2A {\n" + // neither super has explicit annotations, + // but C2 inherits those from the default applicable at its super interface i2.I2 + // whereas I2A cancels that same default + "}\n" + }, + "----------\n" + + "1. ERROR in ctest\\C.java (at line 2)\n" + + " public class C extends c.C2 implements i2.I2A {\n" + + " ^\n" + + "The method m2(Object) from C2 cannot implement the corresponding method from I2A due to incompatible nullness constraints\n" + + "----------\n" + + "2. ERROR in ctest\\C.java (at line 2)\n" + + " public class C extends c.C2 implements i2.I2A {\n" + + " ^\n" + + "The method m1(Object) from C2 cannot implement the corresponding method from I2A due to incompatible nullness constraints\n" + + "----------\n", + libs, + true /* shouldFlush*/, + options); +} + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281 +// report conflict between inheritance and default +public void testBug388281_07() { + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED); + runNegativeTestWithLibs( + new String[] { + "p1/Super.java", + "package p1;\n" + + "import org.eclipse.jdt.annotation.*;\n" + + "public class Super {\n" + + " public @Nullable Object m(@Nullable Object arg) {\n" + + " return null;" + + " }\n" + + "}\n", + "p2/Sub.java", + "package p2;\n" + + "import org.eclipse.jdt.annotation.*;\n" + + "@NonNullByDefault\n" + + "public class Sub extends p1.Super {\n" + + " @Override\n" + + " public Object m(Object arg) { // (a)+(b) conflict at arg and return\n" + + " System.out.println(arg.toString()); // (1)\n" + + " return null;\n" + + " }\n" + + "}\n", + "Client.java", + "public class Client {\n" + + " void test(p2.Sub s) {\n" + + " Object result = s.m(null);\n" + + " System.out.println(result.toString()); // (2)\n" + + " }\n" + + "}\n" + }, + options, + "----------\n" + + "1. ERROR in p2\\Sub.java (at line 6)\n" + + " public Object m(Object arg) { // (a)+(b) conflict at arg and return\n" + + " ^^^^^^\n" + + "The default \'@NonNull\' conflicts with the inherited \'@Nullable\' annotation in the overridden method from Super \n" + + "----------\n" + + "2. ERROR in p2\\Sub.java (at line 6)\n" + + " public Object m(Object arg) { // (a)+(b) conflict at arg and return\n" + + " ^^^\n" + + "The default \'@NonNull\' conflicts with the inherited \'@Nullable\' annotation in the overridden method from Super \n" + + "----------\n" + + "3. ERROR in p2\\Sub.java (at line 7)\n" + + " System.out.println(arg.toString()); // (1)\n" + + " ^^^\n" + + "Potential null pointer access: The variable arg may be null at this location\n" + + "----------\n" + + "----------\n" + + "1. ERROR in Client.java (at line 4)\n" + + " System.out.println(result.toString()); // (2)\n" + + " ^^^^^^\n" + + "Potential null pointer access: The variable result may be null at this location\n" + + "----------\n"); +} + +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281 +// report conflict between inheritance and default - binary types +public void testBug388281_08() { + String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar"; + String[] libs = new String[this.LIBS.length + 1]; + System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length); + libs[this.LIBS.length] = path; + Map options = getCompilerOptions(); + options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED); + runNegativeTest( + new String[] { + "ctest/Ctest.java", + "package ctest;\n" + + "import org.eclipse.jdt.annotation.*;\n" + + "@NonNullByDefault\n" + + "public class Ctest implements i2.II {\n" + + " public Object m1(@Nullable Object a1) { // silent: conflict at a1 avoided\n" + + " return new Object();\n" + + " }\n" + + " public String m2(Object a2) { // (a) conflict at return\n" + + " return null;\n" + + " }\n" + + " public String m1(Object o1, Object o2) { // (b) conflict at o1\n" + + " System.out.println(o1.toString()); // (1) inherited @Nullable\n" + + " return null; // (2) @NonNullByDefault in i2.II\n" + + " }\n" + + "}\n", + "Client.java", + "public class Client {\n" + + " void test(ctest.Ctest c) {\n" + + " Object result = c.m1(null, null); // (3) 2nd arg @NonNullByDefault from i2.II\n" + + " }\n" + + "}\n" + }, + "----------\n" + + "1. ERROR in ctest\\Ctest.java (at line 8)\n" + + " public String m2(Object a2) { // (a) conflict at return\n" + + " ^^^^^^\n" + + "The default \'@NonNull\' conflicts with the inherited \'@Nullable\' annotation in the overridden method from I \n" + + "----------\n" + + "2. ERROR in ctest\\Ctest.java (at line 11)\n" + + " public String m1(Object o1, Object o2) { // (b) conflict at o1\n" + + " ^^\n" + + "The default \'@NonNull\' conflicts with the inherited \'@Nullable\' annotation in the overridden method from II \n" + + "----------\n" + + "3. ERROR in ctest\\Ctest.java (at line 12)\n" + + " System.out.println(o1.toString()); // (1) inherited @Nullable\n" + + " ^^\n" + + "Potential null pointer access: The variable o1 may be null at this location\n" + + "----------\n" + + "4. ERROR in ctest\\Ctest.java (at line 13)\n" + + " return null; // (2) @NonNullByDefault in i2.II\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull String\' but the provided value is null\n" + + "----------\n" + + "----------\n" + + "1. ERROR in Client.java (at line 3)\n" + + " Object result = c.m1(null, null); // (3) 2nd arg @NonNullByDefault from i2.II\n" + + " ^^^^\n" + + "Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + + "----------\n", + libs, + true, // should flush + options); +} } |
