Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type
annotations
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 cd44512..4f93557 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
@@ -767,8 +767,8 @@
 	}
 	
 	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=403216#c9 
-	public void testBug403216_3() {
-		runConformTestWithLibs(
+	public void testBug403216_3a() {
+		runNegativeTestWithLibs(
 			new String[] {
 				"Test.java",
 				"import java.lang.annotation.ElementType;\n" + 
@@ -786,6 +786,33 @@
 				"@interface A {}\n"
 			},
 			getCompilerOptions(),
+			"----------\n" + 
+			"1. ERROR in Test.java (at line 9)\n" + 
+			"	public void foo( @A X. @NonNull Y this) {}\n" + 
+			"	                 ^^^^^^^^^^^^^^^^\n" + 
+			"Nullness annotations are not applicable at this location \n" + 
+			"----------\n");
+	}
+
+	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=403216#c9 
+	public void testBug403216_3b() {
+		runConformTestWithLibs(
+			new String[] {
+				"Test.java",
+				"import java.lang.annotation.ElementType;\n" + 
+				"import java.lang.annotation.Target;\n" +
+				"\n" + 
+				"public class Test {}\n" + 
+				"\n" + 
+				"class X {\n" + 
+				"	class Y {\n" + 
+				"		public void foo( @A X. @A Y this) {}\n" + 
+				"	}\n" + 
+				"}\n" + 
+				"@Target(value={ElementType.TYPE_USE})\n" + 
+				"@interface A {}\n"
+			},
+			getCompilerOptions(),
 			"");
 	}
 
@@ -2138,7 +2165,7 @@
 			"----------\n");
 	}
 
-	// illegal for cast & instanceof with scalar type
+	// illegal / unchecked for cast & instanceof with scalar type
 	public void testUnsupportedLocation03() {
 		runNegativeTestWithLibs(
 			new String[] {
@@ -2170,7 +2197,7 @@
 			"----------\n");
 	}
 
-	// illegal for cast & instanceof with complex type
+	// illegal / unchecked for cast & instanceof with complex type
 	public void testUnsupportedLocation04() {
 		runNegativeTestWithLibs(
 			new String[] {
@@ -2235,6 +2262,27 @@
 			"----------\n");
 	}
 
+	// illegal instanceof check with annotated type argument
+	public void testUnsupportedLocation04a() {
+		runNegativeTestWithLibs(
+			new String[] {
+				"X.java",
+				"import org.eclipse.jdt.annotation.*;\n" +
+				"import java.util.*;\n" +
+				"public class X {\n" +
+				"	boolean instanceOf2(Object o) {\n" + 
+				"		return o instanceof List<@Nullable ?>;\n" + 
+				"	}\n" + 
+				"}\n"
+			},
+			"----------\n" + 
+			"1. ERROR in X.java (at line 5)\n" + 
+			"	return o instanceof List<@Nullable ?>;\n" + 
+			"	                    ^^^^^^^^^^^^^^^^^\n" + 
+			"Nullness annotations are not applicable at this location \n" + 
+			"----------\n");
+	}
+
 	// illegal for allocation expression
 	public void testUnsupportedLocation05() {
 		runNegativeTestWithLibs(
@@ -2261,6 +2309,82 @@
 			"----------\n");
 	}
 
+	// method receiver
+	public void testUnsupportedLocation06() {
+		runNegativeTestWithLibs(
+			new String[] {
+				"X.java",
+				"import org.eclipse.jdt.annotation.*;\n" +
+				"public class X {\n" +
+				"	void receiver(@Nullable X this, Object o) {}\n" + 
+				"}\n"
+			},
+			"----------\n" + 
+			"1. ERROR in X.java (at line 3)\n" + 
+			"	void receiver(@Nullable X this, Object o) {}\n" + 
+			"	              ^^^^^^^^^^^\n" + 
+			"Nullness annotations are not applicable at this location \n" + 
+			"----------\n");
+	}
+
+	// receiver type in method/constructor reference
+	public void testUnsupportedLocation07() {
+		runNegativeTestWithLibs(
+			new String[] {
+				"X.java",
+				"import org.eclipse.jdt.annotation.*;\n" +
+				"import java.util.function.Supplier;\n" +
+				"public class X {\n" +
+				"	void consume(Supplier<Object> c) {}\n" + 
+				"	static Object supply() { return null; }\n" + 
+				"	void consumeSupplied() {\n" + 
+				"		consume(@NonNull X::supply);\n" + 
+				"		consume(@NonNull X::new);\n" + 
+				"	}\n" + 
+				"}\n"
+			},
+			"----------\n" + 
+			"1. ERROR in X.java (at line 7)\n" + 
+			"	consume(@NonNull X::supply);\n" + 
+			"	        ^^^^^^^^^^\n" + 
+			"Nullness annotations are not applicable at this location \n" + 
+			"----------\n" + 
+			"2. ERROR in X.java (at line 8)\n" + 
+			"	consume(@NonNull X::new);\n" + 
+			"	        ^^^^^^^^^^\n" + 
+			"Nullness annotations are not applicable at this location \n" + 
+			"----------\n");
+	}
+
+	// exceptions (throws & catch)
+	public void testUnsupportedLocation08() {
+		runNegativeTestWithLibs(
+			new String[] {
+				"X.java",
+				"import org.eclipse.jdt.annotation.*;\n" +
+				"import java.io.*;\n" +
+				"public class X {\n" +
+				"	void throwsDecl() throws @Nullable IOException {}\n" + 
+				"	void excParam() {\n" + 
+				"		try {\n" + 
+				"			throwsDecl();\n" + 
+				"		} catch (@NonNull IOException ioe) {}\n" + 
+				"	}\n" + 
+				"}\n"
+			},
+			"----------\n" + 
+			"1. ERROR in X.java (at line 4)\n" + 
+			"	void throwsDecl() throws @Nullable IOException {}\n" + 
+			"	                         ^^^^^^^^^^^^^^^^^^^^^\n" + 
+			"Nullness annotations are not applicable at this location \n" + 
+			"----------\n" + 
+			"2. ERROR in X.java (at line 8)\n" + 
+			"	} catch (@NonNull IOException ioe) {}\n" + 
+			"	                  ^^^^^^^^^^^\n" + 
+			"Nullness annotations are not applicable at this location \n" + 
+			"----------\n");
+	}
+
 	public void testForeach() {
 		runNegativeTestWithLibs(
 			new String[] {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
index 25326f7..186893e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
@@ -24,6 +24,7 @@
  *								Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
  *								Bug 403216 - [1.8][null] TypeReference#captureTypeAnnotations treats type annotations as type argument annotations
  *								Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
+ *								Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
@@ -587,6 +588,10 @@
 		if (TypeBinding.notEquals(enclosingReceiver, resolvedReceiverType)) {
 			this.scope.problemReporter().illegalTypeForExplicitThis(this.receiver, enclosingReceiver);
 		}
+
+		if (resolvedReceiverType.hasNullTypeAnnotations()) {
+			this.scope.problemReporter().nullAnnotationUnsupportedLocation(this.receiver.type);
+		}
 	}
 	public void resolveJavadoc() {
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
index b46a2c4..e5567a4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
@@ -15,6 +15,7 @@
  *								bug 186342 - [compiler][null] Using annotations for null checking
  *								bug 365519 - editorial cleanup after bug 186342 and bug 365387
  *								Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
+ *								Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
  *        Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
  *                          Bug 409246 - [1.8][compiler] Type annotations on catch parameters not handled properly
  *******************************************************************************/
@@ -199,6 +200,9 @@
 		}
 		resolveAnnotations(scope, this.annotations, this.binding, true);
 		Annotation.isTypeUseCompatible(this.type, scope, this.annotations);
+		if (this.type.resolvedType != null && this.type.resolvedType.hasNullTypeAnnotations()) {
+			scope.problemReporter().nullAnnotationUnsupportedLocation(this.type);
+		}
 
 		scope.addLocalVariable(this.binding);
 		this.binding.setConstant(Constant.NotAConstant);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
index 5f84c19..405e53f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
@@ -17,6 +17,7 @@
  *								Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking
  *								Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
  *								Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
+ *								Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
  *        Andy Clement - Contributions for
  *                          Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work)
  *******************************************************************************/
@@ -92,8 +93,10 @@
 	this.constant = Constant.NotAConstant;
 	TypeBinding expressionType = this.expression.resolveType(scope);
 	TypeBinding checkedType = this.type.resolveType(scope, true /* check bounds*/);
-	if (expressionType != null && checkedType != null && NullAnnotationMatching.analyse(checkedType, expressionType, -1).isAnyMismatch()) {
-		scope.problemReporter().nullAnnotationUnsupportedLocation(this.type);
+	if (expressionType != null && checkedType != null && checkedType.hasNullTypeAnnotations()) {
+		// don't complain if the entire operation is redundant anyway
+		if (!expressionType.isCompatibleWith(checkedType) || NullAnnotationMatching.analyse(checkedType, expressionType, -1).isAnyMismatch())
+			scope.problemReporter().nullAnnotationUnsupportedLocation(this.type);
 	}
 	if (expressionType == null || checkedType == null)
 		return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
index de28ffa..d1c6a56 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
@@ -28,6 +28,7 @@
  *							Bug 427196 - [1.8][compiler] Compiler error for method reference to overloaded method
  *							Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280)
  *							Bug 428264 - [1.8] method reference of generic class causes problems (wrong inference result or NPE)
+ *							Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
  *        Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contribution for
  *                          Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work)
  *******************************************************************************/
@@ -388,6 +389,10 @@
 			return this.resolvedType = null;
 		}
 		
+		if (this.lhs instanceof TypeReference && lhsType.hasNullTypeAnnotations()) {
+			scope.problemReporter().nullAnnotationUnsupportedLocation((TypeReference) this.lhs);
+		}
+
 		/* 15.28: "It is a compile-time error if a method reference of the form super :: NonWildTypeArgumentsopt Identifier or of the form 
 		   TypeName . super :: NonWildTypeArgumentsopt Identifier occurs in a static context.": This is nop since the primary when it resolves
 		   itself will complain automatically.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
index fb6b282..83be251 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -33,6 +33,7 @@
  *								Bug 416172 - [1.8][compiler][null] null type annotation not evaluated on method return type
  *								Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings.
  *								Bug 426048 - [1.8] NPE in TypeVariableBinding.internalBoundCheck when parentheses are not balanced
+ *								Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
  *      Jesper S Moller <jesper@selskabet.org> -  Contributions for
  *								Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
  *      Till Brychcy - Contributions for
@@ -1815,6 +1816,9 @@
 			if ((resolvedExceptionType.tagBits & TagBits.HasMissingType) != 0) {
 				method.tagBits |= TagBits.HasMissingType;
 			}
+			if (resolvedExceptionType.hasNullTypeAnnotations()) {
+				methodDecl.scope.problemReporter().nullAnnotationUnsupportedLocation(exceptionTypes[i]);
+			}
 			method.modifiers |= (resolvedExceptionType.modifiers & ExtraCompilerModifiers.AccGenericSignature);
 			method.thrownExceptions[count++] = resolvedExceptionType;
 		}