Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 388281 | Differences between
and this patch

Collapse All | Expand All

(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java (+1 lines)
Lines 1880-1885 Link Here
1880
			"		<argument value=\"---OUTPUT_DIR_PLACEHOLDER---\"/>\n" + 
1880
			"		<argument value=\"---OUTPUT_DIR_PLACEHOLDER---\"/>\n" + 
1881
			"	</command_line>\n" + 
1881
			"	</command_line>\n" + 
1882
			"	<options>\n" + 
1882
			"	<options>\n" + 
1883
			"		<option key=\"org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations\" value=\"disabled\"/>\n" +
1883
			"		<option key=\"org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation\" value=\"ignore\"/>\n" + 
1884
			"		<option key=\"org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation\" value=\"ignore\"/>\n" + 
1884
			"		<option key=\"org.eclipse.jdt.core.compiler.annotation.nonnull\" value=\"org.eclipse.jdt.annotation.NonNull\"/>\n" + 
1885
			"		<option key=\"org.eclipse.jdt.core.compiler.annotation.nonnull\" value=\"org.eclipse.jdt.annotation.NonNull\"/>\n" + 
1885
			"		<option key=\"org.eclipse.jdt.core.compiler.annotation.nonnullbydefault\" value=\"org.eclipse.jdt.annotation.NonNullByDefault\"/>\n" + 
1886
			"		<option key=\"org.eclipse.jdt.core.compiler.annotation.nonnullbydefault\" value=\"org.eclipse.jdt.annotation.NonNullByDefault\"/>\n" + 
(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java (+2 lines)
Lines 403-408 Link Here
403
		expectedProblemAttributes.put("ContradictoryNullAnnotations", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
403
		expectedProblemAttributes.put("ContradictoryNullAnnotations", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
404
		expectedProblemAttributes.put("ComparingIdentical", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
404
		expectedProblemAttributes.put("ComparingIdentical", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
405
		expectedProblemAttributes.put("ConflictingImport", new ProblemAttributes(CategorizedProblem.CAT_IMPORT));
405
		expectedProblemAttributes.put("ConflictingImport", new ProblemAttributes(CategorizedProblem.CAT_IMPORT));
406
		expectedProblemAttributes.put("ConflictingNullAnnotations", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
406
		expectedProblemAttributes.put("ConstructorVarargsArgumentNeedCast", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
407
		expectedProblemAttributes.put("ConstructorVarargsArgumentNeedCast", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
407
		expectedProblemAttributes.put("CorruptedSignature", new ProblemAttributes(CategorizedProblem.CAT_BUILDPATH));
408
		expectedProblemAttributes.put("CorruptedSignature", new ProblemAttributes(CategorizedProblem.CAT_BUILDPATH));
408
		expectedProblemAttributes.put("DeadCode", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
409
		expectedProblemAttributes.put("DeadCode", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
Lines 1107-1112 Link Here
1107
		expectedProblemAttributes.put("CodeSnippetMissingMethod", SKIP);
1108
		expectedProblemAttributes.put("CodeSnippetMissingMethod", SKIP);
1108
		expectedProblemAttributes.put("ComparingIdentical", new ProblemAttributes(JavaCore.COMPILER_PB_COMPARING_IDENTICAL));
1109
		expectedProblemAttributes.put("ComparingIdentical", new ProblemAttributes(JavaCore.COMPILER_PB_COMPARING_IDENTICAL));
1109
		expectedProblemAttributes.put("ConflictingImport", SKIP);
1110
		expectedProblemAttributes.put("ConflictingImport", SKIP);
1111
		expectedProblemAttributes.put("ConflictingNullAnnotations", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION));
1110
		expectedProblemAttributes.put("ContradictoryNullAnnotations", SKIP);
1112
		expectedProblemAttributes.put("ContradictoryNullAnnotations", SKIP);
1111
		expectedProblemAttributes.put("ConstructorVarargsArgumentNeedCast", new ProblemAttributes(JavaCore.COMPILER_PB_VARARGS_ARGUMENT_NEED_CAST));
1113
		expectedProblemAttributes.put("ConstructorVarargsArgumentNeedCast", new ProblemAttributes(JavaCore.COMPILER_PB_VARARGS_ARGUMENT_NEED_CAST));
1112
		expectedProblemAttributes.put("CorruptedSignature", SKIP);
1114
		expectedProblemAttributes.put("CorruptedSignature", SKIP);
(-)a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTest.java (-1 / +474 lines)
Lines 53-59 Link Here
53
// Static initializer to specify tests subset using TESTS_* static variables
53
// Static initializer to specify tests subset using TESTS_* static variables
54
// All specified tests which do not belong to the class are skipped...
54
// All specified tests which do not belong to the class are skipped...
55
static {
55
static {
56
//		TESTS_NAMES = new String[] { "testBug385626" };
56
//		TESTS_NAMES = new String[] { "testBug388281_08" };
57
//		TESTS_NUMBERS = new int[] { 561 };
57
//		TESTS_NUMBERS = new int[] { 561 };
58
//		TESTS_RANGE = new int[] { 1, 2049 };
58
//		TESTS_RANGE = new int[] { 1, 2049 };
59
}
59
}
Lines 3715-3718 Link Here
3715
		null,//options
3715
		null,//options
3716
		"");
3716
		"");
3717
}
3717
}
3718
3719
/* Content of Test388281.jar used in the following tests:
3720
3721
// === package i (explicit annotations): ===
3722
package i;
3723
import org.eclipse.jdt.annotation.NonNull;
3724
import org.eclipse.jdt.annotation.Nullable;
3725
public interface I {
3726
    @NonNull Object m1(@Nullable Object a1);
3727
    @Nullable String m2(@NonNull Object a2);
3728
	Object m1(@Nullable Object o1, Object o2);
3729
}
3730
3731
// === package  i2 with package-info.java (default annot, canceled in one type): ===
3732
@org.eclipse.jdt.annotation.NonNullByDefault
3733
package i2;
3734
3735
package i2;
3736
public interface I2 {
3737
    Object m1(Object a1);
3738
    String m2(Object a2);
3739
}
3740
3741
package i2;
3742
public interface II extends i.I {
3743
	String m1(Object o1, Object o2);
3744
}
3745
3746
package i2;
3747
import org.eclipse.jdt.annotation.NonNullByDefault;
3748
@NonNullByDefault(false)
3749
public interface I2A {
3750
    Object m1(Object a1);
3751
    String m2(Object a2);
3752
}
3753
3754
// === package c (no null annotations): ===
3755
package c;
3756
public class C1 implements i.I {
3757
	public Object m1(Object a1) {
3758
		System.out.println(a1.toString()); // (1)
3759
		return null; // (2)
3760
	}
3761
	public String m2(Object a2) {
3762
		System.out.println(a2.toString());
3763
		return null;
3764
	}
3765
	public Object m1(Object o1, Object o2) {
3766
		return null;
3767
	}
3768
}
3769
3770
package c;
3771
public class C2 implements i2.I2 {
3772
	public Object m1(Object a1) {
3773
		return a1;
3774
	}
3775
	public String m2(Object a2) {
3776
		return a2.toString();
3777
	}
3778
}
3779
 */
3780
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281
3781
// Test whether null annotations from a super interface are respected
3782
// Class and its super interface both read from binary
3783
public void testBug388281_01() {
3784
	String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar";
3785
	String[] libs = new String[this.LIBS.length + 1];
3786
	System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length);
3787
	libs[this.LIBS.length] = path;
3788
	Map options = getCompilerOptions();
3789
	options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
3790
	runNegativeTest(
3791
		new String[] {
3792
			"Client.java",
3793
			"import c.C1;\n" +
3794
			"public class Client {\n" + 
3795
			"    void test(C1 c) {\n" + 
3796
			"         String s = c.m2(null);               // (3)\n" + 
3797
			"         System.out.println(s.toUpperCase()); // (4)\n" + 
3798
			"    }\n" + 
3799
			"}\n"
3800
		},
3801
		"----------\n" + 
3802
		"1. ERROR in Client.java (at line 4)\n" + 
3803
		"	String s = c.m2(null);               // (3)\n" + 
3804
		"	                ^^^^\n" + 
3805
		"Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + 
3806
		"----------\n" + 
3807
		"2. ERROR in Client.java (at line 5)\n" + 
3808
		"	System.out.println(s.toUpperCase()); // (4)\n" + 
3809
		"	                   ^\n" + 
3810
		"Potential null pointer access: The variable s may be null at this location\n" + 
3811
		"----------\n",
3812
		libs,
3813
		true /* shouldFlush*/,
3814
		options);
3815
}
3816
3817
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281
3818
// Test whether null annotations from a super interface are respected
3819
// Class from source, its supers (class + super interface) from binary
3820
public void testBug388281_02() {
3821
	String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar";
3822
	String[] libs = new String[this.LIBS.length + 1];
3823
	System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length);
3824
	libs[this.LIBS.length] = path;
3825
	Map options = getCompilerOptions();
3826
	options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
3827
	runNegativeTest(
3828
		new String[] {
3829
			"ctest/C.java",
3830
			"package ctest;\n" +
3831
			"public class C extends c.C1 {\n" +
3832
			"    @Override\n" +
3833
			"    public Object m1(Object a1) {\n" + 
3834
			"         System.out.println(a1.toString());   // (1)\n" + 
3835
			"         return null;                         // (2)\n" + 
3836
			"    }\n" +
3837
			"    @Override\n" +
3838
			"    public String m2(Object a2) {\n" + 
3839
			"         System.out.println(a2.toString());\n" + 
3840
			"         return null;\n" + 
3841
			"    }\n" +
3842
			"}\n",
3843
			"Client.java",
3844
			"import ctest.C;\n" +
3845
			"public class Client {\n" + 
3846
			"    void test(C c) {\n" + 
3847
			"         String s = c.m2(null);               // (3)\n" + 
3848
			"         System.out.println(s.toUpperCase()); // (4)\n" + 
3849
			"    }\n" + 
3850
			"}\n"
3851
		},
3852
		"----------\n" + 
3853
		"1. ERROR in ctest\\C.java (at line 5)\n" + 
3854
		"	System.out.println(a1.toString());   // (1)\n" + 
3855
		"	                   ^^\n" + 
3856
		"Potential null pointer access: The variable a1 may be null at this location\n" + 
3857
		"----------\n" + 
3858
		"2. ERROR in ctest\\C.java (at line 6)\n" + 
3859
		"	return null;                         // (2)\n" + 
3860
		"	       ^^^^\n" + 
3861
		"Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + 
3862
		"----------\n" + 
3863
		"----------\n" +
3864
		"1. ERROR in Client.java (at line 4)\n" + 
3865
		"	String s = c.m2(null);               // (3)\n" + 
3866
		"	                ^^^^\n" + 
3867
		"Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + 
3868
		"----------\n" + 
3869
		"2. ERROR in Client.java (at line 5)\n" + 
3870
		"	System.out.println(s.toUpperCase()); // (4)\n" + 
3871
		"	                   ^\n" + 
3872
		"Potential null pointer access: The variable s may be null at this location\n" + 
3873
		"----------\n",
3874
		libs,
3875
		true /* shouldFlush*/,
3876
		options);
3877
}
3878
3879
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281
3880
// Test whether null annotations from a super interface trigger an error against the overriding implementation
3881
// Class from source, its super interface from binary
3882
public void testBug388281_03() {
3883
	String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar";
3884
	String[] libs = new String[this.LIBS.length + 1];
3885
	System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length);
3886
	libs[this.LIBS.length] = path;
3887
	Map options = getCompilerOptions();
3888
	options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
3889
	runNegativeTest(
3890
		new String[] {
3891
			"ctest/C.java",
3892
			"package ctest;\n" +
3893
			"public class C implements i.I {\n" +
3894
			"    public Object m1(Object a1) {\n" + 
3895
			"         System.out.println(a1.toString());   // (1)\n" + 
3896
			"         return null;                         // (2)\n" + 
3897
			"    }\n" +
3898
			"    public String m2(Object a2) {\n" + 
3899
			"         System.out.println(a2.toString());\n" + 
3900
			"         return null;\n" + 
3901
			"    }\n" +
3902
			"    public Object m1(Object a1, Object a2) {\n" +
3903
			"        System.out.println(a1.toString());   // (3)\n" +
3904
			"        return null;\n" +
3905
			"    }\n" +
3906
			"}\n"
3907
		},
3908
		"----------\n" + 
3909
		"1. ERROR in ctest\\C.java (at line 4)\n" + 
3910
		"	System.out.println(a1.toString());   // (1)\n" + 
3911
		"	                   ^^\n" + 
3912
		"Potential null pointer access: The variable a1 may be null at this location\n" + 
3913
		"----------\n" + 
3914
		"2. ERROR in ctest\\C.java (at line 5)\n" + 
3915
		"	return null;                         // (2)\n" + 
3916
		"	       ^^^^\n" + 
3917
		"Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + 
3918
		"----------\n" + 
3919
		"3. ERROR in ctest\\C.java (at line 12)\n" + 
3920
		"	System.out.println(a1.toString());   // (3)\n" + 
3921
		"	                   ^^\n" + 
3922
		"Potential null pointer access: The variable a1 may be null at this location\n" + 
3923
		"----------\n",
3924
		libs,		
3925
		true /* shouldFlush*/,
3926
		options);
3927
}
3928
3929
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281
3930
// Do inherit even if one parameter/return is annotated
3931
// also features some basic overloading
3932
public void testBug388281_04() {
3933
	Map options = getCompilerOptions();
3934
	options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
3935
	runNegativeTestWithLibs(
3936
		true /* shouldFlush*/,
3937
		new String[] {
3938
			"i/I.java",
3939
			"package i;\n" +
3940
			"import org.eclipse.jdt.annotation.*;\n" +
3941
			"public interface I {\n" +
3942
			"    @NonNull Object m1(@NonNull Object s1, @Nullable String s2);\n" +
3943
			"    @Nullable Object m1(@Nullable String s1, @NonNull Object s2);\n" +
3944
			"}\n",
3945
			"ctest/C.java",
3946
			"package ctest;\n" +
3947
			"import org.eclipse.jdt.annotation.*;\n" +
3948
			"public class C implements i.I {\n" +
3949
			"    public Object m1(@Nullable Object o1, String s2) {\n" + 
3950
			"         System.out.println(s2.toString());   // (1)\n" + 
3951
			"         return null;                         // (2)\n" + 
3952
			"    }\n" +
3953
			"    public @NonNull Object m1(String s1, Object o2) {\n" + 
3954
			"         System.out.println(s1.toString());   // (3)\n" + 
3955
			"         return new Object();\n" + 
3956
			"    }\n" +
3957
			"}\n"
3958
		},
3959
		options,
3960
		"----------\n" + 
3961
		"1. ERROR in ctest\\C.java (at line 5)\n" + 
3962
		"	System.out.println(s2.toString());   // (1)\n" + 
3963
		"	                   ^^\n" + 
3964
		"Potential null pointer access: The variable s2 may be null at this location\n" + 
3965
		"----------\n" + 
3966
		"2. ERROR in ctest\\C.java (at line 6)\n" + 
3967
		"	return null;                         // (2)\n" + 
3968
		"	       ^^^^\n" + 
3969
		"Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + 
3970
		"----------\n" + 
3971
		"3. ERROR in ctest\\C.java (at line 9)\n" + 
3972
		"	System.out.println(s1.toString());   // (3)\n" + 
3973
		"	                   ^^\n" + 
3974
		"Potential null pointer access: The variable s1 may be null at this location\n" + 
3975
		"----------\n");
3976
}
3977
3978
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281
3979
// Test whether null annotations from a super interface trigger an error against the overriding implementation
3980
// Class from source, its super interface from binary
3981
// Super interface subject to package level @NonNullByDefault
3982
public void testBug388281_05() {
3983
	String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar";
3984
	String[] libs = new String[this.LIBS.length + 1];
3985
	System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length);
3986
	libs[this.LIBS.length] = path;
3987
	Map options = getCompilerOptions();
3988
	options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
3989
	runNegativeTest(
3990
		new String[] {
3991
			"ctest/C.java",
3992
			"package ctest;\n" +
3993
			"public class C implements i2.I2 {\n" +
3994
			"    public Object m1(Object a1) {\n" + 
3995
			"         System.out.println(a1.toString());   // silent\n" + 
3996
			"         return null;                         // (1)\n" + 
3997
			"    }\n" +
3998
			"    public String m2(Object a2) {\n" + 
3999
			"         System.out.println(a2.toString());\n" + 
4000
			"         return null;						   // (2)\n" + 
4001
			"    }\n" +
4002
			"}\n",
4003
			"Client.java",
4004
			"import ctest.C;\n" +
4005
			"public class Client {\n" + 
4006
			"    void test(C c) {\n" + 
4007
			"         String s = c.m2(null);               // (3)\n" + 
4008
			"    }\n" + 
4009
			"}\n"			
4010
		},
4011
		"----------\n" + 
4012
		"1. ERROR in ctest\\C.java (at line 5)\n" + 
4013
		"	return null;                         // (1)\n" + 
4014
		"	       ^^^^\n" + 
4015
		"Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + 
4016
		"----------\n" + 
4017
		"2. ERROR in ctest\\C.java (at line 9)\n" + 
4018
		"	return null;						   // (2)\n" + 
4019
		"	       ^^^^\n" + 
4020
		"Null type mismatch: required \'@NonNull String\' but the provided value is null\n" + 
4021
		"----------\n" +
4022
		"----------\n" + 
4023
		"1. ERROR in Client.java (at line 4)\n" + 
4024
		"	String s = c.m2(null);               // (3)\n" + 
4025
		"	                ^^^^\n" + 
4026
		"Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + 
4027
		"----------\n",
4028
		libs,		
4029
		true /* shouldFlush*/,
4030
		options);
4031
}
4032
4033
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281
4034
// Conflicting annotations from several indirect super interfaces must be detected
4035
public void testBug388281_06() {
4036
	String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar";
4037
	String[] libs = new String[this.LIBS.length + 1];
4038
	System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length);
4039
	libs[this.LIBS.length] = path;
4040
	Map options = getCompilerOptions();
4041
	options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
4042
	runNegativeTest(
4043
		new String[] {
4044
			"ctest/C.java",
4045
			"package ctest;\n" +
4046
			"public class C extends c.C2 implements i2.I2A {\n" + // neither super has explicit annotations,
4047
																  // but C2 inherits those from the default applicable at its super interface i2.I2
4048
																  // whereas I2A cancels that same default
4049
			"}\n"
4050
		},
4051
		"----------\n" + 
4052
		"1. ERROR in ctest\\C.java (at line 2)\n" + 
4053
		"	public class C extends c.C2 implements i2.I2A {\n" + 
4054
		"	             ^\n" + 
4055
		"The method m2(Object) from C2 cannot implement the corresponding method from I2A due to incompatible nullness constraints\n" + 
4056
		"----------\n" + 
4057
		"2. ERROR in ctest\\C.java (at line 2)\n" + 
4058
		"	public class C extends c.C2 implements i2.I2A {\n" + 
4059
		"	             ^\n" + 
4060
		"The method m1(Object) from C2 cannot implement the corresponding method from I2A due to incompatible nullness constraints\n" + 
4061
		"----------\n",
4062
		libs,		
4063
		true /* shouldFlush*/,
4064
		options);
4065
}
4066
4067
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281
4068
// report conflict between inheritance and default
4069
public void testBug388281_07() {
4070
	Map options = getCompilerOptions();
4071
	options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
4072
	runNegativeTestWithLibs(
4073
		new String[] {
4074
			"p1/Super.java",
4075
			"package p1;\n" +
4076
			"import org.eclipse.jdt.annotation.*;\n" +
4077
			"public class Super {\n" +
4078
			"    public @Nullable Object m(@Nullable Object arg) {\n" +
4079
			"        return null;" +
4080
			"    }\n" +
4081
			"}\n",
4082
			"p2/Sub.java",
4083
			"package p2;\n" +
4084
			"import org.eclipse.jdt.annotation.*;\n" +
4085
			"@NonNullByDefault\n" +
4086
			"public class Sub extends p1.Super {\n" +
4087
			"    @Override\n" +
4088
			"    public Object m(Object arg) { // (a)+(b) conflict at arg and return\n" +
4089
			"        System.out.println(arg.toString()); // (1)\n" +
4090
			"        return null;\n" +
4091
			"    }\n" +
4092
			"}\n",
4093
			"Client.java",
4094
			"public class Client {\n" +
4095
			"    void test(p2.Sub s) {\n" +
4096
			"        Object result = s.m(null);\n" +
4097
			"        System.out.println(result.toString());  // (2)\n" +
4098
			"    }\n" +
4099
			"}\n"
4100
		}, 
4101
		options,
4102
		"----------\n" + 
4103
		"1. ERROR in p2\\Sub.java (at line 6)\n" + 
4104
		"	public Object m(Object arg) { // (a)+(b) conflict at arg and return\n" + 
4105
		"	       ^^^^^^\n" + 
4106
		"The default \'@NonNull\' conflicts with the inherited \'@Nullable\' annotation in the overridden method from Super \n" + 
4107
		"----------\n" + 
4108
		"2. ERROR in p2\\Sub.java (at line 6)\n" + 
4109
		"	public Object m(Object arg) { // (a)+(b) conflict at arg and return\n" + 
4110
		"	                       ^^^\n" + 
4111
		"The default \'@NonNull\' conflicts with the inherited \'@Nullable\' annotation in the overridden method from Super \n" + 
4112
		"----------\n" + 
4113
		"3. ERROR in p2\\Sub.java (at line 7)\n" + 
4114
		"	System.out.println(arg.toString()); // (1)\n" + 
4115
		"	                   ^^^\n" + 
4116
		"Potential null pointer access: The variable arg may be null at this location\n" + 
4117
		"----------\n" + 
4118
		"----------\n" + 
4119
		"1. ERROR in Client.java (at line 4)\n" + 
4120
		"	System.out.println(result.toString());  // (2)\n" + 
4121
		"	                   ^^^^^^\n" + 
4122
		"Potential null pointer access: The variable result may be null at this location\n" + 
4123
		"----------\n");
4124
}
4125
4126
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=388281
4127
// report conflict between inheritance and default - binary types
4128
public void testBug388281_08() {
4129
	String path = this.getCompilerTestsPluginDirectoryPath() + File.separator + "workspace" + File.separator + "Test388281.jar";
4130
	String[] libs = new String[this.LIBS.length + 1];
4131
	System.arraycopy(this.LIBS, 0, libs, 0, this.LIBS.length);
4132
	libs[this.LIBS.length] = path;
4133
	Map options = getCompilerOptions();
4134
	options.put(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
4135
	runNegativeTest(
4136
		new String[] {
4137
			"ctest/Ctest.java",
4138
			"package ctest;\n" +
4139
			"import org.eclipse.jdt.annotation.*;\n" +
4140
			"@NonNullByDefault\n" +
4141
			"public class Ctest implements i2.II {\n" +
4142
			"    public Object m1(@Nullable Object a1) { // silent: conflict at a1 avoided\n" + 
4143
			"		return new Object();\n" + 
4144
			"    }\n" + 
4145
			"    public String m2(Object a2) { // (a) conflict at return\n" + 
4146
			"    	return null;\n" + 
4147
			"    }\n" + 
4148
			"    public String m1(Object o1, Object o2) { // (b) conflict at o1\n" +
4149
			"        System.out.println(o1.toString()); // (1) inherited @Nullable\n" +  
4150
			"        return null; // (2) @NonNullByDefault in i2.II\n" + 
4151
			"    }\n" +
4152
			"}\n",
4153
			"Client.java",
4154
			"public class Client {\n" +
4155
			"    void test(ctest.Ctest c) {\n" +
4156
			"        Object result = c.m1(null, null); // (3) 2nd arg @NonNullByDefault from i2.II\n" +
4157
			"    }\n" +
4158
			"}\n"
4159
		},
4160
		"----------\n" + 
4161
		"1. ERROR in ctest\\Ctest.java (at line 8)\n" + 
4162
		"	public String m2(Object a2) { // (a) conflict at return\n" + 
4163
		"	       ^^^^^^\n" + 
4164
		"The default \'@NonNull\' conflicts with the inherited \'@Nullable\' annotation in the overridden method from I \n" + 
4165
		"----------\n" + 
4166
		"2. ERROR in ctest\\Ctest.java (at line 11)\n" + 
4167
		"	public String m1(Object o1, Object o2) { // (b) conflict at o1\n" + 
4168
		"	                        ^^\n" + 
4169
		"The default \'@NonNull\' conflicts with the inherited \'@Nullable\' annotation in the overridden method from II \n" + 
4170
		"----------\n" + 
4171
		"3. ERROR in ctest\\Ctest.java (at line 12)\n" + 
4172
		"	System.out.println(o1.toString()); // (1) inherited @Nullable\n" + 
4173
		"	                   ^^\n" + 
4174
		"Potential null pointer access: The variable o1 may be null at this location\n" + 
4175
		"----------\n" + 
4176
		"4. ERROR in ctest\\Ctest.java (at line 13)\n" + 
4177
		"	return null; // (2) @NonNullByDefault in i2.II\n" + 
4178
		"	       ^^^^\n" + 
4179
		"Null type mismatch: required \'@NonNull String\' but the provided value is null\n" + 
4180
		"----------\n" + 
4181
		"----------\n" + 
4182
		"1. ERROR in Client.java (at line 3)\n" + 
4183
		"	Object result = c.m1(null, null); // (3) 2nd arg @NonNullByDefault from i2.II\n" + 
4184
		"	                           ^^^^\n" + 
4185
		"Null type mismatch: required \'@NonNull Object\' but the provided value is null\n" + 
4186
		"----------\n",
4187
		libs,
4188
		true, // should flush
4189
		options);
4190
}
3718
}
4191
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java (+2 lines)
Added Link Here
1503
	int SpecdNonNullLocalVariableComparisonYieldsFalse = Internal + 932;
1503
	int SpecdNonNullLocalVariableComparisonYieldsFalse = Internal + 932;
1504
	/** @since 3.8 */
1504
	/** @since 3.8 */
1505
	int RequiredNonNullButProvidedSpecdNullable = Internal + 933;
1505
	int RequiredNonNullButProvidedSpecdNullable = Internal + 933;
1506
	/** @since 3.9 */
1507
	int ConflictingNullAnnotations = MethodRelated + 939;
1506
1508
1507
	/**
1509
	/**
1508
	 * External problems -- These are problems defined by other plugins
1510
	 * External problems -- These are problems defined by other plugins
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java (-1 / +3 lines)
Lines 84-91 Link Here
84
				argument.createBinding(this.scope, this.binding.parameters[i]);
84
				argument.createBinding(this.scope, this.binding.parameters[i]);
85
				// createBinding() has resolved annotations, now transfer nullness info from the argument to the method:
85
				// createBinding() has resolved annotations, now transfer nullness info from the argument to the method:
86
				if ((argument.binding.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) != 0) {
86
				if ((argument.binding.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) != 0) {
87
					if (this.binding.parameterNonNullness == null)
87
					if (this.binding.parameterNonNullness == null) {
88
						this.binding.parameterNonNullness = new Boolean[this.arguments.length];
88
						this.binding.parameterNonNullness = new Boolean[this.arguments.length];
89
						this.binding.tagBits |= TagBits.IsNullnessKnown;
90
					}
89
					this.binding.parameterNonNullness[i] = Boolean.valueOf((argument.binding.tagBits & TagBits.AnnotationNonNull) != 0);
91
					this.binding.parameterNonNullness[i] = Boolean.valueOf((argument.binding.tagBits & TagBits.AnnotationNonNull) != 0);
90
				}
92
				}
91
			}
93
			}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java (+7 lines)
Lines 35-40 Link Here
35
import org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
35
import org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
36
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
36
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
37
import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding;
37
import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding;
38
import org.eclipse.jdt.internal.compiler.lookup.ImplicitNullAnnotationVerifier;
38
import org.eclipse.jdt.internal.compiler.lookup.PolymorphicMethodBinding;
39
import org.eclipse.jdt.internal.compiler.lookup.PolymorphicMethodBinding;
39
import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
40
import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding;
40
import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
41
import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
Lines 539-544 Link Here
539
		return null;
540
		return null;
540
	}
541
	}
541
542
543
	if (compilerOptions.isAnnotationBasedNullAnalysisEnabled && (this.binding.tagBits & TagBits.IsNullnessKnown) == 0) {
544
		// not interested in reporting problems against this.binding:
545
		new ImplicitNullAnnotationVerifier(compilerOptions.inheritNullAnnotations)
546
				.checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope);
547
	}
548
	
542
	if (((this.bits & ASTNode.InsideExpressionStatement) != 0)
549
	if (((this.bits & ASTNode.InsideExpressionStatement) != 0)
543
			&& this.binding.isPolymorphic()) {
550
			&& this.binding.isPolymorphic()) {
544
		// we only set the return type to be void if this method invocation is used inside an expression statement
551
		// we only set the return type to be void if this method invocation is used inside an expression statement
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java (-1 / +10 lines)
Lines 161-166 Link Here
161
	static final char[][] DEFAULT_NONNULL_ANNOTATION_NAME = CharOperation.splitOn('.', "org.eclipse.jdt.annotation.NonNull".toCharArray()); //$NON-NLS-1$
161
	static final char[][] DEFAULT_NONNULL_ANNOTATION_NAME = CharOperation.splitOn('.', "org.eclipse.jdt.annotation.NonNull".toCharArray()); //$NON-NLS-1$
162
	static final char[][] DEFAULT_NONNULLBYDEFAULT_ANNOTATION_NAME = CharOperation.splitOn('.', "org.eclipse.jdt.annotation.NonNullByDefault".toCharArray()); //$NON-NLS-1$
162
	static final char[][] DEFAULT_NONNULLBYDEFAULT_ANNOTATION_NAME = CharOperation.splitOn('.', "org.eclipse.jdt.annotation.NonNullByDefault".toCharArray()); //$NON-NLS-1$
163
	public static final String OPTION_ReportMissingNonNullByDefaultAnnotation = "org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation";  //$NON-NLS-1$
163
	public static final String OPTION_ReportMissingNonNullByDefaultAnnotation = "org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation";  //$NON-NLS-1$
164
	public static final String OPTION_InheritNullAnnotations = "org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations";  //$NON-NLS-1$
164
	/**
165
	/**
165
	 * Possible values for configurable options
166
	 * Possible values for configurable options
166
	 */
167
	 */
Lines 423-428 Link Here
423
		String tolerateIllegalAmbiguousVarargs = System.getProperty("tolerateIllegalAmbiguousVarargsInvocation"); //$NON-NLS-1$
424
		String tolerateIllegalAmbiguousVarargs = System.getProperty("tolerateIllegalAmbiguousVarargsInvocation"); //$NON-NLS-1$
424
		tolerateIllegalAmbiguousVarargsInvocation = tolerateIllegalAmbiguousVarargs != null && tolerateIllegalAmbiguousVarargs.equalsIgnoreCase("true"); //$NON-NLS-1$
425
		tolerateIllegalAmbiguousVarargsInvocation = tolerateIllegalAmbiguousVarargs != null && tolerateIllegalAmbiguousVarargs.equalsIgnoreCase("true"); //$NON-NLS-1$
425
	}
426
	}
427
	/** Should null annotations of overridden methods be inherited? */
428
	public boolean inheritNullAnnotations;
426
429
427
	// keep in sync with warningTokenToIrritant and warningTokenFromIrritant
430
	// keep in sync with warningTokenToIrritant and warningTokenFromIrritant
428
	public final static String[] warningTokens = {
431
	public final static String[] warningTokens = {
Lines 809-815 Link Here
809
			OPTION_ReportNullSpecViolation,
812
			OPTION_ReportNullSpecViolation,
810
			OPTION_ReportNullAnnotationInferenceConflict,
813
			OPTION_ReportNullAnnotationInferenceConflict,
811
			OPTION_ReportNullUncheckedConversion,
814
			OPTION_ReportNullUncheckedConversion,
812
			OPTION_ReportRedundantNullAnnotation
815
			OPTION_ReportRedundantNullAnnotation,
816
			OPTION_InheritNullAnnotations
813
		};
817
		};
814
		return result;
818
		return result;
815
	}
819
	}
Lines 1105-1110 Link Here
1105
		optionsMap.put(OPTION_NonNullAnnotationName, String.valueOf(CharOperation.concatWith(this.nonNullAnnotationName, '.')));
1109
		optionsMap.put(OPTION_NonNullAnnotationName, String.valueOf(CharOperation.concatWith(this.nonNullAnnotationName, '.')));
1106
		optionsMap.put(OPTION_NonNullByDefaultAnnotationName, String.valueOf(CharOperation.concatWith(this.nonNullByDefaultAnnotationName, '.')));
1110
		optionsMap.put(OPTION_NonNullByDefaultAnnotationName, String.valueOf(CharOperation.concatWith(this.nonNullByDefaultAnnotationName, '.')));
1107
		optionsMap.put(OPTION_ReportMissingNonNullByDefaultAnnotation, getSeverityString(MissingNonNullByDefaultAnnotation));
1111
		optionsMap.put(OPTION_ReportMissingNonNullByDefaultAnnotation, getSeverityString(MissingNonNullByDefaultAnnotation));
1112
		optionsMap.put(OPTION_InheritNullAnnotations, this.inheritNullAnnotations ? ENABLED : DISABLED);
1108
		return optionsMap;
1113
		return optionsMap;
1109
	}
1114
	}
1110
1115
Lines 1263-1268 Link Here
1263
		this.nonNullAnnotationName = DEFAULT_NONNULL_ANNOTATION_NAME;
1268
		this.nonNullAnnotationName = DEFAULT_NONNULL_ANNOTATION_NAME;
1264
		this.nonNullByDefaultAnnotationName = DEFAULT_NONNULLBYDEFAULT_ANNOTATION_NAME;
1269
		this.nonNullByDefaultAnnotationName = DEFAULT_NONNULLBYDEFAULT_ANNOTATION_NAME;
1265
		this.intendedDefaultNonNullness = 0;
1270
		this.intendedDefaultNonNullness = 0;
1271
		this.inheritNullAnnotations = false;
1266
		
1272
		
1267
		this.analyseResourceLeaks = true;
1273
		this.analyseResourceLeaks = true;
1268
1274
Lines 1592-1597 Link Here
1592
				this.nonNullByDefaultAnnotationName = CharOperation.splitAndTrimOn('.', ((String)optionValue).toCharArray());
1598
				this.nonNullByDefaultAnnotationName = CharOperation.splitAndTrimOn('.', ((String)optionValue).toCharArray());
1593
			}
1599
			}
1594
			if ((optionValue = optionsMap.get(OPTION_ReportMissingNonNullByDefaultAnnotation)) != null) updateSeverity(MissingNonNullByDefaultAnnotation, optionValue);
1600
			if ((optionValue = optionsMap.get(OPTION_ReportMissingNonNullByDefaultAnnotation)) != null) updateSeverity(MissingNonNullByDefaultAnnotation, optionValue);
1601
			if ((optionValue = optionsMap.get(OPTION_InheritNullAnnotations)) != null) {
1602
				this.inheritNullAnnotations = ENABLED.equals(optionValue);
1603
			}
1595
		}
1604
		}
1596
1605
1597
		// Javadoc options
1606
		// Javadoc options
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java (-24 / +1 lines)
Lines 1162-1174 Link Here
1162
	if (nullableAnnotationName == null || nonNullAnnotationName == null || nonNullByDefaultAnnotationName == null)
1162
	if (nullableAnnotationName == null || nonNullAnnotationName == null || nonNullByDefaultAnnotationName == null)
1163
		return; // not well-configured to use null annotations
1163
		return; // not well-configured to use null annotations
1164
1164
1165
	int currentDefault = NO_NULL_DEFAULT;
1166
	if ((this.tagBits & TagBits.AnnotationNonNullByDefault) != 0) {
1167
		currentDefault = NONNULL_BY_DEFAULT;
1168
	} else if ((this.tagBits & TagBits.AnnotationNullUnspecifiedByDefault) != 0) {
1169
		currentDefault = NULL_UNSPECIFIED_BY_DEFAULT;
1170
	}
1171
1172
	// return:
1165
	// return:
1173
	IBinaryAnnotation[] annotations = method.getAnnotations();
1166
	IBinaryAnnotation[] annotations = method.getAnnotations();
1174
	boolean explicitNullness = false;
1167
	boolean explicitNullness = false;
Lines 1180-1186 Link Here
1180
			char[][] typeName = CharOperation.splitOn('/', annotationTypeName, 1, annotationTypeName.length-1); // cut of leading 'L' and trailing ';'
1173
			char[][] typeName = CharOperation.splitOn('/', annotationTypeName, 1, annotationTypeName.length-1); // cut of leading 'L' and trailing ';'
1181
			if (CharOperation.equals(typeName, nonNullByDefaultAnnotationName)) {
1174
			if (CharOperation.equals(typeName, nonNullByDefaultAnnotationName)) {
1182
				methodBinding.tagBits |= TagBits.AnnotationNonNullByDefault;
1175
				methodBinding.tagBits |= TagBits.AnnotationNonNullByDefault;
1183
				currentDefault = NONNULL_BY_DEFAULT;
1184
			}
1176
			}
1185
			if (!explicitNullness && CharOperation.equals(typeName, nonNullAnnotationName)) {
1177
			if (!explicitNullness && CharOperation.equals(typeName, nonNullAnnotationName)) {
1186
				methodBinding.tagBits |= TagBits.AnnotationNonNull;
1178
				methodBinding.tagBits |= TagBits.AnnotationNonNull;
Lines 1192-1210 Link Here
1192
			}
1184
			}
1193
		}
1185
		}
1194
	}
1186
	}
1195
	if (!explicitNullness 
1196
			&& (methodBinding.returnType != null && !methodBinding.returnType.isBaseType()) 
1197
			&& currentDefault == NONNULL_BY_DEFAULT) {
1198
		methodBinding.tagBits |= TagBits.AnnotationNonNull;
1199
	}
1200
1187
1201
	// parameters:
1188
	// parameters:
1202
	TypeBinding[] parameters = methodBinding.parameters;
1189
	TypeBinding[] parameters = methodBinding.parameters;
1203
	int numVisibleParams = parameters.length;
1190
	int numVisibleParams = parameters.length;
1204
	int numParamAnnotations = method.getAnnotatedParametersCount();
1191
	int numParamAnnotations = method.getAnnotatedParametersCount();
1205
	if (numParamAnnotations > 0 || currentDefault == NONNULL_BY_DEFAULT) {
1192
	if (numParamAnnotations > 0) {
1206
		for (int j = 0; j < numVisibleParams; j++) {
1193
		for (int j = 0; j < numVisibleParams; j++) {
1207
			explicitNullness = false;
1208
			if (numParamAnnotations > 0) {
1194
			if (numParamAnnotations > 0) {
1209
				int startIndex = numParamAnnotations - numVisibleParams;
1195
				int startIndex = numParamAnnotations - numVisibleParams;
1210
				IBinaryAnnotation[] paramAnnotations = method.getParameterAnnotations(j+startIndex);
1196
				IBinaryAnnotation[] paramAnnotations = method.getParameterAnnotations(j+startIndex);
Lines 1218-1240 Link Here
1218
							if (methodBinding.parameterNonNullness == null)
1204
							if (methodBinding.parameterNonNullness == null)
1219
								methodBinding.parameterNonNullness = new Boolean[numVisibleParams];
1205
								methodBinding.parameterNonNullness = new Boolean[numVisibleParams];
1220
							methodBinding.parameterNonNullness[j] = Boolean.TRUE;
1206
							methodBinding.parameterNonNullness[j] = Boolean.TRUE;
1221
							explicitNullness = true;
1222
							break;
1207
							break;
1223
						} else if (CharOperation.equals(typeName, nullableAnnotationName)) {
1208
						} else if (CharOperation.equals(typeName, nullableAnnotationName)) {
1224
							if (methodBinding.parameterNonNullness == null)
1209
							if (methodBinding.parameterNonNullness == null)
1225
								methodBinding.parameterNonNullness = new Boolean[numVisibleParams];
1210
								methodBinding.parameterNonNullness = new Boolean[numVisibleParams];
1226
							methodBinding.parameterNonNullness[j] = Boolean.FALSE;
1211
							methodBinding.parameterNonNullness[j] = Boolean.FALSE;
1227
							explicitNullness = true;
1228
							break;
1212
							break;
1229
						}
1213
						}
1230
					}
1214
					}
1231
				}
1232
			}
1233
			if (!explicitNullness && currentDefault == NONNULL_BY_DEFAULT) {
1234
				if (methodBinding.parameterNonNullness == null)
1235
					methodBinding.parameterNonNullness = new Boolean[numVisibleParams];
1236
				if (methodBinding.parameters[j]!= null && !methodBinding.parameters[j].isBaseType()) {
1237
					methodBinding.parameterNonNullness[j] = Boolean.TRUE;
1238
				}
1215
				}
1239
			}
1216
			}
1240
		}
1217
		}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java (+363 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2012 GK Software AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     Stephan Herrmann - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.compiler.lookup;
12
13
import java.util.ArrayList;
14
import java.util.HashSet;
15
import java.util.List;
16
import java.util.Set;
17
18
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
19
import org.eclipse.jdt.internal.compiler.ast.Argument;
20
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
21
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
22
23
/**
24
 * Extracted slice from MethodVerifier15, which is responsible only for implicit null annotations.
25
 * First, if enabled, it detects overridden methods from which null annotations are inherited.
26
 * Next, also default nullness is filled into remaining empty slots.
27
 * After all implicit annotations have been filled in compatibility is checked and problems are complained.
28
 */
29
public class ImplicitNullAnnotationVerifier {
30
	
31
	// delegate which to ask for recursive analysis of super methods
32
	// can be 'this', but is never a MethodVerifier (to avoid infinite recursion).
33
	ImplicitNullAnnotationVerifier buddyImplicitNullAnnotationsVerifier;
34
	private boolean inheritNullAnnotations;
35
36
	public ImplicitNullAnnotationVerifier(boolean inheritNullAnnotations) {
37
		this.buddyImplicitNullAnnotationsVerifier = this;
38
		this.inheritNullAnnotations = inheritNullAnnotations;
39
	}
40
41
	// for sub-classes:
42
	ImplicitNullAnnotationVerifier(CompilerOptions options) {
43
		this.buddyImplicitNullAnnotationsVerifier = new ImplicitNullAnnotationVerifier(options.inheritNullAnnotations);
44
		this.inheritNullAnnotations = options.inheritNullAnnotations;
45
	}
46
47
	/**
48
	 * Check and fill in implicit annotations from overridden methods and from default.
49
	 * Precondition: caller has checked whether annotation-based null analysis is enabled.
50
	 */
51
	public void checkImplicitNullAnnotations(MethodBinding currentMethod, AbstractMethodDeclaration srcMethod, boolean complain, Scope scope) {
52
		// check inherited nullness from superclass and superInterfaces
53
		try {
54
			ReferenceBinding currentType = currentMethod.declaringClass;
55
			if (currentType.id == TypeIds.T_JavaLangObject) {
56
				return;
57
			}
58
			boolean needToApplyNonNullDefault = currentMethod.hasNonNullDefault();
59
			// compatibility & inheritance do not consider constructors / static methods:
60
			boolean isInstanceMethod = !currentMethod.isConstructor() && !currentMethod.isStatic();
61
			complain &= isInstanceMethod;
62
			if (!needToApplyNonNullDefault 
63
					&& !complain 
64
					&& !(this.inheritNullAnnotations && isInstanceMethod)) {
65
				return; // short cut, no work to be done
66
			}
67
68
			if (isInstanceMethod) {
69
				List superMethodList = new ArrayList();
70
				
71
				findAllOverriddenMethods(currentMethod.original(), currentMethod.selector, currentMethod.parameters.length,
72
								currentType, new HashSet(), superMethodList);
73
				
74
				int length = superMethodList.size();
75
				for (int i = length; --i >= 0;) {
76
					MethodBinding currentSuper = (MethodBinding) superMethodList.get(i);
77
					if ((currentSuper.tagBits & TagBits.IsNullnessKnown) == 0) {
78
						// recurse to prepare currentSuper
79
						checkImplicitNullAnnotations(currentSuper, null, false, scope); // TODO (stephan) complain=true if currentSuper is source method??
80
					}
81
					checkNullSpecInheritance(currentMethod, srcMethod, needToApplyNonNullDefault, complain, currentSuper, scope);
82
					needToApplyNonNullDefault = false;
83
				}
84
			}
85
			if (needToApplyNonNullDefault) {
86
				currentMethod.fillInDefaultNonNullness(srcMethod);
87
			}
88
		} finally {			
89
			currentMethod.tagBits |= TagBits.IsNullnessKnown;
90
		}
91
	}
92
93
	/* 
94
	 * Recursively traverse the tree of ancestors but whenever we find a matching method prune the super tree.
95
	 * Collect all matching methods in 'result'.
96
	 */
97
	private void findAllOverriddenMethods(MethodBinding original, char[] selector, int suggestedParameterLength, 
98
			ReferenceBinding currentType, Set ifcsSeen, List result) 
99
	{
100
		if (currentType.id == TypeIds.T_JavaLangObject)
101
			return;
102
103
		// superclass:
104
		collectOverriddenMethods(original, selector, suggestedParameterLength, currentType.superclass(), ifcsSeen, result);
105
106
		// superInterfaces:
107
		ReferenceBinding[] superInterfaces = currentType.superInterfaces();
108
		int ifcLen = superInterfaces.length;
109
		for (int i = 0; i < ifcLen; i++) {
110
			ReferenceBinding currentIfc = superInterfaces[i];
111
			if (ifcsSeen.add(currentIfc.original())) {	// process each interface at most once
112
				collectOverriddenMethods(original, selector, suggestedParameterLength, currentIfc, ifcsSeen, result);
113
			}
114
		}
115
	}
116
117
	/* collect matching methods from one supertype. */
118
	private void collectOverriddenMethods(MethodBinding original, char[] selector, int suggestedParameterLength,
119
			ReferenceBinding superType, Set ifcsSeen, List result) 
120
	{
121
		MethodBinding [] ifcMethods = superType.getMethods(selector, suggestedParameterLength);
122
		int length = ifcMethods.length;
123
		for  (int i=0; i<length; i++) {
124
			MethodBinding currentMethod = ifcMethods[i];
125
			if (currentMethod.isStatic())
126
				continue;
127
			if (areParametersEqual(original, currentMethod.original())) {
128
				result.add(currentMethod);
129
				return; // at most one method is overridden from any supertype
130
			}
131
		}
132
		findAllOverriddenMethods(original, selector, suggestedParameterLength, superType, ifcsSeen, result);
133
	}
134
135
	/* The main algorithm in this class */
136
	void checkNullSpecInheritance(MethodBinding currentMethod, AbstractMethodDeclaration srcMethod, 
137
			boolean hasNonNullDefault, boolean shouldComplain,
138
			MethodBinding inheritedMethod, Scope scope) 
139
	{
140
		// Note that basically two different flows lead into this method:
141
		// (1) during MethodVerifyer15.checkMethods() we want to report errors (against srcMethod or against the current type)
142
		//     In this case this method is directly called from MethodVerifier15 (checkAgainstInheritedMethod / checkConcreteInheritedMethod)
143
		// (2) during on-demand invocation we are mainly interested in the side effects of copying inherited null annotations
144
		//     In this case this method is called via checkImplicitNullAnnotations from
145
		//     - MessageSend.resolveType(..)
146
		//     - SourceTypeBinding.createArgumentBindings(..)
147
		//     - recursive calls within this class
148
		//     Still we *might* want to complain about problems found (controlled by 'complain')
149
150
		if ((inheritedMethod.tagBits & TagBits.IsNullnessKnown) == 0) {
151
			// TODO (stephan): even here we may need to report problems? How to discriminate?
152
			this.buddyImplicitNullAnnotationsVerifier.checkImplicitNullAnnotations(inheritedMethod, null, false, scope);
153
		}
154
		long inheritedBits = inheritedMethod.tagBits;
155
		long inheritedNullnessBits = inheritedBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable);
156
		long currentBits = currentMethod.tagBits;
157
		long currentNullnessBits = currentBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable);
158
		
159
		LookupEnvironment environment = scope.environment();
160
		boolean shouldInherit = this.inheritNullAnnotations;
161
162
		// return type:
163
		returnType: {
164
			if (currentMethod.returnType == null || currentMethod.returnType.isBaseType())
165
				break returnType; // no nullness for primitive types
166
			if (currentNullnessBits == 0) {
167
				// unspecified, may fill in either from super or from default
168
				if (shouldInherit) {
169
					if (inheritedNullnessBits != 0) {
170
						if (hasNonNullDefault) {
171
							// both inheritance and default: check for conflict?
172
							if (shouldComplain && inheritedNullnessBits == TagBits.AnnotationNullable)
173
								scope.problemReporter().conflictingNullAnnotations(currentMethod, ((MethodDeclaration) srcMethod).returnType, inheritedMethod);
174
							// 	still use the inherited bits to avoid incompatibility
175
						}
176
						currentMethod.tagBits |= inheritedNullnessBits;
177
						break returnType; // compatible by construction, skip complain phase below
178
					}
179
				}
180
				if (hasNonNullDefault) { // conflict with inheritance already checked
181
					currentMethod.tagBits |= (currentNullnessBits = TagBits.AnnotationNonNull); 
182
				}
183
			}
184
			if (shouldComplain) {
185
				if ((inheritedNullnessBits & TagBits.AnnotationNonNull) != 0
186
						&& currentNullnessBits != TagBits.AnnotationNonNull)
187
				{
188
					if (srcMethod != null) {
189
						scope.problemReporter().illegalReturnRedefinition(srcMethod, inheritedMethod,
190
																	environment.getNonNullAnnotationName());
191
					} else {
192
						scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod);
193
						return;
194
					}
195
				}
196
			}
197
		}
198
199
		// parameters:
200
		Argument[] currentArguments = srcMethod == null ? null : srcMethod.arguments;
201
202
		int length = 0;
203
		if (currentArguments != null)
204
			length = currentArguments.length;
205
		else if (inheritedMethod.parameterNonNullness != null)
206
			length = inheritedMethod.parameterNonNullness.length;
207
		else if (currentMethod.parameterNonNullness != null)
208
			length = currentMethod.parameterNonNullness.length;
209
210
		for (int i = 0; i < length; i++) {
211
			if (currentMethod.parameters[i].isBaseType()) continue;
212
213
			Argument currentArgument = currentArguments == null 
214
										? null : currentArguments[i];
215
			Boolean inheritedNonNullNess = (inheritedMethod.parameterNonNullness == null)
216
										? null : inheritedMethod.parameterNonNullness[i];
217
			Boolean currentNonNullNess = (currentMethod.parameterNonNullness == null)
218
										? null : currentMethod.parameterNonNullness[i];
219
220
			if (currentNonNullNess == null) {
221
				// unspecified, may fill in either from super or from default
222
				if (inheritedNonNullNess != null) {
223
					if (shouldInherit) {
224
						if (hasNonNullDefault) {
225
							// both inheritance and default: check for conflict?
226
							if (shouldComplain
227
									&& inheritedNonNullNess == Boolean.FALSE
228
									&& currentArgument != null)
229
							{
230
								scope.problemReporter().conflictingNullAnnotations(currentMethod, currentArgument, inheritedMethod);
231
							}
232
							// 	still use the inherited info to avoid incompatibility
233
						}
234
						if (currentMethod.parameterNonNullness == null)
235
							currentMethod.parameterNonNullness = new Boolean[length];
236
						currentMethod.parameterNonNullness[i] = inheritedNonNullNess; 
237
						continue; // compatible by construction, skip complain phase below
238
					}
239
				}
240
				if (hasNonNullDefault) { // conflict with inheritance already checked
241
					if (currentMethod.parameterNonNullness == null)
242
						currentMethod.parameterNonNullness = new Boolean[length];
243
					currentMethod.parameterNonNullness[i] = (currentNonNullNess = Boolean.TRUE);
244
				}
245
			}
246
			if (shouldComplain) {
247
				boolean needNonNull = false;
248
				char[][] annotationName;
249
				if (inheritedNonNullNess == Boolean.TRUE) {
250
					needNonNull = true;
251
					annotationName = environment.getNonNullAnnotationName();
252
				} else {
253
					annotationName = environment.getNullableAnnotationName();
254
				}
255
				if (inheritedNonNullNess != Boolean.TRUE		// super parameter is not restricted to @NonNull
256
						&& currentNonNullNess == Boolean.TRUE)	// current parameter is restricted to @NonNull 
257
				{
258
					// incompatible
259
					if (currentArgument != null) {
260
						scope.problemReporter().illegalRedefinitionToNonNullParameter(
261
								currentArgument,
262
								inheritedMethod.declaringClass,
263
								(inheritedNonNullNess == null) ? null : environment.getNullableAnnotationName());
264
					} else {
265
						scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod);
266
					}
267
				} else if (inheritedNonNullNess != null
268
							&& currentNonNullNess == null) 
269
				{
270
					// weak conflict (TODO reconsider this case)
271
					if (currentArgument != null) {
272
						scope.problemReporter().parameterLackingNullAnnotation(
273
								currentArgument,
274
								inheritedMethod.declaringClass,
275
								needNonNull,
276
								annotationName);
277
					} else {
278
						scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod);
279
					}
280
				}
281
			}
282
		}
283
	}
284
	
285
	// ==== minimal set of utility methods previously from MethodVerifier15: ====
286
	
287
	boolean areParametersEqual(MethodBinding one, MethodBinding two) {
288
		TypeBinding[] oneArgs = one.parameters;
289
		TypeBinding[] twoArgs = two.parameters;
290
		if (oneArgs == twoArgs) return true;
291
292
		int length = oneArgs.length;
293
		if (length != twoArgs.length) return false;
294
295
		
296
		// methods with raw parameters are considered equal to inherited methods
297
		// with parameterized parameters for backwards compatibility, need a more complex check
298
		int i;
299
		foundRAW: for (i = 0; i < length; i++) {
300
			if (!areTypesEqual(oneArgs[i], twoArgs[i])) {
301
				if (oneArgs[i].leafComponentType().isRawType()) {
302
					if (oneArgs[i].dimensions() == twoArgs[i].dimensions() && oneArgs[i].leafComponentType().isEquivalentTo(twoArgs[i].leafComponentType())) {
303
						// raw mode does not apply if the method defines its own type variables
304
						if (one.typeVariables != Binding.NO_TYPE_VARIABLES)
305
							return false;
306
						// one parameter type is raw, hence all parameters types must be raw or non generic
307
						// otherwise we have a mismatch check backwards
308
						for (int j = 0; j < i; j++)
309
							if (oneArgs[j].leafComponentType().isParameterizedTypeWithActualArguments())
310
								return false;
311
						// switch to all raw mode
312
						break foundRAW;
313
					}
314
				}
315
				return false;
316
			}
317
		}
318
		// all raw mode for remaining parameters (if any)
319
		for (i++; i < length; i++) {
320
			if (!areTypesEqual(oneArgs[i], twoArgs[i])) {
321
				if (oneArgs[i].leafComponentType().isRawType())
322
					if (oneArgs[i].dimensions() == twoArgs[i].dimensions() && oneArgs[i].leafComponentType().isEquivalentTo(twoArgs[i].leafComponentType()))
323
						continue;
324
				return false;
325
			} else if (oneArgs[i].leafComponentType().isParameterizedTypeWithActualArguments()) {
326
				return false; // no remaining parameter can be a Parameterized type (if one has been converted then all RAW types must be converted)
327
			}
328
		}
329
		return true;
330
	}
331
	boolean areTypesEqual(TypeBinding one, TypeBinding two) {
332
		if (one == two) return true;
333
		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=329584
334
		switch(one.kind()) {
335
			case Binding.TYPE:
336
				switch (two.kind()) {
337
					case Binding.PARAMETERIZED_TYPE:
338
					case Binding.RAW_TYPE:
339
						if (one == two.erasure())
340
							return true;
341
				}
342
				break;
343
			case Binding.RAW_TYPE:
344
			case Binding.PARAMETERIZED_TYPE:
345
				switch(two.kind()) {
346
					case Binding.TYPE:
347
						if (one.erasure() == two)
348
							return true;
349
				}
350
		}
351
352
		// need to consider X<?> and X<? extends Object> as the same 'type'
353
		if (one.isParameterizedType() && two.isParameterizedType())
354
			return one.isEquivalentTo(two) && two.isEquivalentTo(one);
355
356
		// Can skip this since we resolved each method before comparing it, see computeSubstituteMethod()
357
		//	if (one instanceof UnresolvedReferenceBinding)
358
		//		return ((UnresolvedReferenceBinding) one).resolvedType == two;
359
		//	if (two instanceof UnresolvedReferenceBinding)
360
		//		return ((UnresolvedReferenceBinding) two).resolvedType == one;
361
		return false; // all other type bindings are identical
362
	}
363
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java (-4 / +10 lines)
Lines 451-460 Link Here
451
/**
451
/**
452
 * After method verifier has finished, fill in missing @NonNull specification from the applicable default.
452
 * After method verifier has finished, fill in missing @NonNull specification from the applicable default.
453
 */
453
 */
454
protected void fillInDefaultNonNullness() {
454
protected void fillInDefaultNonNullness(AbstractMethodDeclaration sourceMethod) {
455
	if (this.parameterNonNullness == null)
455
	if (this.parameterNonNullness == null)
456
		this.parameterNonNullness = new Boolean[this.parameters.length];
456
		this.parameterNonNullness = new Boolean[this.parameters.length];
457
	AbstractMethodDeclaration sourceMethod = sourceMethod();
458
	boolean added = false;
457
	boolean added = false;
459
	int length = this.parameterNonNullness.length;
458
	int length = this.parameterNonNullness.length;
460
	for (int i = 0; i < length; i++) {
459
	for (int i = 0; i < length; i++) {
Lines 466-472 Link Here
466
			if (sourceMethod != null) {
465
			if (sourceMethod != null) {
467
				sourceMethod.arguments[i].binding.tagBits |= TagBits.AnnotationNonNull;
466
				sourceMethod.arguments[i].binding.tagBits |= TagBits.AnnotationNonNull;
468
			}
467
			}
469
		} else if (this.parameterNonNullness[i].booleanValue()) {
468
		} else if (sourceMethod != null && this.parameterNonNullness[i].booleanValue()) {
470
			sourceMethod.scope.problemReporter().nullAnnotationIsRedundant(sourceMethod, i);
469
			sourceMethod.scope.problemReporter().nullAnnotationIsRedundant(sourceMethod, i);
471
		}
470
		}
472
	}
471
	}
Lines 477-483 Link Here
477
		&& (this.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) == 0)
476
		&& (this.tagBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable)) == 0)
478
	{
477
	{
479
		this.tagBits |= TagBits.AnnotationNonNull;
478
		this.tagBits |= TagBits.AnnotationNonNull;
480
	} else if ((this.tagBits & TagBits.AnnotationNonNull) != 0) {
479
	} else if (sourceMethod != null && (this.tagBits & TagBits.AnnotationNonNull) != 0) {
481
		sourceMethod.scope.problemReporter().nullAnnotationIsRedundant(sourceMethod, -1/*signifies method return*/);
480
		sourceMethod.scope.problemReporter().nullAnnotationIsRedundant(sourceMethod, -1/*signifies method return*/);
482
	}
481
	}
483
}
482
}
Lines 1170-1173 Link Here
1170
public TypeVariableBinding[] typeVariables() {
1169
public TypeVariableBinding[] typeVariables() {
1171
	return this.typeVariables;
1170
	return this.typeVariables;
1172
}
1171
}
1172
public boolean hasNonNullDefault() {
1173
	if ((this.tagBits & TagBits.AnnotationNonNullByDefault) != 0)
1174
		return true;
1175
	if ((this.tagBits & TagBits.AnnotationNullUnspecifiedByDefault) != 0)
1176
		return false;
1177
	return this.declaringClass.hasNonNullDefault();
1178
}
1173
}
1179
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java (-26 / +2 lines)
Lines 18-24 Link Here
18
import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
18
import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
19
import org.eclipse.jdt.internal.compiler.util.SimpleSet;
19
import org.eclipse.jdt.internal.compiler.util.SimpleSet;
20
20
21
public class MethodVerifier {
21
public class MethodVerifier extends ImplicitNullAnnotationVerifier {
22
	SourceTypeBinding type;
22
	SourceTypeBinding type;
23
	HashtableOfObject inheritedMethods;
23
	HashtableOfObject inheritedMethods;
24
	HashtableOfObject currentMethods;
24
	HashtableOfObject currentMethods;
Lines 42-47 Link Here
42
		- defining an interface as a local type (local types can only be classes)
42
		- defining an interface as a local type (local types can only be classes)
43
*/
43
*/
44
MethodVerifier(LookupEnvironment environment) {
44
MethodVerifier(LookupEnvironment environment) {
45
	super(environment.globalOptions);
45
	this.type = null;  // Initialized with the public method verify(SourceTypeBinding)
46
	this.type = null;  // Initialized with the public method verify(SourceTypeBinding)
46
	this.inheritedMethods = null;
47
	this.inheritedMethods = null;
47
	this.currentMethods = null;
48
	this.currentMethods = null;
Lines 52-69 Link Here
52
}
53
}
53
boolean areMethodsCompatible(MethodBinding one, MethodBinding two) {
54
boolean areMethodsCompatible(MethodBinding one, MethodBinding two) {
54
	return isParameterSubsignature(one, two) && areReturnTypesCompatible(one, two);
55
	return isParameterSubsignature(one, two) && areReturnTypesCompatible(one, two);
55
}
56
boolean areParametersEqual(MethodBinding one, MethodBinding two) {
57
	TypeBinding[] oneArgs = one.parameters;
58
	TypeBinding[] twoArgs = two.parameters;
59
	if (oneArgs == twoArgs) return true;
60
61
	int length = oneArgs.length;
62
	if (length != twoArgs.length) return false;
63
64
	for (int i = 0; i < length; i++)
65
		if (!areTypesEqual(oneArgs[i], twoArgs[i])) return false;
66
	return true;
67
}
56
}
68
boolean areReturnTypesCompatible(MethodBinding one, MethodBinding two) {
57
boolean areReturnTypesCompatible(MethodBinding one, MethodBinding two) {
69
	if (one.returnType == two.returnType) return true;
58
	if (one.returnType == two.returnType) return true;
Lines 86-104 Link Here
86
		return two.returnType.isCompatibleWith(one.returnType); // interface methods inherit from Object
75
		return two.returnType.isCompatibleWith(one.returnType); // interface methods inherit from Object
87
76
88
	return one.returnType.isCompatibleWith(two.returnType);
77
	return one.returnType.isCompatibleWith(two.returnType);
89
}
90
boolean areTypesEqual(TypeBinding one, TypeBinding two) {
91
	if (one == two) return true;
92
93
	// its possible that an UnresolvedReferenceBinding can be compared to its resolved type
94
	// when they're both UnresolvedReferenceBindings then they must be identical like all other types
95
	// all wrappers of UnresolvedReferenceBindings are converted as soon as the type is resolved
96
	// so its not possible to have 2 arrays where one is UnresolvedX[] and the other is X[]
97
	if (one instanceof UnresolvedReferenceBinding)
98
		return ((UnresolvedReferenceBinding) one).resolvedType == two;
99
	if (two instanceof UnresolvedReferenceBinding)
100
		return ((UnresolvedReferenceBinding) two).resolvedType == one;
101
	return false; // all other type bindings are identical
102
}
78
}
103
boolean canSkipInheritedMethods() {
79
boolean canSkipInheritedMethods() {
104
	if (this.type.superclass() != null && this.type.superclass().isAbstract())
80
	if (this.type.superclass() != null && this.type.superclass().isAbstract())
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java (-165 / +32 lines)
Lines 41-90 Link Here
41
41
42
	return isParameterSubsignature(one, two);
42
	return isParameterSubsignature(one, two);
43
}
43
}
44
boolean areParametersEqual(MethodBinding one, MethodBinding two) {
45
	TypeBinding[] oneArgs = one.parameters;
46
	TypeBinding[] twoArgs = two.parameters;
47
	if (oneArgs == twoArgs) return true;
48
49
	int length = oneArgs.length;
50
	if (length != twoArgs.length) return false;
51
52
	
53
	// methods with raw parameters are considered equal to inherited methods
54
	// with parameterized parameters for backwards compatibility, need a more complex check
55
	int i;
56
	foundRAW: for (i = 0; i < length; i++) {
57
		if (!areTypesEqual(oneArgs[i], twoArgs[i])) {
58
			if (oneArgs[i].leafComponentType().isRawType()) {
59
				if (oneArgs[i].dimensions() == twoArgs[i].dimensions() && oneArgs[i].leafComponentType().isEquivalentTo(twoArgs[i].leafComponentType())) {
60
					// raw mode does not apply if the method defines its own type variables
61
					if (one.typeVariables != Binding.NO_TYPE_VARIABLES)
62
						return false;
63
					// one parameter type is raw, hence all parameters types must be raw or non generic
64
					// otherwise we have a mismatch check backwards
65
					for (int j = 0; j < i; j++)
66
						if (oneArgs[j].leafComponentType().isParameterizedTypeWithActualArguments())
67
							return false;
68
					// switch to all raw mode
69
					break foundRAW;
70
				}
71
			}
72
			return false;
73
		}
74
	}
75
	// all raw mode for remaining parameters (if any)
76
	for (i++; i < length; i++) {
77
		if (!areTypesEqual(oneArgs[i], twoArgs[i])) {
78
			if (oneArgs[i].leafComponentType().isRawType())
79
				if (oneArgs[i].dimensions() == twoArgs[i].dimensions() && oneArgs[i].leafComponentType().isEquivalentTo(twoArgs[i].leafComponentType()))
80
					continue;
81
			return false;
82
		} else if (oneArgs[i].leafComponentType().isParameterizedTypeWithActualArguments()) {
83
			return false; // no remaining parameter can be a Parameterized type (if one has been converted then all RAW types must be converted)
84
		}
85
	}
86
	return true;
87
}
88
boolean areReturnTypesCompatible(MethodBinding one, MethodBinding two) {
44
boolean areReturnTypesCompatible(MethodBinding one, MethodBinding two) {
89
	if (one.returnType == two.returnType) return true;
45
	if (one.returnType == two.returnType) return true;
90
	if (this.type.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
46
	if (this.type.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
Lines 92-129 Link Here
92
	} else {
48
	} else {
93
		return areTypesEqual(one.returnType.erasure(), two.returnType.erasure());
49
		return areTypesEqual(one.returnType.erasure(), two.returnType.erasure());
94
	}
50
	}
95
}
96
boolean areTypesEqual(TypeBinding one, TypeBinding two) {
97
	if (one == two) return true;
98
	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=329584
99
	switch(one.kind()) {
100
		case Binding.TYPE:
101
			switch (two.kind()) {
102
				case Binding.PARAMETERIZED_TYPE:
103
				case Binding.RAW_TYPE:
104
					if (one == two.erasure())
105
						return true;
106
			}
107
			break;
108
		case Binding.RAW_TYPE:
109
		case Binding.PARAMETERIZED_TYPE:
110
			switch(two.kind()) {
111
				case Binding.TYPE:
112
					if (one.erasure() == two)
113
						return true;
114
			}
115
	}
116
117
	// need to consider X<?> and X<? extends Object> as the same 'type'
118
	if (one.isParameterizedType() && two.isParameterizedType())
119
		return one.isEquivalentTo(two) && two.isEquivalentTo(one);
120
121
	// Can skip this since we resolved each method before comparing it, see computeSubstituteMethod()
122
	//	if (one instanceof UnresolvedReferenceBinding)
123
	//		return ((UnresolvedReferenceBinding) one).resolvedType == two;
124
	//	if (two instanceof UnresolvedReferenceBinding)
125
	//		return ((UnresolvedReferenceBinding) two).resolvedType == one;
126
	return false; // all other type bindings are identical
127
}
51
}
128
// Given `overridingMethod' which overrides `inheritedMethod' answer whether some subclass method that
52
// Given `overridingMethod' which overrides `inheritedMethod' answer whether some subclass method that
129
// differs in erasure from overridingMethod could override `inheritedMethod'
53
// differs in erasure from overridingMethod could override `inheritedMethod'
Lines 147-152 Link Here
147
void checkConcreteInheritedMethod(MethodBinding concreteMethod, MethodBinding[] abstractMethods) {
71
void checkConcreteInheritedMethod(MethodBinding concreteMethod, MethodBinding[] abstractMethods) {
148
	super.checkConcreteInheritedMethod(concreteMethod, abstractMethods);
72
	super.checkConcreteInheritedMethod(concreteMethod, abstractMethods);
149
	boolean analyseNullAnnotations = this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled;
73
	boolean analyseNullAnnotations = this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled;
74
	// TODO (stephan): unclear if this srcMethod is actually needed
75
	AbstractMethodDeclaration srcMethod = null;
76
	if (analyseNullAnnotations && this.type.equals(concreteMethod.declaringClass)) // is currentMethod from the current type?
77
		srcMethod = concreteMethod.sourceMethod();
78
	boolean hasNonNullDefault = concreteMethod.hasNonNullDefault();
150
	for (int i = 0, l = abstractMethods.length; i < l; i++) {
79
	for (int i = 0, l = abstractMethods.length; i < l; i++) {
151
		MethodBinding abstractMethod = abstractMethods[i];
80
		MethodBinding abstractMethod = abstractMethods[i];
152
		if (concreteMethod.isVarargs() != abstractMethod.isVarargs())
81
		if (concreteMethod.isVarargs() != abstractMethod.isVarargs())
Lines 167-174 Link Here
167
				|| this.type.superclass.erasure().findSuperTypeOriginatingFrom(originalInherited.declaringClass) == null)
96
				|| this.type.superclass.erasure().findSuperTypeOriginatingFrom(originalInherited.declaringClass) == null)
168
					this.type.addSyntheticBridgeMethod(originalInherited, concreteMethod.original());
97
					this.type.addSyntheticBridgeMethod(originalInherited, concreteMethod.original());
169
		}
98
		}
170
		if (analyseNullAnnotations && !concreteMethod.isStatic() && !abstractMethod.isStatic())
99
		if (analyseNullAnnotations && !concreteMethod.isStatic() && !abstractMethod.isStatic()) {
171
			checkNullSpecInheritance(concreteMethod, abstractMethod);
100
			checkNullSpecInheritance(concreteMethod, srcMethod, hasNonNullDefault, true, abstractMethod, this.type.scope);
101
		}
172
	}
102
	}
173
}
103
}
174
void checkForBridgeMethod(MethodBinding currentMethod, MethodBinding inheritedMethod, MethodBinding[] allInheritedMethods) {
104
void checkForBridgeMethod(MethodBinding currentMethod, MethodBinding inheritedMethod, MethodBinding[] allInheritedMethods) {
Lines 369-468 Link Here
369
void checkAgainstInheritedMethods(MethodBinding currentMethod, MethodBinding[] methods, int length, MethodBinding[] allInheritedMethods)
299
void checkAgainstInheritedMethods(MethodBinding currentMethod, MethodBinding[] methods, int length, MethodBinding[] allInheritedMethods)
370
{
300
{
371
	super.checkAgainstInheritedMethods(currentMethod, methods, length, allInheritedMethods);
301
	super.checkAgainstInheritedMethods(currentMethod, methods, length, allInheritedMethods);
372
	if (this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
302
	CompilerOptions options = this.environment.globalOptions;
303
	if (options.isAnnotationBasedNullAnalysisEnabled 
304
			&& (currentMethod.tagBits & TagBits.IsNullnessKnown) == 0)
305
	{
306
		// if annotations are inherited these have been checked during STB.resolveTypesFor() (for methods explicit in this.type)
307
		AbstractMethodDeclaration srcMethod = null;
308
		if (this.type.equals(currentMethod.declaringClass)) // is currentMethod from the current type?
309
			srcMethod = currentMethod.sourceMethod();
310
		boolean hasNonNullDefault = currentMethod.hasNonNullDefault();
373
		for (int i = length; --i >= 0;)
311
		for (int i = length; --i >= 0;)
374
			if (!currentMethod.isStatic() && !methods[i].isStatic())
312
			if (!currentMethod.isStatic() && !methods[i].isStatic())
375
				checkNullSpecInheritance(currentMethod, methods[i]);
313
				checkNullSpecInheritance(currentMethod, srcMethod, hasNonNullDefault, true, methods[i], this.type.scope);
376
	}
314
	}
377
}
315
}
378
316
379
void checkNullSpecInheritance(MethodBinding currentMethod, MethodBinding inheritedMethod) {
317
void checkNullSpecInheritance(MethodBinding currentMethod, AbstractMethodDeclaration srcMethod, 
380
	// precondition: caller has checked whether annotation-based null analysis is enabled.
318
		boolean hasNonNullDefault, boolean complain, MethodBinding inheritedMethod, Scope scope)
381
	long inheritedBits = inheritedMethod.tagBits;
319
{
382
	long currentBits = currentMethod.tagBits;
320
	complain &= !currentMethod.isConstructor();
383
	AbstractMethodDeclaration srcMethod = null;
321
	if (!hasNonNullDefault && !complain && !this.environment.globalOptions.inheritNullAnnotations) {
384
	if (this.type.equals(currentMethod.declaringClass)) // is currentMethod from the current type?
322
		// nothing to be done, take the shortcut
385
		srcMethod = currentMethod.sourceMethod();
323
		currentMethod.tagBits |= TagBits.IsNullnessKnown;
386
324
		return;
387
	// return type:
388
	if ((inheritedBits & TagBits.AnnotationNonNull) != 0) {
389
		long currentNullBits = currentBits & (TagBits.AnnotationNonNull|TagBits.AnnotationNullable);
390
		if (currentNullBits != TagBits.AnnotationNonNull) {
391
			if (srcMethod != null) {
392
				this.type.scope.problemReporter().illegalReturnRedefinition(srcMethod, inheritedMethod,
393
															this.environment.getNonNullAnnotationName());
394
			} else {
395
				this.type.scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod);
396
				return;
397
			}
398
		}
399
	}
325
	}
400
326
	// in this context currentMethod can be inherited, too. Recurse if needed.
401
	// parameters:
327
	if (currentMethod.declaringClass != this.type 
402
	Argument[] currentArguments = srcMethod == null ? null : srcMethod.arguments;
328
			&& (currentMethod.tagBits & TagBits.IsNullnessKnown) == 0) 
403
	if (inheritedMethod.parameterNonNullness != null) {
329
	{
404
		// inherited method has null-annotations, check compatibility:
330
		this.buddyImplicitNullAnnotationsVerifier.checkImplicitNullAnnotations(currentMethod, srcMethod, complain, this.type.scope);
405
406
		int length = inheritedMethod.parameterNonNullness.length;
407
		for (int i = 0; i < length; i++) {
408
			Argument currentArgument = currentArguments == null ? null : currentArguments[i];
409
410
			Boolean inheritedNonNullNess = inheritedMethod.parameterNonNullness[i];
411
			Boolean currentNonNullNess = (currentMethod.parameterNonNullness == null)
412
										? null : currentMethod.parameterNonNullness[i];
413
			if (inheritedNonNullNess != null) {				// super has a null annotation
414
				if (currentNonNullNess == null) {			// current parameter lacks null annotation
415
					boolean needNonNull = false;
416
					char[][] annotationName;
417
					if (inheritedNonNullNess == Boolean.TRUE) {
418
						needNonNull = true;
419
						annotationName = this.environment.getNonNullAnnotationName();
420
					} else {
421
						annotationName = this.environment.getNullableAnnotationName();
422
					}
423
					if (currentArgument != null) {
424
						this.type.scope.problemReporter().parameterLackingNullAnnotation(
425
								currentArgument,
426
								inheritedMethod.declaringClass,
427
								needNonNull,
428
								annotationName);
429
						continue;
430
					} else {
431
						this.type.scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod);
432
						break;
433
					}
434
				}
435
			}
436
			if (inheritedNonNullNess != Boolean.TRUE) {		// super parameter is not restricted to @NonNull
437
				if (currentNonNullNess == Boolean.TRUE) { 	// current parameter is restricted to @NonNull
438
					if (currentArgument != null)
439
						this.type.scope.problemReporter().illegalRedefinitionToNonNullParameter(
440
														currentArgument,
441
														inheritedMethod.declaringClass,
442
														inheritedNonNullNess == null
443
														? null
444
														: this.environment.getNullableAnnotationName());
445
					else
446
						this.type.scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod);
447
				}
448
			}
449
		}
450
	} else if (currentMethod.parameterNonNullness != null) {
451
		// super method has no annotations but current has
452
		for (int i = 0; i < currentMethod.parameterNonNullness.length; i++) {
453
			if (currentMethod.parameterNonNullness[i] == Boolean.TRUE) { // tightening from unconstrained to @NonNull
454
				if (currentArguments != null) {
455
					this.type.scope.problemReporter().illegalRedefinitionToNonNullParameter(
456
																	currentArguments[i],
457
																	inheritedMethod.declaringClass,
458
																	null);
459
				} else {
460
					this.type.scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod);
461
					break;
462
				}
463
			}
464
		}
465
	}
331
	}
332
	super.checkNullSpecInheritance(currentMethod, srcMethod, hasNonNullDefault, complain, inheritedMethod, scope);
466
}
333
}
467
334
468
void reportRawReferences() {
335
void reportRawReferences() {
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java (+17 lines)
Lines 973-978 Link Here
973
    return false;
973
    return false;
974
}
974
}
975
975
976
/**
977
 * Answer whether a @NonNullByDefault is applicable at the given method binding.
978
 */
979
boolean hasNonNullDefault() {
980
	// Note, STB overrides for correctly handling local types
981
	ReferenceBinding currentType = this;
982
	while (currentType != null) {
983
		if ((currentType.tagBits & TagBits.AnnotationNonNullByDefault) != 0)
984
			return true;
985
		if ((currentType.tagBits & TagBits.AnnotationNullUnspecifiedByDefault) != 0)
986
			return false;
987
		currentType = currentType.enclosingType();
988
	}
989
	// package
990
	return this.getPackage().defaultNullness == NONNULL_BY_DEFAULT;
991
}
992
976
public final boolean hasRestrictedAccess() {
993
public final boolean hasRestrictedAccess() {
977
	return (this.modifiers & ExtraCompilerModifiers.AccRestrictedAccess) != 0;
994
	return (this.modifiers & ExtraCompilerModifiers.AccRestrictedAccess) != 0;
978
}
995
}
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java (-29 / +30 lines)
Lines 36-41 Link Here
36
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
36
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
37
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
37
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
38
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
38
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
39
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
39
import org.eclipse.jdt.internal.compiler.impl.Constant;
40
import org.eclipse.jdt.internal.compiler.impl.Constant;
40
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
41
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
41
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
42
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
Lines 1114-1119 Link Here
1114
	this.scope.buildMethods();
1115
	this.scope.buildMethods();
1115
}
1116
}
1116
1117
1118
private void initializeNullDefault() {
1119
	// ensure nullness defaults are initialized at all enclosing levels:
1120
	switch (this.nullnessDefaultInitialized) {
1121
	case 0:
1122
		getAnnotationTagBits(); // initialize
1123
		//$FALL-THROUGH$
1124
	case 1:
1125
		getPackage().isViewedAsDeprecated(); // initialize annotations
1126
		this.nullnessDefaultInitialized = 2;
1127
	}
1128
}
1129
1117
/**
1130
/**
1118
 * Returns true if a type is identical to another one,
1131
 * Returns true if a type is identical to another one,
1119
 * or for generic types, true if compared to its raw type.
1132
 * or for generic types, true if compared to its raw type.
Lines 1616-1645 Link Here
1616
				typeParameters[i].binding = null;
1629
				typeParameters[i].binding = null;
1617
		return null;
1630
		return null;
1618
	}
1631
	}
1619
	if (this.scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled)
1632
	CompilerOptions compilerOptions = this.scope.compilerOptions();
1620
		createArgumentBindings(method); // need annotations resolved already at this point
1633
	if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) {
1634
		createArgumentBindings(method, compilerOptions); // need annotations resolved already at this point
1635
	}
1621
	if (foundReturnTypeProblem)
1636
	if (foundReturnTypeProblem)
1622
		return method; // but its still unresolved with a null return type & is still connected to its method declaration
1637
		return method; // but its still unresolved with a null return type & is still connected to its method declaration
1623
1638
1624
	method.modifiers &= ~ExtraCompilerModifiers.AccUnresolved;
1639
	method.modifiers &= ~ExtraCompilerModifiers.AccUnresolved;
1625
	return method;
1640
	return method;
1626
}
1641
}
1627
private void createArgumentBindings(MethodBinding method) {
1642
private void createArgumentBindings(MethodBinding method, CompilerOptions compilerOptions) {
1628
	// ensure nullness defaults are initialized at all enclosing levels:
1643
	initializeNullDefault();
1629
	switch (this.nullnessDefaultInitialized) {
1630
	case 0:
1631
		getAnnotationTagBits(); // initialize
1632
		//$FALL-THROUGH$
1633
	case 1:
1634
		getPackage().isViewedAsDeprecated(); // initialize annotations
1635
		this.nullnessDefaultInitialized = 2;
1636
	}
1637
	AbstractMethodDeclaration methodDecl = method.sourceMethod();
1644
	AbstractMethodDeclaration methodDecl = method.sourceMethod();
1638
	if (methodDecl != null) {
1645
	if (methodDecl != null) {
1646
		// while creating argument bindings we also collect explicit null annotations:
1639
		if (method.parameters != Binding.NO_PARAMETERS)
1647
		if (method.parameters != Binding.NO_PARAMETERS)
1640
			methodDecl.createArgumentBindings();
1648
			methodDecl.createArgumentBindings();
1641
		if ((findNonNullDefault(methodDecl.scope, methodDecl.scope.environment()) == NONNULL_BY_DEFAULT)) {
1649
		// add implicit annotations (inherited(?) & default):
1642
			method.fillInDefaultNonNullness();
1650
		if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) {
1651
			new ImplicitNullAnnotationVerifier(compilerOptions.inheritNullAnnotations).checkImplicitNullAnnotations(method, methodDecl, true, this.scope);
1643
		}
1652
		}
1644
	}
1653
	}
1645
}
1654
}
Lines 1711-1726 Link Here
1711
	return true;
1720
	return true;
1712
}
1721
}
1713
1722
1714
/**
1723
boolean hasNonNullDefault() {
1715
 * Answer the nullness default applicable at the given method binding.
1716
 * Possible values: {@link Binding#NO_NULL_DEFAULT}, {@link Binding#NULL_UNSPECIFIED_BY_DEFAULT}, {@link Binding#NONNULL_BY_DEFAULT}.
1717
 * @param currentScope where to start search for lexically enclosing default
1718
 * @param environment gateway to options
1719
 */
1720
private int findNonNullDefault(Scope currentScope, LookupEnvironment environment) {
1721
	// find the applicable default inside->out:
1724
	// find the applicable default inside->out:
1722
1725
1723
	SourceTypeBinding currentType = null;
1726
	SourceTypeBinding currentType = null;
1727
	Scope currentScope = this.scope;
1724
	while (currentScope != null) {
1728
	while (currentScope != null) {
1725
		switch (currentScope.kind) {
1729
		switch (currentScope.kind) {
1726
			case Scope.METHOD_SCOPE:
1730
			case Scope.METHOD_SCOPE:
Lines 1728-1736 Link Here
1728
				if (referenceMethod != null && referenceMethod.binding != null) {
1732
				if (referenceMethod != null && referenceMethod.binding != null) {
1729
					long methodTagBits = referenceMethod.binding.tagBits;
1733
					long methodTagBits = referenceMethod.binding.tagBits;
1730
					if ((methodTagBits & TagBits.AnnotationNonNullByDefault) != 0)
1734
					if ((methodTagBits & TagBits.AnnotationNonNullByDefault) != 0)
1731
						return NONNULL_BY_DEFAULT;
1735
						return true;
1732
					if ((methodTagBits & TagBits.AnnotationNullUnspecifiedByDefault) != 0)
1736
					if ((methodTagBits & TagBits.AnnotationNullUnspecifiedByDefault) != 0)
1733
						return NULL_UNSPECIFIED_BY_DEFAULT;
1737
						return false;
1734
				}
1738
				}
1735
				break;
1739
				break;
1736
			case Scope.CLASS_SCOPE:
1740
			case Scope.CLASS_SCOPE:
Lines 1738-1744 Link Here
1738
				if (currentType != null) {
1742
				if (currentType != null) {
1739
					int foundDefaultNullness = currentType.defaultNullness;
1743
					int foundDefaultNullness = currentType.defaultNullness;
1740
					if (foundDefaultNullness != NO_NULL_DEFAULT) {
1744
					if (foundDefaultNullness != NO_NULL_DEFAULT) {
1741
						return foundDefaultNullness;
1745
						return foundDefaultNullness == NONNULL_BY_DEFAULT;
1742
					}
1746
					}
1743
				}
1747
				}
1744
				break;
1748
				break;
Lines 1748-1760 Link Here
1748
1752
1749
	// package
1753
	// package
1750
	if (currentType != null) {
1754
	if (currentType != null) {
1751
		int foundDefaultNullness = currentType.getPackage().defaultNullness;
1755
		return currentType.getPackage().defaultNullness == NONNULL_BY_DEFAULT;
1752
		if (foundDefaultNullness != NO_NULL_DEFAULT) {
1753
			return foundDefaultNullness;
1754
		}
1755
	}
1756
	}
1756
1757
1757
	return NO_NULL_DEFAULT;
1758
	return false;
1758
}
1759
}
1759
1760
1760
public AnnotationHolder retrieveAnnotationHolder(Binding binding, boolean forceInitialization) {
1761
public AnnotationHolder retrieveAnnotationHolder(Binding binding, boolean forceInitialization) {
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java (+3 lines)
Lines 61-66 Link Here
61
	long MultiCatchParameter = ASTNode.Bit13; // local
61
	long MultiCatchParameter = ASTNode.Bit13; // local
62
	long IsResource = ASTNode.Bit14; // local
62
	long IsResource = ASTNode.Bit14; // local
63
63
64
	// have implicit null annotations been collected (inherited(?) & default)?
65
	long IsNullnessKnown = ASTNode.Bit13; // method
66
64
	// test bits to see if parts of binary types are faulted
67
	// test bits to see if parts of binary types are faulted
65
	long AreFieldsSorted = ASTNode.Bit13;
68
	long AreFieldsSorted = ASTNode.Bit13;
66
	long AreFieldsComplete = ASTNode.Bit14; // sorted and all resolved
69
	long AreFieldsComplete = ASTNode.Bit14; // sorted and all resolved
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java (+18 lines)
Lines 318-323 Link Here
318
		case IProblem.ParameterLackingNonNullAnnotation:
318
		case IProblem.ParameterLackingNonNullAnnotation:
319
		case IProblem.ParameterLackingNullableAnnotation:
319
		case IProblem.ParameterLackingNullableAnnotation:
320
		case IProblem.CannotImplementIncompatibleNullness:
320
		case IProblem.CannotImplementIncompatibleNullness:
321
		case IProblem.ConflictingNullAnnotations:
321
			return CompilerOptions.NullSpecViolation;
322
			return CompilerOptions.NullSpecViolation;
322
323
323
		case IProblem.RequiredNonNullButProvidedPotentialNull:
324
		case IProblem.RequiredNonNullButProvidedPotentialNull:
Lines 8418-8423 Link Here
8418
	this.handle(IProblem.ContradictoryNullAnnotations, arguments, shortArguments, annotation.sourceStart, annotation.sourceEnd);
8419
	this.handle(IProblem.ContradictoryNullAnnotations, arguments, shortArguments, annotation.sourceStart, annotation.sourceEnd);
8419
}
8420
}
8420
8421
8422
public void conflictingNullAnnotations(MethodBinding currentMethod, ASTNode location, MethodBinding inheritedMethod)
8423
{
8424
	char[][] nonNullAnnotationName = this.options.nonNullAnnotationName;
8425
	char[][] nullableAnnotationName = this.options.nullableAnnotationName;
8426
	String[] arguments = {
8427
		new String(CharOperation.concatWith(nonNullAnnotationName, '.')),
8428
		new String(CharOperation.concatWith(nullableAnnotationName, '.')),
8429
		new String(inheritedMethod.declaringClass.readableName())
8430
	};
8431
	String[] shortArguments = {
8432
			new String(nonNullAnnotationName[nonNullAnnotationName.length-1]),
8433
			new String(nullableAnnotationName[nullableAnnotationName.length-1]),
8434
			new String(inheritedMethod.declaringClass.shortReadableName())
8435
		};
8436
	this.handle(IProblem.ConflictingNullAnnotations, arguments, shortArguments, location.sourceStart, location.sourceEnd);
8437
}
8438
8421
public void illegalAnnotationForBaseType(TypeReference type, Annotation[] annotations, char[] annotationName, long nullAnnotationTagBit)
8439
public void illegalAnnotationForBaseType(TypeReference type, Annotation[] annotations, char[] annotationName, long nullAnnotationTagBit)
8422
{
8440
{
8423
	int typeId = (nullAnnotationTagBit == TagBits.AnnotationNullable) 
8441
	int typeId = (nullAnnotationTagBit == TagBits.AnnotationNullable) 
(-)a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties (+1 lines)
Lines 690-695 Link Here
690
931 = Redundant null check: The variable {0} is specified as @{1}
690
931 = Redundant null check: The variable {0} is specified as @{1}
691
932 = Null comparison always yields false: The variable {0} is specified as @{1}
691
932 = Null comparison always yields false: The variable {0} is specified as @{1}
692
933 = Null type mismatch: required ''@{0} {1}'' but the provided value is specified as @{2}
692
933 = Null type mismatch: required ''@{0} {1}'' but the provided value is specified as @{2}
693
939 = The default ''@{0}'' conflicts with the inherited ''@{1}'' annotation in the overridden method from {2} 
693
694
694
### ELABORATIONS
695
### ELABORATIONS
695
## Access restrictions
696
## Access restrictions
(-)a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java (+20 lines)
Lines 95-100 Link Here
95
 *     								COMPILER_PB_NULL_SPECIFICATION_INSUFFICIENT_INFO
95
 *     								COMPILER_PB_NULL_SPECIFICATION_INSUFFICIENT_INFO
96
 *									COMPILER_PB_MISSING_ENUM_CASE_DESPITE_DEFAULT
96
 *									COMPILER_PB_MISSING_ENUM_CASE_DESPITE_DEFAULT
97
 *									COMPILER_PB_SWITCH_MISSING_DEFAULT_CASE
97
 *									COMPILER_PB_SWITCH_MISSING_DEFAULT_CASE
98
 *									COMPILER_INHERIT_NULL_ANNOTATIONS
98
 *******************************************************************************/
99
 *******************************************************************************/
99
100
100
package org.eclipse.jdt.core;
101
package org.eclipse.jdt.core;
Lines 1671-1676 Link Here
1671
	 */
1672
	 */
1672
	public static final String COMPILER_PB_REDUNDANT_NULL_ANNOTATION = PLUGIN_ID + ".compiler.problem.redundantNullAnnotation"; //$NON-NLS-1$
1673
	public static final String COMPILER_PB_REDUNDANT_NULL_ANNOTATION = PLUGIN_ID + ".compiler.problem.redundantNullAnnotation"; //$NON-NLS-1$
1673
	/**
1674
	/**
1675
	 * Compiler option ID: Inheritance of null annotations.
1676
	 * <p>When enabled, the compiler will check for each method without any explicit null annotations:
1677
	 *    If it overrides a method which has null annotations, it will treat the
1678
	 *    current method as if it had the same annotations as the overridden method.</p>
1679
	 * <p>Annotation inheritance will use the <em>effective</em> nullness of the overridden method
1680
	 *    after transitively applying inheritance and after applying any default nullness
1681
	 *    (see {@link #COMPILER_NONNULL_BY_DEFAULT_ANNOTATION_NAME}) at the site of the overridden method.</p>
1682
	 * <p>Annotation inheritance has precedence over a nullness default, i.e., a nullness default at the site
1683
	 *    of the overriding method will never override an inherited nullness annotation.</p>
1684
	 * <dl>
1685
	 * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations"</code></dd>
1686
	 * <dt>Possible values:</dt><dd><code>{ "disabled", "enabled" }</code></dd>
1687
	 * <dt>Default:</dt><dd><code>"disabled"</code></dd>
1688
	 * </dl>
1689
	 * @since 3.9
1690
	 * @category CompilerOptionID
1691
	 */
1692
	public static final String COMPILER_INHERIT_NULL_ANNOTATIONS = JavaCore.PLUGIN_ID+".compiler.annotation.inheritNullAnnotations"; //$NON-NLS-1$
1693
	/**
1674
	 * Compiler option ID: Setting Source Compatibility Mode.
1694
	 * Compiler option ID: Setting Source Compatibility Mode.
1675
	 * <p>Specify whether which source level compatibility is used. From 1.4 on, <code>'assert'</code> is a keyword
1695
	 * <p>Specify whether which source level compatibility is used. From 1.4 on, <code>'assert'</code> is a keyword
1676
	 *    reserved for assertion support. Also note, than when toggling to 1.4 mode, the target VM
1696
	 *    reserved for assertion support. Also note, than when toggling to 1.4 mode, the target VM

Return to bug 388281