Bug 499716: Quick fix "change return type to @NonNull" generates
exception

- tests & implementation

Signed-off-by: Stephan Herrmann <stephan.herrmann@berlin.de>
Change-Id: Id0910af7c35b51e31e159ecdcda631af93acbb0f
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/NullAnnotationsQuickFixTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/NullAnnotationsQuickFixTest.java
index ba3d9b3..b386314 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/NullAnnotationsQuickFixTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/NullAnnotationsQuickFixTest.java
@@ -1210,17 +1210,16 @@
 
 			proposal= (CUCorrectionProposal)proposals.get(1);
 
-			assertEqualString(proposal.getDisplayString(), "Change parameter 'o' to '@NonNull'");
+			assertEqualString(proposal.getDisplayString(), "Change parameter in overridden 'foo(..)' to '@NonNull'");
 
 			preview= getPreviewContent(proposal);
 
 			buf= new StringBuffer();
 			buf.append("package test1;\n");
 			buf.append("import org.eclipse.jdt.annotation.*;\n");
-			buf.append("@NonNullByDefault\n");
-			buf.append("public class E2 extends E {\n");
+			buf.append("public class E {\n");
 			buf.append("    void foo(@NonNull Object o) {\n");
-			buf.append("        System.out.print(\"E2\");\n");
+			buf.append("        // nop\n");
 			buf.append("    }\n");
 			buf.append("}\n");
 			assertEqualString(preview, buf.toString());
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/NullAnnotationsQuickFixTest18.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/NullAnnotationsQuickFixTest18.java
new file mode 100644
index 0000000..794f6c1
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/NullAnnotationsQuickFixTest18.java
@@ -0,0 +1,456 @@
+/*******************************************************************************
+ * Copyright (c) 2017 GK Software AG and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Stephan Herrmann - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.ui.tests.quickfix;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Hashtable;
+
+import org.osgi.framework.Bundle;
+
+import org.eclipse.jdt.testplugin.JavaProjectHelper;
+import org.eclipse.jdt.testplugin.TestOptions;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
+
+import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
+import org.eclipse.jdt.internal.corext.template.java.CodeTemplateContextType;
+
+import org.eclipse.jdt.ui.PreferenceConstants;
+import org.eclipse.jdt.ui.tests.core.Java18ProjectTestSetup;
+import org.eclipse.jdt.ui.tests.core.ProjectTestSetup;
+import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
+import org.eclipse.jdt.ui.text.java.correction.CUCorrectionProposal;
+
+import org.eclipse.jdt.internal.ui.JavaPlugin;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class NullAnnotationsQuickFixTest18 extends QuickFixTest {
+
+	private static final Class<NullAnnotationsQuickFixTest18> THIS= NullAnnotationsQuickFixTest18.class;
+	private IJavaProject fJProject1;
+	private IPackageFragmentRoot fSourceFolder;
+	private String ANNOTATION_JAR_PATH;
+
+	public NullAnnotationsQuickFixTest18(String name) {
+		super(name);
+	}
+
+	public static Test suite() {
+		return new Java18ProjectTestSetup(new TestSuite(THIS));
+	}
+
+	public static Test setUpTest(Test test) {
+		return new Java18ProjectTestSetup(test);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		Hashtable<String, String> options= TestOptions.getDefaultOptions();
+		options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, JavaCore.SPACE);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, "4");
+		options.put(DefaultCodeFormatterConstants.FORMATTER_NUMBER_OF_EMPTY_LINES_TO_PRESERVE, String.valueOf(99));
+		options.put(JavaCore.COMPILER_PB_STATIC_ACCESS_RECEIVER, JavaCore.ERROR);
+		options.put(JavaCore.COMPILER_PB_UNCHECKED_TYPE_OPERATION, JavaCore.IGNORE);
+		options.put(JavaCore.COMPILER_PB_MISSING_HASHCODE_METHOD, JavaCore.WARNING);
+		options.put(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED);
+		options.put(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION, JavaCore.ERROR);
+		options.put(JavaCore.COMPILER_PB_NULL_REFERENCE, JavaCore.ERROR);
+		options.put(JavaCore.COMPILER_PB_POTENTIAL_NULL_REFERENCE, JavaCore.WARNING);
+		options.put(JavaCore.COMPILER_PB_NULL_ANNOTATION_INFERENCE_CONFLICT, JavaCore.WARNING);
+		options.put(JavaCore.COMPILER_PB_NULL_UNCHECKED_CONVERSION, JavaCore.WARNING);
+		options.put(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK, JavaCore.WARNING);
+		options.put(JavaCore.COMPILER_PB_NULL_UNCHECKED_CONVERSION, JavaCore.WARNING);
+
+		JavaCore.setOptions(options);
+
+		IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore();
+		store.setValue(PreferenceConstants.CODEGEN_ADD_COMMENTS, false);
+
+		StubUtility.setCodeTemplate(CodeTemplateContextType.CATCHBLOCK_ID, "", null);
+		StubUtility.setCodeTemplate(CodeTemplateContextType.CONSTRUCTORSTUB_ID, "", null);
+		StubUtility.setCodeTemplate(CodeTemplateContextType.METHODSTUB_ID, "", null);
+
+		fJProject1= Java18ProjectTestSetup.getProject();
+
+		if (this.ANNOTATION_JAR_PATH == null) {
+			String version= "[2.0.0,3.0.0)"; // tests run at 1.8, need the "new" null annotations
+			Bundle[] bundles= Platform.getBundles("org.eclipse.jdt.annotation", version);
+			File bundleFile= FileLocator.getBundleFile(bundles[0]);
+			if (bundleFile.isDirectory())
+				this.ANNOTATION_JAR_PATH= bundleFile.getPath() + "/bin";
+			else
+				this.ANNOTATION_JAR_PATH= bundleFile.getPath();
+		}
+		JavaProjectHelper.addLibrary(fJProject1, new Path(ANNOTATION_JAR_PATH));
+
+		fSourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		JavaProjectHelper.clear(fJProject1, ProjectTestSetup.getDefaultClasspath());
+	}
+
+	/*
+	 * Problem: package default nonnull conflicts with inherited nullable (via generic substitution) (implicit vs. implicit)
+	 * Location: method return
+	 * Fixes:
+	 * - change local to nullable (equal)
+	 * - change local to nonnull  (covariant return)
+	 * - change super to nonnull  (equal)
+	 */
+	public void testBug499716_a() throws Exception {
+		fJProject1.setOption(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuffer buf= new StringBuffer();
+		buf.append("@org.eclipse.jdt.annotation.NonNullByDefault\n");
+		buf.append("package test1;\n");
+		pack1.createCompilationUnit("package-info.java", buf.toString(), false, null);
+		
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("interface Type<@Nullable K> {\n");
+		buf.append("	@NonNullByDefault(DefaultLocation.RETURN_TYPE)\n"); // no effect
+		buf.append("	K get();\n");
+		buf.append("\n");
+		buf.append("	class U implements Type<@Nullable String> {\n");
+		buf.append("		@Override\n");
+		buf.append("		public String get() { // <-- error \"The default '@NonNull' conflicts...\"\n");
+		buf.append("			return \"\";\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("Test.java", buf.toString(), false, null);
+
+		CompilationUnit astRoot= getASTRoot(cu);
+		ArrayList<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
+		assertNumberOfProposals(proposals, 4);
+		CUCorrectionProposal proposal= (CUCorrectionProposal)proposals.get(0);
+
+		assertEqualString(proposal.getDisplayString(), "Change return type of 'get(..)' to '@Nullable'");
+
+		String preview= getPreviewContent(proposal);
+
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("interface Type<@Nullable K> {\n");
+		buf.append("	@NonNullByDefault(DefaultLocation.RETURN_TYPE)\n");
+		buf.append("	K get();\n");
+		buf.append("\n");
+		buf.append("	class U implements Type<@Nullable String> {\n");
+		buf.append("		@Override\n");
+		buf.append("		public @Nullable String get() { // <-- error \"The default '@NonNull' conflicts...\"\n");
+		buf.append("			return \"\";\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		assertEqualString(preview, buf.toString());
+
+		proposal= (CUCorrectionProposal)proposals.get(1);
+
+		assertEqualString(proposal.getDisplayString(), "Change return type of 'get(..)' to '@NonNull'");
+
+		preview= getPreviewContent(proposal);
+
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("interface Type<@Nullable K> {\n");
+		buf.append("	@NonNullByDefault(DefaultLocation.RETURN_TYPE)\n");
+		buf.append("	K get();\n");
+		buf.append("\n");
+		buf.append("	class U implements Type<@Nullable String> {\n");
+		buf.append("		@Override\n");
+		buf.append("		public @NonNull String get() { // <-- error \"The default '@NonNull' conflicts...\"\n");
+		buf.append("			return \"\";\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		assertEqualString(preview, buf.toString());
+
+		proposal= (CUCorrectionProposal)proposals.get(2);
+
+		assertEqualString(proposal.getDisplayString(), "Change return type of overridden 'get(..)' to '@NonNull'");
+
+		preview= getPreviewContent(proposal);
+
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("interface Type<@Nullable K> {\n");
+		buf.append("	@NonNullByDefault(DefaultLocation.RETURN_TYPE)\n");
+		buf.append("    @NonNull\n");
+		buf.append("	K get();\n");
+		buf.append("\n");
+		buf.append("	class U implements Type<@Nullable String> {\n");
+		buf.append("		@Override\n");
+		buf.append("		public String get() { // <-- error \"The default '@NonNull' conflicts...\"\n");
+		buf.append("			return \"\";\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		assertEqualString(preview, buf.toString());
+	}
+
+	/*
+	 * Problem: package default nonnull conflicts with inherited nullable (via generic substitution) (implicit vs. implicit)
+	 * Location: parameter
+	 * Fixes:
+	 * - change local to nullable
+	 * - change super to nonnull
+	 * No covariant parameter!
+	 */
+	public void testBug499716_b() throws Exception {
+		fJProject1.setOption(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuffer buf= new StringBuffer();
+		buf.append("@org.eclipse.jdt.annotation.NonNullByDefault\n");
+		buf.append("package test1;\n");
+		pack1.createCompilationUnit("package-info.java", buf.toString(), false, null);
+		
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("interface Type<@Nullable K> {\n");
+		buf.append("	void set(int i, K arg);\n");
+		buf.append("\n");
+		buf.append("	class U implements Type<@Nullable String> {\n");
+		buf.append("		@Override\n");
+		buf.append("		public void set(int i, String arg) {\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("Test.java", buf.toString(), false, null);
+
+		CompilationUnit astRoot= getASTRoot(cu);
+		ArrayList<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
+		assertNumberOfProposals(proposals, 3);
+		CUCorrectionProposal proposal= (CUCorrectionProposal)proposals.get(0);
+
+		assertEqualString(proposal.getDisplayString(), "Change parameter 'arg' to '@Nullable'");
+
+		String preview= getPreviewContent(proposal);
+
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("interface Type<@Nullable K> {\n");
+		buf.append("	void set(int i, K arg);\n");
+		buf.append("\n");
+		buf.append("	class U implements Type<@Nullable String> {\n");
+		buf.append("		@Override\n");
+		buf.append("		public void set(int i, @Nullable String arg) {\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		assertEqualString(preview, buf.toString());
+
+		proposal= (CUCorrectionProposal)proposals.get(1);
+
+		assertEqualString(proposal.getDisplayString(), "Change parameter in overridden 'set(..)' to '@NonNull'");
+
+		preview= getPreviewContent(proposal);
+
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("interface Type<@Nullable K> {\n");
+		buf.append("	void set(int i, @NonNull K arg);\n");
+		buf.append("\n");
+		buf.append("	class U implements Type<@Nullable String> {\n");
+		buf.append("		@Override\n");
+		buf.append("		public void set(int i, String arg) {\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		assertEqualString(preview, buf.toString());
+	}
+
+	/*
+	 * Problem: explicit nullable conflicts with inherited nonnull (from type default) (illegal override)
+	 * Location: return type
+	 * Fixes:
+	 * - change local to nonnull
+	 * - change super to nullable
+	 * No contravariant return!
+	 */
+	public void testBug499716_c() throws Exception {
+		fJProject1.setOption(JavaCore.COMPILER_INHERIT_NULL_ANNOTATIONS, JavaCore.ENABLED);
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+
+		StringBuffer buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("@NonNullByDefault(DefaultLocation.RETURN_TYPE)\n");
+		buf.append("interface Type {\n");
+		buf.append("	String get();\n");
+		buf.append("\n");
+		buf.append("	class U implements Type {\n");
+		buf.append("		@Override\n");
+		buf.append("		public @Nullable String get() {\n");
+		buf.append("			return \"\";\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("Test.java", buf.toString(), false, null);
+
+		CompilationUnit astRoot= getASTRoot(cu);
+		ArrayList<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
+		assertNumberOfProposals(proposals, 3);
+		CUCorrectionProposal proposal= (CUCorrectionProposal)proposals.get(0);
+
+		assertEqualString(proposal.getDisplayString(), "Change return type of 'get(..)' to '@NonNull'");
+
+		String preview= getPreviewContent(proposal);
+
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("@NonNullByDefault(DefaultLocation.RETURN_TYPE)\n");
+		buf.append("interface Type {\n");
+		buf.append("	String get();\n");
+		buf.append("\n");
+		buf.append("	class U implements Type {\n");
+		buf.append("		@Override\n");
+		buf.append("		public String get() {\n");
+		buf.append("			return \"\";\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		assertEqualString(preview, buf.toString());
+
+		proposal= (CUCorrectionProposal)proposals.get(1);
+
+		assertEqualString(proposal.getDisplayString(), "Change return type of overridden 'get(..)' to '@Nullable'");
+
+		preview= getPreviewContent(proposal);
+
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("@NonNullByDefault(DefaultLocation.RETURN_TYPE)\n");
+		buf.append("interface Type {\n");
+		buf.append("	@Nullable\n");
+		buf.append("    String get();\n");
+		buf.append("\n");
+		buf.append("	class U implements Type {\n");
+		buf.append("		@Override\n");
+		buf.append("		public @Nullable String get() {\n");
+		buf.append("			return \"\";\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		assertEqualString(preview, buf.toString());
+	}
+
+	/*
+	 * Problem: package default nonnull conflicts with declared nullable in super (illegal override)
+	 * Location: method parameter
+	 * Fixes:
+	 * - change local to nullable
+	 * - change super to implicit nonnull (by removing to make default apply)
+	 * No covariant parameter!
+	 */
+	public void testBug499716_d() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuffer buf= new StringBuffer();
+		buf.append("@org.eclipse.jdt.annotation.NonNullByDefault\n");
+		buf.append("package test1;\n");
+		pack1.createCompilationUnit("package-info.java", buf.toString(), true, null);
+		
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("interface Type {\n");
+		buf.append("	void set(@Nullable String s);\n");
+		buf.append("\n");
+		buf.append("	class U implements Type {\n");
+		buf.append("		@Override\n");
+		buf.append("		public void set(String t) {\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("Test.java", buf.toString(), false, null);
+
+		CompilationUnit astRoot= getASTRoot(cu);
+		ArrayList<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
+		assertNumberOfProposals(proposals, 3);
+		CUCorrectionProposal proposal= (CUCorrectionProposal)proposals.get(0);
+
+		assertEqualString(proposal.getDisplayString(), "Change parameter 't' to '@Nullable'");
+
+		String preview= getPreviewContent(proposal);
+
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("interface Type {\n");
+		buf.append("	void set(@Nullable String s);\n");
+		buf.append("\n");
+		buf.append("	class U implements Type {\n");
+		buf.append("		@Override\n");
+		buf.append("		public void set(@Nullable String t) {\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		assertEqualString(preview, buf.toString());
+
+		proposal= (CUCorrectionProposal)proposals.get(1);
+
+		assertEqualString(proposal.getDisplayString(), "Change parameter in overridden 'set(..)' to '@NonNull'");
+
+		preview= getPreviewContent(proposal);
+
+		buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("import org.eclipse.jdt.annotation.*;\n");
+		buf.append("\n");
+		buf.append("interface Type {\n");
+		buf.append("	void set(String s);\n");
+		buf.append("\n");
+		buf.append("	class U implements Type {\n");
+		buf.append("		@Override\n");
+		buf.append("		public void set(String t) {\n");
+		buf.append("		}\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		assertEqualString(preview, buf.toString());
+	}
+}
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsFix.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsFix.java
index 9c9f3d0..883d5ec 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsFix.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsFix.java
@@ -88,7 +88,8 @@
 		IJavaElement javaElement= compilationUnit.getJavaElement();
 		String nullableAnnotationName= getNullableAnnotationName(javaElement, false);
 		String nonNullAnnotationName= getNonNullAnnotationName(javaElement, false);
-		Builder builder= new Builder(problem, compilationUnit, nullableAnnotationName, nonNullAnnotationName, /*allowRemove*/true, isArgumentProblem);
+		Builder builder= new Builder(problem, compilationUnit, nullableAnnotationName, nonNullAnnotationName,
+										/*allowRemove*/true, isArgumentProblem, changeKind);
 		boolean addNonNull= false;
 
 		switch (problem.getProblemId()) {
@@ -117,8 +118,12 @@
 				}
 				break;
 			case IProblem.ConflictingNullAnnotations:
+				if (isArgumentProblem && changeKind == ChangeKind.INVERSE) {
+					return null; // cannot redefine @Nullable param to @NonNull
+				}
+				//$FALL-THROUGH$
 			case IProblem.ConflictingInheritedNullAnnotations:
-				if (changeKind == ChangeKind.INVERSE) {
+				if (changeKind == ChangeKind.INVERSE || changeKind == ChangeKind.OVERRIDDEN) {
 					addNonNull= true;
 					builder.swapAnnotations();
 				}
@@ -198,7 +203,7 @@
 				continue; // problem was filtered out by createCleanUp()
 			boolean isArgumentProblem= isComplainingAboutArgument(problem.getCoveredNode(compilationUnit));
 			Builder builder= new Builder(problem, compilationUnit, nullableAnnotationName, nonNullAnnotationName,
-											/*allowRemove*/false, isArgumentProblem);
+											/*allowRemove*/false, isArgumentProblem, ChangeKind.LOCAL);
 			boolean addNonNull= false;
 			// cf. createNullAnnotationInSignatureFix() but changeKind is constantly LOCAL
 			switch (problem.getProblemId()) {
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsRewriteOperations.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsRewriteOperations.java
index 8661c75..f7f02bd 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsRewriteOperations.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsRewriteOperations.java
@@ -11,6 +11,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.fix;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -19,7 +21,12 @@
 
 import org.eclipse.text.edits.TextEditGroup;
 
+import org.eclipse.jdt.core.IAnnotation;
 import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IMemberValuePair;
+import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.core.dom.AST;
@@ -57,8 +64,18 @@
 
 import org.eclipse.jdt.ui.text.java.IProblemLocation;
 
+import org.eclipse.jdt.internal.ui.JavaPlugin;
+
 public class NullAnnotationsRewriteOperations {
 
+	static final String TYPE_USE_NAME= ElementType.class.getName()+'.'+ElementType.TYPE_USE.name();
+
+	// reduced copy of org.eclipse.jdt.annotation.DefaultLocation:
+	enum DefaultLocation {
+		PARAMETER,
+		RETURN_TYPE
+	}
+
 	public enum ChangeKind {
 		LOCAL,		// do the normal thing locally in the current method
 		INVERSE,	// insert the inverse annotation in the local method
@@ -68,10 +85,12 @@
 
 	static abstract class SignatureAnnotationRewriteOperation extends CompilationUnitRewriteOperation {
 		// initialized from the Builder:
-		CompilationUnit fUnit;
-		String fAnnotationToAdd;
-		String fAnnotationToRemove;
-		boolean fAllowRemove;
+		protected CompilationUnit fUnit;
+		protected String fAnnotationToAdd;
+		protected String fAnnotationToRemove;
+		protected boolean fAllowRemove;
+		protected boolean fUseNullTypeAnnotations;
+		protected boolean fRequireExplicitAnnotation;
 		// assigned within constructors:
 		protected String fKey;
 		protected String fMessage;
@@ -84,6 +103,8 @@
 			fAnnotationToAdd= builder.fAnnotationToAdd;
 			fAnnotationToRemove= builder.fAnnotationToRemove;
 			fAllowRemove= builder.fAllowRemove;
+			fUseNullTypeAnnotations= builder.fUseNullTypeAnnotations;
+			fRequireExplicitAnnotation= builder.requiresExplicitAnnotation();
 		}
 
 		/* A globally unique key that identifies the position being annotated (for avoiding double annotations). */
@@ -117,7 +138,7 @@
 			return true;
 		}
 
-		/* Is the given element affected by a @NonNullByDefault. */
+		/* Is the given element affected by a @NonNullByDefault v1.x? */
 		boolean hasNonNullDefault(IBinding enclosingElement) {
 			if (!fRemoveIfNonNullByDefault) return false;
 			IAnnotationBinding[] annotations = enclosingElement.getAnnotations();
@@ -148,6 +169,79 @@
 			return false;
 		}
 
+		/* Is the given element affected by a 308-style @NonNullByDefault? */
+		boolean hasNonNullDefault308(IBinding enclosingElement, int parameterRank, DefaultLocation defaultLocation, boolean recursiveCall) {
+			if (!fRemoveIfNonNullByDefault) return false;
+			if (!recursiveCall) {
+				ITypeBinding affectedType= null;
+				if (enclosingElement instanceof IMethodBinding) {
+					switch (defaultLocation) {
+						case RETURN_TYPE:
+							affectedType= ((IMethodBinding) enclosingElement).getReturnType();
+							break;
+						case PARAMETER:
+							affectedType= ((IMethodBinding) enclosingElement).getParameterTypes()[parameterRank];
+							break;
+						default:
+							// no other locations supported yet (fields?)
+					}
+				} else if (enclosingElement instanceof IVariableBinding) {
+					affectedType= ((IVariableBinding) enclosingElement).getType();
+				}
+				if (affectedType != null) {
+					if (affectedType.isTypeVariable() || affectedType.isWildcardType()) {
+						return false; // not affected by @NonNullByDefault
+					}
+				}
+			}
+			IAnnotationBinding[] annotations= enclosingElement.getAnnotations();
+			for (int i= 0; i < annotations.length; i++) {
+				IAnnotationBinding annot= annotations[i];
+				ITypeBinding annotationType= annot.getAnnotationType();
+				if (annotationType != null && annotationType.getQualifiedName().equals(fNonNullByDefaultName)) {
+					IMemberValuePairBinding[] pairs= annot.getDeclaredMemberValuePairs();
+					if (pairs.length > 0) {
+						// does the default's set of locations contain `defaultLocation`?
+						for (int j= 0; j < pairs.length; j++)
+							if (pairs[j].getKey() == null || pairs[j].getKey().equals("value")) { //$NON-NLS-1$
+								return matchesLocation(pairs[j].getValue(), defaultLocation);
+							}
+					}
+					return true;
+				}
+			}
+			if (enclosingElement instanceof IVariableBinding) {
+				IVariableBinding variable= (IVariableBinding) enclosingElement;
+				enclosingElement= variable.isParameter() ? variable.getDeclaringMethod() : variable.getDeclaringClass();
+				return hasNonNullDefault308(enclosingElement, -1, defaultLocation, true);
+			} else if (enclosingElement instanceof IMethodBinding) {
+				return hasNonNullDefault308(((IMethodBinding)enclosingElement).getDeclaringClass(), -1, defaultLocation, true);
+			} else if (enclosingElement instanceof ITypeBinding) {
+				ITypeBinding typeBinding= (ITypeBinding)enclosingElement;
+				if (typeBinding.isLocal())
+					return hasNonNullDefault308(typeBinding.getDeclaringMethod(), -1, defaultLocation, true);
+				else if (typeBinding.isMember())
+					return hasNonNullDefault308(typeBinding.getDeclaringClass(), -1, defaultLocation, true);
+				else
+					return hasNonNullDefault308(typeBinding.getPackage(), -1, defaultLocation, true);
+			}
+			return false;
+		}
+		
+		private boolean matchesLocation(Object value, DefaultLocation location) {
+			if (value instanceof Object[]) {
+				Object[] values= (Object[]) value;
+				for (int i= 0; i < values.length; i++) {
+					if (matchesLocation(values[i], location))
+						return true;
+				}
+			} else if (value instanceof IVariableBinding) {
+				String name= ((IVariableBinding) value).getName();
+				return location.name().equals(name);
+			}
+			return false;
+		}
+
 		public String getMessage() {
 			return fMessage;
 		}
@@ -176,8 +270,12 @@
 			TextEditGroup group= createTextEditGroup(fMessage, cuRewrite);
 			if (!checkExisting(fBodyDeclaration.modifiers(), listRewrite, group))
 				return;
-			if (hasNonNullDefault(fBodyDeclaration.resolveBinding()))
-				return; // should be safe, as in this case checkExisting() should've already produced a change (remove existing annotation).
+			if (!fRequireExplicitAnnotation) {
+				if (fUseNullTypeAnnotations
+						? hasNonNullDefault308(fBodyDeclaration.resolveBinding(), /*parameterRank*/-1, DefaultLocation.RETURN_TYPE, false)
+						: hasNonNullDefault(fBodyDeclaration.resolveBinding()))
+					return; // should be safe, as in this case checkExisting() should've already produced a change (remove existing annotation).
+			}
 			Annotation newAnnotation= ast.newMarkerAnnotation();
 			ImportRewrite importRewrite= cuRewrite.getImportRewrite();
 			String resolvableName= importRewrite.addImport(fAnnotationToAdd);
@@ -198,6 +296,7 @@
 		}
 
 		private SingleVariableDeclaration fArgument;
+		private int fParameterRank;
 
 		// for lambda parameter (can return null):
 		static ParameterAnnotationRewriteOperation create(LambdaExpression lambda, IndexedParameter parameter, String message, Builder builder) {
@@ -223,6 +322,7 @@
 			super(builder);
 			fKey= methodBinding.getKey();
 			fArgument= (SingleVariableDeclaration) parameters.get(paramIdx);
+			fParameterRank= paramIdx;
 			fKey+= fArgument.getName().getIdentifier();
 			fMessage= message;
 		}
@@ -234,6 +334,12 @@
 			TextEditGroup group= createTextEditGroup(fMessage, cuRewrite);
 			if (!checkExisting(fArgument.modifiers(), listRewrite, group))
 				return;
+			if (!fRequireExplicitAnnotation) {
+				if (fUseNullTypeAnnotations
+						? hasNonNullDefault308(fArgument.resolveBinding(), fParameterRank, DefaultLocation.PARAMETER, false)
+						: hasNonNullDefault(fArgument.resolveBinding()))
+					return; // should be safe, as in this case checkExisting() should've already produced a change (remove existing annotation).
+			}
 			Annotation newAnnotation= ast.newMarkerAnnotation();
 			ImportRewrite importRewrite= cuRewrite.getImportRewrite();
 			String resolvableName= importRewrite.addImport(fAnnotationToAdd);
@@ -299,21 +405,62 @@
 	public static class Builder {
 
 		IProblemLocation fProblem;
+		ChangeKind fChangeKind;
 		CompilationUnit fUnit;
 		String fAnnotationToAdd;
 		String fAnnotationToRemove;
 		boolean fAllowRemove;
 		boolean fAffectsParameter;
+		boolean fUseNullTypeAnnotations;
 
 		public Builder(IProblemLocation problem, CompilationUnit unit, String annotationToAdd, String annotationToRemove,
-				boolean allowRemove, boolean affectsParameter)
+				boolean allowRemove, boolean affectsParameter, ChangeKind changeKind)
 		{
-			fProblem= problem;
+			fChangeKind= changeKind;
 			fUnit= unit;
 			fAnnotationToAdd= annotationToAdd;
 			fAnnotationToRemove= annotationToRemove;
 			fAllowRemove= allowRemove;
 			fAffectsParameter= affectsParameter;
+			fProblem= problem;
+			fUseNullTypeAnnotations= usesNullTypeAnnotations(unit.getJavaElement(), annotationToAdd);
+		}
+
+		private boolean usesNullTypeAnnotations(IJavaElement cu, String annotationName) {
+			IJavaProject project= (IJavaProject) cu.getAncestor(IJavaElement.JAVA_PROJECT);
+			if (!JavaModelUtil.is18OrHigher(project)) {
+				return false;
+			}
+			try {
+				IType annotationType= project.findType(annotationName);
+				if (annotationType == null) {
+					return false;
+				}
+				IAnnotation[] annotations= annotationType.getAnnotations();
+				for (int i= 0; i < annotations.length; i++) {
+					if (annotations[i].getElementName().equals(Target.class.getName())) {
+						for (IMemberValuePair valuePair : annotations[i].getMemberValuePairs()) {
+							if (TYPE_USE_NAME.equals(valuePair.getValue())) {
+								return true;
+							}
+						}
+						return false;
+					}
+				}
+			} catch (JavaModelException e) {
+				JavaPlugin.log(e);
+			}
+			return false;
+		}
+
+		public boolean requiresExplicitAnnotation() {
+			switch (fProblem.getProblemId()) {
+				case IProblem.ConflictingInheritedNullAnnotations:
+				case IProblem.ConflictingNullAnnotations:
+					return fChangeKind != ChangeKind.OVERRIDDEN;
+				default:
+					return false;
+			}
 		}
 
 		public void swapAnnotations() {
@@ -498,6 +645,7 @@
 				case IProblem.IllegalRedefinitionToNonNullParameter:
 					break;
 				case IProblem.IllegalReturnNullityRedefinition:
+				case IProblem.ConflictingNullAnnotations:
 					if (declaringNode == null)
 						declaringNode= selectedNode;
 					break;
@@ -515,16 +663,21 @@
 				// complaint is in signature of this method
 				MethodDeclaration declaration= (MethodDeclaration) declaringNode;
 				switch (fProblem.getProblemId()) {
-					case IProblem.IllegalDefinitionToNonNullParameter:
-					case IProblem.IllegalRedefinitionToNonNullParameter:
+				case IProblem.IllegalReturnNullityRedefinition:
+					if (!hasNullAnnotation(declaration)) {
+						return null; // don't adjust super if local has no explicit annotation (?)
+					}
+					//$FALL-THROUGH$
+				case IProblem.IllegalDefinitionToNonNullParameter:
+				case IProblem.IllegalRedefinitionToNonNullParameter:
+				case IProblem.ConflictingNullAnnotations:
+					if (fAffectsParameter) {
 						return createChangeOverriddenParameterOperation(cu, declaration, selectedNode, annotationNameLabel);
-					case IProblem.IllegalReturnNullityRedefinition:
-						if (hasNullAnnotation(declaration)) { // don't adjust super if local has no explicit annotation (?)
-							return createChangeOverriddenReturnOperation(cu, declaration, annotationNameLabel);
-						}
-						break;
-					default:
-						return null;
+					} else {
+						return createChangeOverriddenReturnOperation(cu, declaration, annotationNameLabel);
+					}
+				default:
+					return null;
 				}
 			}
 			return null;
@@ -629,6 +782,7 @@
 		}
 
 		private MethodDeclaration findMethodDeclarationInUnit(ICompilationUnit cu, IMethodBinding method, boolean sameUnitOnly) {
+			method= method.getMethodDeclaration();
 			CompilationUnit compilationUnit= findCUForMethod(fUnit, cu, method);
 			if (compilationUnit == null)
 				return null;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickFixProcessor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickFixProcessor.java
index c7bd5e1..1c509f8 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickFixProcessor.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickFixProcessor.java
@@ -10,7 +10,7 @@
  *     Benjamin Muskalla <b.muskalla@gmx.net> - [quick fix] Quick fix for missing synchronized modifier - https://bugs.eclipse.org/bugs/show_bug.cgi?id=245250
  *     Stephan Herrmann - Contributions for
  *								[quick fix] Add quick fixes for null annotations - https://bugs.eclipse.org/337977
- *								[quick fix] The fix change parameter type to @Nonnull generated a null change - https://bugs.eclipse.org/400668 
+ *								[quick fix] The fix change parameter type to @Nonnull generated a null change - https://bugs.eclipse.org/400668
  *								[quick fix] don't propose null annotations when those are disabled - https://bugs.eclipse.org/405086
  *								[quickfix] Update null annotation quick fixes for bug 388281 - https://bugs.eclipse.org/395555
  *     Lukas Hanke <hanke@yatta.de> - Bug 241696 [quick fix] quickfix to iterate over a collection - https://bugs.eclipse.org/bugs/show_bug.cgi?id=241696
@@ -773,6 +773,7 @@
 			case IProblem.ConflictingInheritedNullAnnotations:
 				NullAnnotationsCorrectionProcessor.addReturnAndArgumentTypeProposal(context, problem, ChangeKind.LOCAL, proposals);
 				NullAnnotationsCorrectionProcessor.addReturnAndArgumentTypeProposal(context, problem, ChangeKind.INVERSE, proposals);
+				NullAnnotationsCorrectionProcessor.addReturnAndArgumentTypeProposal(context, problem, ChangeKind.OVERRIDDEN, proposals);
 				break;
 			case IProblem.IllegalQualifiedEnumConstantLabel:
 				LocalCorrectionsSubProcessor.addIllegalQualifiedEnumConstantLabelProposal(context, problem, proposals);