Bug 458361 - [1.8][null] reconciler throws NPE in
ProblemReporter.illegalReturnRedefinition()

Change-Id: I2341a7b74a5c62c2db7fb5ab6568cef74f884a4f
Signed-off-by: Stephan Herrmann <stephan.herrmann@berlin.de>
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
index 17944a5..6dc56dd 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2014 IBM Corporation and others.
+ * Copyright (c) 2006, 2015 IBM Corporation 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
@@ -36,6 +36,7 @@
  *								Bug 439516 - [1.8][null] NonNullByDefault wrongly applied to implicit type bound of binary type
  *								Bug 438467 - [compiler][null] Better error position for "The method _ cannot implement the corresponding method _ due to incompatible nullness constraints"
  *								Bug 446442 - [1.8] merge null annotations from super methods
+ *								Bug 458361 - [1.8][null] reconciler throws NPE in ProblemReporter.illegalReturnRedefinition()
  *     Jesper S Moller - Contributions for
  *								bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
  *								bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
@@ -583,6 +584,7 @@
 		expectedProblemAttributes.put("IllegalQualifierForExplicitThis", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
 		expectedProblemAttributes.put("IllegalQualifierForExplicitThis2", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
 		expectedProblemAttributes.put("IllegalReturnNullityRedefinition", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
+		expectedProblemAttributes.put("IllegalReturnNullityRedefinitionFreeTypeVariable", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
 		expectedProblemAttributes.put("IllegalRedefinitionToNonNullParameter", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
 		expectedProblemAttributes.put("IllegalStaticModifierForMemberType", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
 		expectedProblemAttributes.put("IllegalTypeAnnotationsInStaticMemberAccess", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
@@ -1409,6 +1411,7 @@
 		expectedProblemAttributes.put("IllegalQualifierForExplicitThis2", SKIP);
 		expectedProblemAttributes.put("IllegalRedefinitionToNonNullParameter", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION));
 		expectedProblemAttributes.put("IllegalReturnNullityRedefinition", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION));
+		expectedProblemAttributes.put("IllegalReturnNullityRedefinitionFreeTypeVariable", new ProblemAttributes(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION));
 		expectedProblemAttributes.put("IllegalStaticModifierForMemberType", SKIP);
 		expectedProblemAttributes.put("IllegalTypeAnnotationsInStaticMemberAccess", SKIP);
 		expectedProblemAttributes.put("IllegalTypeArgumentsInRawConstructorReference", SKIP);
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
index 818c68f..4ca55c1 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullTypeAnnotationTest.java
@@ -5666,7 +5666,7 @@
 		"1. ERROR in Test.java (at line 3)\n" + 
 		"	public <T> @org.eclipse.jdt.annotation.Nullable T foo(T arg) {\n" + 
 		"	           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
-		"The return type is incompatible with 'T' returned from ITest.foo(T) (mismatching null constraints)\n" + 
+		"The return type is incompatible with the free type variable 'T' returned from ITest.foo(T) (mismatching null constraints)\n" + 
 		"----------\n" +
 		"----------\n" + 
 		"1. ERROR in Test2.java (at line 3)\n" + 
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NullAnnotationModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NullAnnotationModelTests.java
index dd65c36..1fcc9eb 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NullAnnotationModelTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/NullAnnotationModelTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2013 GK Software AG and others.
+ * Copyright (c) 2011, 2015 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
@@ -45,6 +45,7 @@
 public class NullAnnotationModelTests extends ReconcilerTests {
 
 	String ANNOTATION_LIB;
+	String ANNOTATION_LIB_V1;
 
 	public static Test suite() {
 		return buildModelTestSuite(NullAnnotationModelTests.class);
@@ -66,6 +67,10 @@
 		Bundle[] bundles = org.eclipse.jdt.core.tests.Activator.getPackageAdmin().getBundles("org.eclipse.jdt.annotation", "[2.0.0,3.0.0)");
 		File bundleFile = FileLocator.getBundleFile(bundles[0]);
 		this.ANNOTATION_LIB = bundleFile.isDirectory() ? bundleFile.getPath()+"/bin" : bundleFile.getPath();
+
+		bundles = org.eclipse.jdt.core.tests.Activator.getPackageAdmin().getBundles("org.eclipse.jdt.annotation", "[1.1.0,2.0.0)");
+		bundleFile = FileLocator.getBundleFile(bundles[0]);
+		this.ANNOTATION_LIB_V1 = bundleFile.isDirectory() ? bundleFile.getPath()+"/bin" : bundleFile.getPath();
 	}
 
 	protected String testJarPath(String jarName) throws IOException {
@@ -646,4 +651,65 @@
 				deleteProject(project);
 		}
 	}
+
+	// was: NPE in ProblemReporter.illegalReturnRedefinition() from ImplicitNullAnnotationVerifier.checkNullSpecInheritance()
+	public void testBug458361a() throws CoreException {
+		IJavaProject project = null;
+		try {
+			project = createJavaProject("Bug458361", new String[] {"src"}, new String[] {"JCL18_LIB", this.ANNOTATION_LIB}, "bin", "1.8");
+
+			project.setOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED);
+			project.setOption(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION, JavaCore.ERROR);
+
+			setUpWorkingCopy("/Bug458361/src/MyCollection.java",
+					"import java.util.Collection;\n" +
+					"import org.eclipse.jdt.annotation.*;\n" +
+					"public interface MyCollection<T> extends Collection<T> {\n" + 
+					"    public @Nullable T get(int i);\n" +
+					"}\n");
+			assertProblems(
+					"Unexpected problems",
+					"----------\n" + 
+					"1. ERROR in /Bug458361/src/MyCollection.java (at line 4)\n" + 
+					"	public @Nullable T get(int i);\n" + 
+					"	       ^^^^^^^^^^^\n" + 
+					"The return type is incompatible with the free type variable \'T\' returned from Collection<T>.get(int) (mismatching null constraints)\n" + 
+					"----------\n");
+		} finally {
+			if (project != null)
+				deleteProject(project);
+		}
+	}
+	public void testBug458361b() throws CoreException {
+		IJavaProject project = null;
+		try {
+			project = createJavaProject("Bug458361", new String[] {"src"}, new String[] {"JCL17_LIB", this.ANNOTATION_LIB_V1}, "bin", "1.7");
+
+			project.setOption(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED);
+			project.setOption(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION, JavaCore.ERROR);
+	
+			createFile("/Bug458361/src/Super.java",
+					"import org.eclipse.jdt.annotation.*;\n" +
+					"public interface Super {\n" +
+					"	@NonNull String getName();\n" +
+					"}\n");
+
+			setUpWorkingCopy("/Bug458361/src/Sub.java",
+					"import org.eclipse.jdt.annotation.*;\n" +
+					"public interface Sub extends Super {\n" + 
+					"    @Nullable String getName();\n" +
+					"}\n");
+			assertProblems(
+					"Unexpected problems",
+					"----------\n" + 
+					"1. ERROR in /Bug458361/src/Sub.java (at line 3)\n" + 
+					"	@Nullable String getName();\n" + 
+					"	^^^^^^^^^^^^^^^^\n" + 
+					"The return type is incompatible with \'@NonNull String\' returned from Super.getName() (mismatching null constraints)\n" + 
+					"----------\n");
+		} finally {
+			if (project != null)
+				deleteProject(project);
+		}
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
index d1df0cd..d30135f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation 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
@@ -195,6 +195,7 @@
  *									ImplicitObjectBoundNoNullDefault
  *									IllegalParameterNullityRedefinition
  *									ContradictoryNullAnnotationsInferredFunctionType
+ *									IllegalReturnNullityRedefinitionFreeTypeVariable
  *      Jesper S Moller  - added the following constants
  *									TargetTypeNotAFunctionalInterface
  *									OuterLocalMustBeEffectivelyFinal
@@ -1801,6 +1802,8 @@
 	int IllegalParameterNullityRedefinition = MethodRelated + 972;
 	/** @since 3.11 */
 	int ContradictoryNullAnnotationsInferredFunctionType = MethodRelated + 973;
+	/** @since 3.11 */
+	int IllegalReturnNullityRedefinitionFreeTypeVariable = MethodRelated + 974;
 
 
 	// Java 8 work
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
index 5bcf14a..a1c2a24 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
@@ -1971,4 +1971,14 @@
 			this.warningThreshold.clear(irritant);
 		}
 	}
+
+	/** 
+	 * Note, if you have a LookupEnvironment you should instead ask
+	 * {@link org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment#usesNullTypeAnnotations()}. */
+	public boolean usesNullTypeAnnotations() {
+		if (this.useNullTypeAnnotations != null)
+			return this.useNullTypeAnnotations;
+		return this.isAnnotationBasedNullAnalysisEnabled
+				&& this.sourceLevel >=  ClassFileConstants.JDK1_8;
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
index 80370ea..384b4b5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2014 GK Software AG, IBM Corporation and others.
+ * Copyright (c) 2012, 2015 GK Software AG, IBM Corporation 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
@@ -296,7 +296,8 @@
 					}
 					if (NullAnnotationMatching.analyse(inheritedMethod.returnType, currentMethod.returnType, substituteReturnType, 0, CheckMode.OVERRIDE).isAnyMismatch()) {
 						if (srcMethod != null)
-							scope.problemReporter().illegalReturnRedefinition(srcMethod, inheritedMethod, null);
+							scope.problemReporter().illegalReturnRedefinition(srcMethod, inheritedMethod,
+																	this.environment.getNonNullAnnotationName());
 						else
 							scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, useTypeAnnotations);
 						return;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
index f69fae4..78e4705 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation 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
@@ -56,6 +56,7 @@
  *								Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
  *								Bug 446442 - [1.8] merge null annotations from super methods
  *								Bug 455723 - Nonnull argument not correctly inferred in loop
+ *								Bug 458361 - [1.8][null] reconciler throws NPE in ProblemReporter.illegalReturnRedefinition()
  *      Jesper S Moller <jesper@selskabet.org> -  Contributions for
  *								bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
  *								bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
@@ -393,6 +394,7 @@
 		case IProblem.RequiredNonNullButProvidedNull:
 		case IProblem.RequiredNonNullButProvidedSpecdNullable:
 		case IProblem.IllegalReturnNullityRedefinition:
+		case IProblem.IllegalReturnNullityRedefinitionFreeTypeVariable:
 		case IProblem.IllegalRedefinitionToNonNullParameter:
 		case IProblem.IllegalDefinitionToNonNullParameter:
 		case IProblem.ParameterLackingNullableAnnotation:
@@ -9195,14 +9197,14 @@
 		nullityMismatchPotentiallyNull(expression, requiredType, annotationName);
 		return;
 	}
-	if (this.options.useNullTypeAnnotations == Boolean.TRUE)
+	if (this.options.usesNullTypeAnnotations())
 		nullityMismatchingTypeAnnotation(expression, providedType, requiredType, NullAnnotationMatching.NULL_ANNOTATIONS_UNCHECKED);
 	else
 		nullityMismatchIsUnknown(expression, providedType, requiredType, annotationName);
 }
 public void nullityMismatchIsNull(Expression expression, TypeBinding requiredType) {
 	int problemId = IProblem.RequiredNonNullButProvidedNull;
-	boolean useNullTypeAnnotations = this.options.useNullTypeAnnotations == Boolean.TRUE;
+	boolean useNullTypeAnnotations = this.options.usesNullTypeAnnotations();
 	if (useNullTypeAnnotations && requiredType.isTypeVariable() && !requiredType.hasNullTypeAnnotations())
 		problemId = IProblem.NullNotCompatibleToFreeTypeVariable;
 	if (requiredType instanceof CaptureBinding) {
@@ -9363,26 +9365,32 @@
 		sourceStart = annotation.sourceStart;
 	}
 	TypeBinding inheritedReturnType = inheritedMethod.returnType;
-	String[] arguments;
-	String[] argumentsShort;
-	if (this.options.useNullTypeAnnotations != Boolean.TRUE) {
-		StringBuilder returnType = new StringBuilder();
+	int problemId = IProblem.IllegalReturnNullityRedefinition;
+	StringBuilder returnType = new StringBuilder();
+	StringBuilder returnTypeShort = new StringBuilder();
+	if (this.options.usesNullTypeAnnotations()) {
+		// 1.8+
+		if (inheritedReturnType.isTypeVariable() && (inheritedReturnType.tagBits & TagBits.AnnotationNullMASK) == 0) {
+			problemId = IProblem.IllegalReturnNullityRedefinitionFreeTypeVariable;
+
+			returnType.append(inheritedReturnType.readableName());
+			returnTypeShort.append(inheritedReturnType.shortReadableName());
+		} else {
+			returnType.append(inheritedReturnType.nullAnnotatedReadableName(this.options, false));
+			returnTypeShort.append(inheritedReturnType.nullAnnotatedReadableName(this.options, true));
+		}
+	} else {
+		// 1.7-
 		returnType.append('@').append(CharOperation.concatWith(nonNullAnnotationName, '.'));
 		returnType.append(' ').append(inheritedReturnType.readableName());
-		arguments = new String[] { methodSignature.toString(), returnType.toString() };
 		
-		returnType = new StringBuilder();
-		returnType.append('@').append(nonNullAnnotationName[nonNullAnnotationName.length-1]);
-		returnType.append(' ').append(inheritedReturnType.shortReadableName());
-		argumentsShort = new String[] { shortSignature.toString(), returnType.toString() };
-	} else {
-		arguments = new String[] { methodSignature.toString(), 
-									String.valueOf(inheritedReturnType.nullAnnotatedReadableName(this.options, false))};
-		argumentsShort = new String[] { shortSignature.toString(),
-									String.valueOf(inheritedReturnType.nullAnnotatedReadableName(this.options, true))};
+		returnTypeShort.append('@').append(nonNullAnnotationName[nonNullAnnotationName.length-1]);
+		returnTypeShort.append(' ').append(inheritedReturnType.shortReadableName());
 	}
+	String[] arguments = new String[] { methodSignature.toString(), returnType.toString() };
+	String[] argumentsShort = new String[] { shortSignature.toString(), returnTypeShort.toString() };
 	this.handle(
-			IProblem.IllegalReturnNullityRedefinition, 
+			problemId, 
 			arguments,
 			argumentsShort,
 			sourceStart,
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index 2cacfa0..70ac81b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -41,6 +41,7 @@
 #							Bug 434600 - Incorrect null analysis error reporting on type parameters
 #							Bug 439516 - [1.8][null] NonNullByDefault wrongly applied to implicit type bound of binary type
 #							Bug 438467 - [compiler][null] Better error position for "The method _ cannot implement the corresponding method _ due to incompatible nullness constraints"
+#							Bug 458361 - [1.8][null] reconciler throws NPE in ProblemReporter.illegalReturnRedefinition()
 #		Jesper S Moller <jesper@selskabet.org> - Contributions for
 #							bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression
 #							bug 384567 - [1.5][compiler] Compiler accepts illegal modifiers on package declaration
@@ -829,6 +830,7 @@
 971 = The explicit type bound 'Object' is not affected by the nullness default for DefaultLocation.TYPE_BOUND.
 972 = Illegal redefinition of parameter {0}, inherited method from {1} declares this parameter as ''{2}'' (mismatching null constraints)
 973 = Contradictory null annotations: function type was inferred as ''{2} ({4})'', but only one of ''@{0}'' and ''@{1}'' can be effective at any location
+974 = The return type is incompatible with the free type variable ''{1}'' returned from {0} (mismatching null constraints)
 
 # Java 8
 1001 = Syntax error, modifiers and annotations are not allowed for the lambda parameter {0} as its type is elided