Bug 527569 - Add new compiler option for --release and fix errors with
JRE 8 along with new tests

Change-Id: I465507fe38840157e769a1e1336284540f5a352e
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
index 6ec5458..ed850ab 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java
@@ -1128,6 +1128,7 @@
 			"		<option key=\"org.eclipse.jdt.core.compiler.problem.unusedWarningToken\" value=\"warning\"/>\n" + 
 			"		<option key=\"org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast\" value=\"warning\"/>\n" + 
 			"		<option key=\"org.eclipse.jdt.core.compiler.processAnnotations\" value=\"disabled\"/>\n" + 
+			"		<option key=\"org.eclipse.jdt.core.compiler.release\" value=\"disabled\"/>\n" + 
 			"		<option key=\"org.eclipse.jdt.core.compiler.source\" value=\"1.5\"/>\n" + 
 			"		<option key=\"org.eclipse.jdt.core.compiler.storeAnnotations\" value=\"disabled\"/>\n" +
 			"		<option key=\"org.eclipse.jdt.core.compiler.taskCaseSensitive\" value=\"enabled\"/>\n" + 
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
index fc1801e..51e4add 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
@@ -1322,7 +1322,10 @@
 	}
 
 	protected IJavaProject createJava9Project(String name) throws CoreException {
-		return createJava9Project(name, new String[]{"src"});
+		return createJava9ProjectWithJREAttributes(name, new String[]{"src"}, null, "9");
+	}
+	protected IJavaProject createJava9Project(String name, String compliance) throws CoreException {
+		return createJava9ProjectWithJREAttributes(name, new String[]{"src"}, null, compliance);
 	}
 	protected IJavaProject createJava9Project(String name, String[] srcFolders) throws CoreException {
 		return createJava9ProjectWithJREAttributes(name, srcFolders, null);
@@ -1341,6 +1344,20 @@
 		project.setRawClasspath(newPath, null);
 		return project;
 	}
+	protected IJavaProject createJava9ProjectWithJREAttributes(String name, String[] srcFolders, IClasspathAttribute[] attributes, String compliance) throws CoreException {
+		String javaHome = System.getProperty("java.home") + File.separator;
+		Path bootModPath = new Path(javaHome +"/lib/jrt-fs.jar");
+		Path sourceAttachment = new Path(javaHome +"/lib/src.zip");
+		IClasspathEntry jrtEntry = JavaCore.newLibraryEntry(bootModPath, sourceAttachment, null, null, attributes, false);
+		IJavaProject project = this.createJavaProject(name, srcFolders, new String[0],
+				new String[0], "bin", compliance);
+		IClasspathEntry[] old = project.getRawClasspath();
+		IClasspathEntry[] newPath = new IClasspathEntry[old.length +1];
+		System.arraycopy(old, 0, newPath, 0, old.length);
+		newPath[old.length] = jrtEntry;
+		project.setRawClasspath(newPath, null);
+		return project;
+	}
 	/*
 	}
 	 * Creates a Java project where prj=src=bin and with JCL_LIB on its classpath.
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java
index aaced5e..e7cc28e 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleBuilderTests.java
@@ -57,7 +57,7 @@
 	}
 
 	static {
-		// TESTS_NAMES = new String[] { "testBug528467" };
+//		 TESTS_NAMES = new String[] { "testBug527569c" };
 	}
 	private String sourceWorkspacePath = null;
 	protected ProblemRequestor problemRequestor;
@@ -6814,7 +6814,130 @@
 			new File(jarPath).delete();
 		}
 	}
+	public void testBug527569a() throws CoreException {
+		if (!isJRE9) return;
+		IJavaProject p1 = createJava9Project("Bug527569", "9");
+		try {
+			createFolder("/Bug527569/src/p1");
+			createFile("/Bug527569/src/p1/X.java",
+					"package p1;\n" +
+					"public class X {\n" +
+					"	public java.util.stream.Stream<String> emptyStream() {\n" +
+					"		return null;\n" +
+					"	}\n" +
+					"}");
 
+			waitForManualRefresh();
+			waitForAutoBuild();
+			p1.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = p1.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers", "", markers);
+		} finally {
+			deleteProject(p1);
+		}
+	}
+	public void testBug527569b() throws CoreException {
+		if (!isJRE9) return;
+		IJavaProject p1 = createJava9Project("Bug527569", "1.7");
+		try {
+			createFolder("/Bug527569/src/p1");
+			createFile("/Bug527569/src/p1/X.java",
+					"package p1;\n" +
+					"public class X {\n" +
+					"	public java.util.stream.Stream<String> emptyStream() {\n" +
+					"		return null;\n" +
+					"	}\n" +
+					"}");
+
+			waitForManualRefresh();
+			waitForAutoBuild();
+			p1.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = p1.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers", "", markers);
+		} finally {
+			deleteProject(p1);
+		}
+	}
+	public void testBug527569c() throws CoreException {
+		if (!isJRE9) return;
+		IJavaProject p1 = createJava9Project("Bug527569", "1.7");
+		Map<String, String> options = new HashMap<>();
+		// Make sure the new options map doesn't reset.
+		options.put(CompilerOptions.OPTION_Compliance, "1.7");
+		options.put(CompilerOptions.OPTION_Source, "1.7");
+		options.put(CompilerOptions.OPTION_TargetPlatform, "1.7");
+		options.put(CompilerOptions.OPTION_Release, "enabled");
+		p1.setOptions(options);
+		try {
+			createFolder("/Bug527569/src/p1");
+			createFile("/Bug527569/src/p1/X.java",
+					"package p1;\n" +
+					"public class X {\n" +
+					"	public java.util.stream.Stream<String> emptyStream() {\n" +
+					"		return null;\n" +
+					"	}\n" +
+					"}");
+
+			waitForManualRefresh();
+			waitForAutoBuild();
+			p1.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = p1.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers", "java.util.stream.Stream cannot be resolved to a type", markers);
+		} finally {
+			deleteProject(p1);
+		}
+	}
+	public void testBug527569d() throws CoreException {
+		if (!isJRE9) return;
+		IJavaProject p1 = createJava9Project("Bug527569", "9");
+		try {
+			createFolder("/Bug527569/src/p1");
+			createFile("/Bug527569/src/p1/X.java",
+					"package p1;\n" +
+					"public class X {\n" +
+					"	public java.lang.Compiler getCompiler() {\n" +
+					"		return null;\n" +
+					"	}\n" +
+					"}");
+
+			waitForManualRefresh();
+			waitForAutoBuild();
+			p1.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = p1.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers", "The type Compiler has been deprecated since version 9 and marked for removal", markers);
+		} finally {
+			deleteProject(p1);
+		}
+	}
+	public void testBug527569e() throws CoreException {
+		if (!isJRE9) return;
+		IJavaProject p1 = createJava9Project("Bug527569", "1.8");
+		Map<String, String> options = new HashMap<>();
+		// Make sure the new options map doesn't reset.
+		options.put(CompilerOptions.OPTION_Compliance, "1.7");
+		options.put(CompilerOptions.OPTION_Source, "1.7");
+		options.put(CompilerOptions.OPTION_TargetPlatform, "1.7");
+		options.put(CompilerOptions.OPTION_Release, "enabled");
+		p1.setOptions(options);
+		try {
+			createFolder("/Bug527569/src/p1");
+			createFile("/Bug527569/src/p1/X.java",
+					"package p1;\n" +
+					"public class X {\n" +
+					"	public java.lang.Compiler getCompiler() {\n" +
+					"		return null;\n" +
+					"	}\n" +
+					"}");
+
+			waitForManualRefresh();
+			waitForAutoBuild();
+			p1.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = p1.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers", "", markers);
+		} finally {
+			deleteProject(p1);
+		}
+	}
 	protected void assertNoErrors() throws CoreException {
 		for (IProject p : getWorkspace().getRoot().getProjects()) {
 			int maxSeverity = p.findMaxProblemSeverity(null, true, IResource.DEPTH_INFINITE);
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 5c129f2..38a5643 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
@@ -116,6 +116,7 @@
 	public static final String OPTION_Source = "org.eclipse.jdt.core.compiler.source"; //$NON-NLS-1$
 	public static final String OPTION_TargetPlatform = "org.eclipse.jdt.core.compiler.codegen.targetPlatform"; //$NON-NLS-1$
 	public static final String OPTION_Compliance = "org.eclipse.jdt.core.compiler.compliance"; //$NON-NLS-1$
+	public static final String OPTION_Release = "org.eclipse.jdt.core.compiler.release"; //$NON-NLS-1$
 	public static final String OPTION_Encoding = "org.eclipse.jdt.core.encoding"; //$NON-NLS-1$
 	public static final String OPTION_MaxProblemPerUnit = "org.eclipse.jdt.core.compiler.maxProblemPerUnit"; //$NON-NLS-1$
 	public static final String OPTION_TaskTags = "org.eclipse.jdt.core.compiler.taskTags"; //$NON-NLS-1$
@@ -1237,6 +1238,7 @@
 		optionsMap.put(OPTION_ReportUnusedLabel, getSeverityString(UnusedLabel));
 		optionsMap.put(OPTION_ReportUnusedTypeArgumentsForMethodInvocation, getSeverityString(UnusedTypeArguments));
 		optionsMap.put(OPTION_Compliance, versionFromJdkLevel(this.complianceLevel));
+		optionsMap.put(OPTION_Release, DISABLED);
 		optionsMap.put(OPTION_Source, versionFromJdkLevel(this.sourceLevel));
 		optionsMap.put(OPTION_TargetPlatform, versionFromJdkLevel(this.targetJDK));
 		optionsMap.put(OPTION_FatalOptionalError, this.treatOptionalErrorAsFatal ? ENABLED : DISABLED);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
index 3d5c0ea..260fd76 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
@@ -2086,6 +2086,22 @@
 	 */
 	public static final String COMPILER_COMPLIANCE = PLUGIN_ID + ".compiler.compliance"; //$NON-NLS-1$
 	/**
+	 * Compiler option ID: Use system libraries from release.
+	 * <p>When enabled, the compiler will compile against the system libraries from release
+	 * of the specified compliance level</p>
+	 * <p>Setting this option sets the {@link #COMPILER_CODEGEN_TARGET_PLATFORM}) and {@link #COMPILER_SOURCE} to
+	 * the same level as the compiler compliance. This option is available to a project only when a supporting 
+	 * JDK is found in the project's build path</p>
+	 * <dl>
+	 * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.release"</code></dd>
+	 * <dt>Possible values:</dt><dd><code>{ "enabled", "disabled" }</code></dd>
+	 * <dt>Default:</dt><dd><code>"disabled"</code></dd>
+	 * </dl>
+	 * @since 3.14
+	 * @category CompilerOptionID
+	 */
+	public static final String COMPILER_RELEASE = PLUGIN_ID + ".compiler.release"; //$NON-NLS-1$
+	/**
 	 * Compiler option ID: Defining the Automatic Task Priorities.
 	 * <p>In parallel with the Automatic Task Tags, this list defines the priorities (high, normal or low)
 	 *    of the task markers issued by the compiler.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java
index 0b7a320..80d378a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrt.java
@@ -70,7 +70,7 @@
 	this.accessRuleSet = accessRuleSet;
 	if (externalAnnotationPath != null)
 		this.externalAnnotationPath = externalAnnotationPath.toString();
-	if (compliance.length() == 0) {
+	if (compliance != null && compliance.length() == 0) {
 		this.compliance = null;
 	} else {
 		this.compliance = compliance;
@@ -196,7 +196,7 @@
 			return;
 		}
 	}
-	this.releasePath = this.fs.getPath(""); //$NON-NLS-1$
+	this.releasePath = this.fs.getPath("/"); //$NON-NLS-1$
 	if (!Files.exists(this.fs.getPath(this.compliance))
 			|| Files.exists(this.fs.getPath(this.compliance, "system-modules"))) { //$NON-NLS-1$
 		this.compliance = null;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java
index fcfd994..8498de9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/NameEnvironment.java
@@ -302,6 +302,9 @@
 							&& JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, true)))
 								? null
 								: entry.getAccessRuleSet();
+					if (JavaCore.DISABLED.equals(javaProject.getOption(JavaCore.COMPILER_RELEASE, true))) {
+						compliance = null;
+					}
 					ClasspathLocation bLocation = ClasspathLocation.forLibrary(path.toOSString(), accessRuleSet, externalAnnotationPath, isOnModulePath, compliance);
 					bLocations.add(bLocation);
 					if (moduleEntries != null) {