Bug 541772 - In Eclipse 2018-09, Maven "runtime" scoped dependencies
cause compilation errors even when not used

- make test even meaner and implementation even safer

Change-Id: I1c0db4a74ff39f946d28290b7e4fff2fb619b1db
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
index 6a2b643..20da9ff 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
@@ -52498,4 +52498,92 @@
 	getCompilerOptions(),
 	null /*customRequestor*/);
 }
+public void testBug541772_typeannotations() {
+	if (this.complianceLevel < ClassFileConstants.JDK1_8) {
+		return;
+	}
+	runConformTest(
+		new String[] {
+			"bug541772Runtime/GeneratedMessage.java",
+			"package bug541772Runtime;\n" +
+			"\n" +
+			"public class GeneratedMessage {\n" +
+			"    public class Builder<T> {\n" +
+			"    }\n" +
+			"}\n" +
+			"",
+		},
+		"",
+		getCompilerOptions()
+	);
+	
+	runConformTest(
+	new String[] {
+		"token/Ann.java",
+		"package token;\n" +
+		"import java.lang.annotation.*;\n" +
+		"@Target(ElementType.TYPE_USE)\n" +
+		"@Retention(RetentionPolicy.CLASS)\n" +
+		"@interface Ann {}\n",
+		"token/Token.java",
+		"package token;\n" +
+		"\n" +
+		"public class Token {\n" +
+		"  \n" +
+		"  public Token() {\n" +
+		"  }\n" +
+		"\n" +
+		"  public Token(TokenProto tokenPB) {\n" +
+		"      tokenPB.hashCode();\n" +
+		"  }\n" +
+		"  public Token(String x) {\n" +
+		"      x.hashCode();\n" +
+		"  }\n" +
+		"}\n" +
+		"",
+		"token/TokenProto.java",
+		"package token;\n" +
+		"\n" +
+		"import bug541772Runtime.GeneratedMessage;\n" +
+		"\n" +
+		"public class TokenProto {\n" +
+		"\n" +
+		"    public TokenProto(GeneratedMessage.@Ann Builder<?> builder) {\n" +
+		"        builder.hashCode();\n" +
+		"    }\n" +
+		"}\n" +
+		"",
+	},
+	"",
+	null /*classLibraries*/,
+	false /*shouldFlushOutputDirectory*/,
+	null /*vmArguments*/,
+	getCompilerOptions(),
+	null /*customRequestor*/);
+
+	Util.flushDirectoryContent(new File(OUTPUT_DIR + File.separator + "bug541772Runtime"));
+
+	Map compilerOptions = getCompilerOptions();
+	compilerOptions.put(JavaCore.COMPILER_ANNOTATION_NULL_ANALYSIS, JavaCore.ENABLED);
+	runConformTest(
+	new String[] {
+		"pkg/Example.java",
+		"package pkg;\n" +
+		"\n" +
+		"import token.Token;\n" +
+		"\n" +
+		"public abstract class Example {\n" +
+		"	public static void setConnectorInfo() {\n" +
+		"		new Token(\"\");\n" +
+		"	}\n" +
+		"}\n" +
+		"",
+	},
+	"",
+	null /*classLibraries*/,
+	false /*shouldFlushOutputDirectory*/,
+	null /*vmArguments*/,
+	compilerOptions,
+	null /*customRequestor*/);
+}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
index 393c864..b1364c6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
@@ -666,61 +666,67 @@
 
 private void createFields(IBinaryField[] iFields, IBinaryType binaryType, long sourceLevel, char[][][] missingTypeNames) {
 	if (!isPrototype()) throw new IllegalStateException();
-	this.fields = Binding.NO_FIELDS;
-	if (iFields != null) {
-		int size = iFields.length;
-		if (size > 0) {
-			FieldBinding[] fields1 = new FieldBinding[size];
-			boolean use15specifics = sourceLevel >= ClassFileConstants.JDK1_5;
-			boolean hasRestrictedAccess = hasRestrictedAccess();
-			int firstAnnotatedFieldIndex = -1;
-			for (int i = 0; i < size; i++) {
-				IBinaryField binaryField = iFields[i];
-				char[] fieldSignature = use15specifics ? binaryField.getGenericSignature() : null;
-				ITypeAnnotationWalker walker = getTypeAnnotationWalker(binaryField.getTypeAnnotations(), getNullDefaultFrom(binaryField.getAnnotations()));
-				if (sourceLevel >= ClassFileConstants.JDK1_8) { // below 1.8, external annotations will be attached later
-					walker = binaryType.enrichWithExternalAnnotationsFor(walker, iFields[i], this.environment);
-				}
-				walker = walker.toField();
-				TypeBinding type = fieldSignature == null
-					? this.environment.getTypeFromSignature(binaryField.getTypeName(), 0, -1, false, this, missingTypeNames, walker)
-					: this.environment.getTypeFromTypeSignature(new SignatureWrapper(fieldSignature), Binding.NO_TYPE_VARIABLES, this, missingTypeNames, walker);
-				FieldBinding field =
-					new FieldBinding(
-						binaryField.getName(),
-						type,
-						binaryField.getModifiers() | ExtraCompilerModifiers.AccUnresolved,
-						this,
-						binaryField.getConstant());
-				boolean forceStoreAnnotations = !this.environment.globalOptions.storeAnnotations
-						&& (this.environment.globalOptions.sourceLevel >= ClassFileConstants.JDK9
-						&& binaryField.getAnnotations() != null
-						&& (binaryField.getTagBits() & TagBits.AnnotationDeprecated) != 0);
-				if (firstAnnotatedFieldIndex < 0
-						&& (this.environment.globalOptions.storeAnnotations || forceStoreAnnotations)
-						&& binaryField.getAnnotations() != null) {
-					firstAnnotatedFieldIndex = i;
-					if (forceStoreAnnotations)
-						storedAnnotations(true, true); // for Java 9 @Deprecated we need to force storing annotations
-				}
-				field.id = i; // ordinal
-				if (use15specifics)
-					field.tagBits |= binaryField.getTagBits();
-				if (hasRestrictedAccess)
-					field.modifiers |= ExtraCompilerModifiers.AccRestrictedAccess;
-				if (fieldSignature != null)
-					field.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
-				fields1[i] = field;
-			}
-			this.fields = fields1;
-			// second pass for reifying annotations, since may refer to fields being constructed (147875)
-			if (firstAnnotatedFieldIndex >= 0) {
-				for (int i = firstAnnotatedFieldIndex; i <size; i++) {
+	boolean save = this.environment.mayTolerateMissingType;
+	this.environment.mayTolerateMissingType = true;
+	try {
+		this.fields = Binding.NO_FIELDS;
+		if (iFields != null) {
+			int size = iFields.length;
+			if (size > 0) {
+				FieldBinding[] fields1 = new FieldBinding[size];
+				boolean use15specifics = sourceLevel >= ClassFileConstants.JDK1_5;
+				boolean hasRestrictedAccess = hasRestrictedAccess();
+				int firstAnnotatedFieldIndex = -1;
+				for (int i = 0; i < size; i++) {
 					IBinaryField binaryField = iFields[i];
-					this.fields[i].setAnnotations(createAnnotations(binaryField.getAnnotations(), this.environment, missingTypeNames), false);
+					char[] fieldSignature = use15specifics ? binaryField.getGenericSignature() : null;
+					ITypeAnnotationWalker walker = getTypeAnnotationWalker(binaryField.getTypeAnnotations(), getNullDefaultFrom(binaryField.getAnnotations()));
+					if (sourceLevel >= ClassFileConstants.JDK1_8) { // below 1.8, external annotations will be attached later
+						walker = binaryType.enrichWithExternalAnnotationsFor(walker, iFields[i], this.environment);
+					}
+					walker = walker.toField();
+					TypeBinding type = fieldSignature == null
+						? this.environment.getTypeFromSignature(binaryField.getTypeName(), 0, -1, false, this, missingTypeNames, walker)
+						: this.environment.getTypeFromTypeSignature(new SignatureWrapper(fieldSignature), Binding.NO_TYPE_VARIABLES, this, missingTypeNames, walker);
+					FieldBinding field =
+						new FieldBinding(
+							binaryField.getName(),
+							type,
+							binaryField.getModifiers() | ExtraCompilerModifiers.AccUnresolved,
+							this,
+							binaryField.getConstant());
+					boolean forceStoreAnnotations = !this.environment.globalOptions.storeAnnotations
+							&& (this.environment.globalOptions.sourceLevel >= ClassFileConstants.JDK9
+							&& binaryField.getAnnotations() != null
+							&& (binaryField.getTagBits() & TagBits.AnnotationDeprecated) != 0);
+					if (firstAnnotatedFieldIndex < 0
+							&& (this.environment.globalOptions.storeAnnotations || forceStoreAnnotations)
+							&& binaryField.getAnnotations() != null) {
+						firstAnnotatedFieldIndex = i;
+						if (forceStoreAnnotations)
+							storedAnnotations(true, true); // for Java 9 @Deprecated we need to force storing annotations
+					}
+					field.id = i; // ordinal
+					if (use15specifics)
+						field.tagBits |= binaryField.getTagBits();
+					if (hasRestrictedAccess)
+						field.modifiers |= ExtraCompilerModifiers.AccRestrictedAccess;
+					if (fieldSignature != null)
+						field.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
+					fields1[i] = field;
+				}
+				this.fields = fields1;
+				// second pass for reifying annotations, since may refer to fields being constructed (147875)
+				if (firstAnnotatedFieldIndex >= 0) {
+					for (int i = firstAnnotatedFieldIndex; i <size; i++) {
+						IBinaryField binaryField = iFields[i];
+						this.fields[i].setAnnotations(createAnnotations(binaryField.getAnnotations(), this.environment, missingTypeNames), false);
+					}
 				}
 			}
 		}
+	} finally {
+		this.environment.mayTolerateMissingType = save;
 	}
 }
 
@@ -945,59 +951,65 @@
  */
 private IBinaryMethod[] createMethods(IBinaryMethod[] iMethods, IBinaryType binaryType, long sourceLevel, char[][][] missingTypeNames) {
 	if (!isPrototype()) throw new IllegalStateException();
-	int total = 0, initialTotal = 0, iClinit = -1;
-	int[] toSkip = null;
-	if (iMethods != null) {
-		total = initialTotal = iMethods.length;
-		boolean keepBridgeMethods = sourceLevel < ClassFileConstants.JDK1_5; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=330347
-		for (int i = total; --i >= 0;) {
-			IBinaryMethod method = iMethods[i];
-			if ((method.getModifiers() & ClassFileConstants.AccSynthetic) != 0) {
-				if (keepBridgeMethods && (method.getModifiers() & ClassFileConstants.AccBridge) != 0)
-					continue; // want to see bridge methods as real methods
-				// discard synthetics methods
-				if (toSkip == null) toSkip = new int[iMethods.length];
-				toSkip[i] = -1;
-				total--;
-			} else if (iClinit == -1) {
-				char[] methodName = method.getSelector();
-				if (methodName.length == 8 && methodName[0] == Util.C_GENERIC_START) {
-					// discard <clinit>
-					iClinit = i;
+	boolean save = this.environment.mayTolerateMissingType;
+	this.environment.mayTolerateMissingType = true;
+	try {
+		int total = 0, initialTotal = 0, iClinit = -1;
+		int[] toSkip = null;
+		if (iMethods != null) {
+			total = initialTotal = iMethods.length;
+			boolean keepBridgeMethods = sourceLevel < ClassFileConstants.JDK1_5; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=330347
+			for (int i = total; --i >= 0;) {
+				IBinaryMethod method = iMethods[i];
+				if ((method.getModifiers() & ClassFileConstants.AccSynthetic) != 0) {
+					if (keepBridgeMethods && (method.getModifiers() & ClassFileConstants.AccBridge) != 0)
+						continue; // want to see bridge methods as real methods
+					// discard synthetics methods
+					if (toSkip == null) toSkip = new int[iMethods.length];
+					toSkip[i] = -1;
 					total--;
+				} else if (iClinit == -1) {
+					char[] methodName = method.getSelector();
+					if (methodName.length == 8 && methodName[0] == Util.C_GENERIC_START) {
+						// discard <clinit>
+						iClinit = i;
+						total--;
+					}
 				}
 			}
 		}
-	}
-	if (total == 0) {
-		this.methods = Binding.NO_METHODS;
-		return NO_BINARY_METHODS;
-	}
-
-	boolean hasRestrictedAccess = hasRestrictedAccess();
-	MethodBinding[] methods1 = new MethodBinding[total];
-	if (total == initialTotal) {
-		for (int i = 0; i < initialTotal; i++) {
-			MethodBinding method = createMethod(iMethods[i], binaryType, sourceLevel, missingTypeNames);
-			if (hasRestrictedAccess)
-				method.modifiers |= ExtraCompilerModifiers.AccRestrictedAccess;
-			methods1[i] = method;
+		if (total == 0) {
+			this.methods = Binding.NO_METHODS;
+			return NO_BINARY_METHODS;
 		}
-		this.methods = methods1;
-		return iMethods;
-	} else {
-		IBinaryMethod[] mappedBinaryMethods = new IBinaryMethod[total];
-		for (int i = 0, index = 0; i < initialTotal; i++) {
-			if (iClinit != i && (toSkip == null || toSkip[i] != -1)) {
+
+		boolean hasRestrictedAccess = hasRestrictedAccess();
+		MethodBinding[] methods1 = new MethodBinding[total];
+		if (total == initialTotal) {
+			for (int i = 0; i < initialTotal; i++) {
 				MethodBinding method = createMethod(iMethods[i], binaryType, sourceLevel, missingTypeNames);
 				if (hasRestrictedAccess)
 					method.modifiers |= ExtraCompilerModifiers.AccRestrictedAccess;
-				mappedBinaryMethods[index] = iMethods[i];
-				methods1[index++] = method;
+				methods1[i] = method;
 			}
+			this.methods = methods1;
+			return iMethods;
+		} else {
+			IBinaryMethod[] mappedBinaryMethods = new IBinaryMethod[total];
+			for (int i = 0, index = 0; i < initialTotal; i++) {
+				if (iClinit != i && (toSkip == null || toSkip[i] != -1)) {
+					MethodBinding method = createMethod(iMethods[i], binaryType, sourceLevel, missingTypeNames);
+					if (hasRestrictedAccess)
+						method.modifiers |= ExtraCompilerModifiers.AccRestrictedAccess;
+					mappedBinaryMethods[index] = iMethods[i];
+					methods1[index++] = method;
+				}
+			}
+			this.methods = methods1;
+			return mappedBinaryMethods;
 		}
-		this.methods = methods1;
-		return mappedBinaryMethods;
+	} finally {
+		this.environment.mayTolerateMissingType = save;
 	}
 }