Merge remote-tracking branch 'origin/R4_7_maintenance' into
BETA_JAVA_18_3

Conflicts:
	org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java

Change-Id: I467262b246fc275a6a667156278b07a7a6f99e86
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
index 9f79087..3d1fa6c 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AbstractRegressionTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -96,6 +96,111 @@
 @SuppressWarnings({ "unchecked", "rawtypes" })
 public abstract class AbstractRegressionTest extends AbstractCompilerTest implements StopableTestCase {
 
+	static final String[] env = System.getenv().entrySet().stream()
+		.filter(e -> !"JAVA_TOOL_OPTIONS".equals(e.getKey()))
+		.map(e -> e.getKey() + "=" + e.getValue())
+		.toArray(String[]::new);
+
+	protected class Runner {
+		boolean shouldFlushOutputDirectory = true;
+		// input:
+		String[] testFiles;
+		String[] dependantFiles;
+		String[] classLibraries;
+		// control compilation:
+		Map<String,String> customOptions;
+		boolean performStatementsRecovery;
+		boolean generateOutput;
+		ICompilerRequestor customRequestor;
+		// compiler result:
+		String expectedCompilerLog;
+		String[] alternateCompilerLogs;
+		boolean showCategory;
+		boolean showWarningToken;
+		// javac:
+		boolean skipJavac;
+		JavacTestOptions javacTestOptions;
+		// execution:
+		boolean forceExecution;
+		String[] vmArguments;
+		String expectedOutputString;
+		String expectedErrorString;
+
+		ASTVisitor visitor;
+
+		@SuppressWarnings("synthetic-access")
+		protected void runConformTest() {
+			runTest(this.shouldFlushOutputDirectory,
+					this.testFiles,
+					this.dependantFiles != null ? this.dependantFiles : new String[] {},
+					this.classLibraries,
+					this.customOptions,
+					this.performStatementsRecovery,
+					new Requestor(
+							this.generateOutput,
+							this.customRequestor,
+							this.showCategory,
+							this.showWarningToken),
+					false,
+					this.expectedCompilerLog,
+					this.alternateCompilerLogs,
+					this.forceExecution,
+					this.vmArguments,
+					this.expectedOutputString,
+					this.expectedErrorString,
+					this.visitor,
+					this.skipJavac ? JavacTestOptions.SKIP : this.javacTestOptions);
+		}
+
+		@SuppressWarnings("synthetic-access")
+		protected void runNegativeTest() {
+			runTest(this.shouldFlushOutputDirectory,
+					this.testFiles,
+					this.dependantFiles != null ? this.dependantFiles : new String[] {},
+					this.classLibraries,
+					this.customOptions,
+					this.performStatementsRecovery,
+					new Requestor(
+							this.generateOutput,
+							this.customRequestor,
+							this.showCategory,
+							this.showWarningToken),
+					true,
+					this.expectedCompilerLog,
+					this.alternateCompilerLogs,
+					this.forceExecution,
+					this.vmArguments,
+					this.expectedOutputString,
+					this.expectedErrorString,
+					this.visitor,
+					this.skipJavac ? JavacTestOptions.SKIP : this.javacTestOptions);
+		}
+
+		@SuppressWarnings("synthetic-access")
+		protected void runWarningTest() {
+			runTest(this.shouldFlushOutputDirectory,
+					this.testFiles,
+					this.dependantFiles != null ? this.dependantFiles : new String[] {},
+					this.classLibraries,
+					this.customOptions,
+					this.performStatementsRecovery,
+					new Requestor(
+							this.generateOutput,
+							this.customRequestor,
+							this.showCategory,
+							this.showWarningToken),
+					false,
+					this.expectedCompilerLog,
+					this.alternateCompilerLogs,
+					this.forceExecution,
+					this.vmArguments,
+					this.expectedOutputString,
+					this.expectedErrorString,
+					this.visitor,
+					this.skipJavac ? JavacTestOptions.SKIP : this.javacTestOptions);
+		}
+	}
+
 	// javac comparison related types, fields and methods - see runJavac for
 	// details
 static class JavacCompiler {
@@ -146,7 +251,7 @@
 	static String getVersion(String javacPathName) throws IOException, InterruptedException {
 		Process fetchVersionProcess = null;
 		try {
-			fetchVersionProcess = Runtime.getRuntime().exec(javacPathName + " -version", null, null);
+			fetchVersionProcess = Runtime.getRuntime().exec(javacPathName + " -version", env, null);
 		    Logger versionStdErrLogger = new Logger(fetchVersionProcess.getErrorStream(), ""); // for javac <= 1.8
 		    Logger versionStdOutLogger = new Logger(fetchVersionProcess.getInputStream(), ""); // for javac >= 9
 		    versionStdErrLogger.start();
@@ -254,7 +359,7 @@
 			} else {
 				cmdLineAsString = cmdLine.toString();
 			}
-			compileProcess = Runtime.getRuntime().exec(cmdLineAsString, null, directory);
+			compileProcess = Runtime.getRuntime().exec(cmdLineAsString, env, directory);
 			Logger errorLogger = new Logger(compileProcess.getErrorStream(),
 					"ERROR", log == null ? new StringBuffer() : log);
 			errorLogger.start();
@@ -306,7 +411,7 @@
 			cmdLine.append(options);
 			cmdLine.append(' ');
 			cmdLine.append(className);
-			executionProcess = Runtime.getRuntime().exec(cmdLine.toString(), null, directory);
+			executionProcess = Runtime.getRuntime().exec(cmdLine.toString(), env, directory);
 			Logger outputLogger = new Logger(executionProcess.getInputStream(),
 					"RUNTIME OUTPUT", stdout == null ? new StringBuffer() : stdout);
 			outputLogger.start();
@@ -1648,7 +1753,7 @@
 
 			// Launch process
 			compileProcess = Runtime.getRuntime().exec(
-				cmdLine.toString(), null, this.outputTestDirectory);
+				cmdLine.toString(), env, this.outputTestDirectory);
 
 			// Log errors
       Logger errorLogger = new Logger(compileProcess.getErrorStream(), "ERROR");
@@ -1713,7 +1818,7 @@
 						javaCmdLine.append(cp);
 						javaCmdLine.append(' ').append(testFiles[0].substring(0, testFiles[0].indexOf('.')));
 							// assume executable class is name of first test file - PREMATURE check if this is also the case in other test fwk classes
-						execProcess = Runtime.getRuntime().exec(javaCmdLine.toString(), null, this.outputTestDirectory);
+						execProcess = Runtime.getRuntime().exec(javaCmdLine.toString(), env, this.outputTestDirectory);
 						Logger logger = new Logger(execProcess.getInputStream(), "");
 						// PREMATURE implement consistent error policy
 	     				logger.start();
@@ -1802,7 +1907,7 @@
 			// Launch process
 			File currentDirectory = new File(currentDirectoryPath);
 			compileProcess = Runtime.getRuntime().exec(
-				cmdLine.toString(), null, currentDirectory);
+				cmdLine.toString(), env, currentDirectory);
 
 			// Log errors
 			Logger errorLogger = new Logger(compileProcess.getErrorStream(), "ERROR");
@@ -3277,6 +3382,10 @@
 		if (outputDir.exists()) {
 			Util.flushDirectoryContent(outputDir);
 		}
+		File libDir = new File(LIB_DIR);
+		if (libDir.exists()) {
+			Util.flushDirectoryContent(libDir);
+		}
 		super.tearDown();
 		if (RUN_JAVAC) {
 			if (JAVAC_OUTPUT_DIR.exists()) {
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AutomaticModuleNamingTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AutomaticModuleNamingTest.java
index 4f7bf13..4693025 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AutomaticModuleNamingTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/AutomaticModuleNamingTest.java
@@ -114,4 +114,9 @@
 				new String(determineAutomaticModuleNameFromFileName("CLASSES12.ZIP", true, true)));
 	}
 
+	public void testBug529680() throws Exception {
+		assertEquals("hibernate.jpa", new String(
+				determineAutomaticModuleNameFromFileName("hibernate-jpa-2.1-api-1.0.0.Final.jar", true, true)));
+	}
+
 }
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 9b7480b..ae3e920 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
@@ -914,7 +914,9 @@
 		expectedProblemAttributes.put("OuterLocalMustBeEffectivelyFinal", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
 		expectedProblemAttributes.put("OuterLocalMustBeFinal", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
 		expectedProblemAttributes.put("OverridingDeprecatedMethod", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
+		expectedProblemAttributes.put("OverridingDeprecatedSinceVersionMethod", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
 		expectedProblemAttributes.put("OverridingTerminallyDeprecatedMethod", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
+		expectedProblemAttributes.put("OverridingTerminallyDeprecatedSinceVersionMethod", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
 		expectedProblemAttributes.put("OverridingMethodWithoutSuperInvocation", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
 		expectedProblemAttributes.put("OverridingNonVisibleMethod", new ProblemAttributes(CategorizedProblem.CAT_NAME_SHADOWING_CONFLICT));
 		expectedProblemAttributes.put("PackageCollidesWithType", new ProblemAttributes(CategorizedProblem.CAT_TYPE));
@@ -1131,10 +1133,18 @@
 		expectedProblemAttributes.put("UsingDeprecatedField", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
 		expectedProblemAttributes.put("UsingDeprecatedMethod", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
 		expectedProblemAttributes.put("UsingDeprecatedType", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
+		expectedProblemAttributes.put("UsingDeprecatedSinceVersionConstructor", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
+		expectedProblemAttributes.put("UsingDeprecatedSinceVersionField", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
+		expectedProblemAttributes.put("UsingDeprecatedSinceVersionMethod", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
+		expectedProblemAttributes.put("UsingDeprecatedSinceVersionType", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
 		expectedProblemAttributes.put("UsingTerminallyDeprecatedConstructor", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
 		expectedProblemAttributes.put("UsingTerminallyDeprecatedField", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
 		expectedProblemAttributes.put("UsingTerminallyDeprecatedMethod", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
 		expectedProblemAttributes.put("UsingTerminallyDeprecatedType", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
+		expectedProblemAttributes.put("UsingTerminallyDeprecatedSinceVersionConstructor", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
+		expectedProblemAttributes.put("UsingTerminallyDeprecatedSinceVersionField", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
+		expectedProblemAttributes.put("UsingTerminallyDeprecatedSinceVersionMethod", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
+		expectedProblemAttributes.put("UsingTerminallyDeprecatedSinceVersionType", new ProblemAttributes(CategorizedProblem.CAT_DEPRECATION));
 		expectedProblemAttributes.put("VarIsNotAllowedHere", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
 		expectedProblemAttributes.put("VarIsReserved", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
 		expectedProblemAttributes.put("VarIsReservedInFuture", new ProblemAttributes(CategorizedProblem.CAT_SYNTAX));
@@ -1811,7 +1821,9 @@
 		expectedProblemAttributes.put("OuterLocalMustBeEffectivelyFinal", SKIP);
 		expectedProblemAttributes.put("OuterLocalMustBeFinal", SKIP);
 		expectedProblemAttributes.put("OverridingDeprecatedMethod", new ProblemAttributes(JavaCore.COMPILER_PB_DEPRECATION));
+		expectedProblemAttributes.put("OverridingDeprecatedSinceVersionMethod", new ProblemAttributes(JavaCore.COMPILER_PB_DEPRECATION));
 		expectedProblemAttributes.put("OverridingTerminallyDeprecatedMethod", new ProblemAttributes(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION));
+		expectedProblemAttributes.put("OverridingTerminallyDeprecatedSinceVersionMethod", new ProblemAttributes(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION));
 		expectedProblemAttributes.put("OverridingMethodWithoutSuperInvocation", new ProblemAttributes(JavaCore.COMPILER_PB_OVERRIDING_METHOD_WITHOUT_SUPER_INVOCATION));
 		expectedProblemAttributes.put("OverridingNonVisibleMethod", new ProblemAttributes(JavaCore.COMPILER_PB_OVERRIDING_PACKAGE_DEFAULT_METHOD));
 		expectedProblemAttributes.put("PackageCollidesWithType", SKIP);
@@ -2028,10 +2040,18 @@
 		expectedProblemAttributes.put("UsingDeprecatedField", new ProblemAttributes(JavaCore.COMPILER_PB_DEPRECATION));
 		expectedProblemAttributes.put("UsingDeprecatedMethod", new ProblemAttributes(JavaCore.COMPILER_PB_DEPRECATION));
 		expectedProblemAttributes.put("UsingDeprecatedType", new ProblemAttributes(JavaCore.COMPILER_PB_DEPRECATION));
+		expectedProblemAttributes.put("UsingDeprecatedSinceVersionConstructor", new ProblemAttributes(JavaCore.COMPILER_PB_DEPRECATION));
+		expectedProblemAttributes.put("UsingDeprecatedSinceVersionField", new ProblemAttributes(JavaCore.COMPILER_PB_DEPRECATION));
+		expectedProblemAttributes.put("UsingDeprecatedSinceVersionMethod", new ProblemAttributes(JavaCore.COMPILER_PB_DEPRECATION));
+		expectedProblemAttributes.put("UsingDeprecatedSinceVersionType", new ProblemAttributes(JavaCore.COMPILER_PB_DEPRECATION));
 		expectedProblemAttributes.put("UsingTerminallyDeprecatedConstructor", new ProblemAttributes(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION));
 		expectedProblemAttributes.put("UsingTerminallyDeprecatedField", new ProblemAttributes(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION));
 		expectedProblemAttributes.put("UsingTerminallyDeprecatedMethod", new ProblemAttributes(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION));
 		expectedProblemAttributes.put("UsingTerminallyDeprecatedType", new ProblemAttributes(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION));
+		expectedProblemAttributes.put("UsingTerminallyDeprecatedSinceVersionConstructor", new ProblemAttributes(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION));
+		expectedProblemAttributes.put("UsingTerminallyDeprecatedSinceVersionField", new ProblemAttributes(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION));
+		expectedProblemAttributes.put("UsingTerminallyDeprecatedSinceVersionMethod", new ProblemAttributes(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION));
+		expectedProblemAttributes.put("UsingTerminallyDeprecatedSinceVersionType", new ProblemAttributes(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION));
 		expectedProblemAttributes.put("VarargsConflict", SKIP);
 		expectedProblemAttributes.put("VarargsElementTypeNotVisible", SKIP);
 		expectedProblemAttributes.put("VarargsElementTypeNotVisibleForConstructor", SKIP);
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/Deprecated9Test.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/Deprecated9Test.java
index 027b98e..0b10539 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/Deprecated9Test.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/Deprecated9Test.java
@@ -64,7 +64,7 @@
 			"1. ERROR in p\\M1.java (at line 4)\n" +
 			"	a.N1.N2.N3 m = null;\n" +
 			"	     ^^\n" +
-			"The type N1.N2 has been deprecated and marked for removal\n" +
+			"The type N1.N2 has been deprecated since version 1.2 and marked for removal\n" +
 			"----------\n" +
 			"2. ERROR in p\\M1.java (at line 4)\n" +
 			"	a.N1.N2.N3 m = null;\n" +
@@ -78,6 +78,61 @@
 			"----------\n",
 			JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
 	}
+	public void test002binary() {
+		Runner runner = new Runner();
+		runner.customOptions = new HashMap<>();
+		runner.customOptions.put(JavaCore.COMPILER_PB_DEPRECATION, CompilerOptions.WARNING);
+		runner.customOptions.put(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION, CompilerOptions.ERROR);
+		runner.customOptions.put(CompilerOptions.OPTION_ReportNullReference, CompilerOptions.IGNORE);
+		runner.testFiles =
+			new String[] {
+				"a/N1.java",
+				"package a;\n" +
+				"public class N1 {\n" +
+				"  @Deprecated(since=\"1.2\",forRemoval=true)\n" +
+				"  public class N2 {" +
+				"    public void foo() {}" +
+				"    public class N3 {" +
+				"      public void foo() {}" +
+				"    }" +
+				"  }" +
+				"}\n"
+			};
+		runner.runConformTest();
+
+		runner.shouldFlushOutputDirectory = false;
+		runner.testFiles =
+			new String[] {
+				"p/M1.java",
+				"package p;\n" +
+				"public class M1 {\n" +
+				"  void bar() {\n" +
+				"    a.N1.N2.N3 m = null;\n" +
+				"    m.foo();\n" +
+				"  }\n" +
+				"}\n"
+			};
+		runner.expectedCompilerLog =
+			"----------\n" +
+			"1. ERROR in p\\M1.java (at line 4)\n" +
+			"	a.N1.N2.N3 m = null;\n" +
+			"	     ^^\n" +
+			"The type N1.N2 has been deprecated since version 1.2 and marked for removal\n" +
+			"----------\n" +
+			"2. ERROR in p\\M1.java (at line 4)\n" +
+			"	a.N1.N2.N3 m = null;\n" +
+			"	        ^^\n" +
+			"The type N1.N2.N3 has been deprecated and marked for removal\n" +
+			"----------\n" +
+			"3. ERROR in p\\M1.java (at line 5)\n" +
+			"	m.foo();\n" +
+			"	  ^^^^^\n" +
+			"The method foo() from the type N1.N2.N3 has been deprecated and marked for removal\n" +
+			"----------\n";
+		runner.javacTestOptions =
+			JavacTestOptions.Excuse.EclipseWarningConfiguredAsError;
+		runner.runNegativeTest();
+	}
 	//https://bugs.eclipse.org/bugs/show_bug.cgi?id=191909
 	public void test004() {
 		Map<String, String> customOptions = new HashMap<>();
@@ -106,12 +161,12 @@
 			"1. ERROR in test1\\E02.java (at line 4)\n" +
 			"	System.out.println(E01.x);\n" +
 			"	                       ^\n" +
-			"The field E01.x has been deprecated and marked for removal\n" +
+			"The field E01.x has been deprecated since version 3 and marked for removal\n" +
 			"----------\n" +
 			"2. ERROR in test1\\E02.java (at line 5)\n" +
 			"	System.out.println(E01.y);\n" +
 			"	                       ^\n" +
-			"The field E01.y has been deprecated and marked for removal\n" +
+			"The field E01.y has been deprecated since version 3 and marked for removal\n" +
 			"----------\n",
 			JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
 	}
@@ -160,8 +215,6 @@
 			"----------\n",
 			JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
 	}
-	// Bug 354536 - compiling package-info.java still depends on the order of compilation units
-	// - option is disabled
 	public void test005b() {
 		Map<String, String> customOptions = new HashMap<>();
 		customOptions.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
@@ -188,14 +241,12 @@
 			},
 			customOptions);
 	}
-	// Bug 354536 - compiling package-info.java still depends on the order of compilation units
-	// some warnings suppressed
 	public void test005c() {
-		Map<String, String> customOptions = new HashMap<>();
-		customOptions.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
-		customOptions.put(CompilerOptions.OPTION_ReportTerminalDeprecation, CompilerOptions.WARNING);
-		this.runNegativeTest(
-			true,
+		Runner runner = new Runner();
+		runner.customOptions = new HashMap<>();
+		runner.customOptions.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
+		runner.customOptions.put(CompilerOptions.OPTION_ReportTerminalDeprecation, CompilerOptions.WARNING);
+		runner.testFiles =
 			new String[] {
 				"p1/X.java",
 				"package p1;\n" +
@@ -216,24 +267,22 @@
 				"        a.foo();\n" +
 				"    }\n" +
 				"}\n",
-			},
-			null, customOptions,
+			};
+		runner.expectedCompilerLog =
 			"----------\n" +
 			"1. WARNING in p2\\C.java (at line 5)\n" + 
 			"	a.foo();\n" + 
 			"	  ^^^^^\n" + 
 			"The method foo() from the type X.Inner has been deprecated and marked for removal\n" + 
-			"----------\n",
-			JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
+			"----------\n";
+		runner.runWarningTest();
 	}
-	// https://bugs.eclipse.org/384870 - [compiler] @Deprecated annotation not detected if preceded by other annotation
-	// old-style deprecation
 	public void test006() {
-		Map<String, String> customOptions = new HashMap<>();
-		customOptions.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
-		customOptions.put(CompilerOptions.OPTION_ReportTerminalDeprecation, CompilerOptions.ERROR);
-		this.runNegativeTest(
-			true,
+		Runner runner = new Runner();
+		runner.customOptions = new HashMap<>();
+		runner.customOptions.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
+		runner.customOptions.put(CompilerOptions.OPTION_ReportTerminalDeprecation, CompilerOptions.ERROR);
+		runner.testFiles =
 			new String[] {
 				"test1/E02.java",
 				"package test1;\n" +
@@ -248,15 +297,15 @@
 				"public class E01 {\n" +
 				"	public static int x = 5;\n" +
 				"}"
-			},
-			null, customOptions,
+			};
+		runner.expectedCompilerLog =
 			"----------\n" + 
 			"1. WARNING in test1\\E02.java (at line 3)\n" + 
 			"	public void foo(E01 arg) {\n" + 
 			"	                ^^^\n" + 
-			"The type E01 is deprecated\n" + 
-			"----------\n",
-			JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
+			"The type E01 is deprecated since version 4\n" + 
+			"----------\n";
+		runner.runWarningTest();
 	}
 	// method overriding
 	public void test007() {
@@ -297,7 +346,239 @@
 			"----------\n",
 			JavacTestOptions.Excuse.EclipseWarningConfiguredAsError);
 	}
+	public void testSinceSource() {
+		Runner runner = new Runner();
+		runner.customOptions = new HashMap<>();
+		runner.customOptions.put(JavaCore.COMPILER_PB_DEPRECATION, CompilerOptions.WARNING);
+		runner.customOptions.put(JavaCore.COMPILER_PB_DEPRECATION_WHEN_OVERRIDING_DEPRECATED_METHOD, CompilerOptions.ENABLED);
+		runner.customOptions.put(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION, CompilerOptions.ERROR);
+		runner.testFiles =
+			new String[] {
+				"test1/E01.java",
+				"package test1;\n" +
+				"public class E01 {\n" +
+				"	@Deprecated(since=\"1.0\") protected static class Old {}\n" +
+				"	@Deprecated(since=\"2\") public static int x = 5, y= 10;\n" +
+				"	@Deprecated(since=\"3.0.0\") public E01() {}\n" +
+				"	@Deprecated(since=\"4-SNAPSHOT\") protected void old() {}\n" +
+				"}",
+				"test1/E02.java",
+				"package test1;\n" +
+				"public class E02 {\n" +
+				"	public void foo() {\n" +
+				"		System.out.println(new E01.Old());\n" +
+				"		E01 e = new E01();\n" +
+				"		e.old();\n" +
+				"		System.out.println(E01.x);\n" +
+				"		System.out.println(E01.y);\n" +
+				"	}\n" +
+				"	class E03 extends E01 {\n" +
+				"		protected void old() {}\n" +
+				"	}\n" +
+				"}"
+			};
+		runner.expectedCompilerLog =
+			"----------\n" + 
+			"1. WARNING in test1\\E02.java (at line 4)\n" + 
+			"	System.out.println(new E01.Old());\n" + 
+			"	                       ^^^^^^^^^\n" + 
+			"The constructor E01.Old() is deprecated since version 1.0\n" + 
+			"----------\n" + 
+			"2. WARNING in test1\\E02.java (at line 4)\n" + 
+			"	System.out.println(new E01.Old());\n" + 
+			"	                           ^^^\n" + 
+			"The type E01.Old is deprecated since version 1.0\n" + 
+			"----------\n" + 
+			"3. WARNING in test1\\E02.java (at line 5)\n" + 
+			"	E01 e = new E01();\n" + 
+			"	            ^^^^^\n" + 
+			"The constructor E01() is deprecated since version 3.0.0\n" + 
+			"----------\n" + 
+			"4. WARNING in test1\\E02.java (at line 6)\n" + 
+			"	e.old();\n" + 
+			"	  ^^^^^\n" + 
+			"The method old() from the type E01 is deprecated since version 4-SNAPSHOT\n" + 
+			"----------\n" + 
+			"5. WARNING in test1\\E02.java (at line 7)\n" + 
+			"	System.out.println(E01.x);\n" + 
+			"	                       ^\n" + 
+			"The field E01.x is deprecated since version 2\n" + 
+			"----------\n" + 
+			"6. WARNING in test1\\E02.java (at line 8)\n" + 
+			"	System.out.println(E01.y);\n" + 
+			"	                       ^\n" + 
+			"The field E01.y is deprecated since version 2\n" + 
+			"----------\n" + 
+			"7. WARNING in test1\\E02.java (at line 10)\n" + 
+			"	class E03 extends E01 {\n" + 
+			"	      ^^^\n" + 
+			"The constructor E01() is deprecated since version 3.0.0\n" + 
+			"----------\n" + 
+			"8. WARNING in test1\\E02.java (at line 11)\n" + 
+			"	protected void old() {}\n" + 
+			"	               ^^^^^\n" + 
+			"The method E02.E03.old() overrides a method from E01 that is deprecated since version 4-SNAPSHOT\n" + 
+			"----------\n";
+		runner.runWarningTest();
+	}
+	public void testSinceBinary() {
+		Runner runner = new Runner();
+		runner.customOptions = new HashMap<>();
+		runner.customOptions.put(JavaCore.COMPILER_PB_DEPRECATION, CompilerOptions.WARNING);
+		runner.customOptions.put(JavaCore.COMPILER_PB_DEPRECATION_WHEN_OVERRIDING_DEPRECATED_METHOD, CompilerOptions.ENABLED);
+		runner.customOptions.put(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION, CompilerOptions.ERROR);
+		runner.testFiles =
+			new String[] {
+				"test1/E01.java",
+				"package test1;\n" +
+				"public class E01 {\n" +
+				"	@Deprecated(since=\"1.0\") protected static class Old {}\n" +
+				"	@Deprecated(since=\"2\") public static int x = 5, y= 10;\n" +
+				"	@Deprecated(since=\"3.0.0\") public E01() {}\n" +
+				"	@Deprecated(since=\"4-SNAPSHOT\") protected void old() {}\n" +
+				"}"
+			};
+		runner.runConformTest();
 
+		runner.shouldFlushOutputDirectory = false;
+		runner.testFiles =
+			new String[] {
+				"test1/E02.java",
+				"package test1;\n" +
+				"public class E02 {\n" +
+				"	public void foo() {\n" +
+				"		System.out.println(new E01.Old());\n" +
+				"		E01 e = new E01();\n" +
+				"		e.old();\n" +
+				"		System.out.println(E01.x);\n" +
+				"		System.out.println(E01.y);\n" +
+				"	}\n" +
+				"	class E03 extends E01 {\n" +
+				"		protected void old() {}\n" +
+				"	}\n" +
+				"}"
+			};
+		runner.expectedCompilerLog =
+			"----------\n" + 
+			"1. WARNING in test1\\E02.java (at line 4)\n" + 
+			"	System.out.println(new E01.Old());\n" + 
+			"	                       ^^^^^^^^^\n" + 
+			"The constructor E01.Old() is deprecated since version 1.0\n" + 
+			"----------\n" + 
+			"2. WARNING in test1\\E02.java (at line 4)\n" + 
+			"	System.out.println(new E01.Old());\n" + 
+			"	                           ^^^\n" + 
+			"The type E01.Old is deprecated since version 1.0\n" + 
+			"----------\n" + 
+			"3. WARNING in test1\\E02.java (at line 5)\n" + 
+			"	E01 e = new E01();\n" + 
+			"	            ^^^^^\n" + 
+			"The constructor E01() is deprecated since version 3.0.0\n" + 
+			"----------\n" + 
+			"4. WARNING in test1\\E02.java (at line 6)\n" + 
+			"	e.old();\n" + 
+			"	  ^^^^^\n" + 
+			"The method old() from the type E01 is deprecated since version 4-SNAPSHOT\n" + 
+			"----------\n" + 
+			"5. WARNING in test1\\E02.java (at line 7)\n" + 
+			"	System.out.println(E01.x);\n" + 
+			"	                       ^\n" + 
+			"The field E01.x is deprecated since version 2\n" + 
+			"----------\n" + 
+			"6. WARNING in test1\\E02.java (at line 8)\n" + 
+			"	System.out.println(E01.y);\n" + 
+			"	                       ^\n" + 
+			"The field E01.y is deprecated since version 2\n" + 
+			"----------\n" + 
+			"7. WARNING in test1\\E02.java (at line 10)\n" + 
+			"	class E03 extends E01 {\n" + 
+			"	      ^^^\n" + 
+			"The constructor E01() is deprecated since version 3.0.0\n" + 
+			"----------\n" + 
+			"8. WARNING in test1\\E02.java (at line 11)\n" + 
+			"	protected void old() {}\n" + 
+			"	               ^^^^^\n" + 
+			"The method E02.E03.old() overrides a method from E01 that is deprecated since version 4-SNAPSHOT\n" + 
+			"----------\n";
+		runner.runWarningTest();
+	}
+	public void testSinceTerminally() {
+		Runner runner = new Runner();
+		runner.customOptions = new HashMap<>();
+		runner.customOptions.put(JavaCore.COMPILER_PB_DEPRECATION, CompilerOptions.WARNING);
+		runner.customOptions.put(JavaCore.COMPILER_PB_DEPRECATION_WHEN_OVERRIDING_DEPRECATED_METHOD, CompilerOptions.ENABLED);
+		runner.customOptions.put(JavaCore.COMPILER_PB_TERMINAL_DEPRECATION, CompilerOptions.ERROR);
+		runner.testFiles =
+			new String[] {
+				"test1/E01.java",
+				"package test1;\n" +
+				"public class E01 {\n" +
+				"	@Deprecated(since=\"1.0\", forRemoval=true) protected static class Old {}\n" +
+				"	@Deprecated(since=\"2\", forRemoval=true) public static int x = 5, y= 10;\n" +
+				"	@Deprecated(since=\"3.0.0\", forRemoval=true) public E01() {}\n" +
+				"	@Deprecated(since=\"4-SNAPSHOT\", forRemoval=true) protected void old() {}\n" +
+				"}",
+				"test1/E02.java",
+				"package test1;\n" +
+				"public class E02 {\n" +
+				"	public void foo() {\n" +
+				"		System.out.println(new E01.Old());\n" +
+				"		E01 e = new E01();\n" +
+				"		e.old();\n" +
+				"		System.out.println(E01.x);\n" +
+				"		System.out.println(E01.y);\n" +
+				"	}\n" +
+				"	class E03 extends E01 {\n" +
+				"		protected void old() {}\n" +
+				"	}\n" +
+				"}"
+			};
+		runner.expectedCompilerLog =
+			"----------\n" + 
+			"1. ERROR in test1\\E02.java (at line 4)\n" + 
+			"	System.out.println(new E01.Old());\n" + 
+			"	                       ^^^^^^^^^\n" + 
+			"The constructor E01.Old() has been deprecated since version 1.0 and marked for removal\n" + 
+			"----------\n" + 
+			"2. ERROR in test1\\E02.java (at line 4)\n" + 
+			"	System.out.println(new E01.Old());\n" + 
+			"	                           ^^^\n" + 
+			"The type E01.Old has been deprecated since version 1.0 and marked for removal\n" + 
+			"----------\n" + 
+			"3. ERROR in test1\\E02.java (at line 5)\n" + 
+			"	E01 e = new E01();\n" + 
+			"	            ^^^^^\n" + 
+			"The constructor E01() has been deprecated since version 3.0.0 and marked for removal\n" + 
+			"----------\n" + 
+			"4. ERROR in test1\\E02.java (at line 6)\n" + 
+			"	e.old();\n" + 
+			"	  ^^^^^\n" + 
+			"The method old() from the type E01 has been deprecated since version 4-SNAPSHOT and marked for removal\n" + 
+			"----------\n" + 
+			"5. ERROR in test1\\E02.java (at line 7)\n" + 
+			"	System.out.println(E01.x);\n" + 
+			"	                       ^\n" + 
+			"The field E01.x has been deprecated since version 2 and marked for removal\n" + 
+			"----------\n" + 
+			"6. ERROR in test1\\E02.java (at line 8)\n" + 
+			"	System.out.println(E01.y);\n" + 
+			"	                       ^\n" + 
+			"The field E01.y has been deprecated since version 2 and marked for removal\n" + 
+			"----------\n" + 
+			"7. ERROR in test1\\E02.java (at line 10)\n" + 
+			"	class E03 extends E01 {\n" + 
+			"	      ^^^\n" + 
+			"The constructor E01() has been deprecated since version 3.0.0 and marked for removal\n" + 
+			"----------\n" + 
+			"8. ERROR in test1\\E02.java (at line 11)\n" + 
+			"	protected void old() {}\n" + 
+			"	               ^^^^^\n" + 
+			"The method E02.E03.old() overrides a method from E01 that has been deprecated since version 4-SNAPSHOT and marked for removal\n" + 
+			"----------\n";
+		runner.javacTestOptions =
+			JavacTestOptions.Excuse.EclipseWarningConfiguredAsError;
+		runner.runNegativeTest();
+	}
 	public static Class<?> testClass() {
 		return Deprecated9Test.class;
 	}
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/DeprecatedTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/DeprecatedTest.java
index f59d3c3..c75a8b5 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/DeprecatedTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/DeprecatedTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -10,22 +10,70 @@
  *******************************************************************************/
 package org.eclipse.jdt.core.tests.compiler.regression;
 
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.tests.util.Util;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
+import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 
 import junit.framework.Test;
 
 @SuppressWarnings({ "unchecked", "rawtypes" })
 public class DeprecatedTest extends AbstractRegressionTest {
+
+static {
+//	TESTS_NAMES = new String[] { "test008a" };
+}
+
+protected char[][] invisibleType;
+
 public DeprecatedTest(String name) {
 	super(name);
 }
 public static Test suite() {
 	return buildAllCompliancesTestSuite(testClass());
 }
+
+@Override
+protected void tearDown() throws Exception {
+	this.invisibleType = null;
+	super.tearDown();
+}
+
+@Override
+protected INameEnvironment getNameEnvironment(final String[] testFiles, String[] classPaths) {
+	// constructs a name environment that is able to hide a type of name 'this.invisibleType':
+	this.classpaths = classPaths == null ? getDefaultClassPaths() : classPaths;
+	return new InMemoryNameEnvironment(testFiles, getClassLibs(classPaths == null)) {
+		@Override
+		public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
+			if (DeprecatedTest.this.invisibleType != null && CharOperation.equals(DeprecatedTest.this.invisibleType, compoundTypeName))
+				return null;
+			return super.findType(compoundTypeName);
+		}
+		@Override
+		public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
+			if (DeprecatedTest.this.invisibleType != null && DeprecatedTest.this.invisibleType.length == packageName.length+1) {
+				char[][] packName = CharOperation.subarray(DeprecatedTest.this.invisibleType, 0, DeprecatedTest.this.invisibleType.length-1);
+				if (CharOperation.equals(packageName, packName)) {
+					char[] simpleName = DeprecatedTest.this.invisibleType[DeprecatedTest.this.invisibleType.length-1];
+					if (CharOperation.equals(simpleName, typeName))
+						return null;
+				}
+			}
+			return super.findType(typeName, packageName);
+		}
+	};
+}
+
 public void test001() {
 	this.runNegativeTest(new String[] {
 		"p/B.java",
@@ -316,6 +364,47 @@
 		false, // flush previous output dir content
 		null);  // custom options
 }
+// variation of test008 on behalf of Bug 526335 - [9][hovering] Deprecation warning should show the new 'since' deprecation value
+// verify that we don't attempt to access java.lang.Deprecated in a 1.4 based compilation.
+public void test008a() throws IOException {
+	String jarPath = LIB_DIR+File.separator+"p008"+File.separator+"x.jar";
+	Util.createJar(new String[] {
+			"X.java",
+			"package p008;\n" +
+			"@Deprecated\n" +
+			"public class X {\n" +
+			"}\n",
+		},
+		jarPath,
+		"1.5");
+
+	Runner runner = new Runner();
+	runner.testFiles =
+		new String[] {
+			"Y.java",
+			"public class Y {\n" +
+			"  void foo() {\n" +
+			"    p008.X x;\n" +
+			"  }\n" +
+			"}\n",
+		};
+	String[] libs = getDefaultClassPaths();
+	libs = Arrays.copyOf(libs, libs.length+1);
+	libs[libs.length-1] = jarPath;
+	runner.classLibraries = libs;
+	runner.expectedCompilerLog =
+		"----------\n" +
+		"1. WARNING in Y.java (at line 3)\n" + 
+		"	p008.X x;\n" + 
+		"	     ^\n" + 
+		"The type X is deprecated\n" + 
+		"----------\n";
+	if (this.complianceLevel < ClassFileConstants.JDK1_5) {
+		// simulate we were running on a JRE without java.lang.Deprecated
+		this.invisibleType = TypeConstants.JAVA_LANG_DEPRECATED;
+	}
+	runner.runWarningTest();
+}
 //https://bugs.eclipse.org/bugs/show_bug.cgi?id=88124 - variation
 public void test009() {
 	this.runNegativeTest(
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 59ae369..89fa5fc 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
@@ -39798,24 +39798,11 @@
 			"}\n", // =================
 		},
 		// compiler results
-		this.complianceLevel < ClassFileConstants.JDK1_8 ? 
 		"----------\n" + /* expected compiler log */
 		"1. ERROR in X.java (at line 5)\n" +
 		"	return compound(asList(a, b));\n" +
 		"	       ^^^^^^^^\n" +
 		"The method compound(Iterable<? extends Comparator<? super T>>) in the type X is not applicable for the arguments (List<Comparator<? extends Object>>)\n" +
-		"----------\n"
-		// 1.8+ ATM, we generate an extra error due to inner poly expression evaluation.
-		:"----------\n" + 
-		"1. ERROR in X.java (at line 5)\n" + 
-		"	return compound(asList(a, b));\n" + 
-		"	       ^^^^^^^^\n" + 
-		"The method compound(Iterable<? extends Comparator<? super T>>) in the type X is not applicable for the arguments (List<Comparator<? extends Object>>)\n" + 
-		"----------\n" + 
-		"2. ERROR in X.java (at line 5)\n" + 
-		"	return compound(asList(a, b));\n" + 
-		"	                ^^^^^^^^^^^^\n" + 
-		"Type mismatch: cannot convert from List<Comparator<? extends Object>> to Iterable<? extends Comparator<? super T>>\n" + 
 		"----------\n",
 		// javac options
 		JavacTestOptions.JavacHasABug.JavacBug6573446 /* javac test options */);
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
index 9b05540..d6409a5 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericsRegressionTest_1_8.java
@@ -1235,12 +1235,7 @@
 		"	^^^^^^^^^^^^\n" + 
 		"The method addAttribute(Test.Attribute<T>, T) in the type Test is not applicable for the arguments (Test.Attribute<capture#1-of ?>, capture#2-of ?)\n" + 
 		"----------\n" + 
-		"2. ERROR in Test.java (at line 3)\n" + 
-		"	addAttribute(java.util.Objects.requireNonNull(attribute, \"\"),\n" + 
-		"	             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
-		"Type mismatch: cannot convert from Test.Attribute<capture#1-of ?> to Test.Attribute<T>\n" + 
-		"----------\n" + 
-		"3. ERROR in Test.java (at line 5)\n" + 
+		"2. ERROR in Test.java (at line 5)\n" + 
 		"	addAttribute(attribute, attribute.getDefault());\n" + 
 		"	^^^^^^^^^^^^\n" + 
 		"The method addAttribute(Test.Attribute<T>, T) in the type Test is not applicable for the arguments (Test.Attribute<capture#3-of ?>, capture#4-of ?)\n" + 
@@ -7011,11 +7006,6 @@
 		"	Stuff.func(Comparator.naturalOrder());\n" + 
 		"	      ^^^^\n" + 
 		"The method func(Comparator<T>) in the type Stuff is not applicable for the arguments (Comparator<Comparable<Comparable<B>>>)\n" + 
-		"----------\n" + 
-		"2. ERROR in makeCompilerFreeze\\EclipseJava8Bug.java (at line 20)\n" + 
-		"	Stuff.func(Comparator.naturalOrder());\n" + 
-		"	           ^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
-		"Type mismatch: cannot convert from Comparator<Comparable<Comparable<B>>> to Comparator<T>\n" + 
 		"----------\n"
 	);
 }
@@ -8540,4 +8530,40 @@
 			"Type safety: The expression of type Action[] needs unchecked conversion to conform to Action<S2>[]\n" + 
 			"----------\n");
 	}
+	public void testBug519147() {
+		runConformTest(
+			new String[] {
+				"Main.java",
+				"import java.util.HashMap;\n" + 
+				"import java.util.HashSet;\n" + 
+				"import java.util.Set;\n" + 
+				"\n" + 
+				"public class Main<MyKey, MyValue> {\n" + 
+				"\n" + 
+				"    static class MyMap<K, V> extends HashMap<K, V> {\n" + 
+				"        public MyMap<K, V> putAllReturning(MyMap<K, V> c) { putAll(c); return this; }\n" + 
+				"        public MyMap<K, V> putReturning(K key, V value) { put(key, value); return this; }\n" + 
+				"    }\n" + 
+				"\n" + 
+				"    public Main() {\n" + 
+				"        Set<MyValue> values = new HashSet<>(); // actually something better\n" + 
+				"        final MyMap<MyKey, MyValue> myMap =\n" + 
+				"                values.stream()\n" + 
+				"                    .reduce(\n" + 
+				"                        new MyMap<MyKey, MyValue>(),\n" + 
+				"                        (map, value) -> {\n" + 
+				"                            Set<MyKey> keys = new HashSet<>(); // actually something better\n" + 
+				"\n" + 
+				"                            return keys.stream()\n" + 
+				"                                .reduce(\n" + 
+				"                                    map, // this would work syntactically: new MyMap<MyKey, MyValue>(),\n" + 
+				"                                    (map2, key) -> map2.putReturning(key, value),\n" + 
+				"                                    MyMap::putAllReturning);\n" + 
+				"                        },\n" + 
+				"                        MyMap::putAllReturning\n" + 
+				"                    );\n" + 
+				"    }\n" + 
+				"}\n"
+			});
+	}
 }
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InnerClass15Test.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InnerClass15Test.java
index da87c14..c1d45d1 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InnerClass15Test.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/InnerClass15Test.java
@@ -708,6 +708,54 @@
 		"Cycle detected: a cycle exists in the type hierarchy between A and C\n" + 
 		"----------\n");
 }
+public void testBug526681() {
+	runNegativeTest(
+		new String[] {
+			"p/A.java",
+			"package p;\n" +
+			"import p.B;\n" +
+			"public class A extends B {\n" +
+			"	public static abstract class C {}\n" +
+			"}\n",
+			"p/B.java",
+			"package p;\n" +
+			"import p.A.C;\n" +
+			"public abstract class B extends C {}"
+		},
+		"----------\n" + 
+		"1. ERROR in p\\A.java (at line 3)\n" + 
+		"	public class A extends B {\n" + 
+		"	             ^\n" + 
+		"The hierarchy of the type A is inconsistent\n" + 
+		"----------\n" + 
+		"----------\n" + 
+		"1. ERROR in p\\B.java (at line 3)\n" + 
+		"	public abstract class B extends C {}\n" + 
+		"	                                ^\n" + 
+		"Cycle detected: a cycle exists in the type hierarchy between B and A\n" + 
+		"----------\n");
+}
+public void testBug527731() {
+	if (this.complianceLevel < ClassFileConstants.JDK1_8) return; // uses diamond, 1.7-inference fails, only 1.8 is good
+	runConformTest(
+		new String[] {
+			"OuterClass.java",
+			"import java.util.ArrayList;\n" + 
+			"\n" + 
+			"public class OuterClass<T> extends ArrayList<OuterClass.InnerTypedClass<T>> {\n" + 
+			"	\n" + 
+			"	public static interface InnerInterface {}\n" + 
+			"	\n" + 
+			"	public static class InnerTypedClass<T> implements InnerInterface {}\n" + 
+			"	\n" + 
+			"	public static void main(String[] args) {\n" + 
+			"		OuterClass<String> outerClass = new OuterClass<>();\n" + 
+			"		outerClass.add(new InnerTypedClass<>());\n" + 
+			"		System.out.println(outerClass);\n" + 
+			"	}\n" + 
+			"}\n"
+		});
+}
 public static Class<InnerClass15Test> testClass() {
 	return InnerClass15Test.class;
 }
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 31de767..a3948b4 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
@@ -6905,8 +6905,8 @@
 		"----------\n" + 
 		"1. ERROR in BuildIdeMain.java (at line 9)\n" + 
 		"	filter2.map(p -> new SimpleEntry<>(updateToFile.get(p), p->ideFiles.get(p)));\n" + 
-		"	                                                        ^^^^^^^^^^^^^^^^^^\n" + 
-		"The target type of this expression must be a functional interface\n" + 
+		"	                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
+		"Cannot infer type arguments for SimpleEntry<>\n" + 
 		"----------\n");
 }
 public void testBug445227() {
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/LocalVMLauncher.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/LocalVMLauncher.java
index 4595280..484c911 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/LocalVMLauncher.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/runtime/LocalVMLauncher.java
@@ -30,6 +30,11 @@
 @SuppressWarnings({ "unchecked", "rawtypes" })
 public abstract class LocalVMLauncher implements RuntimeConstants {
 
+	static final String[] env = System.getenv().entrySet().stream()
+		.filter(e -> !"JAVA_TOOL_OPTIONS".equals(e.getKey()))
+		.map(e -> e.getKey() + "=" + e.getValue())
+		.toArray(String[]::new);
+
 	/**
 	 * Whether the target has a file system and thus whether it supports writing
 	 * class files to disk. See org.eclipse.jdt.core.tests.eval.target.CodeSnippetRunner for more
@@ -130,7 +135,7 @@
 		// Use Runtime.exec(String[]) with tokens because Runtime.exec(String) with commandLineString
 		// does not properly handle spaces in arguments on Unix/Linux platforms.
 		String[] commandLine = getCommandLine();
-		vmProcess= Runtime.getRuntime().exec(commandLine);
+		vmProcess= Runtime.getRuntime().exec(commandLine, env);
 	} catch (IOException e) {
 		throw new TargetException("Error launching VM at " + this.vmPath);
 	}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava9Tests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava9Tests.java
index 15566b2..56e6a51 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava9Tests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/RunAllJava9Tests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2016, 2017 IBM Corporation and others.
+ * Copyright (c) 2016, 2018 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
@@ -20,6 +20,7 @@
 import org.eclipse.jdt.core.tests.model.JavaConventionTests;
 import org.eclipse.jdt.core.tests.model.JavaSearchBugs9Tests;
 import org.eclipse.jdt.core.tests.model.ModuleBuilderTests;
+import org.eclipse.jdt.core.tests.model.ModuleOptionsTests;
 import org.eclipse.jdt.core.tests.model.ResolveTests9;
 import org.eclipse.jdt.core.tests.util.AbstractCompilerTest;
 
@@ -36,6 +37,7 @@
 	public static Class[] getAllTestClasses() {
 		return new Class[] {
 			ModuleBuilderTests.class,
+			ModuleOptionsTests.class,
 			Java9ElementTests.class,
 			JavaSearchBugs9Tests.class,
 			CompletionTests9.class,
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 57c65ed..ff5c1bd 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -3258,6 +3258,10 @@
 			new CompilerOptions(options).toString());
 	}
 
+	protected IPath getJRE9Path() {
+		return new Path(System.getProperty("java.home") + "/lib/jrt-fs.jar");
+	}
+
 	/**
 	 * Wait for autobuild notification to occur
 	 */
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java
index 4c19df1..c2ff7ff 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AllJavaModelTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -47,6 +47,7 @@
 		JavaProjectTests.class,
 		// Modularity tests (Java 9)
 		ModuleBuilderTests.class,
+		ModuleOptionsTests.class,
 
 		// Compilation unit tests
 		CompilationUnitTests.class,
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java
index 0f868ee..4e29db6 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaProjectTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
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 65ffee3..1070abe 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
@@ -5916,6 +5916,105 @@
 		}
 	}
 
+	public void testBug522670() throws Exception {
+		if (!isJRE9) return;
+		Hashtable<String, String> javaCoreOptions = JavaCore.getOptions();
+		try {
+			Hashtable<String, String> newOptions=new Hashtable<>(javaCoreOptions);
+			newOptions.put(CompilerOptions.OPTION_Store_Annotations, JavaCore.ENABLED);
+			JavaCore.setOptions(newOptions);
+			IJavaProject p1 = setupModuleProject("util",
+				new String[] {
+					"src/module-info.java",
+					"module util {\n" +
+					"	exports my.util;\n" +
+					"}\n" +
+					"",
+					"src/my/util/Data.java",
+					"package my.util;\n" +
+					"public class Data {\n" +
+					"}\n" +
+					"",
+					"src/my/util/AnnotatedInModule.java",
+					"package my.util;\n" +
+					"import static java.lang.annotation.ElementType.TYPE_USE;\n" +
+					"import java.lang.annotation.Target;\n" +
+					"@Target(TYPE_USE)\n" +
+					"@interface Y {\n" +
+					"}\n" +
+					"public abstract class AnnotatedInModule {\n" +
+					"	abstract public @Y Data getTime();\n" +
+					"}\n" +
+					"",
+				});
+			IJavaProject p2 = setupModuleProject("util2",
+				new String[] {
+					"src/module-info.java",
+					"module util2 {\n" +
+					"	exports my.util.nested;\n" +
+					"}\n" +
+					"",
+					"src/my/util/nested/Unrelated.java",
+					"package my.util.nested;\n" +
+					"class Unrelated {\n" +
+					"}\n" +
+					"",
+				});
+			String[] sources3 = {
+				"src/a/other/AnnotatedInOtherNonModule.java",
+				"package a.other;\n" +
+				"import static java.lang.annotation.ElementType.TYPE_USE;\n" +
+				"import java.lang.annotation.Target;\n" +
+				"import my.util.Data;\n" +
+				"@Target(TYPE_USE)\n" +
+				"@interface X {\n" +
+				"}\n" +
+				"public class AnnotatedInOtherNonModule {\n" +
+				"	@X\n" +
+				"	Data generationDate;\n" +
+				"}\n" +
+				"",
+			};
+			IClasspathAttribute[] attr = { JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true") };
+			// modulepath
+			IClasspathEntry[] deps3 = { JavaCore.newProjectEntry(p1.getPath(), null, false, attr, false) };
+			IJavaProject p3 = setupModuleProject("other", sources3, deps3);
+	
+			String[] sources4 = {
+				"src/test/Test.java",
+				"package test;\n" +
+				"\n" +
+				"import a.other.AnnotatedInOtherNonModule;\n" +
+				"import my.util.AnnotatedInModule;\n" +
+				"import my.util.Data;\n" +
+				"\n" +
+				"public class Test extends AnnotatedInOtherNonModule {\n" +
+				"	public Data f(AnnotatedInModule calendar) {\n" +
+				"		return calendar.getTime();\n" +
+				"	}\n" +
+				"}\n" +
+				"",
+			};
+			IClasspathEntry[] deps4 = { //
+					// modulepath (with split package my.util)
+					JavaCore.newProjectEntry(p1.getPath(), null, false, attr, false), //
+					JavaCore.newProjectEntry(p2.getPath(), null, false, attr, false), //
+					// classpath
+					JavaCore.newProjectEntry(p3.getPath()) //
+			};
+			IJavaProject p4 = setupModuleProject("test", sources4, deps4);
+			p4.getProject().getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+	
+			assertNoErrors();
+		} finally {
+			JavaCore.setOptions(javaCoreOptions);
+			deleteProject("util");
+			deleteProject("util2");
+			deleteProject("other");
+			deleteProject("test");
+		}
+	}
+
 	public void testBug525522() throws Exception {
 		if (!isJRE9) return;
 		String save = System.getProperty("modules.to.load");
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleOptionsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleOptionsTests.java
new file mode 100644
index 0000000..543dcc7
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ModuleOptionsTests.java
@@ -0,0 +1,706 @@
+/*******************************************************************************
+ * Copyright (c) 2018 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.core.tests.model;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jdt.core.IClasspathAttribute;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.tests.util.Util;
+import org.eclipse.jdt.internal.compiler.util.JRTUtil;
+import org.eclipse.jdt.internal.core.ClasspathAttribute;
+import org.eclipse.jdt.internal.core.builder.ClasspathJrt;
+
+import junit.framework.Test;
+
+public class ModuleOptionsTests extends ModifyingResourceTests {
+
+	public ModuleOptionsTests(String name) {
+		super(name);
+	}
+
+	static {
+//		 TESTS_NAMES = new String[] { "testAddReads" };
+	}
+	
+	private String savedModulesOption = null;
+	public static Test suite() {
+		return buildModelTestSuite(ModuleOptionsTests.class, BYTECODE_DECLARATION_ORDER);
+	}
+	public void setUpSuite() throws Exception {
+		super.setUpSuite();
+		this.savedModulesOption = System.getProperty("modules.to.load", "");
+		System.setProperty("modules.to.load", "");
+		JRTUtil.reset();
+		ClasspathJrt.resetCaches();
+	}	
+	public void tearDownSuite() throws Exception {
+		System.setProperty("modules.to.load", this.savedModulesOption);
+		super.tearDownSuite();
+	}
+	// testing auto rebuild after change of limit-modules
+	public void testLimitModules3() throws CoreException, IOException {
+		if (!isJRE9) return;
+		try {
+			IClasspathAttribute[] attributes = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+					JavaCore.newClasspathAttribute(IClasspathAttribute.LIMIT_MODULES, "java.se") // test transitive closure
+			};
+			IJavaProject project = createJava9ProjectWithJREAttributes("org.astro", new String[]{"src", "src2"}, attributes);
+
+			String[] sources = {
+				"src/module-info.java",
+				"module org.astro {\n" +
+				"	requires java.base;\n" +
+				"	requires java.desktop;\n" +
+				"	requires java.datatransfer;\n" +
+				"	requires java.sql;\n" +
+				"}\n",
+				"src/org/astro/Test2.java",
+				"package org.astro;\n" +
+				"class Test2 {\n" +
+				"	java.awt.Window window;\n" +
+				"}\n",
+				"src2/org/astro/Test3.java",
+				"package org.astro;\n" +
+				"class Test3 {\n" +
+				"	java.awt.datatransfer.Clipboard clippy;\n" +
+				"}\n"
+			};
+			createSourceFiles(project, sources);
+
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = project.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"",
+					markers);
+
+			IClasspathAttribute[] newLimits = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+					JavaCore.newClasspathAttribute(IClasspathAttribute.LIMIT_MODULES, "java.base,java.sql") // no more awt etc
+			};
+			setJRECPAttributes(project, newLimits);
+
+			getWorkspace().build(IncrementalProjectBuilder.AUTO_BUILD, null);
+
+			markers = project.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			Arrays.sort(markers, (a,b) -> a.getAttribute(IMarker.CHAR_START, 0) - b.getAttribute(IMarker.CHAR_START, 0));
+			assertMarkers("Unexpected markers",
+					"java.awt cannot be resolved to a type\n" + 
+					"java.awt cannot be resolved to a type\n" +
+					"java.desktop cannot be resolved to a module\n" + 
+					"java.datatransfer cannot be resolved to a module",
+					markers);
+		} finally {
+			this.deleteProject("org.astro");
+		}
+	}
+	public void testAddExports() throws CoreException, IOException {
+		if (!isJRE9) return;
+		try {
+			String[] sources = {
+				"src/module-info.java",
+				"module org.astro {\n" +
+				"	requires java.base;\n" +
+				"	requires java.desktop;\n" +
+				"	requires java.datatransfer;\n" +
+				"	requires java.sql;\n" +
+				"}\n",
+				"src/org/astro/Test2.java",
+				"package org.astro;\n" +
+				"public class Test2 {\n" +
+				"	java.awt.Window window;\n" +
+				"}\n",
+				"src2/org/astro/Test3.java",
+				"package org.astro;\n" +
+				"class Test3 {\n" +
+				"	java.awt.datatransfer.Clipboard clippy;\n" +
+				"}\n"
+			};
+			IJavaProject project = setupModuleProject("org.astro", new String[] {"src", "src2"}, sources, null);
+
+			sources = new String[] {
+					"src/module-info.java",
+					"module test {\n" +
+					"	requires org.astro;\n" +
+					"}\n",
+					"src/test/Test.java",
+					"package test;\n" +
+					"class Test {\n" +
+					"	org.astro.Test2 t;\n" +
+					"}\n"
+				};
+			IClasspathAttribute[] attributes = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+					JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_EXPORTS, "org.astro/org.astro=test")
+			};
+			IClasspathEntry cp = JavaCore.newProjectEntry(project.getPath(), null, false, attributes, false);
+			IJavaProject p2 = setupModuleProject("test", sources, new IClasspathEntry[] {cp});
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = p2.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"",
+					markers);
+
+			IClasspathAttribute[] newAttrs = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true")
+			};
+			setCPAttributes(p2, newAttrs, cp);
+
+			getWorkspace().build(IncrementalProjectBuilder.AUTO_BUILD, null);
+
+			markers = p2.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"The type org.astro.Test2 is not accessible",
+					markers);
+		} finally {
+			this.deleteProject("org.astro");
+			this.deleteProject("test");
+		}
+	}
+
+	public void testAddExports_JRE() throws CoreException, IOException {
+		if (!isJRE9) return;
+		try {
+			String[] sources = {
+				"src/module-info.java",
+				"module org.astro {\n" +
+				"	requires java.base;\n" +
+				"	requires java.desktop;\n" +
+				"	requires java.datatransfer;\n" +
+				"	requires java.sql;\n" +
+				"}\n",
+				"src/org/astro/Test2.java",
+				"package org.astro;\n" +
+				"public class Test2 {\n" +
+				"	int test(jdk.internal.misc.Unsafe unsafe) {\n" + 
+				"		return unsafe.addressSize();\n" + 
+				"	}" +
+				"}\n",
+			};
+			IClasspathAttribute[] attrs = new IClasspathAttribute[] {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+					JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_EXPORTS, "java.base/jdk.internal.misc=org.astro")
+			};
+			IJavaProject project = createJava9ProjectWithJREAttributes("org.astro", new String[] {"src"}, attrs);
+			createSourceFiles(project, sources);
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = project.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"",
+					markers);
+
+			IClasspathAttribute[] newAttrs = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true")
+			};
+			setJRECPAttributes(project, newAttrs);
+
+			getWorkspace().build(IncrementalProjectBuilder.AUTO_BUILD, null);
+
+			markers = project.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"The type jdk.internal.misc.Unsafe is not accessible",
+					markers);
+		} finally {
+			this.deleteProject("org.astro");
+		}
+	}
+	public void testAddExports_multi() throws CoreException, IOException {
+		if (!isJRE9) return;
+		try {
+			String[] sources = {
+				"src/module-info.java",
+				"module org.astro {\n" +
+				"	requires java.base;\n" +
+				"	requires java.desktop;\n" +
+				"	requires java.datatransfer;\n" +
+				"	requires java.sql;\n" +
+				"}\n",
+				"src/org/astro/Test2.java",
+				"package org.astro;\n" +
+				"public class Test2 {\n" +
+				"	java.awt.Window window;\n" +
+				"}\n",
+				"src2/org/astro/sub/Test3.java",
+				"package org.astro.sub;\n" +
+				"public class Test3 {\n" +
+				"	java.awt.datatransfer.Clipboard clippy;\n" +
+				"}\n"
+			};
+			IJavaProject project = setupModuleProject("org.astro", new String[] {"src", "src2"}, sources, null);
+
+			sources = new String[] {
+					"src/module-info.java",
+					"module test {\n" +
+					"	requires org.astro;\n" +
+					"}\n",
+					"src/test/Test.java",
+					"package test;\n" +
+					"class Test {\n" +
+					"	org.astro.Test2 t;\n" +
+					"	org.astro.sub.Test3 t3;\n" +
+					"}\n"
+				};
+			IClasspathAttribute[] attributes = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+					JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_EXPORTS, "org.astro/org.astro=test")
+			};
+			IClasspathEntry cp = JavaCore.newProjectEntry(project.getPath(), null, false, attributes, false);
+			IJavaProject p2 = setupModuleProject("test", sources, new IClasspathEntry[] {cp});
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = p2.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"The type org.astro.sub.Test3 is not accessible",
+					markers);
+
+			IClasspathAttribute[] newAttrs = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+					JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_EXPORTS, "org.astro/org.astro=test:org.astro/org.astro.sub=test")
+			};
+			setCPAttributes(p2, newAttrs, cp);
+
+			getWorkspace().build(IncrementalProjectBuilder.AUTO_BUILD, null);
+
+			markers = p2.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"",
+					markers);
+		} finally {
+			this.deleteProject("org.astro");
+			this.deleteProject("test");
+		}
+	}
+	public void testAddExports_classFolder() throws CoreException, IOException {
+		if (!isJRE9) return;
+		try {
+			String[] sources = {
+				"src/module-info.java",
+				"module org.astro {\n" +
+				"	requires java.base;\n" +
+				"	requires java.desktop;\n" +
+				"	requires java.datatransfer;\n" +
+				"	requires java.sql;\n" +
+				"}\n",
+				"src/org/astro/Test2.java",
+				"package org.astro;\n" +
+				"public class Test2 {\n" +
+				"	java.awt.Window window;\n" +
+				"}\n",
+				"src2/org/astro/sub/Test3.java",
+				"package org.astro.sub;\n" +
+				"public class Test3 {\n" +
+				"	java.awt.datatransfer.Clipboard clippy;\n" +
+				"}\n"
+			};
+			IJavaProject project = setupModuleProject("org.astro", new String[] {"src", "src2"}, sources, null);
+
+			sources = new String[] {
+					"src/module-info.java",
+					"module test {\n" +
+					"	requires org.astro;\n" +
+					"}\n",
+					"src/test/Test.java",
+					"package test;\n" +
+					"class Test {\n" +
+					"	org.astro.Test2 t;\n" +
+					"	org.astro.sub.Test3 t3;\n" +
+					"}\n"
+				};
+			IClasspathAttribute[] attributes = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+					JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_EXPORTS, "org.astro/org.astro=test")
+			};
+			IClasspathEntry cp = JavaCore.newLibraryEntry(project.getProject().findMember("bin").getFullPath(), null,
+					null, null, attributes, false);
+			IJavaProject p2 = setupModuleProject("test", sources, new IClasspathEntry[] {cp});
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = p2.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"The type org.astro.sub.Test3 is not accessible",
+					markers);
+
+			IClasspathAttribute[] newAttrs = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+					JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_EXPORTS, "org.astro/org.astro=test:org.astro/org.astro.sub=test")
+			};
+			setCPAttributes(p2, newAttrs, cp);
+
+			getWorkspace().build(IncrementalProjectBuilder.AUTO_BUILD, null);
+
+			markers = p2.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"",
+					markers);
+		} finally {
+			this.deleteProject("org.astro");
+			this.deleteProject("test");
+		}
+	}
+	public void testAddReads() throws CoreException, IOException {
+		if (!isJRE9) return;
+		String libPath = "externalLib/mod.one.jar";
+		try {
+			String[] sources = new String[] {
+					"src/module-info.java",
+					"module org.astro {\n" +
+					"	exports org.astro;\n" + 
+					"}",
+					"src/org/astro/World.java",
+					"package org.astro;\n" +
+					"public interface World {\n" +
+					"	public String name();\n" +
+					"}"
+			};
+			IJavaProject p = setupModuleProject("org.astro", sources);
+
+			String[] src1 = new String[] {
+					"src/module-info.java",
+					"module mod.one {\n" +
+					"	exports one.p;\n" +
+					"}\n",
+					"src/org/astro/World.java",
+					"package org.astro;\n" +
+					"public interface World { public String name(); }\n",
+					"src/one/p/C.java",
+					"package one.p;\n" +
+					"public class C implements org.astro.World {\n" +
+					"	public String name() {\n" +
+					"		return \"C\";\n" +
+					"	}\n" +
+					"}\n"
+			};
+			IJavaProject p1 = setupModuleProject("mod.one", src1);
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			// jar-up without the required class, should be supplied by the other module
+			deleteFile("/mod.one/src/org/astro/World.java");
+			deleteFile("/mod.one/bin/org/astro/World.class");
+			File rootDir = new File(p1.getProject().findMember("bin").getLocation().toString());
+			Util.zip(rootDir, getExternalResourcePath(libPath));
+
+			String[] src2 = new String[] {
+				"src/module-info.java",
+				"module com.greetings {\n" +
+				"	requires mod.one;\n" +
+				"}",
+				"src/com/greetings/MyTest.java",
+				"package com.greetings;\n" +
+				"public class MyTest extends one.p.C {}"
+			};
+			IClasspathEntry dep1 = JavaCore.newProjectEntry(p.getPath(), null, false,
+															new IClasspathAttribute[] {new ClasspathAttribute("module", "true")},
+															false/*not exported*/);
+			IClasspathEntry dep2 = JavaCore.newLibraryEntry(new Path(getExternalResourcePath(libPath)), null, null, null,
+															new IClasspathAttribute[] {
+																	new ClasspathAttribute("module", "true"),
+																	new ClasspathAttribute(IClasspathAttribute.ADD_READS, "mod.one=org.astro")
+															},
+															false/*not exported*/);
+			IJavaProject p2 = setupModuleProject("com.greetings", src2, new IClasspathEntry[] { dep1, dep2 });
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = p2.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",	"",  markers);
+			IClasspathAttribute[] attrs = new IClasspathAttribute[] {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true")
+			};
+			setCPAttributes(p2, attrs, dep2);
+			getWorkspace().build(IncrementalProjectBuilder.AUTO_BUILD, null);
+			markers = p2.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",	
+					"The project was not built since its build path is incomplete. Cannot find the class file for org.astro.World. Fix the build path then try building this project\n" + 
+					"The type org.astro.World cannot be resolved. It is indirectly referenced from required .class files",
+					markers);
+		} finally {
+			deleteExternalResource(libPath);
+			deleteProject("mod.one");
+			deleteProject("org.astro");
+			deleteProject("com.greetings");
+		}
+	}
+	public void testAddReads2() throws CoreException, IOException {
+		if (!isJRE9) return;
+		String libPath = "externalLib/mod.one.jar";
+		try {
+			String[] sources = new String[] {
+					"src/module-info.java",
+					"module org.astro {\n" +
+					"	exports org.astro;\n" + 
+					"}",
+					"src/org/astro/World.java",
+					"package org.astro;\n" +
+					"public interface World {\n" +
+					"	public String name();\n" +
+					"}"
+			};
+			IJavaProject p = setupModuleProject("org.astro", sources);
+
+			String[] src1 = new String[] {
+					"src/module-info.java",
+					"module mod.one {\n" +
+					"	exports one.p;\n" +
+					"}\n",
+					"src/org/astro/World.java",
+					"package org.astro;\n" +
+					"public interface World { public String name(); }\n",
+					"src/one/p/C.java",
+					"package one.p;\n" +
+					"public class C implements org.astro.World {\n" +
+					"	public String name() {\n" +
+					"		return \"C\";\n" +
+					"	}\n" +
+					"}\n"
+			};
+			IJavaProject p1 = setupModuleProject("mod.one", src1);
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			// jar-up without the required class, should be supplied by the other module
+			deleteFile("/mod.one/src/org/astro/World.java");
+			deleteFile("/mod.one/bin/org/astro/World.class");
+			File rootDir = new File(p1.getProject().findMember("bin").getLocation().toString());
+			Util.zip(rootDir, getExternalResourcePath(libPath));
+
+			String[] src2 = new String[] {
+				"src/module-info.java",
+				"module com.greetings {\n" +
+				"	requires mod.one;\n" +
+				"}",
+				"src/com/greetings/MyTest.java",
+				"package com.greetings;\n" +
+				"public class MyTest extends one.p.C {}"
+			};
+			IClasspathEntry dep1 = JavaCore.newProjectEntry(p.getPath(), null, false,
+															new IClasspathAttribute[] {new ClasspathAttribute("module", "true")},
+															false/*not exported*/);
+			IClasspathEntry dep2 = JavaCore.newLibraryEntry(new Path(getExternalResourcePath(libPath)), null, null, null,
+															new IClasspathAttribute[] {
+																	new ClasspathAttribute("module", "true"),
+															},
+															false/*not exported*/);
+			IJavaProject p2 = setupModuleProject("com.greetings", src2, new IClasspathEntry[] { dep1, dep2 });
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = p2.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",	
+					"The project was not built since its build path is incomplete. Cannot find the class file for org.astro.World. Fix the build path then try building this project\n" + 
+					"The type org.astro.World cannot be resolved. It is indirectly referenced from required .class files",
+					markers);
+			IClasspathAttribute[] attrs = new IClasspathAttribute[] {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+					JavaCore.newClasspathAttribute(IClasspathAttribute.ADD_READS, "mod.one=org.astro")
+			};
+			setCPAttributes(p2, attrs, dep2);
+			getWorkspace().build(IncrementalProjectBuilder.AUTO_BUILD, null);
+			markers = p2.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",	"",  markers);
+		} finally {
+			deleteExternalResource(libPath);
+			deleteProject("mod.one");
+			deleteProject("org.astro");
+			deleteProject("com.greetings");
+		}
+	}
+	public void _testPatchModule() throws CoreException, IOException {
+		if (!isJRE9) return;
+		try {
+			String[] sources = {
+				"src/module-info.java",
+				"module org.astro {\n" +
+				"	requires java.base;\n" +
+				"	requires java.desktop;\n" +
+				"	requires java.datatransfer;\n" +
+				"	requires java.sql;\n" +
+				"	exports org.astro;\n" +
+				"}\n",
+				"src/org/astro/Test2.java",
+				"package org.astro;\n" +
+				"public class Test2 {\n" +
+				"	java.awt.Window window;\n" +
+				"}\n"
+			};
+			IJavaProject project = setupModuleProject("org.astro", sources);
+
+			sources = new String[] {
+					"src/code/Code.java",
+					"package code;\n" +
+					"class Code {\n" +
+					"}\n",
+					"src2/org/astro/Galaxy.java",
+					"package org.astro;\n" +
+					"public class Galaxy { }\n"
+				};
+			IClasspathAttribute[] attributes = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+			};
+			IClasspathEntry cp = JavaCore.newProjectEntry(project.getPath(), null, false, attributes, false);
+			IJavaProject p2 = setupModuleProject("patch", new String[] {"src", "src2"}, sources, null);
+			attributes = new IClasspathAttribute[] {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+					JavaCore.newClasspathAttribute(IClasspathAttribute.PATCH_MODULE, "org.astro")
+			};
+			IClasspathEntry cp2 = JavaCore.newProjectEntry(p2.getPath(), null, false, attributes, false);
+			sources = new String[] {
+					"src/module-info.java",
+					"module test {\n" +
+					"	requires org.astro;\n" +
+					"}\n",
+					"src/test/Test.java",
+					"package test;\n" +
+					"class Test {\n" +
+					"	org.astro.World w = null;\n" +
+					"	org.astro.Galaxy g = null;\n" +
+					"}\n",
+			};
+			IJavaProject p3 = setupModuleProject("test", sources, new IClasspathEntry[] {cp, cp2});
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = p3.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"",
+					markers);
+		} finally {
+			this.deleteProject("org.astro");
+			this.deleteProject("patch");
+			this.deleteProject("test");
+		}
+
+	}
+	public void testPatchModule() throws CoreException, IOException {
+		if (!isJRE9) return;
+		try {
+			IClasspathAttribute[] attributes = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true")
+			};
+			IJavaProject patchProject = createJava9ProjectWithJREAttributes("org.astro.patch", new String[]{"src", "src2"}, attributes);
+
+			String[] patchSources = {
+				"src/org/astro/Test2.java",
+				"package org.astro;\n" +
+				"class Test2 {\n" +
+				"	int test(jdk.internal.misc.Unsafe unsafe) {\n" +
+				"		return unsafe.addressSize();\n" +
+				"	}\n" +
+				"}\n",
+				"src2/jdk/internal/misc/Test3.java",
+				"package jdk.internal.misc;\n" +
+				"class Test3 {\n" +
+				"	Signal.NativeHandler handler;\n" + // package access
+				"}\n"
+			};
+			createSourceFiles(patchProject, patchSources);
+			
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			IMarker[] markers = patchProject.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"The type jdk.internal.misc.Unsafe is not accessible\n" + 
+					"Signal cannot be resolved to a type",
+					markers);
+			
+			attributes = new IClasspathAttribute[] {
+				JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+				JavaCore.newClasspathAttribute(IClasspathAttribute.PATCH_MODULE, "java.base")
+			};
+			setJRECPAttributes(patchProject, attributes);
+			
+			getWorkspace().build(IncrementalProjectBuilder.AUTO_BUILD, null);
+
+			markers = patchProject.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"",
+					markers);
+		} finally {
+			this.deleteProject("org.astro.patch");
+		}
+	}
+	public void testPatchModule2() throws CoreException, IOException {
+		if (!isJRE9) return;
+		try {
+			IClasspathAttribute[] attributes = {
+					JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+					JavaCore.newClasspathAttribute(IClasspathAttribute.PATCH_MODULE, "java.base")
+			};
+			IJavaProject patchProject = createJava9ProjectWithJREAttributes("org.astro.patch", new String[]{"src", "src2"}, attributes);
+
+			String[] patchSources = {
+				"src/org/astro/Test2.java",
+				"package org.astro;\n" +
+				"class Test2 {\n" +
+				"	int test(jdk.internal.misc.Unsafe unsafe) {\n" +
+				"		return unsafe.addressSize();\n" +
+				"	}\n" +
+				"}\n",
+				"src2/jdk/internal/misc/Test3.java",
+				"package jdk.internal.misc;\n" +
+				"class Test3 {\n" +
+				"	Signal.NativeHandler handler;\n" + // package access
+				"}\n"
+			};
+			createSourceFiles(patchProject, patchSources);
+			
+			getWorkspace().build(IncrementalProjectBuilder.FULL_BUILD, null);
+			
+			attributes = new IClasspathAttribute[] {
+				JavaCore.newClasspathAttribute(IClasspathAttribute.MODULE, "true"),
+			};
+			setJRECPAttributes(patchProject, attributes);
+			
+			getWorkspace().build(IncrementalProjectBuilder.AUTO_BUILD, null);
+
+			IMarker[] markers = patchProject.getProject().findMarkers(null, true, IResource.DEPTH_INFINITE);
+			assertMarkers("Unexpected markers",
+					"The type jdk.internal.misc.Unsafe is not accessible\n" + 
+					"Signal cannot be resolved to a type",
+					markers);
+		} finally {
+			this.deleteProject("org.astro.patch");
+		}
+	}
+	private void setCPAttributes(IJavaProject javaProject, IClasspathAttribute[] attributes, IClasspathEntry entryToReplace) throws JavaModelException {
+		IClasspathEntry[] oldClasspath= javaProject.getRawClasspath();
+		int nEntries= oldClasspath.length;
+		IClasspathEntry[] newEntries= Arrays.copyOf(oldClasspath, nEntries);
+		for (int i = 0; i < newEntries.length; i++) {
+			if (newEntries[i].getPath().equals(entryToReplace.getPath())) {
+				switch(entryToReplace.getEntryKind()) {
+				case IClasspathEntry.CPE_PROJECT:
+					newEntries[i] = JavaCore.newProjectEntry(entryToReplace.getPath(), entryToReplace.getAccessRules(), entryToReplace.combineAccessRules(), attributes, entryToReplace.isExported());
+					break;
+				case IClasspathEntry.CPE_LIBRARY:
+					newEntries[i] = JavaCore.newLibraryEntry(entryToReplace.getPath(), newEntries[i].getSourceAttachmentPath(), null, null, attributes, false);
+					break;
+					default:
+						// not supported
+						break;
+				}
+				break;
+			}
+		}
+		javaProject.setRawClasspath(newEntries, null);
+	}
+	private void setJRECPAttributes(IJavaProject javaProject, IClasspathAttribute[] attributes) throws JavaModelException {
+		IClasspathEntry[] oldClasspath= javaProject.getRawClasspath();
+		int nEntries= oldClasspath.length;
+		IClasspathEntry[] newEntries= Arrays.copyOf(oldClasspath, nEntries);
+		for (int i = 0; i < newEntries.length; i++) {
+			if (newEntries[i].getPath().equals(getJRE9Path())) {
+				newEntries[i] = JavaCore.newLibraryEntry(getJRE9Path(), newEntries[i].getSourceAttachmentPath(), null, null, attributes, false);
+				break;
+			}
+		}
+		javaProject.setRawClasspath(newEntries, null);
+	}
+}
diff --git a/org.eclipse.jdt.core/.settings/.api_filters b/org.eclipse.jdt.core/.settings/.api_filters
index f93f3d7..1c71707 100644
--- a/org.eclipse.jdt.core/.settings/.api_filters
+++ b/org.eclipse.jdt.core/.settings/.api_filters
@@ -13,6 +13,12 @@
                 <message_argument value="3.13.0"/>
             </message_arguments>
         </filter>
+        <filter comment="new API was backported" id="924844039">
+            <message_arguments>
+                <message_argument value="3.13.101"/>
+                <message_argument value="3.13.100"/>
+            </message_arguments>
+        </filter>
         <filter id="924844039">
             <message_arguments>
                 <message_argument value="3.13.50"/>
diff --git a/org.eclipse.jdt.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.core/META-INF/MANIFEST.MF
index 63c1167..89f6742 100644
--- a/org.eclipse.jdt.core/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.core/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.core; singleton:=true
-Bundle-Version: 3.15.0.qualifier
+Bundle-Version: 3.13.102.qualifier
 Bundle-Activator: org.eclipse.jdt.core.JavaCore
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
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 3fa9876..dc3bee8 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
@@ -1950,6 +1950,7 @@
 	/** @since 3.14 */
 	int DuplicateResource = Internal + 1251;
 
+	// terminally
 	/** @since 3.14 */
 	int UsingTerminallyDeprecatedType = TypeRelated + 1400;
 	/** @since 3.14 */
@@ -1960,7 +1961,30 @@
 	int UsingTerminallyDeprecatedField = FieldRelated + 1403;
 	/** @since 3.14 */
 	int OverridingTerminallyDeprecatedMethod = MethodRelated + 1404;
+	// with since
+	/** @since 3.13 */
+	int UsingDeprecatedSinceVersionType = TypeRelated + 1405;
+	/** @since 3.13 */
+	int UsingDeprecatedSinceVersionMethod = MethodRelated + 1406;
+	/** @since 3.13 */
+	int UsingDeprecatedSinceVersionConstructor = MethodRelated + 1407;
+	/** @since 3.13 */
+	int UsingDeprecatedSinceVersionField = FieldRelated + 1408;
+	/** @since 3.13 */
+	int OverridingDeprecatedSinceVersionMethod = MethodRelated + 1409;
+	// terminally with since
+	/** @since 3.13 */
+	int UsingTerminallyDeprecatedSinceVersionType = TypeRelated + 1410;
+	/** @since 3.13 */
+	int UsingTerminallyDeprecatedSinceVersionMethod = MethodRelated + 1411;
+	/** @since 3.13 */
+	int UsingTerminallyDeprecatedSinceVersionConstructor = MethodRelated + 1412;
+	/** @since 3.13 */
+	int UsingTerminallyDeprecatedSinceVersionField = FieldRelated + 1413;
+	/** @since 3.13 */
+	int OverridingTerminallyDeprecatedSinceVersionMethod = MethodRelated + 1414;
 
+	
 	/** @since 3.14 */
 	int NotAccessibleType = TypeRelated + 1450;
 	/** @since 3.14 */
@@ -2005,29 +2029,29 @@
 	int UnlikelyEqualsArgumentType = 1201;
 
 	/* Local-Variable Type Inference */
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarLocalMultipleDeclarators = Syntax + 1500; // ''var'' is not allowed in a compound declaration
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarLocalCannotBeArray = Syntax + 1501; // ''var'' is not allowed as an element type of an array
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarLocalReferencesItself = Syntax + 1502; // Declaration using ''var'' may not contin references to itself
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarLocalWithoutInitizalier = Syntax + 1503; // Cannot use ''var'' on variable without initializer
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarLocalInitializedToNull = TypeRelated + 1504; // Variable initialized to ''null'' needs an explicit target-type
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarLocalInitializedToVoid = TypeRelated + 1505; // Variable initializer is ''void'' -- cannot infer variable type 
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarLocalCannotBeArrayInitalizers = TypeRelated + 1506; // Array initializer needs an explicit target-type
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarLocalCannotBeLambda = TypeRelated + 1507; // Lambda expression needs an explicit target-type 
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarLocalCannotBeMethodReference = TypeRelated + 1508; // Method reference needs an explicit target-type
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarIsReserved = Syntax + 1509; // ''var'' is not a valid type name
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarIsReservedInFuture = Syntax + 1510; // ''var'' should not be used as an type name, since it is a reserved word from source level 10 on
-	/** @since 3.15 */
+	/** @since 3.13 */
 	int VarIsNotAllowedHere = Syntax + 1511; // ''var'' is not allowed here
 	
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
index ad9daa3..aa6e653 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
@@ -745,7 +745,7 @@
 					type.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
 					if (length > 0) {
 						annotations = new AnnotationBinding[length];
-						type.setAnnotations(annotations);
+						type.setAnnotations(annotations, false);
 					}
 					break;
 				case Binding.METHOD :
@@ -754,7 +754,7 @@
 					method.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
 					if (length > 0) {
 						annotations = new AnnotationBinding[length];
-						method.setAnnotations(annotations);
+						method.setAnnotations(annotations, false);
 					}
 					break;
 				case Binding.FIELD :
@@ -763,7 +763,7 @@
 					field.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
 					if (length > 0) {
 						annotations = new AnnotationBinding[length];
-						field.setAnnotations(annotations);
+						field.setAnnotations(annotations, false);
 					}
 					break;
 				case Binding.LOCAL :
@@ -772,7 +772,7 @@
 					local.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
 					if (length > 0) {
 						annotations = new AnnotationBinding[length];
-						local.setAnnotations(annotations, scope);
+						local.setAnnotations(annotations, scope, false);
 					}
 					break;
 				case Binding.TYPE_PARAMETER :
@@ -786,7 +786,7 @@
 					module.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
 					if (length > 0) {
 						annotations = new AnnotationBinding[length];
-						module.setAnnotations(annotations, scope);
+						module.setAnnotations(annotations, scope, false);
 					}
 					break;
 				default :
@@ -1092,7 +1092,7 @@
 			}
 			if (newLength != length) {
 				System.arraycopy(recipientAnnotations, 0, recipientAnnotations = new AnnotationBinding[newLength],  0, newLength);
-				recipient.setAnnotations(recipientAnnotations, scope);
+				recipient.setAnnotations(recipientAnnotations, scope, false);
 			}
 		}
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
index dcb04ac..164559f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
@@ -888,12 +888,15 @@
 				pairs[i].resolveTypeExpecting(scope, null); // resilient
 			}
 		}
-//		if (scope.compilerOptions().storeAnnotations)
 		this.compilerAnnotation = scope.environment().createAnnotation((ReferenceBinding) this.resolvedType, computeElementValuePairs());
 		// recognize standard annotations ?
 		long tagBits = detectStandardAnnotation(scope, annotationType, valueAttribute);
 		int defaultNullness = (int)(tagBits & Binding.NullnessDefaultMASK);
 		tagBits &= ~Binding.NullnessDefaultMASK;
+		CompilerOptions compilerOptions = scope.compilerOptions();
+		if ((tagBits & TagBits.AnnotationDeprecated) != 0 && compilerOptions.complianceLevel >= ClassFileConstants.JDK9 && !compilerOptions.storeAnnotations) {
+			this.recipient.setAnnotations(new AnnotationBinding[] {this.compilerAnnotation}, true); // force storing enhanced deprecation
+		}
 
 		// record annotation positions in the compilation result
 		scope.referenceCompilationUnit().recordSuppressWarnings(IrritantSet.NLS, null, this.sourceStart, this.declarationSourceEnd, scope.referenceContext());
@@ -918,7 +921,7 @@
 							} else {
 								start = typeDeclaration.declarationSourceStart;
 							}
-							recordSuppressWarnings(scope, start, typeDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
+							recordSuppressWarnings(scope, start, typeDeclaration.declarationSourceEnd, compilerOptions.suppressWarnings);
 						}
 						sourceType.defaultNullness |= defaultNullness;
 						break;
@@ -928,7 +931,7 @@
 						if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
 							sourceType = (SourceTypeBinding) sourceMethod.declaringClass;
 							AbstractMethodDeclaration methodDeclaration = sourceType.scope.referenceContext.declarationOf(sourceMethod);
-							recordSuppressWarnings(scope, methodDeclaration.declarationSourceStart, methodDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
+							recordSuppressWarnings(scope, methodDeclaration.declarationSourceStart, methodDeclaration.declarationSourceEnd, compilerOptions.suppressWarnings);
 						}
 						long nullBits = sourceMethod.tagBits & TagBits.AnnotationNullMASK;
 						if (nullBits == TagBits.AnnotationNullMASK) {
@@ -936,7 +939,7 @@
 							sourceMethod.tagBits &= ~TagBits.AnnotationNullMASK; // avoid secondary problems
 						}
 						if (nullBits != 0 && sourceMethod.isConstructor()) {
-							if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8)
+							if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8)
 								scope.problemReporter().nullAnnotationUnsupportedLocation(this);
 							// for declaration annotations the inapplicability will be reported below
 							sourceMethod.tagBits &= ~TagBits.AnnotationNullMASK;
@@ -949,7 +952,7 @@
 						if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
 							sourceType = (SourceTypeBinding) sourceField.declaringClass;
 							FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField);
-							recordSuppressWarnings(scope, fieldDeclaration.declarationSourceStart, fieldDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
+							recordSuppressWarnings(scope, fieldDeclaration.declarationSourceStart, fieldDeclaration.declarationSourceEnd, compilerOptions.suppressWarnings);
 						}
 						if (defaultNullness != 0) {
 							sourceType = (SourceTypeBinding) sourceField.declaringClass;
@@ -976,7 +979,7 @@
 						}
 						if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) {
 							LocalDeclaration localDeclaration = variable.declaration;
-							recordSuppressWarnings(scope, localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd, scope.compilerOptions().suppressWarnings);
+							recordSuppressWarnings(scope, localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd, compilerOptions.suppressWarnings);
 						}
 						// note: defaultNullness for local declarations has been already been handled earlier by handleNonNullByDefault() 
 						break;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
index 4aafc6d..d3b6e0c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
@@ -624,8 +624,8 @@
 	boolean pauseHierarchyCheck = false;
 	try {
 		if (ref.isHierarchyBeingConnected()) {
+			pauseHierarchyCheck = (ref.tagBits & TagBits.PauseHierarchyCheck) == 0;
 			ref.tagBits |= TagBits.PauseHierarchyCheck;
-			pauseHierarchyCheck = true;
 		}
 	    return resolveType(classScope, Binding.DefaultLocationTypeArgument);
 	} finally {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/AnnotationInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/AnnotationInfo.java
index fd258d4..1b053c0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/AnnotationInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/AnnotationInfo.java
@@ -163,6 +163,10 @@
 public char[] getTypeName() {
 	return this.typename;
 }
+@Override
+public boolean isDeprecatedAnnotation() {
+	return (this.standardAnnotationTagBits & (TagBits.AnnotationDeprecated | TagBits.AnnotationTerminallyDeprecated)) != 0;
+}
 void initialize() {
 	if (this.pairs == null)
 		decodeAnnotation();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/AnnotationMethodInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/AnnotationMethodInfo.java
index bba584c..de19990 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/AnnotationMethodInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/AnnotationMethodInfo.java
@@ -16,8 +16,8 @@
 public class AnnotationMethodInfo extends MethodInfo {
 	protected Object defaultValue = null;
 
-public static MethodInfo createAnnotationMethod(byte classFileBytes[], int offsets[], int offset) {
-	MethodInfo methodInfo = new MethodInfo(classFileBytes, offsets, offset);
+public static MethodInfo createAnnotationMethod(byte classFileBytes[], int offsets[], int offset, long version) {
+	MethodInfo methodInfo = new MethodInfo(classFileBytes, offsets, offset, version);
 	int attributesCount = methodInfo.u2At(6);
 	int readOffset = 8;
 	AnnotationInfo[] annotations = null;
@@ -98,7 +98,7 @@
 }
 
 AnnotationMethodInfo(MethodInfo methodInfo, Object defaultValue) {
-	super(methodInfo.reference, methodInfo.constantPoolOffsets, methodInfo.structOffset);
+	super(methodInfo.reference, methodInfo.constantPoolOffsets, methodInfo.structOffset, methodInfo.version);
 	this.defaultValue = defaultValue;
 
 	this.accessFlags = methodInfo.accessFlags;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
index 8f81410..d625594 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
@@ -312,7 +312,7 @@
 			FieldInfo field;
 			this.fields = new FieldInfo[this.fieldsCount];
 			for (int i = 0; i < this.fieldsCount; i++) {
-				field = FieldInfo.createField(this.reference, this.constantPoolOffsets, readOffset);
+				field = FieldInfo.createField(this.reference, this.constantPoolOffsets, readOffset, this.version);
 				this.fields[i] = field;
 				readOffset += field.sizeInBytes();
 			}
@@ -325,8 +325,8 @@
 			boolean isAnnotationType = (this.accessFlags & ClassFileConstants.AccAnnotation) != 0;
 			for (int i = 0; i < this.methodsCount; i++) {
 				this.methods[i] = isAnnotationType
-					? AnnotationMethodInfo.createAnnotationMethod(this.reference, this.constantPoolOffsets, readOffset)
-					: MethodInfo.createMethod(this.reference, this.constantPoolOffsets, readOffset);
+					? AnnotationMethodInfo.createAnnotationMethod(this.reference, this.constantPoolOffsets, readOffset, this.version)
+					: MethodInfo.createMethod(this.reference, this.constantPoolOffsets, readOffset, this.version);
 				readOffset += this.methods[i].sizeInBytes();
 			}
 		}
@@ -486,11 +486,12 @@
 			long standardTagBits = newInfo.standardAnnotationTagBits;
 			if (standardTagBits != 0) {
 				this.tagBits |= standardTagBits;
-			} else {
-				if (newInfos == null)
-					newInfos = new AnnotationInfo[numberOfAnnotations - i];
-				newInfos[newInfoCount++] = newInfo;
+				if (this.version < ClassFileConstants.JDK9 || (standardTagBits & TagBits.AnnotationDeprecated) == 0)
+					continue;
 			}
+			if (newInfos == null)
+				newInfos = new AnnotationInfo[numberOfAnnotations - i];
+			newInfos[newInfoCount++] = newInfo;
 		}
 		if (newInfos == null)
 			return; // nothing to record in this.annotations
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java
index 039f3a4..462c00f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfo.java
@@ -18,6 +18,7 @@
 import org.eclipse.jdt.internal.compiler.env.IBinaryField;
 import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
 import org.eclipse.jdt.internal.compiler.impl.*;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
 import org.eclipse.jdt.internal.compiler.util.Util;
 
@@ -32,9 +33,10 @@
 	protected int signatureUtf8Offset;
 	protected long tagBits;
 	protected Object wrappedConstantValue;
+	protected long version;
 
-public static FieldInfo createField(byte classFileBytes[], int offsets[], int offset) {
-	FieldInfo fieldInfo = new FieldInfo(classFileBytes, offsets, offset);
+public static FieldInfo createField(byte classFileBytes[], int offsets[], int offset, long version) {
+	FieldInfo fieldInfo = new FieldInfo(classFileBytes, offsets, offset, version);
 	
 	int attributesCount = fieldInfo.u2At(6);
 	int readOffset = 8;
@@ -100,11 +102,13 @@
  * @param classFileBytes byte[]
  * @param offsets int[]
  * @param offset int
+ * @param version class file version
  */
-protected FieldInfo (byte classFileBytes[], int offsets[], int offset) {
+protected FieldInfo (byte classFileBytes[], int offsets[], int offset, long version) {
 	super(classFileBytes, offsets, offset);
 	this.accessFlags = -1;
 	this.signatureUtf8Offset = -1;
+	this.version = version;
 }
 private AnnotationInfo[] decodeAnnotations(int offset, boolean runtimeVisible) {
 	int numberOfAnnotations = u2At(offset + 6);
@@ -120,11 +124,12 @@
 			long standardTagBits = newInfo.standardAnnotationTagBits;
 			if (standardTagBits != 0) {
 				this.tagBits |= standardTagBits;
-			} else {
-				if (newInfos == null)
-					newInfos = new AnnotationInfo[numberOfAnnotations - i];
-				newInfos[newInfoCount++] = newInfo;
+				if (this.version < ClassFileConstants.JDK9 || (standardTagBits & TagBits.AnnotationDeprecated) == 0)
+					continue;
 			}
+			if (newInfos == null)
+				newInfos = new AnnotationInfo[numberOfAnnotations - i];
+			newInfos[newInfoCount++] = newInfo;
 		}
 		if (newInfos != null) {
 			if (newInfoCount != newInfos.length)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfoWithAnnotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfoWithAnnotation.java
index c2190cd..c5470ba 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfoWithAnnotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/FieldInfoWithAnnotation.java
@@ -16,7 +16,7 @@
 	private AnnotationInfo[] annotations;
 
 FieldInfoWithAnnotation(FieldInfo info, AnnotationInfo[] annos) {
-	super(info.reference, info.constantPoolOffsets, info.structOffset);
+	super(info.reference, info.constantPoolOffsets, info.structOffset, info.version);
 	this.accessFlags = info.accessFlags;
 	this.attributeBytes = info.attributeBytes;
 	this.constant = info.constant;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java
index bb0ad54..d080932 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -20,6 +20,7 @@
 import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
 import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
 import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
 
 @SuppressWarnings("rawtypes")
 public class MethodInfo extends ClassFileStruct implements IBinaryMethod, Comparable {
@@ -35,9 +36,10 @@
 	protected int signatureUtf8Offset;
 	protected long tagBits;
 	protected char[][] argumentNames;
+	protected long version;
 
-public static MethodInfo createMethod(byte classFileBytes[], int offsets[], int offset) {
-	MethodInfo methodInfo = new MethodInfo(classFileBytes, offsets, offset);
+public static MethodInfo createMethod(byte classFileBytes[], int offsets[], int offset, long version) {
+	MethodInfo methodInfo = new MethodInfo(classFileBytes, offsets, offset, version);
 	int attributesCount = methodInfo.u2At(6);
 	int readOffset = 8;
 	AnnotationInfo[] annotations = null;
@@ -146,22 +148,25 @@
 	if (numberOfAnnotations > 0) {
 		AnnotationInfo[] annos = decodeAnnotations(offset + 8, runtimeVisible, numberOfAnnotations, methodInfo);
 		if (runtimeVisible){
-			int numStandardAnnotations = 0;
+			int numRetainedAnnotations = 0;
 			for( int i=0; i<numberOfAnnotations; i++ ){
 				long standardAnnoTagBits = annos[i].standardAnnotationTagBits;
 				methodInfo.tagBits |= standardAnnoTagBits;
 				if(standardAnnoTagBits != 0){
-					annos[i] = null;
-					numStandardAnnotations ++;
+					if (methodInfo.version < ClassFileConstants.JDK9 || (standardAnnoTagBits & TagBits.AnnotationDeprecated) == 0) { // must retain enhanced deprecation
+						annos[i] = null;
+						continue;
+					}
 				}
+				numRetainedAnnotations++;
 			}
 
-			if( numStandardAnnotations != 0 ){
-				if( numStandardAnnotations == numberOfAnnotations )
+			if(numRetainedAnnotations != numberOfAnnotations){
+				if(numRetainedAnnotations == 0)
 					return null;
 
 				// need to resize
-				AnnotationInfo[] temp = new AnnotationInfo[numberOfAnnotations - numStandardAnnotations ];
+				AnnotationInfo[] temp = new AnnotationInfo[numRetainedAnnotations];
 				int tmpIndex = 0;
 				for (int i = 0; i < numberOfAnnotations; i++)
 					if (annos[i] != null)
@@ -213,11 +218,13 @@
  * @param classFileBytes byte[]
  * @param offsets int[]
  * @param offset int
+ * @param version class file version 
  */
-protected MethodInfo (byte classFileBytes[], int offsets[], int offset) {
+protected MethodInfo (byte classFileBytes[], int offsets[], int offset, long version) {
 	super(classFileBytes, offsets, offset);
 	this.accessFlags = -1;
 	this.signatureUtf8Offset = -1;
+	this.version = version;
 }
 public int compareTo(Object o) {
 	MethodInfo otherMethod = (MethodInfo) o;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfoWithAnnotations.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfoWithAnnotations.java
index c2621f4..3e166a2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfoWithAnnotations.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/MethodInfoWithAnnotations.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2016 BEA Systems, Inc.
+ * Copyright (c) 2005, 2018 BEA Systems, Inc 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
@@ -16,7 +16,7 @@
 	protected AnnotationInfo[] annotations;
 
 MethodInfoWithAnnotations(MethodInfo methodInfo, AnnotationInfo[] annotations) {
-	super(methodInfo.reference, methodInfo.constantPoolOffsets, methodInfo.structOffset);
+	super(methodInfo.reference, methodInfo.constantPoolOffsets, methodInfo.structOffset, methodInfo.version);
 	this.annotations = annotations;
 
 	this.accessFlags = methodInfo.accessFlags;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AutomaticModuleNaming.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AutomaticModuleNaming.java
index 765c0a1..bb1c9d1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AutomaticModuleNaming.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/AutomaticModuleNaming.java
@@ -95,7 +95,7 @@
 		dashLoop: for (index = start; index < end - 1; index++) {
 			if (name.charAt(index) == '-' && name.charAt(index + 1) >= '0' && name.charAt(index + 1) <= '9') {
 				for (int index2 = index + 2; index2 < end; index2++) {
-					final char c = name.charAt(index2 + 1);
+					final char c = name.charAt(index2);
 					if (c == '.') {
 						break;
 					}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryAnnotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryAnnotation.java
index 36b1a17..eae5895 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryAnnotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryAnnotation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2007 BEA Systems, Inc.
+ * Copyright (c) 2005, 2018 BEA Systems, Inc 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
@@ -31,5 +31,12 @@
 default boolean isExternalAnnotation() {
 	return false;
 }
+
+/**
+ * @return true, if this is a @Deprecated annotation.
+ */
+default boolean isDeprecatedAnnotation() {
+	return false;
+}
 }
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IUpdatableModule.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IUpdatableModule.java
index 1a2d237..f851a34 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IUpdatableModule.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IUpdatableModule.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2017 GK Software AG, and others.
+ * Copyright (c) 2017, 2018 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
@@ -15,6 +15,7 @@
 import java.util.List;
 import java.util.function.Consumer;
 
+import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.util.SimpleSetOfCharArray;
 
 /**
@@ -29,6 +30,88 @@
 	 */
 	enum UpdateKind { MODULE, PACKAGE }
 
+	class AddExports implements Consumer<IUpdatableModule> {
+
+		char[] name;
+		char[][] targets;
+		public AddExports(char[] pkgName, char[][] targets) {
+			this.name = pkgName;
+			this.targets = targets;
+		}
+		@Override
+		public void accept(IUpdatableModule t) {
+			// TODO Auto-generated method stub
+			t.addExports(this.name, this.targets);
+		}
+		
+		public char[] getName() {
+			return this.name;
+		}
+		
+		public char[][] getTargetModules() {
+			return this.targets;
+		}
+		
+		public UpdateKind getKind() {
+			return UpdateKind.PACKAGE;
+		}
+		@Override
+		public boolean equals(Object other) {
+			if (this == other) return true;
+			if (!(other instanceof AddExports)) return false;
+			AddExports pu = (AddExports) other;
+			
+			if (!CharOperation.equals(this.name, pu.name))
+				return false;
+			if (!CharOperation.equals(this.targets, pu.targets))
+				return false;
+			return true;
+		}
+		@Override
+		public int hashCode() {
+			int hash = CharOperation.hashCode(this.name);
+			if (this.targets != null) {
+				for (int i = 0; i < this.targets.length; i++) {
+					hash += 17 * CharOperation.hashCode(this.targets[i]);
+				}
+			}
+			return hash;
+		}
+	}
+	
+	class AddReads implements Consumer<IUpdatableModule> {
+
+		char[] targetModule;
+		
+		public AddReads(char[] target) {
+			this.targetModule = target;
+		}
+		@Override
+		public void accept(IUpdatableModule t) {
+			// TODO Auto-generated method stub
+			t.addReads(this.targetModule);
+		}
+		
+		public char[] getTarget() {
+			return this.targetModule;
+		}
+		
+		public UpdateKind getKind() {
+			return UpdateKind.MODULE;
+		}
+
+		@Override
+		public boolean equals(Object other) {
+			if (this == other) return true;
+			if (!(other instanceof AddReads)) return false;
+			AddReads mu = (AddReads) other;
+			return CharOperation.equals(this.targetModule, mu.targetModule);
+		}
+		@Override
+		public int hashCode() {
+			return CharOperation.hashCode(this.targetModule);
+		}
+	}
 	/** Structure for update operations, sorted by {@link UpdateKind}. */
 	class UpdatesByKind {
 		List<Consumer<IUpdatableModule>> moduleUpdates = Collections.emptyList();
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 fccd206..d9c4ec3 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
@@ -48,10 +48,12 @@
 import org.eclipse.jdt.internal.compiler.ast.Annotation;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider.IMethodAnnotationWalker;
+import org.eclipse.jdt.internal.compiler.classfmt.MethodInfoWithAnnotations;
 import org.eclipse.jdt.internal.compiler.classfmt.NonNullDefaultAwareTypeAnnotationWalker;
 import org.eclipse.jdt.internal.compiler.classfmt.TypeAnnotationWalker;
 import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
 import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.impl.BooleanConstant;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
@@ -565,8 +567,27 @@
 				}
 			}
 		}
-		if (this.environment.globalOptions.storeAnnotations)
-			setAnnotations(createAnnotations(binaryType.getAnnotations(), this.environment, missingTypeNames));
+		if (this.environment.globalOptions.storeAnnotations) {
+			setAnnotations(createAnnotations(binaryType.getAnnotations(), this.environment, missingTypeNames), false);
+		} else if (sourceLevel >= ClassFileConstants.JDK9 && isDeprecated() && binaryType.getAnnotations() != null) {
+			// prior to Java 9 all standard annotations were marker annotations, not needing to be stored,
+			// but since Java 9 we need more information from the @Deprecated annotation:
+			for (IBinaryAnnotation annotation : binaryType.getAnnotations()) {
+				if (annotation.isDeprecatedAnnotation()) {
+					AnnotationBinding[] annotationBindings = createAnnotations(new IBinaryAnnotation[] { annotation }, this.environment, missingTypeNames);
+					setAnnotations(annotationBindings, true); // force storing
+					for (ElementValuePair elementValuePair : annotationBindings[0].getElementValuePairs()) {
+						if (CharOperation.equals(elementValuePair.name, TypeConstants.FOR_REMOVAL)) {
+							if (elementValuePair.value instanceof BooleanConstant && ((BooleanConstant) elementValuePair.value).booleanValue()) {
+								this.tagBits |= TagBits.AnnotationTerminallyDeprecated;
+								markImplicitTerminalDeprecation(this);
+							}
+						}
+					}
+					break;
+				}
+			}
+		}
 		if (this.isAnnotationType())
 			scanTypeForContainerAnnotation(binaryType, missingTypeNames);
 	} finally {
@@ -577,6 +598,21 @@
 			this.methods = Binding.NO_METHODS;
 	}
 }
+void markImplicitTerminalDeprecation(ReferenceBinding type) {
+	for (ReferenceBinding member : type.memberTypes()) {
+		member.tagBits |= TagBits.AnnotationTerminallyDeprecated;
+		markImplicitTerminalDeprecation(member);
+	}
+	MethodBinding[] methodsOfType = type.unResolvedMethods();
+	if (methodsOfType != null)
+		for (MethodBinding methodBinding : methodsOfType)
+			methodBinding.tagBits |= TagBits.AnnotationTerminallyDeprecated;
+
+	FieldBinding[] fieldsOfType = type.unResolvedFields();
+	if (fieldsOfType != null)
+		for (FieldBinding fieldBinding : fieldsOfType)
+			fieldBinding.tagBits |= TagBits.AnnotationTerminallyDeprecated;
+}
 
 /* When creating a method we need to pass in any default 'nullness' from a @NNBD immediately on this method. */
 private ITypeAnnotationWalker getTypeAnnotationWalker(IBinaryTypeAnnotation[] annotations, int nullness) {
@@ -638,10 +674,16 @@
 						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
+						&& (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)
@@ -657,7 +699,7 @@
 			if (firstAnnotatedFieldIndex >= 0) {
 				for (int i = firstAnnotatedFieldIndex; i <size; i++) {
 					IBinaryField binaryField = iFields[i];
-					this.fields[i].setAnnotations(createAnnotations(binaryField.getAnnotations(), this.environment, missingTypeNames));
+					this.fields[i].setAnnotations(createAnnotations(binaryField.getAnnotations(), this.environment, missingTypeNames), false);
 				}
 			}
 		}
@@ -842,7 +884,13 @@
 		result.receiver = this.environment.createAnnotatedType(this, createAnnotations(receiverAnnotations, this.environment, missingTypeNames));
 	}
 
-	if (this.environment.globalOptions.storeAnnotations) {
+	boolean forceStoreAnnotations = !this.environment.globalOptions.storeAnnotations
+										&& (this.environment.globalOptions.sourceLevel >= ClassFileConstants.JDK9
+										&& method instanceof MethodInfoWithAnnotations
+										&& (method.getTagBits() & TagBits.AnnotationDeprecated) != 0);
+	if (this.environment.globalOptions.storeAnnotations || forceStoreAnnotations) {
+		if (forceStoreAnnotations)
+			storedAnnotations(true, true); // for Java 9 @Deprecated we need to force storing annotations
 		IBinaryAnnotation[] annotations = method.getAnnotations();
 		if (method.isConstructor()) {
 			IBinaryAnnotation[] tAnnotations = walker.toMethodReturn().getAnnotationsAtCursor(this.id, false);
@@ -1549,13 +1597,13 @@
 		this.containerAnnotationType = new ProblemReferenceBinding(this.containerAnnotationType.compoundName, this.containerAnnotationType, ProblemReasons.DefectiveContainerAnnotationType);
 }
 
-SimpleLookupTable storedAnnotations(boolean forceInitialize) {
+SimpleLookupTable storedAnnotations(boolean forceInitialize, boolean forceStore) {
 	
 	if (!isPrototype())
-		return this.prototype.storedAnnotations(forceInitialize);
+		return this.prototype.storedAnnotations(forceInitialize, forceStore);
 	
 	if (forceInitialize && this.storedAnnotations == null) {
-		if (!this.environment.globalOptions.storeAnnotations)
+		if (!this.environment.globalOptions.storeAnnotations && !forceStore)
 			return null; // not supported during this compile
 		this.storedAnnotations = new SimpleLookupTable(3);
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
index cbb24760..48e95fc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java
@@ -191,10 +191,10 @@
 	public AnnotationBinding[] getAnnotations() {
 		return Binding.NO_ANNOTATIONS;
 	}
-	public void setAnnotations(AnnotationBinding[] annotations, Scope scope) {
-		setAnnotations(annotations);
+	public void setAnnotations(AnnotationBinding[] annotations, Scope scope, boolean forceStore) {
+		setAnnotations(annotations, forceStore);
 	}
-	public void setAnnotations(AnnotationBinding[] annotations) {
+	public void setAnnotations(AnnotationBinding[] annotations, boolean forceStore) {
 		// Left to subtypes.
 	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java
index 7c6d065..1396fa9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/FieldBinding.java
@@ -46,7 +46,7 @@
 	super(initialFieldBinding.name, initialFieldBinding.type, initialFieldBinding.modifiers, initialFieldBinding.constant());
 	this.declaringClass = declaringClass;
 	this.id = initialFieldBinding.id;
-	setAnnotations(initialFieldBinding.getAnnotations());
+	setAnnotations(initialFieldBinding.getAnnotations(), false);
 }
 /* API
 * Answer the receiver's binding type from Binding.BindingID.
@@ -411,8 +411,8 @@
 public FieldBinding original() {
 	return this;
 }
-public void setAnnotations(AnnotationBinding[] annotations) {
-	this.declaringClass.storeAnnotations(this, annotations);
+public void setAnnotations(AnnotationBinding[] annotations, boolean forceStore) {
+	this.declaringClass.storeAnnotations(this, annotations, forceStore);
 }
 public FieldDeclaration sourceField() {
 	SourceTypeBinding sourceType;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
index e7411e1..6b4e585 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
@@ -1648,9 +1648,12 @@
 	 * unless the given candidate is tolerable to be compatible with buggy javac.
 	 */
 	public MethodBinding getReturnProblemMethodIfNeeded(TypeBinding expectedType, MethodBinding method) {
-		if (InferenceContext18.SIMULATE_BUG_JDK_8026527 && expectedType != null 
+		if (InferenceContext18.SIMULATE_BUG_JDK_8026527 && expectedType != null
+				&& !(method.original() instanceof SyntheticFactoryMethodBinding)
 				&& (method.returnType instanceof ReferenceBinding || method.returnType instanceof ArrayBinding)) {
-			if (method.returnType.erasure().isCompatibleWith(expectedType))
+			if (!expectedType.isProperType(true))
+				return null; // not ready
+			if (this.environment.convertToRawType(method.returnType.erasure(), false).isCompatibleWith(expectedType))
 				return method; // don't count as problem.
 		}
 		/* We used to check if expected type is null and if so return method, but that is wrong - it injects an incompatible method into overload resolution.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java
index 62f2e19..82bb67e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java
@@ -252,14 +252,14 @@
 		this.initializationCount++;
 	}
 
-	public void setAnnotations(AnnotationBinding[] annotations, Scope scope) {
+	public void setAnnotations(AnnotationBinding[] annotations, Scope scope, boolean forceStore) {
 		// note: we don's use this.declaringScope because we might be called before Scope.addLocalVariable(this)
 		//       which is where this.declaringScope is set.
 		if (scope == null)
 			return;
 		SourceTypeBinding sourceType = scope.enclosingSourceType();
 		if (sourceType != null)
-			sourceType.storeAnnotations(this, annotations);
+			sourceType.storeAnnotations(this, annotations, forceStore);
 	}
 
 	public void resetInitializations() {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
index ba7af95..a415460 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -981,8 +981,8 @@
 public void setTypeAnnotations(AnnotationBinding[] annotations) {
 	this.typeAnnotations = annotations;
 }
-public void setAnnotations(AnnotationBinding[] annotations) {
-	this.declaringClass.storeAnnotations(this, annotations);
+public void setAnnotations(AnnotationBinding[] annotations, boolean forceStore) {
+	this.declaringClass.storeAnnotations(this, annotations, forceStore);
 }
 public void setAnnotations(AnnotationBinding[] annotations, AnnotationBinding[][] parameterAnnotations, Object defaultValue, LookupEnvironment optionalEnv) {
 	this.declaringClass.storeAnnotationHolder(this,  AnnotationHolder.storeAnnotations(annotations, parameterAnnotations, defaultValue, optionalEnv));
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index d71be81..6ab74ba 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -1702,7 +1702,7 @@
 }
 
 public AnnotationHolder retrieveAnnotationHolder(Binding binding, boolean forceInitialization) {
-	SimpleLookupTable store = storedAnnotations(forceInitialization);
+	SimpleLookupTable store = storedAnnotations(forceInitialization, false);
 	return store == null ? null : (AnnotationHolder) store.get(binding);
 }
 
@@ -1711,8 +1711,8 @@
 	return holder == null ? Binding.NO_ANNOTATIONS : holder.getAnnotations();
 }
 
-public void setAnnotations(AnnotationBinding[] annotations) {
-	storeAnnotations(this, annotations);
+public void setAnnotations(AnnotationBinding[] annotations, boolean forceStore) {
+	storeAnnotations(this, annotations, forceStore);
 }
 public void setContainerAnnotationType(ReferenceBinding value) {
 	// Leave this to subclasses
@@ -1839,25 +1839,25 @@
 
 void storeAnnotationHolder(Binding binding, AnnotationHolder holder) {
 	if (holder == null) {
-		SimpleLookupTable store = storedAnnotations(false);
+		SimpleLookupTable store = storedAnnotations(false, false);
 		if (store != null)
 			store.removeKey(binding);
 	} else {
-		SimpleLookupTable store = storedAnnotations(true);
+		SimpleLookupTable store = storedAnnotations(true, false);
 		if (store != null)
 			store.put(binding, holder);
 	}
 }
 
-void storeAnnotations(Binding binding, AnnotationBinding[] annotations) {
+void storeAnnotations(Binding binding, AnnotationBinding[] annotations, boolean forceStore) {
 	AnnotationHolder holder = null;
 	if (annotations == null || annotations.length == 0) {
-		SimpleLookupTable store = storedAnnotations(false);
+		SimpleLookupTable store = storedAnnotations(false, forceStore);
 		if (store != null)
 			holder = (AnnotationHolder) store.get(binding);
 		if (holder == null) return; // nothing to delete
 	} else {
-		SimpleLookupTable store = storedAnnotations(true);
+		SimpleLookupTable store = storedAnnotations(true, forceStore);
 		if (store == null) return; // not supported
 		holder = (AnnotationHolder) store.get(binding);
 		if (holder == null)
@@ -1866,7 +1866,7 @@
 	storeAnnotationHolder(binding, holder.setAnnotations(annotations));
 }
 
-SimpleLookupTable storedAnnotations(boolean forceInitialize) {
+SimpleLookupTable storedAnnotations(boolean forceInitialize, boolean forceStore) {
 	return null; // overrride if interested in storing annotations for the receiver, its fields and methods
 }
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceModuleBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceModuleBinding.java
index 6074fe8..5f12684 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceModuleBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceModuleBinding.java
@@ -110,7 +110,7 @@
 		return retrieveAnnotations(this);
 	}
 	public AnnotationHolder retrieveAnnotationHolder(Binding binding, boolean forceInitialization) {
-		SimpleLookupTable store = storedAnnotations(forceInitialization);
+		SimpleLookupTable store = storedAnnotations(forceInitialization, false);
 		return store == null ? null : (AnnotationHolder) store.get(binding);
 	}
 
@@ -119,30 +119,30 @@
 		return holder == null ? Binding.NO_ANNOTATIONS : holder.getAnnotations();
 	}
 
-	public void setAnnotations(AnnotationBinding[] annotations) {
-		storeAnnotations(this, annotations);
+	public void setAnnotations(AnnotationBinding[] annotations, boolean forceStore) {
+		storeAnnotations(this, annotations, forceStore);
 	}
 	void storeAnnotationHolder(Binding binding, AnnotationHolder holder) {
 		if (holder == null) {
-			SimpleLookupTable store = storedAnnotations(false);
+			SimpleLookupTable store = storedAnnotations(false, false);
 			if (store != null)
 				store.removeKey(binding);
 		} else {
-			SimpleLookupTable store = storedAnnotations(true);
+			SimpleLookupTable store = storedAnnotations(true, false);
 			if (store != null)
 				store.put(binding, holder);
 		}
 	}
 
-	void storeAnnotations(Binding binding, AnnotationBinding[] annotations) {
+	void storeAnnotations(Binding binding, AnnotationBinding[] annotations, boolean forceStore) {
 		AnnotationHolder holder = null;
 		if (annotations == null || annotations.length == 0) {
-			SimpleLookupTable store = storedAnnotations(false);
+			SimpleLookupTable store = storedAnnotations(false, forceStore);
 			if (store != null)
 				holder = (AnnotationHolder) store.get(binding);
 			if (holder == null) return; // nothing to delete
 		} else {
-			SimpleLookupTable store = storedAnnotations(true);
+			SimpleLookupTable store = storedAnnotations(true, forceStore);
 			if (store == null) return; // not supported
 			holder = (AnnotationHolder) store.get(binding);
 			if (holder == null)
@@ -151,11 +151,11 @@
 		storeAnnotationHolder(binding, holder.setAnnotations(annotations));
 	}
 
-	SimpleLookupTable storedAnnotations(boolean forceInitialize) {
+	SimpleLookupTable storedAnnotations(boolean forceInitialize, boolean forceStore) {
 		if (forceInitialize && this.storedAnnotations == null && this.scope != null) { // scope null when no annotation cached, and type got processed fully (159631)
 			this.scope.referenceCompilationUnit().compilationResult.hasAnnotations = true;
 			final CompilerOptions globalOptions = this.scope.environment().globalOptions;
-			if (!globalOptions.storeAnnotations)
+			if (!globalOptions.storeAnnotations && !forceStore)
 				return null; // not supported during this compile
 			this.storedAnnotations = new SimpleLookupTable(3);
 		}
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 e6199fa..426b6f4 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -2457,14 +2457,14 @@
 
 	return this.scope.referenceContext.sourceStart;
 }
-SimpleLookupTable storedAnnotations(boolean forceInitialize) {
+SimpleLookupTable storedAnnotations(boolean forceInitialize, boolean forceStore) {
 	if (!isPrototype())
-		return this.prototype.storedAnnotations(forceInitialize);
+		return this.prototype.storedAnnotations(forceInitialize, forceStore);
 
 	if (forceInitialize && this.storedAnnotations == null && this.scope != null) { // scope null when no annotation cached, and type got processed fully (159631)
 		this.scope.referenceCompilationUnit().compilationResult.hasAnnotations = true;
 		final CompilerOptions globalOptions = this.scope.environment().globalOptions;
-		if (!globalOptions.storeAnnotations)
+		if (!globalOptions.storeAnnotations && !forceStore)
 			return null; // not supported during this compile
 		this.storedAnnotations = new SimpleLookupTable(3);
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
index 166a8ab..8741722 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
@@ -175,6 +175,7 @@
 	char[][] JAVA_UTIL_LIST = {JAVA, UTIL, "List".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_DEPRECATED = {JAVA, LANG, "Deprecated".toCharArray()}; //$NON-NLS-1$
 	char[] FOR_REMOVAL = "forRemoval".toCharArray(); //$NON-NLS-1$
+	char[] SINCE = "since".toCharArray(); //$NON-NLS-1$
 	char[][] JAVA_LANG_ANNOTATION_DOCUMENTED = {JAVA, LANG, ANNOTATION, "Documented".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_ANNOTATION_INHERITED = {JAVA, LANG, ANNOTATION, "Inherited".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_ANNOTATION_REPEATABLE = {JAVA, LANG, ANNOTATION, "Repeatable".toCharArray()}; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
index e01b439..a50f020 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
@@ -503,6 +503,9 @@
 	
 	public void updateCaches(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType) {
 		final int unresolvedTypeId = unresolvedType.id;
+		if (resolvedType.id != TypeIds.NoId) {
+			unresolvedType.id = resolvedType.id;
+		}
 		if (unresolvedTypeId != TypeIds.NoId) {
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=432977
 			TypeBinding[] derivedTypes = this.types[unresolvedTypeId];
@@ -510,7 +513,8 @@
 				if (derivedTypes[i] == null)
 					break;
 				if (derivedTypes[i] == unresolvedType) { //$IDENTITY-COMPARISON$
-					resolvedType.id = unresolvedTypeId;
+					if(resolvedType.id == TypeIds.NoId)
+						resolvedType.id = unresolvedTypeId;
 					derivedTypes[i] = resolvedType;
 				}
 			}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java
index b80272a..6cb7126 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java
@@ -119,9 +119,6 @@
 			// create a proxy for the missing BinaryType
 			targetType = environment.createMissingType(null, this.compoundName);
 		}
-		if (targetType.id != TypeIds.NoId) {
-			this.id = targetType.id;
-		}
 		setResolvedType(targetType, environment);
 	}
 	if (convertGenericToRawType) {
@@ -147,7 +144,7 @@
 	ReferenceBinding annotatedType = (ReferenceBinding) unannotatedType.clone(null);
 	this.resolvedType = annotatedType;
 	annotatedType.setTypeAnnotations(getTypeAnnotations(), environment.globalOptions.isAnnotationBasedNullAnalysisEnabled);
-	annotatedType.id = unannotatedType.id = this.id;
+
 	environment.updateCaches(this, annotatedType);
 	if (this.wrappers != null)
 		for (int i = 0, l = this.wrappers.length; i < l; i++)
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 47aae15..0ae933d 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
@@ -85,6 +85,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
 import org.eclipse.jdt.core.compiler.CategorizedProblem;
@@ -167,9 +168,12 @@
 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
+import org.eclipse.jdt.internal.compiler.impl.StringConstant;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair;
 import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
 import org.eclipse.jdt.internal.compiler.lookup.InvocationSite;
@@ -247,6 +251,11 @@
 		case IProblem.UsingDeprecatedMethod :
 		case IProblem.UsingDeprecatedConstructor :
 		case IProblem.UsingDeprecatedField :
+		case IProblem.OverridingDeprecatedSinceVersionMethod :
+		case IProblem.UsingDeprecatedSinceVersionType :
+		case IProblem.UsingDeprecatedSinceVersionMethod :
+		case IProblem.UsingDeprecatedSinceVersionConstructor :
+		case IProblem.UsingDeprecatedSinceVersionField :
 			return CompilerOptions.UsingDeprecatedAPI;
 
 		case IProblem.OverridingTerminallyDeprecatedMethod :
@@ -254,6 +263,11 @@
 		case IProblem.UsingTerminallyDeprecatedMethod :
 		case IProblem.UsingTerminallyDeprecatedConstructor :
 		case IProblem.UsingTerminallyDeprecatedField :
+		case IProblem.OverridingTerminallyDeprecatedSinceVersionMethod :
+		case IProblem.UsingTerminallyDeprecatedSinceVersionType :
+		case IProblem.UsingTerminallyDeprecatedSinceVersionMethod :
+		case IProblem.UsingTerminallyDeprecatedSinceVersionConstructor :
+		case IProblem.UsingTerminallyDeprecatedSinceVersionField :
 			return CompilerOptions.UsingTerminallyDeprecatedAPI;
 
 		case IProblem.LocalVariableIsNeverUsed :
@@ -1708,20 +1722,37 @@
 		sourceStart, sourceEnd);
 }
 
-public void deprecatedField(FieldBinding field, ASTNode location) {
-	this.handle(
-		(field.tagBits & TagBits.AnnotationTerminallyDeprecated) == 0 ? IProblem.UsingDeprecatedField : IProblem.UsingTerminallyDeprecatedField,
-		new String[] {new String(field.declaringClass.readableName()), new String(field.name)},
-		new String[] {new String(field.declaringClass.shortReadableName()), new String(field.name)},
-		nodeSourceStart(field, location),
-		nodeSourceEnd(field, location));
+public void deprecatedField(final FieldBinding field, ASTNode location) {
+	String fieldName = new String(field.name);
+	int sourceStart = nodeSourceStart(field, location);
+	int sourceEnd = nodeSourceEnd(field, location);
+	String sinceValue = deprecatedSinceValue(() -> field.getAnnotations());
+	if (sinceValue != null) {
+		this.handle(
+			(field.tagBits & TagBits.AnnotationTerminallyDeprecated) == 0 ? IProblem.UsingDeprecatedSinceVersionField : IProblem.UsingTerminallyDeprecatedSinceVersionField,
+			new String[] {new String(field.declaringClass.readableName()), fieldName, sinceValue},
+			new String[] {new String(field.declaringClass.shortReadableName()), fieldName, sinceValue},
+			sourceStart, sourceEnd);
+	} else {
+		this.handle(
+			(field.tagBits & TagBits.AnnotationTerminallyDeprecated) == 0 ? IProblem.UsingDeprecatedField : IProblem.UsingTerminallyDeprecatedField,
+			new String[] {new String(field.declaringClass.readableName()), fieldName},
+			new String[] {new String(field.declaringClass.shortReadableName()), fieldName},
+			sourceStart, sourceEnd);
+	}
 }
 
-public void deprecatedMethod(MethodBinding method, ASTNode location) {
+public void deprecatedMethod(final MethodBinding method, ASTNode location) {
+	// common arguments:
+	String readableClassName = new String(method.declaringClass.readableName());
+	String shortReadableClassName = new String(method.declaringClass.shortReadableName());
+	String selector = new String(method.selector);
+	String signature = typesAsString(method, false);
+	String shortSignature = typesAsString(method, true);
+	
 	boolean isConstructor = method.isConstructor();
-	boolean terminally = (method.tagBits & TagBits.AnnotationTerminallyDeprecated) != 0;
+	int start = -1;
 	if (isConstructor) {
-		int start = -1;
 		if(location instanceof AllocationExpression) {
 			// omit the new keyword from the warning marker
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=300031
@@ -1731,25 +1762,50 @@
 			}
 			start = allocationExpression.type.sourceStart;
 		}
-		this.handle(
-			terminally ? IProblem.UsingTerminallyDeprecatedConstructor : IProblem.UsingDeprecatedConstructor,
-			new String[] {new String(method.declaringClass.readableName()), typesAsString(method, false)},
-			new String[] {new String(method.declaringClass.shortReadableName()), typesAsString(method, true)},
-			(start == -1) ? location.sourceStart : start,
-			location.sourceEnd);
 	} else {
-		int start = -1;
 		if (location instanceof MessageSend) {
 			// start the warning marker from the location where the name of the method starts
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=300031
 			start = (int) (((MessageSend)location).nameSourcePosition >>> 32);
 		}
-		this.handle(
-			terminally ? IProblem.UsingTerminallyDeprecatedMethod : IProblem.UsingDeprecatedMethod,
-			new String[] {new String(method.declaringClass.readableName()), new String(method.selector), typesAsString(method, false)},
-			new String[] {new String(method.declaringClass.shortReadableName()), new String(method.selector), typesAsString(method, true)},
-			(start == -1) ? location.sourceStart : start,
-			location.sourceEnd);
+	}
+	int sourceStart = (start == -1) ? location.sourceStart : start;
+	int sourceEnd = location.sourceEnd;
+
+	// discriminate:
+	boolean terminally = (method.tagBits & TagBits.AnnotationTerminallyDeprecated) != 0;
+	String sinceValue = deprecatedSinceValue(() -> method.getAnnotations());
+	if (sinceValue == null && method.isConstructor()) {
+		sinceValue = deprecatedSinceValue(() -> method.declaringClass.getAnnotations()); // for default ctor
+	}
+	if (sinceValue != null) {
+		if (isConstructor) {
+			this.handle(
+				terminally ? IProblem.UsingTerminallyDeprecatedSinceVersionConstructor : IProblem.UsingDeprecatedSinceVersionConstructor,
+				new String[] {readableClassName, signature, sinceValue},
+				new String[] {shortReadableClassName, shortSignature, sinceValue},
+				sourceStart, sourceEnd);
+		} else {
+			this.handle(
+				terminally ? IProblem.UsingTerminallyDeprecatedSinceVersionMethod : IProblem.UsingDeprecatedSinceVersionMethod,
+				new String[] {readableClassName, selector, signature, sinceValue},
+				new String[] {shortReadableClassName, selector, shortSignature, sinceValue},
+				sourceStart, sourceEnd);
+		}
+	} else {
+		if (isConstructor) {
+			this.handle(
+				terminally ? IProblem.UsingTerminallyDeprecatedConstructor : IProblem.UsingDeprecatedConstructor,
+				new String[] {readableClassName, signature},
+				new String[] {shortReadableClassName, shortSignature},
+				sourceStart, sourceEnd);
+		} else {
+			this.handle(
+				terminally ? IProblem.UsingTerminallyDeprecatedMethod : IProblem.UsingDeprecatedMethod,
+				new String[] {readableClassName, selector, signature},
+				new String[] {shortReadableClassName, selector, shortSignature},
+				sourceStart, sourceEnd);
+		}
 	}
 }
 public void deprecatedType(TypeBinding type, ASTNode location) {
@@ -1759,7 +1815,7 @@
 // a deprecated type in a qualified reference (see bug 292510)
 public void deprecatedType(TypeBinding type, ASTNode location, int index) {
 	if (location == null) return; // 1G828DN - no type ref for synthetic arguments
-	type = type.leafComponentType();
+	final TypeBinding leafType = type.leafComponentType();
 	int sourceStart = -1;
 	if (location instanceof QualifiedTypeReference) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=300031
 		QualifiedTypeReference ref = (QualifiedTypeReference) location;
@@ -1767,12 +1823,36 @@
 			sourceStart = (int) (ref.sourcePositions[index] >> 32);
 		}
 	}
-	this.handle(
-		((type.tagBits & TagBits.AnnotationTerminallyDeprecated) == 0) ? IProblem.UsingDeprecatedType : IProblem.UsingTerminallyDeprecatedType,
-		new String[] {new String(type.readableName())},
-		new String[] {new String(type.shortReadableName())},
-		(sourceStart == -1) ? location.sourceStart : sourceStart,
-		nodeSourceEnd(null, location, index));
+	String sinceValue = deprecatedSinceValue(() -> leafType.getAnnotations());
+	if (sinceValue != null) {
+		this.handle(
+			((leafType.tagBits & TagBits.AnnotationTerminallyDeprecated) == 0) ? IProblem.UsingDeprecatedSinceVersionType : IProblem.UsingTerminallyDeprecatedSinceVersionType,
+			new String[] {new String(leafType.readableName()), sinceValue},
+			new String[] {new String(leafType.shortReadableName()), sinceValue},
+			(sourceStart == -1) ? location.sourceStart : sourceStart,
+			nodeSourceEnd(null, location, index));
+	} else {
+		this.handle(
+			((leafType.tagBits & TagBits.AnnotationTerminallyDeprecated) == 0) ? IProblem.UsingDeprecatedType : IProblem.UsingTerminallyDeprecatedType,
+			new String[] {new String(leafType.readableName())},
+			new String[] {new String(leafType.shortReadableName())},
+			(sourceStart == -1) ? location.sourceStart : sourceStart,
+			nodeSourceEnd(null, location, index));
+	}
+}
+String deprecatedSinceValue(Supplier<AnnotationBinding[]> annotations) {
+	if (this.options != null && this.options.complianceLevel >= ClassFileConstants.JDK9) {
+		for (AnnotationBinding annotationBinding : annotations.get()) {
+			if (annotationBinding.getAnnotationType().id == TypeIds.T_JavaLangDeprecated) {
+				for (ElementValuePair elementValuePair : annotationBinding.getElementValuePairs()) {
+					if (CharOperation.equals(elementValuePair.getName(), TypeConstants.SINCE) && elementValuePair.value instanceof StringConstant)
+						return ((StringConstant) elementValuePair.value).stringValue();
+				}
+				break;
+			}
+		}
+	}
+	return null;
 }
 public void disallowedTargetForAnnotation(Annotation annotation) {
 	this.handle(
@@ -6962,25 +7042,45 @@
 		assignment.sourceEnd);
 }
 public void overridesDeprecatedMethod(MethodBinding localMethod, MethodBinding inheritedMethod) {
-	this.handle(
-		(inheritedMethod.tagBits & TagBits.AnnotationTerminallyDeprecated) != 0
+	String localMethodName = new String(
+								CharOperation.concat(
+									localMethod.declaringClass.readableName(),
+									localMethod.readableName(),
+									'.'));
+	String localMethodShortName = new String(
+									CharOperation.concat(
+										localMethod.declaringClass.shortReadableName(),
+										localMethod.shortReadableName(),
+										'.'));
+	String sinceValue = deprecatedSinceValue(() -> inheritedMethod.getAnnotations());
+	if (sinceValue != null) {
+		this.handle(
+			(inheritedMethod.tagBits & TagBits.AnnotationTerminallyDeprecated) != 0
+				? IProblem.OverridingTerminallyDeprecatedSinceVersionMethod : IProblem.OverridingDeprecatedSinceVersionMethod,
+			new String[] {
+				localMethodName,
+				new String(inheritedMethod.declaringClass.readableName()),
+				sinceValue},
+			new String[] {
+				localMethodShortName,
+				new String(inheritedMethod.declaringClass.shortReadableName()),
+				sinceValue},
+			localMethod.sourceStart(),
+			localMethod.sourceEnd());
+		
+	} else {
+		this.handle(
+			(inheritedMethod.tagBits & TagBits.AnnotationTerminallyDeprecated) != 0
 				? IProblem.OverridingTerminallyDeprecatedMethod : IProblem.OverridingDeprecatedMethod,
-		new String[] {
-			new String(
-					CharOperation.concat(
-						localMethod.declaringClass.readableName(),
-						localMethod.readableName(),
-						'.')),
-			new String(inheritedMethod.declaringClass.readableName())},
-		new String[] {
-			new String(
-					CharOperation.concat(
-						localMethod.declaringClass.shortReadableName(),
-						localMethod.shortReadableName(),
-						'.')),
-			new String(inheritedMethod.declaringClass.shortReadableName())},
-		localMethod.sourceStart(),
-		localMethod.sourceEnd());
+			new String[] {
+				localMethodName,
+				new String(inheritedMethod.declaringClass.readableName())},
+			new String[] {
+				localMethodShortName,
+				new String(inheritedMethod.declaringClass.shortReadableName())},
+			localMethod.sourceStart(),
+			localMethod.sourceEnd());
+	}
 }
 public void overridesMethodWithoutSuperInvocation(MethodBinding localMethod) {
 	this.handle(
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 db0f437..7f3e65c 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
@@ -915,6 +915,18 @@
 1403 = The field {0}.{1} has been deprecated and marked for removal
 1404 = The method {0} overrides a method from {1} that has been deprecated and marked for removal
 
+1405 = The type {0} is deprecated since version {1}
+1406 = The method {1}({2}) from the type {0} is deprecated since version {3}
+1407 = The constructor {0}({1}) is deprecated since version {2}
+1408 = The field {0}.{1} is deprecated since version {2}
+1409 = The method {0} overrides a method from {1} that is deprecated since version {2}
+
+1410 = The type {0} has been deprecated since version {1} and marked for removal
+1411 = The method {1}({2}) from the type {0} has been deprecated since version {3} and marked for removal
+1412 = The constructor {0}({1}) has been deprecated since version {2} and marked for removal
+1413 = The field {0}.{1} has been deprecated since version {2} and marked for removal
+1414 = The method {0} overrides a method from {1} that has been deprecated since version {2} and marked for removal
+
 1450 = The type {0} is not accessible
 1451 = The field {1}.{0} is not accessible
 1452 = The method {1}({2}) from the type {0} is not accessible
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
index 683d70d..93c0e01 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java
@@ -17,23 +17,23 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.formatter;
 
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_BLOCK;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_JAVADOC;
+import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_LINE;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameEOF;
 import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameNotAToken;
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_JAVADOC;
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_BLOCK;
-import static org.eclipse.jdt.internal.compiler.parser.TerminalTokens.TokenNameCOMMENT_LINE;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.Path;
 import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IModuleDescription;
 import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.core.compiler.InvalidInputException;
 import org.eclipse.jdt.core.dom.AST;
@@ -49,7 +49,8 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
 import org.eclipse.jdt.internal.compiler.util.Util;
-import org.eclipse.jdt.internal.core.PackageFragment;
+import org.eclipse.jdt.internal.core.JavaProject;
+import org.eclipse.jdt.internal.core.SourceModule;
 import org.eclipse.jdt.internal.formatter.linewrap.CommentWrapExecutor;
 import org.eclipse.jdt.internal.formatter.linewrap.WrapPreparator;
 import org.eclipse.jface.text.IRegion;
@@ -328,16 +329,7 @@
 		ASTParser parser = ASTParser.newParser(AST.JLS9);
 
 		if (kind == K_MODULE_INFO) {
-			Path fakeModuleInfoPath = new Path("project/" + TypeConstants.MODULE_INFO_FILE_NAME_STRING); //$NON-NLS-1$
-			IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(fakeModuleInfoPath);
-			ICompilationUnit unit = JavaCore.createCompilationUnitFrom(file);
-			parser.setSource(new org.eclipse.jdt.internal.core.CompilationUnit((PackageFragment) unit.getParent(),
-					unit.getElementName(), unit.getOwner()) {
-				@Override
-				public char[] getContents() {
-					return DefaultCodeFormatter.this.sourceArray;
-				}
-			});
+			parser.setSource(createDummyModuleInfoCompilationUnit());
 		} else {
 			parser.setSource(this.sourceArray);
 		}
@@ -350,6 +342,32 @@
 		return parser;
 	}
 
+	private ICompilationUnit createDummyModuleInfoCompilationUnit() {
+		IJavaProject dummyProject = new JavaProject() {
+			@Override
+			public Map<String, String> getOptions(boolean inheritJavaCoreOptions) {
+				return new HashMap<>();
+			}
+
+			@Override
+			public IModuleDescription getModuleDescription() throws JavaModelException {
+				return new SourceModule(this, ""); //$NON-NLS-1$
+			}
+		};
+		return new org.eclipse.jdt.internal.core.CompilationUnit(null, TypeConstants.MODULE_INFO_FILE_NAME_STRING,
+				null) {
+			@Override
+			public char[] getContents() {
+				return DefaultCodeFormatter.this.sourceArray;
+			}
+
+			@Override
+			public IJavaProject getJavaProject() {
+				return dummyProject;
+			}
+		};
+	}
+
 	private boolean hasErrors(ASTNode astNode) {
 		CompilationUnit root = (CompilationUnit) astNode.getRoot();
 		for (IProblem problem : root.getProblems()) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleUpdater.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleUpdater.java
index 16947f9..c9696d1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleUpdater.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleUpdater.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2017 GK Software AG, and others.
+ * Copyright (c) 2017, 2018 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
@@ -62,7 +62,7 @@
 						String modName = value.substring(0, slash);
 						char[] packName = value.substring(slash+1, equals).toCharArray();
 						char[][] targets = CharOperation.splitOn(',', value.substring(equals+1).toCharArray());
-						addModuleUpdate(modName, m -> m.addExports(packName, targets), UpdateKind.PACKAGE);
+						addModuleUpdate(modName, new IUpdatableModule.AddExports(packName, targets), UpdateKind.PACKAGE);
 					} else {
 						Util.log(IStatus.WARNING, "Invalid argument to add-exports: "+value); //$NON-NLS-1$
 					}
@@ -73,7 +73,7 @@
 					if (equals != -1) {
 						String srcMod = value.substring(0, equals);
 						char[] targetMod = value.substring(equals+1).toCharArray();
-						addModuleUpdate(srcMod, m -> m.addReads(targetMod), UpdateKind.MODULE);
+						addModuleUpdate(srcMod, new IUpdatableModule.AddReads(targetMod), UpdateKind.MODULE);
 					} else {
 						Util.log(IStatus.WARNING, "Invalid argument to add-reads: "+value); //$NON-NLS-1$
 					}
@@ -108,4 +108,7 @@
 			}
 		}
 	}
+	public UpdatesByKind getUpdates(String moduleName) {
+		return this.moduleUpdates.get(moduleName);
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java
index 74f3332..a0ea9eb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathDirectory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -136,10 +136,10 @@
 	if (this.accessRuleSet != dir.accessRuleSet)
 		if (this.accessRuleSet == null || !this.accessRuleSet.equals(dir.accessRuleSet))
 			return false;
-	if (this.module != dir.module)
-		if (this.module == null || !this.module.equals(dir.module))
-			return false;
-	return this.binaryFolder.equals(dir.binaryFolder);
+	if (this.isOnModulePath != dir.isOnModulePath)
+		return false;
+
+	return this.binaryFolder.equals(dir.binaryFolder) && areAllModuleOptionsEqual(dir);
 }
 public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) {
 	if (!doesFileExist(binaryFileName, qualifiedPackageName, qualifiedBinaryFileName)) return null; // most common case
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
index 210c43c..b433fc0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJar.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -207,7 +207,8 @@
 			return false;
 	return this.zipFilename.equals(jar.zipFilename) 
 			&& lastModified() == jar.lastModified()
-			&& this.isOnModulePath == jar.isOnModulePath;
+			&& this.isOnModulePath == jar.isOnModulePath
+			&& areAllModuleOptionsEqual(jar);
 }
 
 public NameEnvironmentAnswer findClass(String binaryFileName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) {
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 855525d..e408838 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2016, 2017 IBM Corporation and others.
+ * Copyright (c) 2016, 2018 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
@@ -181,7 +181,8 @@
 	if (this == o) return true;
 	if (!(o instanceof ClasspathJrt)) return false;
 	ClasspathJrt jar = (ClasspathJrt) o;
-	return this.zipFilename.endsWith(jar.zipFilename);
+
+	return this.zipFilename.endsWith(jar.zipFilename) && areAllModuleOptionsEqual(jar);
 }
 
 @Override
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java
index 938151f..bdbe6e5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathLocation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -12,12 +12,18 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.builder;
 
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
 import org.eclipse.jdt.internal.compiler.env.IModule;
+import org.eclipse.jdt.internal.compiler.env.IUpdatableModule;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
+import org.eclipse.jdt.internal.compiler.env.IUpdatableModule.UpdateKind;
 import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
 import org.eclipse.jdt.internal.compiler.util.Util;
 
@@ -25,6 +31,9 @@
 
 	protected boolean isOnModulePath;
 	protected IModule module;
+	protected IUpdatableModule.UpdatesByKind updates;
+	protected Set<String> limitModuleNames = null;
+	protected String patchModuleName = null;
 	// In the following signatures, passing a null moduleName signals "don't care":
 	abstract public NameEnvironmentAnswer findClass(String typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName);
 	abstract public NameEnvironmentAnswer findClass(String typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly);
@@ -45,6 +54,62 @@
 	public IModule getModule() {
 		return this.module;
 	}
+	protected boolean areAllModuleOptionsEqual(ClasspathLocation other) {
+		if (this.patchModuleName != null) {
+			if (other.patchModuleName == null)
+				return false;
+			if (!this.patchModuleName.equals(other.patchModuleName))
+				return false;
+		} else {
+			if (other.patchModuleName != null)
+				return false;
+		}
+		if (this.limitModuleNames != null) {
+			if (other.limitModuleNames == null)
+				return false;
+			if (other.limitModuleNames.size() != this.limitModuleNames.size())
+				return false;
+			if (!this.limitModuleNames.containsAll(other.limitModuleNames))
+				return false;
+		} else {
+			if (other.limitModuleNames != null)
+				return false;
+		}
+		if (this.updates != null) {
+			if (other.updates == null)
+				return false;
+			List<Consumer<IUpdatableModule>> packageUpdates = this.updates.getList(UpdateKind.PACKAGE, false);
+			List<Consumer<IUpdatableModule>> otherPackageUpdates = other.updates.getList(UpdateKind.PACKAGE, false);
+			if (packageUpdates != null) {
+				if (otherPackageUpdates == null)
+					return false;
+				if (packageUpdates.size() != otherPackageUpdates.size())
+					return false;
+				if (!packageUpdates.containsAll(otherPackageUpdates))
+					return false;
+			} else {
+				if (otherPackageUpdates != null)
+					return false;
+			}
+			List<Consumer<IUpdatableModule>> moduleUpdates = this.updates.getList(UpdateKind.MODULE, false);
+			List<Consumer<IUpdatableModule>> otherModuleUpdates = other.updates.getList(UpdateKind.MODULE, false);
+			if (moduleUpdates != null) {
+				if (otherModuleUpdates == null)
+					return false;
+				if (moduleUpdates.size() != otherModuleUpdates.size())
+					return false;
+				if (!moduleUpdates.containsAll(otherModuleUpdates))
+					return false;
+			} else {
+				if (otherModuleUpdates != null)
+					return false;
+			}
+		} else {
+			if (other.updates != null)
+				return false;
+		}
+		return true;
+	}
 	static ClasspathLocation forSourceFolder(IContainer sourceFolder, IContainer outputFolder,
 			char[][] inclusionPatterns, char[][] exclusionPatterns, boolean ignoreOptionalProblems) {
 		return new ClasspathMultiDirectory(sourceFolder, outputFolder, inclusionPatterns, exclusionPatterns,
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 bcf5f72..054b11c 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
@@ -23,6 +23,7 @@
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.env.*;
+import org.eclipse.jdt.internal.compiler.env.IUpdatableModule.UpdateKind;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
@@ -33,6 +34,7 @@
 
 import java.io.*;
 import java.util.*;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
 @SuppressWarnings({"rawtypes", "unchecked"})
@@ -162,6 +164,7 @@
 							entry.ignoreOptionalProblems());
 				if (patchedModule != null) {
 					ModuleEntryProcessor.combinePatchIntoModuleEntry(sourceLocation, patchedModule, moduleEntries);
+					sourceLocation.patchModuleName = patchedModuleName;
 				}
 				sLocations.add(sourceLocation);
 				continue nextEntry;
@@ -221,6 +224,12 @@
 					ModulePathEntry projectEntry = new ModulePathEntry(prereqJavaProject.getPath(), info,
 							projectLocations.toArray(new ClasspathLocation[projectLocations.size()]));
 					String moduleName = String.valueOf(info.name());
+					IUpdatableModule.UpdatesByKind updates = this.moduleUpdater.getUpdates(moduleName);
+					for (ClasspathLocation loc : projectLocations) {
+						loc.limitModuleNames = limitModules;
+						loc.updates = updates;
+						loc.patchModuleName = patchedModuleName;
+					}
 					if (limitModules == null || limitModules.contains(moduleName)) {
 						moduleEntries.put(moduleName, projectEntry);
 						if (moduleName.equals(patchedModuleName))
@@ -339,8 +348,28 @@
 								String patchedModuleName, IModule patchedModule, Map<String, IModulePathEntry> moduleEntries) {
 	if (bLocation instanceof IMultiModuleEntry) {
 		IMultiModuleEntry binaryModulePathEntry = (IMultiModuleEntry) bLocation;
+		bLocation.limitModuleNames = limitModules;
+		bLocation.patchModuleName = patchedModuleName;
+		IUpdatableModule.UpdatesByKind updates = null;//new IUpdatableModule.UpdatesByKind();
+		IUpdatableModule.UpdatesByKind finalUpdates = new IUpdatableModule.UpdatesByKind();
+		List<Consumer<IUpdatableModule>> packageUpdates = null;
+		List<Consumer<IUpdatableModule>> moduleUpdates = null;
 		for (String moduleName : binaryModulePathEntry.getModuleNames(limitModules)) {
 			moduleEntries.put(moduleName, binaryModulePathEntry);
+			updates = this.moduleUpdater.getUpdates(moduleName);
+			if (updates != null) {
+				List<Consumer<IUpdatableModule>> pu = updates.getList(UpdateKind.PACKAGE, false);
+				if (pu != null) {
+					(packageUpdates = finalUpdates.getList(UpdateKind.PACKAGE, true)).addAll(pu);
+				}
+				List<Consumer<IUpdatableModule>> mu = updates.getList(UpdateKind.MODULE, false);
+				if (mu != null) {
+					(moduleUpdates = finalUpdates.getList(UpdateKind.MODULE, true)).addAll(mu);
+				}
+			}
+		}
+		if (packageUpdates != null || moduleUpdates != null) {
+			bLocation.updates = finalUpdates;
 		}
 		if (patchedModuleName != null) {
 			IModule module = binaryModulePathEntry.getModule(patchedModuleName.toCharArray());
@@ -353,6 +382,9 @@
 		IModule module = binaryModulePathEntry.getModule();
 		if (module != null) {
 			String moduleName = String.valueOf(module.name());
+			bLocation.updates = this.moduleUpdater.getUpdates(moduleName);
+			bLocation.limitModuleNames = limitModules;
+			bLocation.patchModuleName = patchedModuleName;
 			if (limitModules == null || limitModules == ClasspathJrt.NO_LIMIT_MODULES || limitModules.contains(moduleName)) {
 				moduleEntries.put(moduleName, binaryModulePathEntry);
 				if (patchedModuleName != null) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java
index a6d5695..2ea610a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 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
@@ -17,6 +17,8 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
+import org.eclipse.jdt.internal.compiler.env.IUpdatableModule;
+import org.eclipse.jdt.internal.compiler.env.IUpdatableModule.*;
 import org.eclipse.jdt.internal.compiler.env.AccessRule;
 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
 import org.eclipse.jdt.internal.compiler.util.Util;
@@ -25,6 +27,8 @@
 
 import java.io.*;
 import java.util.*;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
 
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class State {
@@ -281,6 +285,38 @@
 					newState.binaryLocations[i] = ClasspathLocation.forLibrary(root.getFile(new Path(in.readUTF())),
 							readRestriction(in), new Path(in.readUTF()), in.readBoolean());
 		}
+		ClasspathLocation loc = newState.binaryLocations[i];
+		char[] patchName = readName(in);
+		loc.patchModuleName = patchName.length > 0 ? new String(patchName) : null;
+		int limitSize = in.readInt();
+		if (limitSize != 0) {
+			loc.limitModuleNames = new HashSet<>(limitSize);
+			for (int j = 0; j < limitSize; j++) {
+				loc.limitModuleNames.add(in.readUTF());
+			}
+		} else {
+			loc.limitModuleNames = null;
+		}
+		IUpdatableModule.UpdatesByKind updates = new IUpdatableModule.UpdatesByKind();
+		List<Consumer<IUpdatableModule>> packageUpdates = null;
+		int packageUpdatesSize = in.readInt();
+		if (packageUpdatesSize != 0) {
+			packageUpdates = updates.getList(UpdateKind.PACKAGE, true);
+			for (int j = 0; j < packageUpdatesSize; j++) {
+				char[] pkgName = readName(in);
+				char[][] targets = readNames(in);
+				packageUpdates.add(new AddExports(pkgName, targets));
+			}
+		}
+		List<Consumer<IUpdatableModule>> moduleUpdates = null;
+		int moduleUpdatesSize = in.readInt();
+		if (moduleUpdatesSize != 0) {
+			moduleUpdates = updates.getList(UpdateKind.MODULE, true);
+			char[] modName = readName(in);
+			moduleUpdates.add(new AddReads(modName));
+		}
+		if (packageUpdates != null || moduleUpdates != null)
+			loc.updates = updates;
 	}
 
 	newState.structuralBuildTimes = new SimpleLookupTable(length = in.readInt());
@@ -443,14 +479,14 @@
  * String		path(s)
 */
 	out.writeInt(length = this.binaryLocations.length);
-	next : for (int i = 0; i < length; i++) {
+	for (int i = 0; i < length; i++) {
 		ClasspathLocation c = this.binaryLocations[i];
 		if (c instanceof ClasspathMultiDirectory) {
 			out.writeByte(SOURCE_FOLDER);
 			for (int j = 0, m = this.sourceLocations.length; j < m; j++) {
 				if (this.sourceLocations[j] == c) {
 					out.writeInt(j);
-					continue next;
+					//continue next;
 				}
 			}
 		} else if (c instanceof ClasspathDirectory) {
@@ -482,6 +518,55 @@
 			writeRestriction(null, out);
 			out.writeUTF(""); //$NON-NLS-1$
 		}
+		char[] patchName = c.patchModuleName == null ? CharOperation.NO_CHAR : c.patchModuleName.toCharArray();
+		writeName(patchName, out);
+		if (c.limitModuleNames != null) {
+			out.writeInt(c.limitModuleNames.size());
+			for (String name : c.limitModuleNames) {
+				out.writeUTF(name);
+			}
+		} else {
+			out.writeInt(0);
+		}
+		if (c.updates != null) {
+			List<Consumer<IUpdatableModule>> pu = c.updates.getList(UpdateKind.PACKAGE, false);
+			if (pu != null) {
+				Map<String, List<Consumer<IUpdatableModule>>> map = pu.stream().
+						collect(Collectors.groupingBy(
+								update -> CharOperation.charToString(((IUpdatableModule.AddExports)update).getName())));
+				out.writeInt(map.size());
+				map.entrySet().stream().forEach(entry -> {
+					String pkgName = entry.getKey();
+					try {
+						writeName(pkgName.toCharArray(), out);
+						char[][] targetModules = entry.getValue().stream()
+								.map(consumer -> ((IUpdatableModule.AddExports) consumer).getTargetModules())
+								.filter(targets -> targets != null)
+								.reduce((f,s) -> CharOperation.arrayConcat(f,s))
+								.orElse(null);
+						writeNames(targetModules, out);
+					} catch (IOException e) {
+						// ignore
+					}
+					
+				});
+			} else {
+				out.writeInt(0);
+			}
+			List<Consumer<IUpdatableModule>> mu = c.updates.getList(UpdateKind.MODULE, false);
+			if (mu != null) {
+				out.writeInt(mu.size());
+				for (Consumer<IUpdatableModule> cons : mu) {
+					AddReads m = (AddReads) cons;
+					writeName(m.getTarget(), out);
+				}
+			} else {
+				out.writeInt(0);
+			}
+		} else {
+			out.writeInt(0);
+			out.writeInt(0);
+		}
 	}
 
 /*
diff --git a/org.eclipse.jdt.core/pom.xml b/org.eclipse.jdt.core/pom.xml
index 8a47770..64897ac 100644
--- a/org.eclipse.jdt.core/pom.xml
+++ b/org.eclipse.jdt.core/pom.xml
@@ -18,7 +18,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.core</artifactId>
-  <version>3.15.0-SNAPSHOT</version>
+  <version>3.13.102-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 
   <properties>