Update to JDTCore #48c3f7668a46f2742 (16Apr2020)
diff --git a/org.eclipse.jdt.core/.classpath b/org.eclipse.jdt.core/.classpath
index d9d0992..99676b5 100644
--- a/org.eclipse.jdt.core/.classpath
+++ b/org.eclipse.jdt.core/.classpath
@@ -12,7 +12,7 @@
 	<classpathentry kind="src" path="apt"/>
 	<classpathentry kind="src" path="search"/>
 	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-	<classpathentry kind="lib" path="lib/java9api.jar"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+	<classpathentry kind="lib" path="lib/java14api.jar"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
diff --git a/org.eclipse.jdt.core/.settings/.api_filters b/org.eclipse.jdt.core/.settings/.api_filters
new file mode 100644
index 0000000..4ddad2d
--- /dev/null
+++ b/org.eclipse.jdt.core/.settings/.api_filters
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.jdt.core" version="2">
+    <resource path="compiler/org/eclipse/jdt/core/compiler/CategorizedProblem.java" type="org.eclipse.jdt.core.compiler.CategorizedProblem">
+        <filter comment="Java 14" id="576725006">
+            <message_arguments>
+                <message_argument value="IProblem"/>
+                <message_argument value="CategorizedProblem"/>
+            </message_arguments>
+        </filter>
+    </resource>
+    <resource path="compiler/org/eclipse/jdt/core/compiler/IProblem.java" type="org.eclipse.jdt.core.compiler.IProblem">
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionaYieldSwitchLabeledBlockCompletesNormally"/>
+                <message_argument value="2098855"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldBreakNotAllowed"/>
+                <message_argument value="2098863"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldEmptySwitchBlock"/>
+                <message_argument value="2098853"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldIllegalLastStatement"/>
+                <message_argument value="2098862"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldIllegalStatement"/>
+                <message_argument value="2098868"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldIncompatibleResultExpressionTypes"/>
+                <message_argument value="2098852"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldLastStatementCompletesNormally"/>
+                <message_argument value="2098856"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldMissingDefaultCase"/>
+                <message_argument value="2098859"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldMissingEnumConstantCase"/>
+                <message_argument value="2098861"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldMissingValue"/>
+                <message_argument value="2098860"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldNoResultExpression"/>
+                <message_argument value="2098854"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldOutsideSwitchExpression"/>
+                <message_argument value="2098866"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldRestrictedGeneralWarning"/>
+                <message_argument value="2098867"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldTrailingSwitchLabels"/>
+                <message_argument value="2098857"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldTypeDeclarationError"/>
+                <message_argument value="2098870"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldTypeDeclarationWarning"/>
+                <message_argument value="2098869"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldUnqualifiedMethodError"/>
+                <message_argument value="2098865"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchExpressionsYieldUnqualifiedMethodWarning"/>
+                <message_argument value="2098864"/>
+            </message_arguments>
+        </filter>
+        <filter comment="Needed for Java14" id="388194388">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.compiler.IProblem"/>
+                <message_argument value="SwitchPreviewMixedCase"/>
+                <message_argument value="2098858"/>
+            </message_arguments>
+        </filter>
+    </resource>
+    <resource path="dom/org/eclipse/jdt/core/dom/InstanceofExpression.java" type="org.eclipse.jdt.core.dom.InstanceofExpression">
+        <filter comment="For Java 14" id="336658481">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.dom.InstanceofExpression"/>
+                <message_argument value="PATTERN_VARIABLE_PROPERTY"/>
+            </message_arguments>
+        </filter>
+    </resource>
+    <resource path="dom/org/eclipse/jdt/core/dom/MethodDeclaration.java" type="org.eclipse.jdt.core.dom.MethodDeclaration">
+        <filter comment="Needed for Java 14" id="336658481">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.dom.MethodDeclaration"/>
+                <message_argument value="COMPACT_CONSTRUCTOR_PROPERTY"/>
+            </message_arguments>
+        </filter>
+    </resource>
+    <resource path="model/org/eclipse/jdt/core/util/IClassFileReader.java" type="org.eclipse.jdt.core.util.IClassFileReader">
+        <filter comment="For the Java 14 preview feature record" id="404000815">
+            <message_arguments>
+                <message_argument value="org.eclipse.jdt.core.util.IClassFileReader"/>
+                <message_argument value="getRecordAttribute()"/>
+            </message_arguments>
+        </filter>
+    </resource>
+</component>
diff --git a/org.eclipse.jdt.core/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.jdt.core/.settings/org.eclipse.jdt.ui.prefs
index 4f5ca89..e65281d 100644
--- a/org.eclipse.jdt.core/.settings/org.eclipse.jdt.ui.prefs
+++ b/org.eclipse.jdt.core/.settings/org.eclipse.jdt.ui.prefs
@@ -88,7 +88,7 @@
 sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
 sp_cleanup.remove_private_constructors=true
 sp_cleanup.remove_redundant_type_arguments=false
-sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces=true
 sp_cleanup.remove_trailing_whitespaces_all=true
 sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
 sp_cleanup.remove_unnecessary_casts=false
diff --git a/org.eclipse.jdt.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.core/META-INF/MANIFEST.MF
index 53f0c78..eaa30d4 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.16.0.qualifier
+Bundle-Version: 3.22.0.qualifier
 Bundle-Activator: org.eclipse.jdt.core.JavaCore
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
@@ -16,9 +16,9 @@
  org.eclipse.jdt.core.formatter,
  org.eclipse.jdt.core.index,
  org.eclipse.jdt.core.jdom,
+ org.eclipse.jdt.core.provisional;x-friends:="org.eclipse.jdt.debug.ui,org.eclipse.jdt.launching,org.eclipse.jdt.ui",
  org.eclipse.jdt.core.search,
  org.eclipse.jdt.core.util,
- org.eclipse.jdt.core.provisional;x-friends:="org.eclipse.jdt.debug.ui,org.eclipse.jdt.launching",
  org.eclipse.jdt.internal.codeassist;x-internal:=true,
  org.eclipse.jdt.internal.codeassist.complete;x-internal:=true,
  org.eclipse.jdt.internal.codeassist.impl;x-internal:=true,
@@ -30,7 +30,7 @@
  org.eclipse.jdt.internal.compiler.codegen;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core,org.eclipse.pde.api.tools",
  org.eclipse.jdt.internal.compiler.env;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
  org.eclipse.jdt.internal.compiler.flow;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
- org.eclipse.jdt.internal.compiler.impl;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
+ org.eclipse.jdt.internal.compiler.impl;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core,org.eclipse.jdt.debug",
  org.eclipse.jdt.internal.compiler.lookup;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
  org.eclipse.jdt.internal.compiler.parser;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
  org.eclipse.jdt.internal.compiler.parser.diagnose;x-friends:="org.eclipse.jdt.compiler.tool,org.eclipse.jdt.apt.pluggable.core",
@@ -59,7 +59,7 @@
  org.eclipse.jdt.internal.core.search.indexing;x-internal:=true,
  org.eclipse.jdt.internal.core.search.matching;x-internal:=true,
  org.eclipse.jdt.internal.core.search.processing;x-internal:=true,
- org.eclipse.jdt.internal.core.util;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.pde.api.tools",
+ org.eclipse.jdt.internal.core.util;x-friends:="org.eclipse.jdt.apt.pluggable.core,org.eclipse.pde.api.tools,org.eclipse.jdt.debug",
  org.eclipse.jdt.internal.eval;x-internal:=true,
  org.eclipse.jdt.internal.formatter;x-internal:=true,
  org.eclipse.jdt.internal.formatter.linewrap;x-internal:=true,
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java
index 18a7c2c..5a8885a 100644
--- a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java
@@ -188,8 +188,11 @@
 			case ERROR :
 				severity = ProblemSeverities.Error;
 				break;
+			case NOTE :
+			case OTHER:
+				severity = ProblemSeverities.Info;
+				break;
 			default :
-				// There is no "INFO" equivalent in JDT
 				severity = ProblemSeverities.Warning;
 				break;
 		}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java
index 5a088fb..2c8ead2 100644
--- a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java
@@ -150,6 +150,9 @@
 			if (this._compiler.options.sourceLevel == ClassFileConstants.JDK13) {
 				return SourceVersion.valueOf("RELEASE_13"); //$NON-NLS-1$
 			}
+			if (this._compiler.options.sourceLevel == ClassFileConstants.JDK14) {
+				return SourceVersion.valueOf("RELEASE_14"); //$NON-NLS-1$
+			}
 		} catch(IllegalArgumentException e) {
 			// handle call on a JDK 6
 			return SourceVersion.RELEASE_6;
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java
index 873af32..2a192e6 100644
--- a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java
@@ -18,6 +18,7 @@
 import java.io.IOException;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ServiceConfigurationError;
@@ -116,9 +117,7 @@
 			else if ("-processor".equals(option)) { //$NON-NLS-1$
 				commandLineProcessors = new ArrayList<>();
 				String procs = commandLineArguments[++i];
-				for (String proc : procs.split(",")) { //$NON-NLS-1$
-					commandLineProcessors.add(proc);
-				}
+				commandLineProcessors.addAll(Arrays.asList(procs.split(","))); //$NON-NLS-1$
 				break;
 			}
 		}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java
index edd4098..a6a9d97 100644
--- a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java
@@ -17,6 +17,7 @@
 import java.lang.reflect.Field;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
@@ -84,9 +85,7 @@
 			Charset charset = encoding != null ? Charset.forName(encoding) : null;
 			JavaFileManager manager = new EclipseFileManager(batchCompiler.compilerLocale, charset);
 			ArrayList<String> options = new ArrayList<>();
-			for (String argument : commandLineArguments) {
-				options.add(argument);
-			}
+			options.addAll(Arrays.asList(commandLineArguments));
 			for (Iterator<String> iterator = options.iterator(); iterator.hasNext(); ) {
 				manager.handleOption(iterator.next(), iterator);
 			}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java
index ecc54ec..5dcffa9 100644
--- a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java
@@ -347,6 +347,7 @@
 			case CLASS :
 			case ENUM :
 			case INTERFACE :
+			case RECORD :
 				TypeElementImpl typeElementImpl = (TypeElementImpl) e;
 				ReferenceBinding referenceBinding = (ReferenceBinding)typeElementImpl._binding;
 				if (referenceBinding instanceof SourceTypeBinding) {
@@ -377,6 +378,7 @@
 					referenceContext = sourceMethod;
 				}
 				break;
+			case RECORD_COMPONENT :
 			case ENUM_CONSTANT :
 			case FIELD :
 				VariableElementImpl variableElementImpl = (VariableElementImpl) e;
@@ -582,6 +584,7 @@
 			case CLASS :
 			case ENUM :
 			case INTERFACE :
+			case RECORD :
 				TypeElementImpl typeElementImpl = (TypeElementImpl) type;
 				ReferenceBinding referenceBinding = (ReferenceBinding)typeElementImpl._binding;
 				return (PackageElement) _env.getFactory().newElement(referenceBinding.fPackage);
@@ -594,6 +597,7 @@
 				return (PackageElement) _env.getFactory().newElement(methodBinding.declaringClass.fPackage);
 			case ENUM_CONSTANT :
 			case FIELD :
+			case RECORD_COMPONENT :
 				VariableElementImpl variableElementImpl = (VariableElementImpl) type;
 				FieldBinding fieldBinding = (FieldBinding) variableElementImpl._binding;
 				return (PackageElement) _env.getFactory().newElement(fieldBinding.declaringClass.fPackage);
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/Factory.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/Factory.java
index 8ea41f0..a3b1fbf 100644
--- a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/Factory.java
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/Factory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2017 BEA Systems, Inc. and others
+ * Copyright (c) 2007, 2020 BEA Systems, Inc. and others
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -312,6 +312,7 @@
 			case ANNOTATION_TYPE :
 			case INTERFACE :
 			case CLASS :
+			case RECORD :
 				// for type
 				decodeModifiers(result, modifiers, new int[] {
 					ClassFileConstants.AccPublic,
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java
index e4bcd24..c157fc3 100644
--- a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java
@@ -59,7 +59,7 @@
 	{
 		PackageBinding packageBinding = (PackageBinding) this._binding;
 		char[][] compoundName = CharOperation.arrayConcat(packageBinding.compoundName, TypeConstants.PACKAGE_INFO_NAME);
-		ReferenceBinding type = this._env.getLookupEnvironment().getType(compoundName);
+		ReferenceBinding type = packageBinding.environment.getType(compoundName);
 		AnnotationBinding[] annotations = null;
 		if (type != null && type.isValidBinding()) {
 			annotations = type.getAnnotations();
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/RecordComponentElementImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/RecordComponentElementImpl.java
new file mode 100644
index 0000000..2ce4c12
--- /dev/null
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/RecordComponentElementImpl.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2020 IBM Corporation.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.compiler.apt.model;
+
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.RecordComponentElement;
+
+import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
+import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
+
+public class RecordComponentElementImpl extends VariableElementImpl implements RecordComponentElement {
+
+	protected RecordComponentElementImpl(BaseProcessingEnvImpl env, FieldBinding binding) {
+		super(env, binding);
+	}
+
+	@Override
+	public ElementKind getKind() {
+		return ElementKind.RECORD_COMPONENT;
+	}
+
+	@Override
+	public ExecutableElement getAccessor() {
+		FieldBinding field = (FieldBinding) this._binding;
+		ReferenceBinding binding = field.declaringClass;
+		if (binding instanceof SourceTypeBinding) {
+			MethodBinding accessor = ((SourceTypeBinding) binding).getRecordComponentAccessor(field.name);
+			return new ExecutableElementImpl(_env, accessor);
+		}
+		return null;
+	}
+}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java
index 8a8afde..a0efdf8 100644
--- a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2017 IBM Corporation and others.
+ * Copyright (c) 2005, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -29,6 +29,7 @@
 import javax.lang.model.element.Name;
 import javax.lang.model.element.NestingKind;
 import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.RecordComponentElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.TypeParameterElement;
 import javax.lang.model.element.VariableElement;
@@ -84,6 +85,7 @@
 				case INTERFACE :
 				case CLASS :
 				case ENUM :
+				case RECORD :
 					TypeElementImpl typeElementImpl = (TypeElementImpl) e;
 					Binding typeBinding = typeElementImpl._binding;
 					if (typeBinding instanceof SourceTypeBinding) {
@@ -103,6 +105,7 @@
 					break;
 				case ENUM_CONSTANT :
 				case FIELD :
+				case RECORD_COMPONENT :
 					VariableElementImpl variableElementImpl = (VariableElementImpl) e;
 					binding = variableElementImpl._binding;
 					if (binding instanceof FieldBinding) {
@@ -160,6 +163,13 @@
 				 enclosed.add(variable);
 			}
 		}
+		if (binding.isRecord() && binding instanceof SourceTypeBinding) {
+			SourceTypeBinding sourceBinding = (SourceTypeBinding) binding;
+			for (FieldBinding field : sourceBinding.getRecordComponents()) {
+				RecordComponentElement rec = new RecordComponentElementImpl(_env, field);
+				enclosed.add(rec);
+			}
+		}
 		for (ReferenceBinding memberType : binding.memberTypes()) {
 			TypeElement type = new TypeElementImpl(_env, memberType, null);
 			enclosed.add(type);
@@ -171,6 +181,24 @@
 	}
 
 	@Override
+    public List<? extends RecordComponentElement> getRecordComponents() {
+		if (_binding instanceof SourceTypeBinding) {
+			SourceTypeBinding binding = (SourceTypeBinding) _binding;
+			List<RecordComponentElement> enclosed = new ArrayList<>();
+			for (FieldBinding field : binding.fields()) {
+				if (!field.isSynthetic()) {
+					 RecordComponentElement variable = new RecordComponentElementImpl(_env, field);
+					 enclosed.add(variable);
+				}
+			}
+			Collections.sort(enclosed, new SourceLocationComparator());
+			return Collections.unmodifiableList(enclosed);
+		}
+		// TODO: Add code for BinaryTypeBinding, which, as of now doesn't seem to contain components
+		return Collections.emptyList();
+    }
+
+	@Override
 	public Element getEnclosingElement() {
 		ReferenceBinding binding = (ReferenceBinding)_binding;
 		ReferenceBinding enclosingType = binding.enclosingType();
@@ -222,6 +250,9 @@
 		if (refBinding.isEnum()) {
 			return ElementKind.ENUM;
 		}
+		else if (refBinding.isRecord()) {
+			return ElementKind.RECORD;
+		}
 		else if (refBinding.isAnnotationType()) {
 			return ElementKind.ANNOTATION_TYPE;
 		}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java
index 9962e63..0071599 100644
--- a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java
@@ -138,6 +138,7 @@
 			break;
 		case FIELD:
 		case ENUM_CONSTANT:
+		case RECORD_COMPONENT:
 			typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
 				@Override
 				public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
@@ -159,7 +160,7 @@
 		case ANNOTATION_TYPE:
 		case INTERFACE:
 		case CLASS:
-
+		case RECORD:
 			typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
 				@Override
 				public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/BasicModule.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/BasicModule.java
index 1dcfc22..1bf653f 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/BasicModule.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/BasicModule.java
@@ -103,7 +103,7 @@
 	Service[] provides;
 	IModule.IPackageExport[] opens;
 	private ICompilationUnit compilationUnit;
-	
+
 	public BasicModule(ModuleDeclaration descriptor, IModulePathEntry root) {
 		this.compilationUnit = descriptor.compilationResult().compilationUnit;
 		this.name = descriptor.moduleName;
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
index b59f9fc..1442f94 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
@@ -146,7 +146,7 @@
 		try {
 			ClassFileReader reader = ClassFileReader.read(this.path + qualifiedBinaryFileName);
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=321115, package names are to be treated case sensitive.
-			String typeSearched = qualifiedPackageName.length() > 0 ? 
+			String typeSearched = qualifiedPackageName.length() > 0 ?
 					qualifiedPackageName.replace(File.separatorChar, '/') + "/" + fileName //$NON-NLS-1$
 					: fileName;
 			if (!CharOperation.equals(reader.getName(), typeSearched.toCharArray())) {
@@ -205,8 +205,8 @@
 	Hashtable<String, String> packageEntry = new Hashtable<>();
 
 	String[] dirList = (String[]) this.directoryCache.get(qualifiedPackageName);
-	if (dirList == this.missingPackageHolder // package exists in another classpath directory or jar 
-			|| dirList == null) 
+	if (dirList == this.missingPackageHolder // package exists in another classpath directory or jar
+			|| dirList == null)
 		return packageEntry;
 
 	File dir = new File(this.path + qualifiedPackageName);
@@ -221,7 +221,7 @@
 		if (!(s.endsWith(SUFFIX_STRING_java) || s.endsWith(SUFFIX_STRING_JAVA))) continue;
 		CompilationUnit cu = new CompilationUnit(null, s, this.encoding, this.destinationPath);
 		CompilationResult compilationResult = new CompilationResult(s.toCharArray(), 1, 1, 10);
-		ProblemReporter problemReporter = 
+		ProblemReporter problemReporter =
 				new ProblemReporter(
 					DefaultErrorHandlingPolicies.proceedWithAllProblems(),
 					new CompilerOptions(this.options),
@@ -235,14 +235,14 @@
 		for (int j = 0, k = types.length; j < k; j++) {
 			TypeDeclaration type = types[j];
 			char[] name = type.isSecondary() ? type.name : null;  // add only secondary types
-			if (name != null) 
+			if (name != null)
 				packageEntry.put(new String(name), s);
 		}
 	}
 	return packageEntry;
 }
 private NameEnvironmentAnswer findSourceSecondaryType(String typeName, String qualifiedPackageName, String qualifiedBinaryFileName) {
-	
+
 	if (this.packageSecondaryTypes == null) this.packageSecondaryTypes = new Hashtable<>();
 	Hashtable<String, String> packageEntry = this.packageSecondaryTypes.get(qualifiedPackageName);
 	if (packageEntry == null) {
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java
index c3a28d0..d49d5f7 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java
@@ -172,7 +172,7 @@
 
 						@Override
 						public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException {
-							if (attrs.isDirectory() || f.getNameCount() < 3) 
+							if (attrs.isDirectory() || f.getNameCount() < 3)
 								return FileVisitResult.CONTINUE;
 							if (f.getFileName().toString().equals(MODULE_INFO) && Files.exists(f)) {
 								byte[] content = JRTUtil.safeReadBytes(f);
@@ -222,7 +222,7 @@
 		return null;
 	}
 	void acceptModule(String name, byte[] content, Map<String, IModule> cache) {
-		if (content == null) 
+		if (content == null)
 			return;
 
 		if (cache.containsKey(name))
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJmod.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJmod.java
index 09786d6..7334d2b 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJmod.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJmod.java
@@ -39,7 +39,7 @@
 
 	public static char[] CLASSES = "classes".toCharArray(); //$NON-NLS-1$
 	public static char[] CLASSES_FOLDER = "classes/".toCharArray(); //$NON-NLS-1$
-	
+
 public ClasspathJmod(File file, boolean closeZipFileAtEnd,
 		AccessRuleSet accessRuleSet, String destinationPath) {
 	super(file, closeZipFileAtEnd, accessRuleSet, destinationPath);
@@ -97,7 +97,7 @@
 @Override
 public boolean hasAnnotationFileFor(String qualifiedTypeName) {
 	qualifiedTypeName = new String(CharOperation.append(CLASSES_FOLDER, qualifiedTypeName.toCharArray()));
-	return this.zipFile.getEntry(qualifiedTypeName+ExternalAnnotationProvider.ANNOTATION_FILE_SUFFIX) != null; 
+	return this.zipFile.getEntry(qualifiedTypeName+ExternalAnnotationProvider.ANNOTATION_FILE_SUFFIX) != null;
 }
 @SuppressWarnings({ "rawtypes", "unchecked" })
 @Override
@@ -142,7 +142,7 @@
 
 	this.packageCache = new HashSet<>(41);
 	this.packageCache.add(Util.EMPTY_STRING);
-	
+
 	for (Enumeration<? extends ZipEntry> e = this.zipFile.entries(); e.hasMoreElements(); ) {
 		char[] entryName = e.nextElement().getName().toCharArray();
 		int index = CharOperation.indexOf('/', entryName);
@@ -175,7 +175,7 @@
 				}
 			}
 		}
-	}	
+	}
 	return false;
 }
 @Override
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java
index 03cdb86..104a9f0 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java
@@ -128,14 +128,14 @@
 			return null; // most common case
 		final char[] packageArray = qualifiedPackageName.toCharArray();
 		final ArrayList answers = new ArrayList();
-	
+
 		try {
 			JRTUtil.walkModuleImage(this.file, new JRTUtil.JrtFileVisitor<java.nio.file.Path>() {
 
 				@Override
 				public FileVisitResult visitPackage(java.nio.file.Path dir, java.nio.file.Path modPath, BasicFileAttributes attrs) throws IOException {
 					if (qualifiedPackageName.startsWith(dir.toString())) {
-						return FileVisitResult.CONTINUE;	
+						return FileVisitResult.CONTINUE;
 					}
 					return FileVisitResult.SKIP_SUBTREE;
 				}
@@ -168,7 +168,7 @@
 		} catch (IOException e) {
 			// Ignore and move on
 		}
-		
+
 		int size = answers.size();
 		if (size != 0) {
 			char[][][] result = new char[size][][];
@@ -193,7 +193,7 @@
 		loadModules();
 	}
 //	public void acceptModule(IModuleDeclaration mod) {
-//		if (this.isJrt) 
+//		if (this.isJrt)
 //			return;
 //		this.module = mod;
 //	}
@@ -252,7 +252,7 @@
 	}
 
 	void acceptModule(byte[] content, Map<String, IModule> cache) {
-		if (content == null) 
+		if (content == null)
 			return;
 		ClassFileReader reader = null;
 		try {
@@ -264,7 +264,7 @@
 			acceptModule(reader, cache);
 		}
 	}
-	
+
 	@Override
 	public Collection<String> getModuleNames(Collection<String> limitModule, Function<String, IModule> getModule) {
 		Map<String, IModule> cache = ModulesCache.get(this.file.getPath());
@@ -288,7 +288,7 @@
 			boolean isPotentialRoot = !isJavaDotStart;	// always include non-java.*
 			if (!hasJavaDotSE)
 				isPotentialRoot |= isJavaDotStart;		// no java.se => add all java.*
-			
+
 			if (isPotentialRoot) {
 				IModule m = getModule.apply(mod);
 				if (m != null) {
@@ -320,7 +320,7 @@
 //
 //		this.packageCache = new HashSet<>(41);
 //		this.packageCache.add(Util.EMPTY_STRING);
-//		
+//
 //			try {
 //				JRTUtil.walkModuleImage(this.file, new JRTUtil.JrtFileVisitor<java.nio.file.Path>() {
 //
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathLocation.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathLocation.java
index 125fa61..e2c3c7c 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathLocation.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathLocation.java
@@ -81,7 +81,7 @@
 		}
 		return this.accessRuleSet.getViolatedRestriction(qualifiedTypeName);
 	}
-	
+
 	public int getMode() {
 		return SOURCE | BINARY;
 	}
@@ -121,7 +121,7 @@
 	public String getDestinationPath() {
 		return this.destinationPath;
 	}
-	
+
 	@Override
 	public void acceptModule(IModule mod) {
 		this.module = mod;
@@ -191,9 +191,9 @@
 			return new char[][] { this.module.name() };
 		return new char[][] { ModuleBinding.UNNAMED };
 	}
-	
+
 	@Override
 	public void reset() {
-		this.module = null;	
+		this.module = null;
 	}
 }
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathMultiReleaseJar.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathMultiReleaseJar.java
index 4175688..2a108c0 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathMultiReleaseJar.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathMultiReleaseJar.java
@@ -72,7 +72,7 @@
 
 		this.packageCache = new HashSet<>(41);
 		this.packageCache.add(Util.EMPTY_STRING);
-		
+
 		for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) {
 			String fileName = ((ZipEntry) e.nextElement()).getName();
 			addToPackageCache(fileName, false);
@@ -159,8 +159,8 @@
 						}
 					if (this.accessRuleSet == null)
 						return new NameEnvironmentAnswer(reader, null, modName);
-					return new NameEnvironmentAnswer(reader, 
-							this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), 
+					return new NameEnvironmentAnswer(reader,
+							this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()),
 							modName);
 				}
 			} catch (IOException | ClassFormatException e) {
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathSourceJar.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathSourceJar.java
index e0ffd3f..126409d 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathSourceJar.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathSourceJar.java
@@ -41,7 +41,7 @@
 		if (sourceEntry != null) {
 			try {
 				InputStream stream = null;
-				char[] contents = null; 
+				char[] contents = null;
 				try {
 					stream = this.zipFile.getInputStream(sourceEntry);
 					contents = Util.getInputStreamAsCharArray(stream, -1, this.encoding);
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileFinder.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileFinder.java
index 280cc81..247c0c4 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileFinder.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileFinder.java
@@ -23,7 +23,7 @@
 
 /**
  * Although the file finder is meant to be generic for any file name patters,
- * at the moment it is used only for *.java files. This method handles the 
+ * at the moment it is used only for *.java files. This method handles the
  * module-info.java in a special way by always placing it as the first element
  * of the resulting array.
  */
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
index cfe517c..06a9d6a 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
@@ -663,7 +663,7 @@
 				int infos = 0;
 				for (int i = 0; i < count; i++) {
 					CategorizedProblem problem = problems.get(i);
-					if (problem != null) {
+					if (!this.main.isIgnored(problem)) {
 						currentMain.globalProblemsCount++;
 						logExtraProblem(problem, localProblemCount, currentMain.globalProblemsCount);
 						localProblemCount++;
@@ -684,7 +684,7 @@
 						startLoggingExtraProblems(count);
 						for (int i = 0; i < count; i++) {
 							CategorizedProblem problem = problems.get(i);
-							if (problem!= null) {
+							if (!this.main.isIgnored(problem)) {
 								if (problem.getID() != IProblem.Task) {
 									logXmlExtraProblem(problem, localProblemCount, currentMain.globalProblemsCount);
 								}
@@ -1739,10 +1739,14 @@
  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_4</code></li>
  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_5</code></li>
  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_6</code></li>
+ * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_7</code></li>
  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_8</code></li>
  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK9</code></li>
  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK10</code></li>
  * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK11</code></li>
+ * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK12</code></li>
+ * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK13</code></li>
+ * <li><code>org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK14</code></li>
  * 
  * </ul>
  * @param minimalSupportedVersion the given minimal version
@@ -2232,6 +2236,16 @@
 					mode = DEFAULT;
 					continue;
 				}
+				if (currentArg.equals("-14") || currentArg.equals("-14.0")) { //$NON-NLS-1$ //$NON-NLS-2$
+					if (didSpecifyCompliance) {
+						throw new IllegalArgumentException(
+							this.bind("configure.duplicateCompliance", currentArg)); //$NON-NLS-1$
+					}
+					didSpecifyCompliance = true;
+					this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_14);
+					mode = DEFAULT;
+					continue;
+				}
 				if (currentArg.equals("-d")) { //$NON-NLS-1$
 					if (this.destinationPath != null) {
 						StringBuffer errorMessage = new StringBuffer();
@@ -2792,6 +2806,8 @@
 					this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_12);
 				} else if (currentArg.equals("13") || currentArg.equals("13.0")) { //$NON-NLS-1$//$NON-NLS-2$
 					this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_13);
+				} else if (currentArg.equals("14") ||  currentArg.equals("14.0")) { //$NON-NLS-1$//$NON-NLS-2$
+					this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_14);
 				}
 				else if (currentArg.equals("jsr14")) { //$NON-NLS-1$
 					this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_JSR14);
@@ -3466,6 +3482,9 @@
 		}
 	}
 	this.options.put(CompilerOptions.OPTION_TaskTags, Util.EMPTY_STRING);
+	if (newValue != null) {
+		this.options.remove(newValue);
+}
 }
 protected void disableAll(int severity) {
 	String checkedValue = null;
@@ -3486,6 +3505,9 @@
 			this.options.put(entry.getKey(), CompilerOptions.IGNORE);
 		}
 	}
+	if (checkedValue != null) {
+		this.options.put(checkedValue, CompilerOptions.IGNORE);
+	}
 	if (severity == ProblemSeverities.Warning) {
 		disableAll(ProblemSeverities.Info);
 	}
@@ -3928,6 +3950,26 @@
 	return FileSystem.EMPTY_CLASSPATH;
 }
 
+protected boolean isIgnored(IProblem problem) {
+	if (problem == null) {
+		return true;
+	}
+	if (problem.isError()) {
+		return false;
+	}
+	String key = problem.isInfo() ? CompilerOptions.INFO : CompilerOptions.WARNING;
+	if (CompilerOptions.IGNORE.equals(this.options.get(key))) {
+		return true;
+	}
+	if (this.ignoreOptionalProblemsFromFolders != null) {
+		char[] fileName = problem.getOriginatingFileName();
+		if (fileName != null) {
+			return shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, fileName);
+		}
+	}
+	return false;
+}
+
 /*
  * External API
  * Handle a single warning token.
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java
index fd89bd8..bfb46da 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java
@@ -53,14 +53,14 @@
 		}
 		return modulePath;
 	}
-	protected static void scanForModules(String destinationPath, Parser parser, Map<String, String> options, boolean isModulepath, 
+	protected static void scanForModules(String destinationPath, Parser parser, Map<String, String> options, boolean isModulepath,
 			boolean thisAnAutomodule, List<FileSystem.Classpath> collector, final File file, String release) {
 		FileSystem.Classpath entry = FileSystem.getClasspath(
 				file.getAbsolutePath(),
 				null,
 				!isModulepath,
 				null,
-				destinationPath == null ? null : (destinationPath + File.separator + file.getName()), 
+				destinationPath == null ? null : (destinationPath + File.separator + file.getName()),
 				options,
 				release);
 		if (entry != null) {
@@ -140,10 +140,10 @@
 	 * Extracts the single reads clause from the given
 	 * command line option (--add-reads). The result is a String[] with two
 	 * element, first being the source module and second being the target module.
-	 * The expected format is: 
+	 * The expected format is:
 	 *  --add-reads <source-module>=<target-module>
 	 * @param option
-	 * @return a String[] with source and target module of the "reads" clause. 
+	 * @return a String[] with source and target module of the "reads" clause.
 	 */
 	protected static String[] extractAddonRead(String option) {
 		StringTokenizer tokenizer = new StringTokenizer(option, "="); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
index 37a2143..9485ac5 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2018 IBM Corporation and others.
+# Copyright (c) 2000, 2019 IBM Corporation and others.
 #
 # This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License 2.0
@@ -30,7 +30,7 @@
 compiler.name = Eclipse Compiler for Java(TM)
 #Format: compiler.version = (The place holders will be automatically filled. Do not remove or alter it)
 compiler.version = bundle_qualifier, bundle_version
-compiler.copyright = Copyright IBM Corp 2000, 2015. All rights reserved.
+compiler.copyright = Copyright IBM Corp 2000, 2020. All rights reserved.
 
 ### progress
 progress.compiling = Compiling
@@ -54,6 +54,7 @@
 compile.severalInfos = {0} info
 compile.oneClassFileGenerated = [1 .class file generated]
 compile.severalClassFilesGenerated = [{0} .class files generated]
+compile.failOnWarning = error: warnings found and -failOnWarning specified
 
 ### configure
 configure.requiresJDK1.2orAbove = Need to use a JVM >= 1.2
@@ -102,6 +103,7 @@
 configure.invalidInfoOption = invalid info option: ''{0}''. Must specify an info token
 
 configure.notOnModuleSourcePath = ''{0}'' does not belong to a module on the module source path
+configure.no.ModuleDescriptorVersionparse = Could not invoke method java.lang.module.ModuleDescriptor.Version.parse(), cannot validate module version.
 
 ## configure.directoryNotExist = directory does not exist: {0}
 configure.unrecognizedOption = Unrecognized option : {0}
@@ -140,7 +142,7 @@
 configure.differentencoding=Found encoding {0}. A different encoding was specified: {1}
 
 ### null annotations
-configure.invalidNullAnnot = Token {0} is not in the expected format "nullAnnot(<non null annotation name> | <nullable annotation name> | <non-null by default annotation name>)"
+configure.invalidNullAnnot = Token {0} is not in the expected format "nullAnnot(<nullable annotation name> | <non null annotation name> | <non-null by default annotation name>)"
 configure.missingAnnotationPath = Missing argument to -annotationpath at ''{0}''
 
 ### requestor
@@ -316,6 +318,7 @@
 \                       do not stop at first error, dumping class files with\n\
 \                       problem methods\n\
 \                       With ":Fatal", all optional errors are treated as fatal\n\
+\    -failOnWarning     fail compilation if there are warnings\n\
 \    -verbose           enable verbose output\n\
 \    -referenceInfo     compute reference info\n\
 \    -progress          show progress (only in -log mode)\n\
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
index d0ea034..ca7cf66 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -51,6 +51,7 @@
 import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.compiler.InvalidInputException;
 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
 import org.eclipse.jdt.core.search.IJavaSearchConstants;
 import org.eclipse.jdt.core.search.IJavaSearchScope;
@@ -259,7 +260,7 @@
 public final class CompletionEngine
 	extends Engine
 	implements ISearchRequestor, TypeConstants , TerminalTokens , RelevanceConstants, SuffixConstants {
-	
+
 	private static class AcceptedConstructor {
 		public int modifiers;
 		public char[] simpleTypeName;
@@ -274,9 +275,9 @@
 		public boolean proposeType = false;
 		public boolean proposeConstructor = false;
 		public char[] fullyQualifiedName = null;
-		
+
 		public boolean mustBeQualified = false;
-		
+
 		public AcceptedConstructor(
 				int modifiers,
 				char[] simpleTypeName,
@@ -311,7 +312,7 @@
 			return buffer.toString();
 		}
 	}
-	
+
 	private static class AcceptedType {
 		public char[] packageName;
 		public char[] simpleTypeName;
@@ -348,7 +349,7 @@
 			return buffer.toString();
 		}
 	}
-	
+
 	public class CompletionProblemFactory extends DefaultProblemFactory {
 		private int lastErrorStart;
 
@@ -464,7 +465,7 @@
 			this.checkProblems = false;
 		}
 	}
-	
+
 	public static char[] createBindingKey(char[] packageName, char[] typeName) {
 		char[] signature = createTypeSignature(packageName, typeName);
 		CharOperation.replace(signature, '.', '/');
@@ -573,7 +574,7 @@
 		result = CharOperation.replaceOnCopy(result, '/', '.');
 		return result;
 	}
-	
+
 	private static char[] getTypeName(TypeReference typeReference) {
 		char[] typeName = CharOperation.concatWith(typeReference.getTypeName(), '.');
 		int dims = typeReference.dimensions();
@@ -586,10 +587,10 @@
 				typeName[k+1] = ']';
 			}
 		}
-		
+
 		return typeName;
 	}
-	
+
 	private static boolean hasStaticMemberTypes(ReferenceBinding typeBinding, SourceTypeBinding invocationType, CompilationUnitScope unitScope) {
 		ReferenceBinding[] memberTypes = typeBinding.memberTypes();
 		int length = memberTypes == null ? 0 : memberTypes.length;
@@ -600,18 +601,18 @@
 			} else if(invocationType == null && !memberType.canBeSeenBy(unitScope.fPackage)) {
 				continue next;
 			}
-			
+
 			if ((memberType.modifiers & ClassFileConstants.AccStatic) != 0) {
 				return true;
 			}
 		}
 		return false;
 	}
-	
+
 	private static boolean hasMemberTypesInEnclosingScope(SourceTypeBinding typeBinding, Scope scope) {
 		ReferenceBinding[] memberTypes = typeBinding.memberTypes();
 		int length = memberTypes == null ? 0 : memberTypes.length;
-		
+
 		if (length > 0) {
 			MethodScope methodScope = scope.methodScope();
 			if (methodScope != null && !methodScope.isStatic) {
@@ -627,16 +628,16 @@
 		}
 		return false;
 	}
-	
+
 	public HashtableOfObject typeCache;
 	public int openedBinaryTypes; // used during InternalCompletionProposal#findConstructorParameterNames()
-	
+
 	public static boolean DEBUG = false;
 	public static boolean PERF = false;
-	
+
 	private static final char[] KNOWN_TYPE_WITH_UNKNOWN_CONSTRUCTORS = new char[]{};
 	private static final char[] KNOWN_TYPE_WITH_KNOWN_CONSTRUCTORS = new char[]{};
-	
+
 	private static final char[] ARG = "arg".toCharArray();  //$NON-NLS-1$
 	private static final char[] ARG0 = "arg0".toCharArray();  //$NON-NLS-1$
 	private static final char[] ARG1 = "arg1".toCharArray();  //$NON-NLS-1$
@@ -646,12 +647,12 @@
 	private static final char[][] ARGS2 = new char[][]{ARG0, ARG1};
 	private static final char[][] ARGS3 = new char[][]{ARG0, ARG1, ARG2};
 	private static final char[][] ARGS4 = new char[][]{ARG0, ARG1, ARG2, ARG3};
-	
+
 	private final static int CHECK_CANCEL_FREQUENCY = 50;
-	
+
 	// temporary constants to quickly disabled polish features if necessary
 	public final static boolean NO_TYPE_COMPLETION_ON_EMPTY_TOKEN = false;
-	
+
 	private final static char[] ERROR_PATTERN = "*error*".toCharArray();  //$NON-NLS-1$
 	private final static char[] EXCEPTION_PATTERN = "*exception*".toCharArray();  //$NON-NLS-1$
 	private final static char[] SEMICOLON = new char[] { ';' };
@@ -664,11 +665,11 @@
 	private final static char[] EXTENDS = "extends".toCharArray();  //$NON-NLS-1$
 	private final static char[] SUPER = "super".toCharArray();  //$NON-NLS-1$
 	private final static char[] DEFAULT_CONSTRUCTOR_SIGNATURE = "()V".toCharArray();  //$NON-NLS-1$
-	
+
 	private final static char[] DOT = ".".toCharArray();  //$NON-NLS-1$
 
 	private final static char[] VARARGS = "...".toCharArray();  //$NON-NLS-1$
-	
+
 	private final static char[] IMPORT = "import".toCharArray();  //$NON-NLS-1$
 	private final static char[] STATIC = "static".toCharArray();  //$NON-NLS-1$
 	private final static char[] ON_DEMAND = ".*".toCharArray();  //$NON-NLS-1$
@@ -678,11 +679,11 @@
 		createTypeSignature(CharOperation.concatWith(JAVA_LANG, '.'), OBJECT);
 	private final static char[] JAVA_LANG_NAME =
 		CharOperation.concatWith(JAVA_LANG, '.');
-	
+
 	private final static int NONE = 0;
 	private final static int SUPERTYPE = 1;
 	private final static int SUBTYPE = 2;
-	
+
 	int expectedTypesPtr = -1;
 	TypeBinding[] expectedTypes = new TypeBinding[1];
 	int expectedTypesFilter;
@@ -694,9 +695,9 @@
 	int forbbidenBindingsPtr = -1;
 	Binding[] forbbidenBindings = new Binding[1];
 	int uninterestingBindingsFilter;     // only set when completing on an exception type
-	
+
 	ImportBinding[] favoriteReferenceBindings;
-	
+
 	boolean assistNodeIsClass;
 	boolean assistNodeIsEnum;
 	boolean assistNodeIsException;
@@ -710,9 +711,9 @@
 	boolean assistNodeCanBeSingleMemberAnnotation = false;
 	boolean assistNodeIsInsideCase = false; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=195346
 	boolean assistNodeIsString = false;	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=343476
-	
+
 	long targetedElement;
-	
+
 	WorkingCopyOwner owner;
 	IProgressMonitor monitor;
 	IJavaProject javaProject;
@@ -744,7 +745,7 @@
 	HashtableOfObject knownModules = new HashtableOfObject(10);
 	HashtableOfObject knownPkgs = new HashtableOfObject(10);
 	HashtableOfObject knownTypes = new HashtableOfObject(10);
-	
+
  	/*
 		static final char[][] mainDeclarations =
 			new char[][] {
@@ -793,7 +794,7 @@
 			BASE_TYPE_NAMES_WITHOUT_VOID[i] = BASE_TYPES[i].simpleName;
 		}
  	}
-	
+
 	static final char[] classField = "class".toCharArray();  //$NON-NLS-1$
 	static final char[] lengthField = "length".toCharArray();  //$NON-NLS-1$
 	static final char[] cloneMethod = "clone".toCharArray();  //$NON-NLS-1$
@@ -835,7 +836,7 @@
 
 	private int foundTypesCount;
 	private ObjectVector acceptedTypes;
-	
+
 	private int foundConstructorsCount;
 	private ObjectVector acceptedConstructors;
 
@@ -884,7 +885,7 @@
 		this.owner = owner;
 		this.monitor = monitor;
 	}
-	
+
 	@Override
 	public void accept(ICompilationUnit sourceUnit, AccessRestriction accessRestriction) {
 		if (!CharOperation.equals(sourceUnit.getMainTypeName(), TypeConstants.PACKAGE_INFO_NAME)) {
@@ -896,7 +897,7 @@
 			super.accept(sourceUnit, accessRestriction);
 		}
 	}
-	
+
 	@Override
 	public void acceptConstructor(
 			int modifiers,
@@ -910,13 +911,13 @@
 			int extraFlags,
 			String path,
 			AccessRestriction accessRestriction) {
-		
+
 		// does not check cancellation for every types to avoid performance loss
 		if ((this.foundConstructorsCount % (CHECK_CANCEL_FREQUENCY)) == 0) checkCancel();
 		this.foundConstructorsCount++;
-		
+
 		if ((typeModifiers & ClassFileConstants.AccEnum) != 0) return;
-		
+
 		if (this.options.checkDeprecation && (typeModifiers & ClassFileConstants.AccDeprecated) != 0) return;
 
 		if (this.options.checkVisibility) {
@@ -926,7 +927,7 @@
 				if (this.currentPackageName == null) {
 					initializePackageCache();
 				}
-				
+
 				if(!CharOperation.equals(packageName, this.currentPackageName)) return;
 			}
 		}
@@ -948,7 +949,7 @@
 					break;
 			}
 		}
-		
+
 		if(this.acceptedConstructors == null) {
 			this.acceptedConstructors = new ObjectVector();
 		}
@@ -965,31 +966,31 @@
 						extraFlags,
 						accessibility));
 	}
-	
+
 	private void acceptConstructors(Scope scope) {
 		final boolean DEFER_QUALIFIED_PROPOSALS = false;
-		
+
 		this.checkCancel();
-		
+
 		if(this.acceptedConstructors == null) return;
 
 		int length = this.acceptedConstructors.size();
 
 		if(length == 0) return;
-		
+
 		HashtableOfObject onDemandFound = new HashtableOfObject();
-		
+
 		ArrayList deferredProposals = null;
 		if (DEFER_QUALIFIED_PROPOSALS) {
 			deferredProposals = new ArrayList();
 		}
-		
+
 		try {
 			next : for (int i = 0; i < length; i++) {
-				
+
 				// does not check cancellation for every types to avoid performance loss
 				if ((i % CHECK_CANCEL_FREQUENCY) == 0) checkCancel();
-				
+
 				AcceptedConstructor acceptedConstructor = (AcceptedConstructor)this.acceptedConstructors.elementAt(i);
 				final int typeModifiers = acceptedConstructor.typeModifiers;
 				final char[] packageName = acceptedConstructor.packageName;
@@ -1001,11 +1002,11 @@
 				final char[][] parameterNames = acceptedConstructor.parameterNames;
 				final int extraFlags = acceptedConstructor.extraFlags;
 				final int accessibility = acceptedConstructor.accessibility;
-				
+
 				boolean proposeType = hasArrayTypeAsExpectedSuperTypes() || (extraFlags & ExtraFlags.HasNonPrivateStaticMemberTypes) != 0;
-				
+
 				char[] fullyQualifiedName = CharOperation.concat(packageName, simpleTypeName, '.');
-						
+
 				Object knownTypeKind = this.knownTypes.get(fullyQualifiedName);
 				if (knownTypeKind != null) {
 					if (knownTypeKind == KNOWN_TYPE_WITH_KNOWN_CONSTRUCTORS) {
@@ -1017,9 +1018,9 @@
 				} else {
 					this.knownTypes.put(fullyQualifiedName, KNOWN_TYPE_WITH_UNKNOWN_CONSTRUCTORS);
 				}
-				
+
 				boolean proposeConstructor = true;
-					
+
 				if (this.options.checkVisibility) {
 					if((modifiers & ClassFileConstants.AccPublic) == 0) {
 						if((modifiers & ClassFileConstants.AccPrivate) != 0) {
@@ -1029,9 +1030,9 @@
 							if (this.currentPackageName == null) {
 								initializePackageCache();
 							}
-							
+
 							if(!CharOperation.equals(packageName, this.currentPackageName)) {
-								
+
 								if((typeModifiers & ClassFileConstants.AccAbstract) == 0 ||
 										(modifiers & ClassFileConstants.AccProtected) == 0) {
 									if (!proposeType) continue next;
@@ -1041,16 +1042,16 @@
 						}
 					}
 				}
-				
+
 				acceptedConstructor.fullyQualifiedName = fullyQualifiedName;
 				acceptedConstructor.proposeType = proposeType;
 				acceptedConstructor.proposeConstructor = proposeConstructor;
-				
-				
+
+
 				if(!this.importCachesInitialized) {
 					initializeImportCaches();
 				}
-				
+
 				for (int j = 0; j < this.importCacheCount; j++) {
 					char[][] importName = this.importsCache[j];
 					if(CharOperation.equals(simpleTypeName, importName[0])) {
@@ -1065,7 +1066,7 @@
 									!CharOperation.equals(fullyQualifiedName, importName[1]),
 									scope);
 						}
-						
+
 						if (proposeConstructor && !Flags.isEnum(typeModifiers)) {
 							boolean isQualified = !CharOperation.equals(fullyQualifiedName, importName[1]);
 							if (!isQualified) {
@@ -1110,7 +1111,7 @@
 								false,
 								scope);
 					}
-					
+
 					if (proposeConstructor && !Flags.isEnum(typeModifiers)) {
 						proposeConstructor(
 								simpleTypeName,
@@ -1193,7 +1194,7 @@
 								true,
 								scope);
 					}
-					
+
 					if (proposeConstructor && !Flags.isEnum(typeModifiers)) {
 						acceptedConstructor.mustBeQualified = true;
 						if (DEFER_QUALIFIED_PROPOSALS) {
@@ -1204,15 +1205,15 @@
 					}
 				}
 			}
-		
+
 			char[][] keys = onDemandFound.keyTable;
 			Object[] values = onDemandFound.valueTable;
 			int max = keys.length;
 			for (int i = 0; i < max; i++) {
-				
+
 				// does not check cancellation for every types to avoid performance loss
 				if ((i % CHECK_CANCEL_FREQUENCY) == 0) checkCancel();
-				
+
 				if(keys[i] != null) {
 					AcceptedConstructor value = (AcceptedConstructor) values[i];
 					if(value != null) {
@@ -1249,7 +1250,7 @@
 									value.mustBeQualified,
 									scope);
 						}
-						
+
 						if (value.proposeConstructor && !Flags.isEnum(value.modifiers)) {
 							if (!value.mustBeQualified) {
 								proposeConstructor(
@@ -1278,16 +1279,16 @@
 					}
 				}
 			}
-			
+
 			if (DEFER_QUALIFIED_PROPOSALS) {
 				int size = deferredProposals.size();
 				for (int i = 0; i < size; i++) {
-					
+
 					// does not check cancellation for every types to avoid performance loss
 					if ((i % CHECK_CANCEL_FREQUENCY) == 0) checkCancel();
-				
+
 					AcceptedConstructor deferredProposal = (AcceptedConstructor)deferredProposals.get(i);
-					
+
 					if (deferredProposal.proposeConstructor) {
 						proposeConstructor(
 								deferredProposal.simpleTypeName,
@@ -1311,7 +1312,7 @@
 			this.acceptedTypes = null; // reset
 		}
 	}
-	
+
 	/**
 	 * One result of the search consists of a new module.
 	 *
@@ -1346,7 +1347,7 @@
 				this.printDebug(proposal);
 			}
 		}
-		
+
 	}
 
 	@Override
@@ -1355,7 +1356,7 @@
 		if (this.knownPkgs.containsKey(packageName)) return;
 
 		if (!isValidPackageName(packageName)) return;
-		
+
 		if (this.skipDefaultPackage &&
 			CharOperation.equals(packageName, CharOperation.NO_CHAR))
 			return;
@@ -1405,13 +1406,14 @@
 		char[][] enclosingTypeNames,
 		int modifiers,
 		AccessRestriction accessRestriction) {
-		
+
 		// does not check cancellation for every types to avoid performance loss
 		if ((this.foundTypesCount % CHECK_CANCEL_FREQUENCY) == 0) checkCancel();
 		this.foundTypesCount++;
-		
+
 		if (this.options.checkDeprecation && (modifiers & ClassFileConstants.AccDeprecated) != 0) return;
 		if (this.assistNodeIsExtendedType && (modifiers & ClassFileConstants.AccFinal) != 0) return;
+		if (this.assistNodeIsExtendedType && (modifiers & ExtraCompilerModifiers.AccRecord) != 0) return;
 
 		if (this.options.checkVisibility) {
 			if((modifiers & ClassFileConstants.AccPublic) == 0) {
@@ -1440,7 +1442,7 @@
 					break;
 			}
 		}
-		
+
 		if (isForbidden(packageName, simpleTypeName, enclosingTypeNames)) {
 			return;
 		}
@@ -1453,7 +1455,7 @@
 
 	private void acceptTypes(Scope scope) {
 		this.checkCancel();
-		
+
 		if(this.acceptedTypes == null) return;
 
 		int length = this.acceptedTypes.size();
@@ -1461,20 +1463,20 @@
 		if(length == 0) return;
 
 		HashtableOfObject onDemandFound = new HashtableOfObject();
-		
+
 		try {
 			next : for (int i = 0; i < length; i++) {
-				
+
 				// does not check cancellation for every types to avoid performance loss
 				if ((i % CHECK_CANCEL_FREQUENCY) == 0) checkCancel();
-				
+
 				AcceptedType acceptedType = (AcceptedType)this.acceptedTypes.elementAt(i);
 				char[] packageName = acceptedType.packageName;
 				char[] simpleTypeName = acceptedType.simpleTypeName;
 				char[][] enclosingTypeNames = acceptedType.enclosingTypeNames;
 				int modifiers = acceptedType.modifiers;
 				int accessibility = acceptedType.accessibility;
-	
+
 				char[] typeName;
 				char[] flatEnclosingTypeNames;
 				if(enclosingTypeNames == null || enclosingTypeNames.length == 0) {
@@ -1485,36 +1487,36 @@
 					typeName = CharOperation.concat(flatEnclosingTypeNames, simpleTypeName, '.');
 				}
 				char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.');
-	
+
 				if (this.knownTypes.containsKey(fullyQualifiedName)) continue next;
-	
+
 				this.knownTypes.put(fullyQualifiedName, KNOWN_TYPE_WITH_UNKNOWN_CONSTRUCTORS);
-	
+
 				if (this.resolvingImports) {
 					if(this.compilerOptions.complianceLevel >= ClassFileConstants.JDK1_4 && packageName.length == 0) {
 						continue next; // import of default package is forbidden when compliance is 1.4 or higher
 					}
-	
+
 					char[] completionName = this.insideQualifiedReference ? simpleTypeName : fullyQualifiedName;
-	
+
 					if(this.resolvingStaticImports) {
 						if(enclosingTypeNames == null || enclosingTypeNames.length == 0) {
 							completionName = CharOperation.concat(completionName, new char[] { '.' });
 						} else if ((modifiers & ClassFileConstants.AccStatic) == 0) {
 							continue next;
 						} else {
-							completionName = CharOperation.concat(completionName, new char[] { ';' });
+							completionName = appendUnlessNextToken(completionName, new char[] { ';' }, TerminalTokens.TokenNameSEMICOLON);
 						}
 					} else {
-						completionName = CharOperation.concat(completionName, new char[] { ';' });
+						completionName = appendUnlessNextToken(completionName, new char[] {';'}, TerminalTokens.TokenNameSEMICOLON);
 					}
-	
+
 					int relevance = computeBaseRelevance();
 					relevance += computeRelevanceForResolution();
 					relevance += computeRelevanceForInterestingProposal(packageName, fullyQualifiedName);
 					relevance += computeRelevanceForRestrictions(accessibility);
 					relevance += computeRelevanceForCaseMatching(this.completionToken, simpleTypeName);
-	
+
 					this.noProposal = false;
 					if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
 						createTypeProposal(packageName, typeName, modifiers, accessibility, completionName, relevance);
@@ -1523,7 +1525,7 @@
 					if(!this.importCachesInitialized) {
 						initializeImportCaches();
 					}
-	
+
 					for (int j = 0; j < this.importCacheCount; j++) {
 						char[][] importName = this.importsCache[j];
 						if(CharOperation.equals(typeName, importName[0])) {
@@ -1539,8 +1541,8 @@
 							continue next;
 						}
 					}
-	
-	
+
+
 					if ((enclosingTypeNames == null || enclosingTypeNames.length == 0 ) && CharOperation.equals(this.currentPackageName, packageName)) {
 						proposeType(
 								packageName,
@@ -1554,15 +1556,15 @@
 						continue next;
 					} else {
 						char[] fullyQualifiedEnclosingTypeOrPackageName = null;
-	
+
 						AcceptedType foundType = null;
 						if((foundType = (AcceptedType)onDemandFound.get(simpleTypeName)) == null) {
 							for (int j = 0; j < this.onDemandImportCacheCount; j++) {
 								ImportBinding importBinding = this.onDemandImportsCache[j];
-	
+
 								char[][] importName = importBinding.compoundName;
 								char[] importFlatName = CharOperation.concatWith(importName, '.');
-	
+
 								if(fullyQualifiedEnclosingTypeOrPackageName == null) {
 									if(enclosingTypeNames != null && enclosingTypeNames.length != 0) {
 										fullyQualifiedEnclosingTypeOrPackageName =
@@ -1598,10 +1600,10 @@
 						} else if(!foundType.mustBeQualified){
 							done : for (int j = 0; j < this.onDemandImportCacheCount; j++) {
 								ImportBinding importBinding = this.onDemandImportsCache[j];
-	
+
 								char[][] importName = importBinding.compoundName;
 								char[] importFlatName = CharOperation.concatWith(importName, '.');
-	
+
 								if(fullyQualifiedEnclosingTypeOrPackageName == null) {
 									if(enclosingTypeNames != null && enclosingTypeNames.length != 0) {
 										fullyQualifiedEnclosingTypeOrPackageName =
@@ -1639,7 +1641,7 @@
 					}
 				}
 			}
-		
+
 			char[][] keys = onDemandFound.keyTable;
 			Object[] values = onDemandFound.valueTable;
 			int max = keys.length;
@@ -1664,7 +1666,28 @@
 			this.acceptedTypes = null; // reset
 		}
 	}
-	
+
+	private char[] appendUnlessNextToken(char[] completionName, char[] suffix, int nextToken) {
+		if (this.source == null)
+			return CharOperation.concat(completionName, suffix);
+
+		AssistParser assistParser = getParser();
+		Object parserState = assistParser.becomeSimpleParser();
+
+		assistParser.scanner.setSource(this.source);
+		assistParser.scanner.resetTo(this.endPosition, Integer.MAX_VALUE);
+		try {
+			if (assistParser.scanner.getNextToken() != nextToken) {
+				return CharOperation.concat(completionName, suffix);
+			}
+		} catch (InvalidInputException e) {
+			// ignore
+		} finally {
+			assistParser.restoreAssistParser(parserState);
+		}
+		return completionName;
+	}
+
 	public void acceptUnresolvedName(char[] name) {
 		int relevance = computeBaseRelevance();
 		relevance += computeRelevanceForResolution(false);
@@ -1862,6 +1885,8 @@
 			}
 		} else if (astNode instanceof CompletionOnKeyword3 && ((CompletionOnKeyword3) astNode).afterTryOrCatch()) {
 				context.setTokenLocation(CompletionContext.TL_STATEMENT_START);
+		} else if (astNode instanceof CompletionOnImportReference) {
+			context.setTokenLocation(CompletionContext.TL_IN_IMPORT);
 		} else {
 			ReferenceContext referenceContext = scope.referenceContext();
 			if (referenceContext instanceof AbstractMethodDeclaration) {
@@ -2044,9 +2069,10 @@
 			this.actualCompletionPosition = completionPosition - 1;
 			this.offset = pos;
 			this.typeRoot = root;
-			
+			this.source = sourceUnit.getContents();
+
 			this.checkCancel();
-			
+
 			// for now until we can change the UI.
 			CompilationResult result = new CompilationResult(sourceUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit);
 			CompilationUnitDeclaration parsedUnit = this.parser.dietParse(sourceUnit, result, this.actualCompletionPosition);
@@ -2068,7 +2094,7 @@
 						if(!this.requestor.isIgnored(CompletionProposal.MODULE_DECLARATION)) {
 							proposeModuleName(parsedUnit);
 						}
-						debugPrintf(); 
+						debugPrintf();
 						return;
 					}
 					if (this.moduleDeclaration instanceof CompletionOnKeywordModuleDeclaration) {
@@ -2183,7 +2209,7 @@
 							this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
 							if ((this.unitScope = parsedUnit.scope) != null) {
 								contextAccepted = true;
-								buildContext(importReference, null, parsedUnit, null, null);
+								buildContext(importReference, null, parsedUnit, null, this.unitScope);
 
 								long positions = importReference.sourcePositions[importReference.tokens.length - 1];
 								setSourceAndTokenRange((int) (positions >>> 32), (int) positions);
@@ -2244,7 +2270,6 @@
 						this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
 
 						if ((this.unitScope = parsedUnit.scope) != null) {
-							this.source = sourceUnit.getContents();
 							this.lookupEnvironment.completeTypeBindings(parsedUnit, true);
 							parsedUnit.scope.faultInTypes();
 							parseBlockStatements(parsedUnit, this.actualCompletionPosition);
@@ -2566,7 +2591,7 @@
 			this.requestor.endReporting();
 		}
 	}
-	
+
 	private void completionOnBranchStatementLabel(ASTNode astNode) {
 		if (!this.requestor.isIgnored(CompletionProposal.LABEL_REF)) {
 			CompletionOnBranchStatementLabel label = (CompletionOnBranchStatementLabel) astNode;
@@ -2574,7 +2599,7 @@
 			findLabels(this.completionToken, label.possibleLabels);
 		}
 	}
-	
+
 	private void completionOnClassLiteralAccess(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
 		if (!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
 			CompletionOnClassLiteralAccess access = (CompletionOnClassLiteralAccess) astNode;
@@ -2590,7 +2615,7 @@
 					false);
 		}
 	}
-	
+
 	private void completionOnExplicitConstructorCall(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
 		if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
 			setSourceAndTokenRange(astNode.sourceStart, astNode.sourceEnd, false);
@@ -2608,7 +2633,7 @@
 				false);
 		}
 	}
-	
+
 	private void completionOnFieldName(ASTNode astNode, Scope scope) {
 		if (!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) {
 			CompletionOnFieldName field = (CompletionOnFieldName) astNode;
@@ -2621,18 +2646,18 @@
 
 			this.completionToken = field.realName;
 
-			
+
 			int kind =
-				 (field.modifiers & ClassFileConstants.AccStatic) == 0 ? 
+				 (field.modifiers & ClassFileConstants.AccStatic) == 0 ?
 						InternalNamingConventions.VK_INSTANCE_FIELD :
-							(field.modifiers & ClassFileConstants.AccFinal) == 0 ? 
+							(field.modifiers & ClassFileConstants.AccFinal) == 0 ?
 									InternalNamingConventions.VK_STATIC_FIELD :
 										InternalNamingConventions.VK_STATIC_FINAL_FIELD;
-			
+
 			findVariableNames(field.realName, field.type, excludeNames, null, kind);
 		}
 	}
-	
+
 	private void completionOnFieldType(ASTNode astNode, Scope scope) {
 		CompletionOnFieldType field = (CompletionOnFieldType) astNode;
 		CompletionOnSingleTypeReference type = (CompletionOnSingleTypeReference) field.type;
@@ -2667,7 +2692,7 @@
 	//TODO
 	private void completionOnJavadocAllocationExpression(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
 		// setSourceRange(astNode.sourceStart, astNode.sourceEnd, false);
-		
+
 		CompletionOnJavadocAllocationExpression allocExpression = (CompletionOnJavadocAllocationExpression) astNode;
 		this.javadocTagPosition = allocExpression.tagSourceStart;
 		int rangeStart = astNode.sourceStart;
@@ -2881,14 +2906,14 @@
 			findJavadocParamNames(paramRef.token, paramRef.missingParams, true);
 		}
 	}
-	
+
 	private void completionOnKeyword(ASTNode astNode) {
 		if (!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
 			CompletionOnKeyword keyword = (CompletionOnKeyword)astNode;
 			findKeywords(keyword.getToken(), keyword.getPossibleKeywords(), false, false);
 		}
 	}
-	
+
 	private void completionOnLocalOrArgumentName(ASTNode astNode, Scope scope) {
 		if (!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) {
 			LocalDeclaration variable = (LocalDeclaration) astNode;
@@ -2921,7 +2946,7 @@
 			findVariableNames(this.completionToken, variable.type, discouragedNames, forbiddenNames, kind);
 		}
 	}
-	
+
 	private void completionOnMarkerAnnotationName(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
 		CompletionOnMarkerAnnotationName annot = (CompletionOnMarkerAnnotationName) astNode;
 
@@ -3008,7 +3033,7 @@
 			}
 		}
 	}
-	
+
 	private void completionOnMemberAccess(ASTNode astNode, ASTNode enclosingNode, Binding qualifiedBinding,
 			Scope scope, boolean insideTypeAnnotation) {
 		this.insideQualifiedReference = true;
@@ -3067,9 +3092,9 @@
 					-1);
 
 				if (!superCall) {
-					
+
 					checkCancel();
-					
+
 					findFieldsAndMethodsFromCastedReceiver(
 							enclosingNode,
 							qualifiedBinding,
@@ -3083,7 +3108,7 @@
 			}
 		}
 	}
-	
+
 	private void completionOnMemberValueName(ASTNode astNode, ASTNode astNodeParent, Scope scope,
 			boolean insideTypeAnnotation) {
 		CompletionOnMemberValueName memberValuePair = (CompletionOnMemberValueName) astNode;
@@ -3133,7 +3158,7 @@
 			}
 		}
 	}
-	
+
 	private void completionOnMessageSend(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
 		setSourceAndTokenRange(astNode.sourceStart, astNode.sourceEnd, false);
 
@@ -3145,9 +3170,9 @@
 				ObjectVector methodsFound = new ObjectVector();
 
 				findImplicitMessageSends(this.completionToken, argTypes, scope, messageSend, scope, methodsFound);
-				
+
 				checkCancel();
-				
+
 				findLocalMethodsFromStaticImports(
 						this.completionToken,
 						scope,
@@ -3181,7 +3206,7 @@
 				-1);
 		}
 	}
-	
+
 	private void completionOnMessageSendName(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
 		if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
 			CompletionOnMessageSendName messageSend = (CompletionOnMessageSendName) astNode;
@@ -3233,7 +3258,7 @@
 			this.insideQualifiedReference = true;
 			this.completionToken = referenceExpression.selector;
 			boolean onlyStatic = false;
-			
+
 			TypeBinding receiverType = (TypeBinding) qualifiedBinding;
 			if (receiverType != null && receiverType instanceof ReferenceBinding) {
 				setSourceAndTokenRange(referenceExpression.nameSourceStart, referenceExpression.sourceEnd);
@@ -3266,7 +3291,7 @@
 		}
 	}
 
-	
+
 	private void completionOnMethodName(ASTNode astNode, Scope scope) {
 		if (!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) {
 			CompletionOnMethodName method = (CompletionOnMethodName) astNode;
@@ -3281,18 +3306,18 @@
 
 			this.completionToken = method.selector;
 
-			
+
 			int kind =
-				 (method.modifiers & ClassFileConstants.AccStatic) == 0 ? 
+				 (method.modifiers & ClassFileConstants.AccStatic) == 0 ?
 						InternalNamingConventions.VK_INSTANCE_FIELD :
-							(method.modifiers & ClassFileConstants.AccFinal) == 0 ? 
+							(method.modifiers & ClassFileConstants.AccFinal) == 0 ?
 									InternalNamingConventions.VK_STATIC_FIELD :
 										InternalNamingConventions.VK_STATIC_FINAL_FIELD;
-						
+
 			findVariableNames(this.completionToken, method.returnType, excludeNames, null, kind);
 		}
 	}
-	
+
 	private void completionOnMethodReturnType(ASTNode astNode, Scope scope) {
 		CompletionOnMethodReturnType method = (CompletionOnMethodReturnType) astNode;
 		SingleTypeReference type = (CompletionOnSingleTypeReference) method.returnType;
@@ -3323,7 +3348,7 @@
 			}
 		}
 	}
-	
+
 	private void completionOnParameterizedQualifiedTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope) {
 		if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
 			CompletionOnParameterizedQualifiedTypeReference ref = (CompletionOnParameterizedQualifiedTypeReference) astNode;
@@ -3362,9 +3387,9 @@
 							(BlockScope)scope,
 							typesFound);
 				}
-				
+
 				checkCancel();
-				
+
 				findMemberTypes(
 					this.completionToken,
 					(ReferenceBinding) qualifiedBinding,
@@ -3387,7 +3412,7 @@
 			return false;
 		if (astNodeParent instanceof TypeDeclaration) {
 			TypeDeclaration typeDeclaration = (TypeDeclaration) astNodeParent;
-			return (typeDeclaration.superclass == astNode);	
+			return (typeDeclaration.superclass == astNode);
 		} else if (astNodeParent instanceof TypeParameter) {
 			TypeParameter typeParameter = (TypeParameter) astNodeParent;
 			return (typeParameter.type == astNode);
@@ -3397,7 +3422,7 @@
 		}
 		return false;
 	}
-	
+
 	private boolean assistNodeIsInterfaceExcludingAnnotation(ASTNode astNode, ASTNode astNodeParent) {
 		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=310423, don't propose annotations for implements.
 		if (astNodeParent == null)
@@ -3413,9 +3438,9 @@
 		}
 		return false;
 	}
-	
+
 	private boolean assistNodeIsInsideCase(ASTNode astNode, ASTNode astNodeParent) {
-		// To find whether we're completing inside the case expression in a 
+		// To find whether we're completing inside the case expression in a
 		// switch case construct (https://bugs.eclipse.org/bugs/show_bug.cgi?id=195346)
 		if (astNodeParent instanceof SwitchStatement) {
 			CaseStatement[] cases = ((SwitchStatement) astNodeParent).cases;
@@ -3437,7 +3462,7 @@
 		TypeBinding[] argTypes = computeTypes(allocExpression.arguments);
 
 		ReferenceBinding ref = (ReferenceBinding) qualifiedBinding;
-		
+
 		if (ref.problemId() == ProblemReasons.NotFound) {
 			findConstructorsFromMissingType(
 					allocExpression.type,
@@ -3459,9 +3484,9 @@
 						null,
 						false);
 			}
-			
+
 			checkCancel();
-			
+
 			if (!this.requestor.isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION)
 					&& !ref.isFinal()
 					&& !ref.isEnum()){
@@ -3477,7 +3502,7 @@
 			}
 		}
 	}
-	
+
 	private void completionOnQualifiedNameReference(ASTNode astNode, ASTNode enclosingNode, Binding qualifiedBinding,
 			Scope scope, boolean insideTypeAnnotation) {
 		this.insideQualifiedReference = true;
@@ -3485,7 +3510,7 @@
 			(CompletionOnQualifiedNameReference) astNode;
 		this.completionToken = ref.completionIdentifier;
 		long completionPosition = ref.sourcePositions[ref.sourcePositions.length - 1];
-		
+
 		if (qualifiedBinding.problemId() == ProblemReasons.NotFound) {
 			setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
 			// complete field members with missing fields type
@@ -3503,9 +3528,9 @@
 					boolean foundSomeFields = findFieldsAndMethodsFromMissingFieldType(ref.tokens[0], scope, ref, insideTypeAnnotation);
 
 					if (!foundSomeFields) {
-						
+
 						checkCancel();
-						
+
 						findMembersFromMissingType(
 								ref.tokens[0],
 								ref.sourcePositions[0],
@@ -3540,7 +3565,7 @@
 						null,
 						-1,
 						-1);
-				
+
 				checkCancel();
 
 				findFieldsAndMethodsFromCastedReceiver(
@@ -3614,7 +3639,7 @@
 			findTypesAndSubpackages(this.completionToken, (PackageBinding) qualifiedBinding, scope);
 		}
 	}
-	
+
 	private void completionOnQualifiedTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding,
 			Scope scope) {
 		this.insideQualifiedReference = true;
@@ -3629,7 +3654,7 @@
 		this.assistNodeIsSuperType = ref.isSuperType();
 		this.assistNodeIsExtendedType = assistNodeIsExtendedType(astNode, astNodeParent);
 		this.assistNodeIsInterfaceExcludingAnnotation = assistNodeIsInterfaceExcludingAnnotation(astNode, astNodeParent);
-		
+
 		this.completionToken = ref.completionIdentifier;
 		long completionPosition = ref.sourcePositions[ref.tokens.length];
 
@@ -3659,7 +3684,7 @@
 							(BlockScope)scope,
 							typesFound);
 				}
-				
+
 				checkCancel();
 
 				findMemberTypes(
@@ -3683,7 +3708,7 @@
 			findTypesAndSubpackages(this.completionToken, (PackageBinding) qualifiedBinding, scope);
 		}
 	}
-	
+
 	private void completionOnProvidesInterfacesQualifiedTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope) {
 		// TODO: Filter the results wrt accessibility and add relevance to the results.
 		completionOnQualifiedTypeReference(astNode, astNodeParent, qualifiedBinding, scope);
@@ -3736,9 +3761,9 @@
 						(BlockScope)scope,
 						alreadyDefinedName);
 			}
-			
+
 			checkCancel();
-			
+
 			findVariablesAndMethods(
 				this.completionToken,
 				scope,
@@ -3746,9 +3771,9 @@
 				scope,
 				insideTypeAnnotation,
 				singleNameReference.isInsideAnnotationAttribute);
-			
+
 			checkCancel();
-			
+
 			// can be the start of a qualified type name
 			findTypesAndPackages(this.completionToken, scope, true, false, new ObjectVector());
 			if (!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
@@ -3769,7 +3794,7 @@
 			}
 		}
 	}
-	
+
 	private void completionOnSingleTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope) {
 		CompletionOnSingleTypeReference singleRef = (CompletionOnSingleTypeReference) astNode;
 
@@ -3782,7 +3807,7 @@
 		this.assistNodeIsSuperType = singleRef.isSuperType();
 		this.assistNodeIsExtendedType = assistNodeIsExtendedType(astNode, astNodeParent);
 		this.assistNodeIsInterfaceExcludingAnnotation = assistNodeIsInterfaceExcludingAnnotation(astNode, astNodeParent);
-		
+
 		// can be the start of a qualified type name
 		if (qualifiedBinding == null) {
 			if (this.completionToken.length == 0 &&
@@ -3801,9 +3826,9 @@
 							(BlockScope)scope,
 							typesFound);
 				}
-				
+
 				checkCancel();
-				
+
 				findTypesAndPackages(this.completionToken, scope, this.assistNodeIsConstructor, false, typesFound);
 			}
 		} else if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
@@ -4179,13 +4204,13 @@
 				// completing inside the diamond
 				if (this.parser.enclosingNode instanceof AbstractVariableDeclaration) {
 					AbstractVariableDeclaration abstractVariableDeclaration = (AbstractVariableDeclaration) this.parser.enclosingNode;
-					expected = abstractVariableDeclaration.initialization != null ? abstractVariableDeclaration.initialization.expectedType() : null;					
+					expected = abstractVariableDeclaration.initialization != null ? abstractVariableDeclaration.initialization.expectedType() : null;
 				} else {
 					ReturnStatement returnStatement = (ReturnStatement) this.parser.enclosingNode;
 					if (returnStatement.expression != null) {
 						expected = returnStatement.expression.expectedType();
 					}
-				}	
+				}
 				addExpectedType(expected, scope);
 			} else {
 				TypeVariableBinding[] typeVariables = ((ReferenceBinding)ref.resolvedType).typeVariables();
@@ -4193,7 +4218,7 @@
 				if(typeVariables != null && typeVariables.length >= length) {
 					int index = length - 1;
 					while(index > -1 && ref.typeArguments[index] != node) index--;
-	
+
 					TypeBinding bound = typeVariables[index].firstBound;
 					addExpectedType(bound == null ? scope.getJavaLangObject() : bound, scope);
 				}
@@ -4328,7 +4353,7 @@
 		// type if we are completing inside if(), for (; ;), while() and do while()
 		} else if (parent instanceof WhileStatement) {  // covers both while and do-while loops
 			addExpectedType(TypeBinding.BOOLEAN, scope);
-		} else if (parent instanceof IfStatement) {  
+		} else if (parent instanceof IfStatement) {
 			addExpectedType(TypeBinding.BOOLEAN, scope);
 		} else if (parent instanceof AssertStatement) {
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=274466
@@ -4337,7 +4362,7 @@
 			if (assertStatement.assertExpression == node) {
 				addExpectedType(TypeBinding.BOOLEAN, scope);
 			}
-		} else if (parent instanceof ForStatement) {   // astNodeParent set to ForStatement only for the condition  
+		} else if (parent instanceof ForStatement) {   // astNodeParent set to ForStatement only for the condition
 			addExpectedType(TypeBinding.BOOLEAN, scope);
 
 		// Expected types for javadoc
@@ -4585,6 +4610,8 @@
 				return R_CAMEL_CASE;
 		} else if (this.options.substringMatch && CharOperation.substringMatch(token, proposalName)) {
 			return R_SUBSTRING;
+		} else if (this.options.subwordMatch && CharOperation.subWordMatch(token, proposalName)) {
+			return R_SUBWORD;
 		}
 		return 0;
 	}
@@ -4595,7 +4622,7 @@
 		}
 		return 0;
 	}
-	
+
 	private int computeRelevanceForConstructor() {
 		if (this.assistNodeIsConstructor) {
 			return R_CONSTRUCTOR;
@@ -4661,13 +4688,13 @@
 		if(this.expectedTypes != null && proposalType != null) {
 			int relevance = 0;
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=271296
-			// If there is at least one expected type, then void proposal types attract a degraded relevance.  
+			// If there is at least one expected type, then void proposal types attract a degraded relevance.
 			if (proposalType == TypeBinding.VOID && this.expectedTypesPtr >=0) {
 				return R_VOID;
-			}	
+			}
 			for (int i = 0; i <= this.expectedTypesPtr; i++) {
 				if((this.expectedTypesFilter & SUBTYPE) != 0
-						&& proposalType.isCompatibleWith(this.expectedTypes[i])) {
+						&& (proposalType.erasure().isCompatibleWith(this.expectedTypes[i].erasure()))) {
 
 					if(CharOperation.equals(this.expectedTypes[i].qualifiedPackageName(), proposalType.qualifiedPackageName()) &&
 							CharOperation.equals(this.expectedTypes[i].qualifiedSourceName(), proposalType.qualifiedSourceName())) {
@@ -4730,7 +4757,7 @@
 		}
 		return R_INTERESTING;
 	}
-	
+
 	private int computeRelevanceForInterestingProposal(char[] givenPkgName, char[] fullTypeName) {
 		for (int i = 0; i <= this.uninterestingBindingsPtr; i++) {
 			if (this.uninterestingBindings[i] instanceof TypeBinding) {
@@ -4795,7 +4822,7 @@
 		}
 		return 0;
 	}
-	
+
 	private int computeRelevanceForFinal(boolean onlyFinal, boolean isFinal) {
 		if (onlyFinal && isFinal) {
 			return R_FINAL;
@@ -4901,7 +4928,7 @@
 						}
 					}
 				}
-				
+
 			}
 		}
 	}
@@ -5361,16 +5388,16 @@
 			int[] missingElementsStarts,
 			int[] missingElementsEnds,
 			boolean missingElementsHaveProblems) {
-		
+
 		int relevance = computeBaseRelevance();
 		relevance += computeRelevanceForResolution();
 		relevance += computeRelevanceForInterestingProposal(currentType);
 		relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
-		
+
 		if (missingElements != null) {
 			relevance += computeRelevanceForMissingElements(missingElementsHaveProblems);
 		}
-		
+
 		findAnonymousType(
 				currentType,
 				argTypes,
@@ -5401,7 +5428,7 @@
 			char[] completion = CharOperation.NO_CHAR;
 			char[] typeCompletion = null;
 			if (!exactMatch) {
-				typeCompletion = 
+				typeCompletion =
 					isQualified ?
 							CharOperation.concat(currentType.qualifiedPackageName(), currentType.qualifiedSourceName(), '.') :
 								currentType.sourceName();
@@ -5419,7 +5446,7 @@
 				if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
 					char[] packageName = currentType.isLocalType() ? null : currentType.qualifiedPackageName();
 					char[] typeName = currentType.qualifiedSourceName();
-					
+
 					InternalCompletionProposal proposal = createProposal(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, this.actualCompletionPosition);
 					proposal.setDeclarationSignature(getSignature(currentType));
 					proposal.setDeclarationKey(currentType.computeUniqueKey());
@@ -5438,7 +5465,7 @@
 					//proposal.setPackageName(null);
 					//proposal.setTypeName(null);
 					proposal.setName(currentType.sourceName());
-					
+
 					InternalCompletionProposal typeProposal = createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
 					typeProposal.nameLookup = this.nameEnvironment.nameLookup;
 					typeProposal.completionEngine = this;
@@ -5452,7 +5479,7 @@
 					typeProposal.setTokenRange(this.startPosition - this.offset, this.endPosition - this.offset);
 					typeProposal.setRelevance(relevance);
 					proposal.setRequiredProposals( new CompletionProposal[]{typeProposal});
-								
+
 					proposal.setCompletion(completion);
 					proposal.setFlags(Flags.AccPublic);
 					proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
@@ -5597,7 +5624,7 @@
 			}
 		}
 	}
-	
+
 	void findConstructors(
 		ReferenceBinding currentType,
 		TypeBinding[] argTypes,
@@ -5608,16 +5635,16 @@
 		int[] missingElementsStarts,
 		int[] missingElementsEnds,
 		boolean missingElementsHaveProblems) {
-		
+
 		int relevance = computeBaseRelevance();
 		relevance += computeRelevanceForResolution();
 		relevance += computeRelevanceForInterestingProposal();
 		relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
-		
+
 		if (missingElements != null) {
 			relevance += computeRelevanceForMissingElements(missingElementsHaveProblems);
 		}
-		
+
 		findConstructors(
 				currentType,
 				argTypes,
@@ -5632,8 +5659,8 @@
 				false,
 				relevance);
 	}
-	
-	
+
+
 	private void findConstructorsFromMissingType(
 			TypeReference typeRef,
 			final TypeBinding[] argTypes,
@@ -5665,9 +5692,9 @@
 									missingElementsEnds,
 									hasProblems);
 						}
-								
+
 						checkCancel();
-			
+
 						if (!isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION, missingElements != null)
 								&& !ref.isFinal()
 								&& !ref.isEnum()){
@@ -5686,7 +5713,7 @@
 			};
 		missingTypesConverter.guess(typeRef, scope, substitutionRequestor);
 	}
-		
+
 	private void findConstructors(
 		ReferenceBinding currentType,
 		TypeBinding[] argTypes,
@@ -5757,11 +5784,11 @@
 					char[][] parameterNames = findMethodParameterNames(constructor,parameterTypeNames);
 
 					char[] completion = CharOperation.NO_CHAR;
-					
+
 					if(forAnonymousType){
 						char[] typeCompletion = null;
 						if (!exactMatch) {
-							typeCompletion = 
+							typeCompletion =
 								isQualified ?
 										CharOperation.concat(currentType.qualifiedPackageName(), currentType.qualifiedSourceName(), '.') :
 											currentType.sourceName();
@@ -5773,13 +5800,13 @@
 								completion = new char[] { '(', ')' };
 							}
 						}
-						
+
 						this.noProposal = false;
 						if (!exactMatch) {
 							if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
 								char[] packageName = currentType.isLocalType() ? null : currentType.qualifiedPackageName();
 								char[] typeName = currentType.qualifiedSourceName();
-								
+
 								InternalCompletionProposal proposal = createProposal(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, this.actualCompletionPosition);
 								proposal.setBinding(constructor);
 								proposal.setDeclarationSignature(getSignature(currentType));
@@ -5797,7 +5824,7 @@
 								//proposal.setPackageName(null);
 								//proposal.setTypeName(null);
 								proposal.setName(currentType.sourceName());
-								
+
 								InternalCompletionProposal typeProposal = createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
 								typeProposal.nameLookup = this.nameEnvironment.nameLookup;
 								typeProposal.completionEngine = this;
@@ -5811,7 +5838,7 @@
 								typeProposal.setTokenRange(this.startPosition - this.offset, this.endPosition - this.offset);
 								typeProposal.setRelevance(relevance);
 								proposal.setRequiredProposals( new CompletionProposal[]{typeProposal});
-								
+
 								proposal.setCompletion(completion);
 								proposal.setFlags(constructor.modifiers);
 								proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
@@ -5919,11 +5946,11 @@
 							}
 						} else {
 							if (!exactMatch) {
-								typeCompletion = 
+								typeCompletion =
 									isQualified ?
 											CharOperation.concat(currentType.qualifiedPackageName(), currentType.qualifiedSourceName(), '.') :
 												currentType.sourceName();
-								
+
 								if (this.source != null
 											&& this.source.length > this.endPosition
 											&& this.source[this.endPosition] == '(') {
@@ -5956,7 +5983,7 @@
 								//proposal.setPackageName(null);
 								//proposal.setTypeName(null);
 								proposal.setName(currentType.sourceName());
-					
+
 								InternalCompletionProposal typeProposal = createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
 								typeProposal.nameLookup = this.nameEnvironment.nameLookup;
 								typeProposal.completionEngine = this;
@@ -5970,7 +5997,7 @@
 								typeProposal.setTokenRange(this.startPosition - this.offset, this.endPosition - this.offset);
 								typeProposal.setRelevance(constructorRelevance);
 								proposal.setRequiredProposals( new CompletionProposal[]{typeProposal});
-								
+
 								proposal.setIsContructor(true);
 								proposal.setCompletion(completion);
 								proposal.setFlags(constructor.modifiers);
@@ -6061,7 +6088,7 @@
 			}
 		}
 	}
-	
+
 	private char[] getResolvedSignature(char[][] parameterTypes, char[] fullyQualifiedTypeName, int parameterCount, Scope scope) {
 		char[][] cn = CharOperation.splitOn('.', fullyQualifiedTypeName);
 
@@ -6071,7 +6098,7 @@
 		} else {
 			ref = new QualifiedTypeReference(cn,new long[cn.length]);
 		}
-		
+
 		TypeBinding guessedType = null;
 		INameEnvironment oldNameEnvironment = this.lookupEnvironment.nameEnvironment;
 		this.lookupEnvironment.nameEnvironment = getNoCacheNameEnvironment();
@@ -6085,38 +6112,38 @@
 					guessedType = ref.resolveType((ClassScope)scope);
 					break;
 			}
-		
+
 
 			if (guessedType != null && guessedType.isValidBinding()) {
 				// the erasure must be used because guessedType can be a RawTypeBinding (https://bugs.eclipse.org/bugs/show_bug.cgi?id=276890)
 				guessedType = guessedType.erasure();
-				
+
 				if (guessedType instanceof SourceTypeBinding) {
 					SourceTypeBinding refBinding = (SourceTypeBinding) guessedType;
-					
+
 					if (refBinding.scope == null || refBinding.scope.referenceContext == null) return null;
-					
+
 					TypeDeclaration typeDeclaration = refBinding.scope.referenceContext;
 					AbstractMethodDeclaration[] methods = typeDeclaration.methods;
-					
+
 					next : for (int i = 0; i < methods.length; i++) {
 						AbstractMethodDeclaration method = methods[i];
-						
+
 						if (!method.isConstructor()) continue next;
-						
+
 						Argument[] arguments = method.arguments;
 						int argumentsLength = arguments == null ? 0 : arguments.length;
-						
+
 						if (parameterCount != argumentsLength) continue next;
-						
+
 						for (int j = 0; j < argumentsLength; j++) {
 							char[] argumentTypeName = getTypeName(arguments[j].type);
-	
+
 							if (!CharOperation.equals(argumentTypeName, parameterTypes[j])) {
 								continue next;
 							}
 						}
-						
+
 						refBinding.resolveTypesFor(method.binding); // force resolution
 						if (method.binding == null) continue next;
 						return getSignature(method.binding);
@@ -6126,17 +6153,17 @@
 		} finally {
 			this.lookupEnvironment.nameEnvironment = oldNameEnvironment;
 		}
-		
+
 		return null;
 	}
-	
+
 	private void findConstructorsOrAnonymousTypes(
 			ReferenceBinding currentType,
 			Scope scope,
 			InvocationSite invocationSite,
 			boolean isQualified,
 			int relevance) {
-		
+
 		if (!isIgnored(CompletionProposal.CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)
 				&& currentType.isClass()
 				&& !currentType.isAbstract()) {
@@ -6154,7 +6181,7 @@
 					isQualified,
 					relevance);
 		}
-		
+
 		// This code is disabled because there is too much proposals when constructors and anonymous are proposed
 		if (!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)
 				&& !currentType.isFinal()
@@ -6455,7 +6482,7 @@
 				return;
 			}
 		}
-		
+
 		if (isForbidden(exceptionType)) return;
 
 		for (int j = typesFound.size; --j >= 0;) {
@@ -6751,7 +6778,7 @@
 		int fieldLength = fieldName.length;
 		next : for (int f = fields.length; --f >= 0;) {
 			FieldBinding field = fields[f];
-			
+
 			// Content assist invoked inside some field's initialization.
 			// bug 310427 and 325481
 			if (fieldBeingCompletedId >= 0 && field.id >= fieldBeingCompletedId) {
@@ -6768,7 +6795,7 @@
 					}
 				}
 			}
-			
+
 			if (field.isSynthetic())	continue next;
 
 			if (onlyStaticFields && !field.isStatic()) continue next;
@@ -6784,7 +6811,7 @@
 
 			if (this.options.checkVisibility
 				&& !field.canBeSeenBy(receiverType, invocationSite, scope))	continue next;
-			
+
 			// don't propose non constant fields or strings (1.6 or below) in case expression
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=195346
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=343342
@@ -6794,9 +6821,9 @@
 						if (field.type == null || field.type.id != TypeIds.T_JavaLangString)
 							continue next;
 					} else if (!(field.type instanceof BaseTypeBinding))
-						continue next; 
+						continue next;
 				} else {
-					continue next; // non-constants not allowed in case.	
+					continue next; // non-constants not allowed in case.
 				}
 			}
 
@@ -7365,9 +7392,9 @@
 
 			receiverType = scope.getJavaLangObject();
 		}
-		
+
 		checkCancel();
-		
+
 		if(proposeField) {
 			findFields(
 				token,
@@ -7505,29 +7532,29 @@
 		IfStatement ifStatement = (IfStatement)enclosingNode;
 		while (true) {
 			if (!(ifStatement.condition instanceof InstanceOfExpression)) return;
-	
+
 			InstanceOfExpression instanceOfExpression = (InstanceOfExpression) ifStatement.condition;
-	
+
 			TypeReference instanceOfType = instanceOfExpression.type;
-	
+
 			if (instanceOfType.resolvedType == null) return;
-	
+
 			boolean findFromAnotherReceiver = false;
-	
+
 			char[][] receiverName = null;
 			int receiverStart = -1;
 			int receiverEnd = -1;
-	
+
 			if (receiver instanceof QualifiedNameReference) {
 				QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) receiver;
-	
+
 				receiverName = qualifiedNameReference.tokens;
-	
+
 				if (receiverName.length != 1) return;
-	
+
 				receiverStart = (int) (qualifiedNameReference.sourcePositions[0] >>> 32);
 				receiverEnd = (int) qualifiedNameReference.sourcePositions[qualifiedNameReference.tokens.length - 1] + 1;
-	
+
 				// if (local instanceof X) local.|
 				// if (field instanceof X) field.|
 				if (instanceOfExpression.expression instanceof SingleNameReference &&
@@ -7535,11 +7562,11 @@
 						(qualifiedBinding instanceof LocalVariableBinding || qualifiedBinding instanceof FieldBinding)) {
 					findFromAnotherReceiver = true;
 				}
-	
+
 				// if (this.field instanceof X) field.|
 				if (instanceOfExpression.expression instanceof FieldReference) {
 					FieldReference fieldReference = (FieldReference)instanceOfExpression.expression;
-	
+
 					if (fieldReference.receiver instanceof ThisReference &&
 							qualifiedBinding instanceof FieldBinding &&
 							fieldReference.binding == qualifiedBinding) {
@@ -7548,24 +7575,24 @@
 				}
 			} else if (receiver instanceof FieldReference) {
 				FieldReference fieldReference1 = (FieldReference) receiver;
-	
+
 				receiverStart = fieldReference1.sourceStart;
 				receiverEnd = fieldReference1.sourceEnd + 1;
-	
+
 				if (fieldReference1.receiver instanceof ThisReference) {
-	
+
 					receiverName = new char[][] {THIS, fieldReference1.token};
-	
+
 					// if (field instanceof X) this.field.|
 					if (instanceOfExpression.expression instanceof SingleNameReference &&
 							((SingleNameReference)instanceOfExpression.expression).binding == fieldReference1.binding) {
 						findFromAnotherReceiver = true;
 					}
-	
+
 					// if (this.field instanceof X) this.field.|
 					if (instanceOfExpression.expression instanceof FieldReference) {
 						FieldReference fieldReference2 = (FieldReference)instanceOfExpression.expression;
-	
+
 						if (fieldReference2.receiver instanceof ThisReference &&
 								fieldReference2.binding == fieldReference1.binding) {
 									findFromAnotherReceiver = true;
@@ -7573,18 +7600,18 @@
 					}
 				}
 			}
-	
+
 			if (findFromAnotherReceiver) {
 				TypeBinding receiverTypeBinding = instanceOfType.resolvedType;
 				char[] castedReceiver = null;
-	
+
 				char[] castedTypeChars = CharOperation.concatWith(instanceOfType.getTypeName(), '.');
 				if(this.source != null) {
 					int memberRefStart = this.startPosition;
-	
+
 					char[] receiverChars = CharOperation.subarray(this.source, receiverStart, receiverEnd);
 					char[] dotChars = CharOperation.subarray(this.source, receiverEnd, memberRefStart);
-	
+
 					castedReceiver =
 						CharOperation.concat(
 							CharOperation.concat(
@@ -7605,12 +7632,12 @@
 								')'),
 							DOT);
 				}
-	
+
 				if (castedReceiver == null) return;
-	
+
 				int oldStartPosition = this.startPosition;
 				this.startPosition = receiverStart;
-	
+
 				findFieldsAndMethods(
 						this.completionToken,
 						receiverTypeBinding,
@@ -7628,7 +7655,7 @@
 						castedReceiver,
 						receiverStart,
 						receiverEnd);
-	
+
 				this.startPosition = oldStartPosition;
 			}
 			// traverse the enclosing node to find the instanceof expression corresponding
@@ -8429,7 +8456,7 @@
 			}
 		}
 	}
-	
+
 	private void findInterfacesMethodDeclarations(
 		char[] selector,
 		ReferenceBinding receiverType,
@@ -8476,7 +8503,7 @@
 			}
 		}
 	}
-	
+
 	private void findInterfacesMethods(
 		char[] selector,
 		TypeBinding[] typeArgTypes,
@@ -8713,7 +8740,7 @@
 			}
 		}
 
-		if (astNode instanceof CompletionOnFieldType && 
+		if (astNode instanceof CompletionOnFieldType &&
 	        this.compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) {
 	        FieldBinding astNodeBinding = ((CompletionOnFieldType) astNode).binding;
 	        ReferenceBinding declaringClass = astNodeBinding != null ? astNodeBinding.declaringClass : null;
@@ -9170,7 +9197,7 @@
 						&& this.source.length > this.endPosition
 						&& this.source[this.endPosition] == '(')
 						completion = method.selector;
-					else 
+					else
 						completion = CharOperation.concat(method.selector, new char[] { '(', ')' });
 
 					if (castedReceiver != null) {
@@ -9613,7 +9640,7 @@
 	/**
 	 * Helper method for findMethods(char[], TypeBinding[], ReferenceBinding, Scope, ObjectVector, boolean, boolean, boolean)
 	 * Note that the method doesn't do a comparison of the method names and expects the client to handle the same.
-	 * 
+	 *
 	 * @methodName method as entered by the user, the one to completed
 	 * @param methods a resultant array of MethodBinding, whose names should match methodName. The calling client must ensure that this check is handled.
 	 */
@@ -10229,7 +10256,7 @@
 			}
 
 			boolean allowingLongComputationProposals = isAllowingLongComputationProposals();
-			
+
 			this.noProposal = false;
 			if (!this.assistNodeIsConstructor ||
 					!allowingLongComputationProposals ||
@@ -10247,7 +10274,7 @@
 						missingElementsEnds,
 						missingElementsHaveProblems);
 			}
-			
+
 			if (this.assistNodeIsConstructor && allowingLongComputationProposals) {
 				findConstructorsOrAnonymousTypes(
 						memberType,
@@ -10292,7 +10319,7 @@
 		typeRef.resolvedType = new ProblemReferenceBinding(new char[][]{ typeName }, null, ProblemReasons.NotFound);
 		missingTypesConverter.guess(typeRef, scope, substitutionRequestor);
 	}
-	
+
 	private void findMemberTypesFromMissingType(
 			TypeReference typeRef,
 			final long pos,
@@ -10350,7 +10377,7 @@
 		}
 
 		ReferenceBinding currentType = receiverType;
-		
+
 		findInterfacesMethodDeclarations(
 			selector,
 			receiverType,
@@ -10361,13 +10388,13 @@
 			missingElementsStarts,
 			missingElementsEnds,
 			missingElementsHaveProblems);
-		
+
 		if (receiverType.isInterface()) {
 			currentType = scope.getJavaLangObject();
 		} else {
 			currentType = receiverType.superclass();
 		}
-		
+
 		boolean hasPotentialDefaultAbstractMethods = true;
 		boolean java8Plus = this.compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8;
 		while (currentType != null) {
@@ -10407,7 +10434,7 @@
 			currentType = currentType.superclass();
 		}
 	}
-	
+
 	private char[][] findMethodParameterNames(MethodBinding method, char[][] parameterTypeNames){
 		TypeBinding erasure =  method.declaringClass.erasure();
 		if(!(erasure instanceof ReferenceBinding)) return null;
@@ -10513,7 +10540,7 @@
 		if (selector == null && notInJavadoc) {
 			return;
 		}
-		
+
 		if (this.assistNodeIsInsideCase)
 			return;		// no methods should be proposed inside case expression
 
@@ -10626,7 +10653,7 @@
 		Scope scope,
 		boolean proposeAllMemberTypes,
 		ObjectVector typesFound) {
-		
+
 		if (typeName == null)
 			return;
 
@@ -10700,7 +10727,7 @@
 												false);
 									}
 								}
-								
+
 								if (this.assistNodeIsConstructor && allowingLongComputationProposals) {
 									findConstructorsOrAnonymousTypes(
 											localType,
@@ -10750,7 +10777,7 @@
 		if (moduleName.length > 0) {// do not propose invalid names
 			if (!Character.isJavaIdentifierStart(moduleName[0])) return;
 			for (char c : moduleName) {
-				if (!Character.isJavaIdentifierPart(c) && c != '.') return; 
+				if (!Character.isJavaIdentifierPart(c) && c != '.') return;
 			}
 		}
 		this.completionToken = CharOperation.concatWith(this.moduleDeclaration.tokens, '.');
@@ -11058,34 +11085,34 @@
 
 		if (token == null)
 			return;
-		
+
 		boolean allowingLongComputationProposals = isAllowingLongComputationProposals();
-		
+
 		boolean proposeType =
 			!this.requestor.isIgnored(CompletionProposal.TYPE_REF) ||
 			((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF));
 
 		boolean proposeAllMemberTypes = !this.assistNodeIsConstructor;
-		
+
 		boolean proposeConstructor =
 			allowingLongComputationProposals &&
 			this.assistNodeIsConstructor &&
 			(!isIgnored(CompletionProposal.CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF) ||
 					!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF));
-		
+
 
 		if ((proposeType || proposeConstructor) && scope.enclosingSourceType() != null) {
-			
+
 			checkCancel();
-			
+
 			findNestedTypes(token, scope.enclosingSourceType(), scope, proposeAllMemberTypes, typesFound);
 			if(!this.assistNodeIsInterface &&
 					!this.assistNodeIsConstructor &&
 					!this.assistNodeIsAnnotation &&
 					this.assistNodeInJavadoc == 0) {
-				
+
 				checkCancel();
-				
+
 				// don't propose type parameters if the completion is a constructor ('new |')
 				findTypeParameters(token, scope);
 			}
@@ -11094,7 +11121,7 @@
 		boolean isEmptyPrefix = token.length == 0;
 
 		if ((proposeType || proposeConstructor) && this.unitScope != null) {
-			
+
 			ReferenceBinding outerInvocationType = scope.enclosingSourceType();
 			if(outerInvocationType != null) {
 				ReferenceBinding temp = outerInvocationType.enclosingType();
@@ -11108,9 +11135,9 @@
 			SourceTypeBinding[] types = this.unitScope.topLevelTypes;
 
 			next : for (int i = 0, length = types.length; i < length; i++) {
-				
+
 				checkCancel();
-				
+
 				SourceTypeBinding sourceType = types[i];
 
 				if(isForbidden(sourceType)) continue next;
@@ -11144,10 +11171,11 @@
 
 					if (TypeBinding.equalsEquals(sourceType, otherType)) continue next;
 				}
-				
+
 				typesFound.add(sourceType);
 
 				if (this.assistNodeIsExtendedType && sourceType.isFinal()) continue next;
+				if (this.assistNodeIsExtendedType && sourceType.isRecord()) continue next;
 				if (this.assistNodeIsInterfaceExcludingAnnotation && sourceType.isAnnotationType()) continue next;
 				if(this.assistNodeIsClass) {
 					if(!sourceType.isClass()) continue next;
@@ -11181,8 +11209,8 @@
 					relevance += computeRelevanceForClass();
 					relevance += computeRelevanceForException(sourceType.sourceName);
 				}
-				
-				
+
+
 				this.noProposal = false;
 				if(proposeType &&
 						(!this.assistNodeIsConstructor ||
@@ -11202,7 +11230,7 @@
 								null,
 								false);
 				}
-				
+
 				if (proposeConstructor) {
 					findConstructorsOrAnonymousTypes(
 							sourceType,
@@ -11215,21 +11243,21 @@
 		}
 
 		if (proposeConstructor && !isEmptyPrefix) {
-			
+
 			checkCancel();
-			
+
 			findTypesFromImports(token, scope, proposeType, typesFound);
 		} else if(proposeType) {
-			
+
 			checkCancel();
-			
+
 			findTypesFromStaticImports(token, scope, proposeAllMemberTypes, typesFound);
 		}
-		
+
 		if (proposeConstructor) {
-			
+
 			checkCancel();
-			
+
 			findTypesFromExpectedTypes(token, scope, typesFound, proposeType, proposeConstructor);
 		}
 
@@ -11249,7 +11277,7 @@
 					}
 				}
 			}
-			
+
 			if (proposeConstructor) {
 				int l = typesFound.size();
 				for (int i = 0; i < l; i++) {
@@ -11261,9 +11289,9 @@
 								'.');
 					this.knownTypes.put(fullyQualifiedTypeName, KNOWN_TYPE_WITH_KNOWN_CONSTRUCTORS);
 				}
-				
+
 				checkCancel();
-				
+
 				this.foundConstructorsCount = 0;
 				this.nameEnvironment.findConstructorDeclarations(
 						token,
@@ -11294,9 +11322,9 @@
 				} else if(this.assistNodeIsAnnotation) {
 					searchFor = IJavaSearchConstants.ANNOTATION_TYPE;
 				}
-				
+
 				checkCancel();
-				
+
 				this.foundTypesCount = 0;
 				this.nameEnvironment.findTypes(
 						token,
@@ -11308,9 +11336,9 @@
 				acceptTypes(scope);
 			}
 			if(!isEmptyPrefix && !this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) {
-				
+
 				checkCancel();
-				
+
 				this.nameEnvironment.findPackages(token, this);
 			}
 		}
@@ -11320,13 +11348,13 @@
 		char[] token,
 		PackageBinding packageBinding,
 		Scope scope) {
-		
+
 		boolean allowingLongComputationProposals = isAllowingLongComputationProposals();
 
 		boolean proposeType =
 			!this.requestor.isIgnored(CompletionProposal.TYPE_REF) ||
 			((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF));
-		
+
 		boolean proposeConstructor =
 			allowingLongComputationProposals &&
 			this.assistNodeIsConstructor &&
@@ -11354,11 +11382,11 @@
 			SourceTypeBinding[] types = this.unitScope.topLevelTypes;
 
 			for (int i = 0, length = types.length; i < length; i++) {
-				
+
 				checkCancel();
-				
+
 				SourceTypeBinding sourceType = types[i];
-				
+
 				if (isForbidden(sourceType)) continue;
 				if (this.assistNodeIsClass && sourceType.isInterface()) continue;
 				if (this.assistNodeIsInterface && sourceType.isClass()) continue;
@@ -11419,7 +11447,7 @@
 					relevance += computeRelevanceForClass();
 					relevance += computeRelevanceForException(sourceType.sourceName);
 				}
-				
+
 				this.noProposal = false;
 				if(proposeType &&
 						(!this.assistNodeIsConstructor ||
@@ -11439,7 +11467,7 @@
 							null,
 							false);
 				}
-				
+
 				if (proposeConstructor) {
 					findConstructorsOrAnonymousTypes(
 							sourceType,
@@ -11453,9 +11481,9 @@
 
 		if (proposeConstructor) {
 
-			
+
 			checkCancel();
-			
+
 			this.foundConstructorsCount = 0;
 			this.nameEnvironment.findConstructorDeclarations(
 					qualifiedName,
@@ -11476,9 +11504,9 @@
 			} else if(this.assistNodeIsAnnotation) {
 				searchFor = IJavaSearchConstants.ANNOTATION_TYPE;
 			}
-			
+
 			checkCancel();
-			
+
 			this.foundTypesCount = 0;
 			this.nameEnvironment.findTypes(
 					qualifiedName,
@@ -11489,28 +11517,28 @@
 					this.monitor);
 			acceptTypes(scope);
 		}
-		
+
 		if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) {
 			this.nameEnvironment.findPackages(qualifiedName, this);
 		}
 	}
-	
+
 	private void findTypesFromExpectedTypes(char[] token, Scope scope, ObjectVector typesFound, boolean proposeType, boolean proposeConstructor) {
 		if(this.expectedTypesPtr > -1) {
 			boolean allowingLongComputationProposals = isAllowingLongComputationProposals();
-			
+
 			int typeLength = token == null ? 0 : token.length;
-			
+
 			next : for (int i = 0; i <= this.expectedTypesPtr; i++) {
-				
+
 				checkCancel();
-				
+
 				if(this.expectedTypes[i] instanceof ReferenceBinding) {
 					ReferenceBinding refBinding = (ReferenceBinding)this.expectedTypes[i];
-					
+
 					if (typeLength > 0) {
 						if (typeLength > refBinding.sourceName.length) continue next;
-	
+
 						if (isFailedMatch(token, refBinding.sourceName)) continue next;
 					}
 
@@ -11552,7 +11580,7 @@
 							continue next;
 						}
 					}
-					
+
 					typesFound.add(refBinding);
 
 					boolean inSameUnit = this.unitScope.isDefinedInSameUnit(refBinding);
@@ -11600,7 +11628,7 @@
 						} else if(refBinding.isInterface()) {
 							relevance += computeRelevanceForInterface();
 						}
-						
+
 						if (proposeType &&
 								(!this.assistNodeIsConstructor ||
 										!allowingLongComputationProposals ||
@@ -11625,7 +11653,7 @@
 								}
 							}
 						}
-						
+
 						if (proposeConstructor) {
 							findConstructorsOrAnonymousTypes(
 									refBinding,
@@ -11678,7 +11706,7 @@
 							if (typeLength > typeBinding.sourceName.length)	continue next;
 
 							if (isFailedMatch(token, typeBinding.sourceName)) continue next;
-							
+
 							int accessibility = IAccessRule.K_ACCESSIBLE;
 							if(typeBinding.hasRestrictedAccess()) {
 								AccessRestriction accessRestriction = this.lookupEnvironment.getAccessRestriction(typeBinding);
@@ -11699,11 +11727,11 @@
 									}
 								}
 							}
-							
+
 							if (typesFound.contains(typeBinding)) continue next;
-							
+
 							typesFound.add(typeBinding);
-							
+
 							if (this.assistNodeIsExtendedType && typeBinding.isFinal()) continue;
 							if (this.assistNodeIsInterfaceExcludingAnnotation && typeBinding.isAnnotationType()) continue;
 							if(this.assistNodeIsClass) {
@@ -11713,7 +11741,7 @@
 							} else if (this.assistNodeIsAnnotation) {
 								if(!typeBinding.isAnnotationType()) continue;
 							}
-							
+
 							int relevance = computeBaseRelevance();
 							relevance += computeRelevanceForResolution();
 							relevance += computeRelevanceForInterestingProposal(typeBinding);
@@ -11721,7 +11749,7 @@
 							relevance += computeRelevanceForExpectingType(typeBinding);
 							relevance += computeRelevanceForQualification(false);
 							relevance += computeRelevanceForRestrictions(accessibility);
-			
+
 							if (typeBinding.isAnnotationType()) {
 								relevance += computeRelevanceForAnnotation();
 								relevance += computeRelevanceForAnnotationTarget(typeBinding);
@@ -11731,8 +11759,8 @@
 								relevance += computeRelevanceForClass();
 								relevance += computeRelevanceForException(typeBinding.sourceName);
 							}
-							
-							if (proposeType && 
+
+							if (proposeType &&
 									(hasStaticMemberTypes(typeBinding, scope.enclosingSourceType(), this.unitScope) || hasArrayTypeAsExpectedSuperTypes())) {
 								this.noProposal = false;
 								if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
@@ -11752,7 +11780,7 @@
 									}
 								}
 							}
-							
+
 							findConstructorsOrAnonymousTypes(
 									typeBinding,
 									scope,
@@ -11765,7 +11793,7 @@
 			}
 		}
 	}
-	
+
 	private void findTypesFromStaticImports(char[] token, Scope scope, boolean proposeAllMemberTypes, ObjectVector typesFound) {
 		ImportBinding[] importBindings = scope.compilationUnitScope().imports;
 		if (importBindings == null) return;
@@ -12069,7 +12097,7 @@
 						findPackagesInCurrentModule();
 					}
 					return;
-					
+
 				} catch (JavaModelException e) {
 					//
 				}
@@ -12156,9 +12184,9 @@
 			IType[] subclasses = newTypeHierarchy.getSubclasses(iClass);
 			for (IType iType2 : subclasses) {
 				getAllTypesInHierarchy(newTypeHierarchy,iType2,allTypes);
-											
+
 			}
-		
+
 	}
 
 	private char[][] findVariableFromUnresolvedReference(LocalDeclaration variable, BlockScope scope, final char[][] discouragedNames) {
@@ -12415,7 +12443,7 @@
 					forbiddenNames,
 					type.dimensions(),
 					kind);
-				
+
 				if (tb.isParameterizedType() &&
 						tb.findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilCollection, false) != null) {
 					ParameterizedTypeBinding ptb = ((ParameterizedTypeBinding) tb);
@@ -12489,13 +12517,13 @@
 
 							if (local.isSecret())
 								continue next;
-							
+
 							// https://bugs.eclipse.org/bugs/show_bug.cgi?id=328674
 							if (local.declaration.initialization != null && !local.declaration.type.isTypeNameVar(null)) {
 								// proposal being asked inside field's initialization. Don't propose this field.
 								continue next;
 							}
-												
+
 							// don't propose non constant variables or strings (1.6 or below) in case expression
 							// https://bugs.eclipse.org/bugs/show_bug.cgi?id=195346
 							// https://bugs.eclipse.org/bugs/show_bug.cgi?id=343342
@@ -12505,12 +12533,12 @@
 										if (local.type == null || local.type.id != TypeIds.T_JavaLangString)
 											continue next;
 									} else if (!(local.type instanceof BaseTypeBinding))
-										continue next; 
+										continue next;
 								} else {
-									continue next; // non-constants not allowed in case.	
+									continue next; // non-constants not allowed in case.
 								}
 							}
-							
+
 							int ptr = this.uninterestingBindingsPtr;
 							// Cases where the binding is uninteresting eg. for completion occurring inside a local var
 							// declaration, the local var binding is uninteresting and shouldn't be proposed.
@@ -12574,7 +12602,7 @@
 				currentScope = currentScope.parent;
 			}
 		}
-		
+
 		checkCancel();
 
 		boolean proposeField = !this.requestor.isIgnored(CompletionProposal.FIELD_REF);
@@ -12655,9 +12683,9 @@
 				}
 				currentScope = currentScope.parent;
 			}
-			
+
 			checkCancel();
-			
+
 			findFieldsAndMethodsFromStaticImports(
 					token,
 					scope,
@@ -12672,9 +12700,9 @@
 					proposeMethod);
 
 			if (this.assistNodeInJavadoc == 0) {
-				
+
 				checkCancel();
-				
+
 				// search in favorites import
 				findFieldsAndMethodsFromFavorites(
 						token,
@@ -12685,9 +12713,9 @@
 						fieldsFound,
 						methodsFound);
 			}
-			
+
 			checkCancel();
-			
+
 			findEnumConstantsFromExpectedTypes(
 					token,
 					invocationScope,
@@ -12820,7 +12848,7 @@
 
 		return this.favoriteReferenceBindings = resolvedImports;
 	}
-	
+
 	private INameEnvironment getNoCacheNameEnvironment() {
 		if (this.noCacheNameEnvironment == null) {
 			JavaModelManager.getJavaModelManager().cacheZipFiles(this);
@@ -12836,7 +12864,7 @@
 	}
 	protected boolean hasArrayTypeAsExpectedSuperTypes() {
 		if ((this.expectedTypesFilter & ~SUBTYPE) != 0) return false;
-		
+
 		if (!this.hasComputedExpectedArrayTypes) {
 			if(this.expectedTypes != null) {
 				done : for (int i = 0; i <= this.expectedTypesPtr; i++) {
@@ -12846,10 +12874,10 @@
 					}
 				}
 			}
-			
+
 			this.hasComputedExpectedArrayTypes = true;
 		}
-		
+
 		return this.hasExpectedArrayTypes;
 	}
 	protected boolean hasPossibleAnnotationTarget(TypeBinding typeBinding, Scope scope) {
@@ -12905,12 +12933,12 @@
 	private boolean isAllowingLongComputationProposals() {
 		return this.monitor != null;
 	}
-	
+
 	/**
 	 * Checks whether name matches the token according to the current
 	 * code completion settings (substring match, camel case match etc.)
 	 * and sets whether the current match is a suffix proposal.
-	 * 
+	 *
 	 * @param token the token that is tested
 	 * @param name the name to match
 	 * @return <code>true</code> if the token does not match,
@@ -12919,7 +12947,8 @@
 	private boolean isFailedMatch(char[] token, char[] name) {
 		if ((this.options.substringMatch && CharOperation.substringMatch(token, name))
 				|| (this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, name))
-				|| CharOperation.prefixEquals(token, name, false)) {
+				|| CharOperation.prefixEquals(token, name, false)
+				|| (this.options.subwordMatch && CharOperation.subWordMatch(token, name))) {
 			return false;
 		}
 
@@ -12952,11 +12981,11 @@
 				}
 			}
 		}
-		
+
 		if (!isValidPackageName(givenPkgName)) {
 			return true;
 		}
-		
+
 		return false;
 	}
 
@@ -13266,7 +13295,7 @@
 			buffer.append('\t');
 		}
 	}
-	
+
 	private void proposeConstructor(AcceptedConstructor deferredProposal, Scope scope) {
 		if (deferredProposal.proposeConstructor) {
 			proposeConstructor(
@@ -13286,7 +13315,7 @@
 					deferredProposal.extraFlags);
 		}
 	}
-	
+
 	private void proposeConstructor(
 			char[] simpleTypeName,
 			int parameterCount,
@@ -13311,12 +13340,14 @@
 			typeCompletion = simpleTypeName;
 		}
 
+		ReferenceBinding typeBinding = this.lookupEnvironment.getType(CharOperation.splitOn('.', fullyQualifiedName));
+
 		int relevance = computeBaseRelevance();
 		relevance += computeRelevanceForResolution();
 		relevance += computeRelevanceForInterestingProposal();
 		relevance += computeRelevanceForRestrictions(accessibility);
 		relevance += computeRelevanceForCaseMatching(this.completionToken, simpleTypeName);
-		relevance += computeRelevanceForExpectingType(packageName, simpleTypeName);
+		relevance += computeRelevanceForExpectingType(typeBinding);
 		relevance += computeRelevanceForQualification(isQualified);
 		relevance += computeRelevanceForConstructor();
 
@@ -13341,7 +13372,7 @@
 				relevance += computeRelevanceForException(simpleTypeName);
 				break;
 		}
-		
+
 		char[] completion;
 		if (this.source != null
 					&& this.source.length > this.endPosition
@@ -13350,7 +13381,7 @@
 		} else {
 			completion = new char[] { '(', ')' };
 		}
-		
+
 		InternalCompletionProposal typeProposal = createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
 		typeProposal.nameLookup = this.nameEnvironment.nameLookup;
 		typeProposal.completionEngine = this;
@@ -13363,14 +13394,14 @@
 		typeProposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
 		typeProposal.setTokenRange(this.startPosition - this.offset, this.endPosition - this.offset);
 		typeProposal.setRelevance(relevance);
-		
+
 		switch (parameterCount) {
 			case -1: // default constructor
 				int flags = Flags.AccPublic;
 				if (Flags.isDeprecated(typeModifiers)) {
 					flags |= Flags.AccDeprecated;
 				}
-				
+
 				if (isInterface || (typeModifiers & ClassFileConstants.AccAbstract) != 0) {
 					this.noProposal = false;
 					if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
@@ -13423,7 +13454,7 @@
 				}
 				break;
 			case 0: // constructor with no parameter
-				
+
 				if ((typeModifiers & ClassFileConstants.AccAbstract) != 0) {
 					this.noProposal = false;
 					if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
@@ -13483,12 +13514,12 @@
 				} else {
 					signature = CharOperation.replaceOnCopy(signature, '/', '.');
 				}
-				
+
 				int parameterNamesLength = parameterNames == null ? 0 : parameterNames.length;
 				if (parameterCount != parameterNamesLength) {
 					parameterNames = null;
 				}
-				
+
 				if ((typeModifiers & ClassFileConstants.AccAbstract) != 0) {
 					this.noProposal = false;
 					if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
@@ -13541,7 +13572,7 @@
 						proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
 						proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
 						proposal.setRelevance(relevance);
-						
+
 						this.requestor.accept(proposal);
 						if(DEBUG) {
 							this.printDebug(proposal);
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java
index 93f6e39..fb47fd6 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ISearchRequestor.java
@@ -93,6 +93,6 @@
 	 *    The default package is represented by an empty array.
 	 */
 	public void acceptPackage(char[] packageName);
-	
+
 	public void acceptModule(char[] moduleName);
 }
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionContext.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionContext.java
index 06882ab..def77c8 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionContext.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionContext.java
@@ -122,9 +122,9 @@
 	@Override
 	public IJavaElement getEnclosingElement() {
 		if (!this.isExtended) throw new UnsupportedOperationException("Operation only supported in extended context"); //$NON-NLS-1$
-	
+
 		if (this.extendedContext == null) return null;
-	
+
 		return this.extendedContext.getEnclosingElement();
 	}
 
@@ -172,9 +172,9 @@
 	@Override
 	public IJavaElement[] getVisibleElements(String typeSignature) {
 		if (!this.isExtended) throw new UnsupportedOperationException("Operation only supported in extended context"); //$NON-NLS-1$
-	
+
 		if (this.extendedContext == null) return new IJavaElement[0];
-	
+
 		return this.extendedContext.getVisibleElements(typeSignature);
 	}
 
@@ -197,7 +197,7 @@
 	public boolean isInJavadocText() {
 		return (this.javadoc & CompletionOnJavadoc.TEXT) != 0;
 	}
-	
+
 	/**
 	 * Return the completion node associated with the current completion.
 	 *
@@ -208,12 +208,12 @@
 	 */
 	public ASTNode getCompletionNode() {
 		if (!this.isExtended) throw new UnsupportedOperationException("Operation only supported in extended context"); //$NON-NLS-1$
-	
+
 		if (this.extendedContext == null) return null;
-	
+
 		return this.extendedContext.getCompletionNode();
 	}
-	
+
 	/**
 	 * Return the parent AST node of the completion node associated with the current completion.
 	 *
@@ -224,12 +224,12 @@
 	 */
 	public ASTNode getCompletionNodeParent() {
 		if (!this.isExtended) throw new UnsupportedOperationException("Operation only supported in extended context"); //$NON-NLS-1$
-	
+
 		if (this.extendedContext == null) return null;
-	
+
 		return this.extendedContext.getCompletionNodeParent();
 	}
-	
+
 	/**
 	 * Return the bindings of all visible local variables in the current completion context.
 	 *
@@ -241,12 +241,12 @@
 	 */
 	public ObjectVector getVisibleLocalVariables() {
 		if (!this.isExtended) throw new UnsupportedOperationException("Operation only supported in extended context"); //$NON-NLS-1$
-	
+
 		if (this.extendedContext == null) return null;
-	
+
 		return this.extendedContext.getVisibleLocalVariables();
 	}
-	
+
 	/**
 	 * Return the bindings of all visible fields in the current completion context.
 	 *
@@ -258,12 +258,12 @@
 	 */
 	public ObjectVector getVisibleFields() {
 		if (!this.isExtended) throw new UnsupportedOperationException("Operation only supported in extended context"); //$NON-NLS-1$
-	
+
 		if (this.extendedContext == null) return null;
-	
+
 		return this.extendedContext.getVisibleFields();
 	}
-	
+
 	/**
 	 * Return the bindings of all visible methods in the current completion context.
 	 *
@@ -275,9 +275,9 @@
 	 */
 	public ObjectVector getVisibleMethods() {
 		if (!this.isExtended) throw new UnsupportedOperationException("Operation only supported in extended context"); //$NON-NLS-1$
-	
+
 		if (this.extendedContext == null) return null;
-	
+
 		return this.extendedContext.getVisibleMethods();
 	}
 }
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java
index 11738ea..1ba27d2 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalCompletionProposal.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Andreas Magnusson <andreas.ch.magnusson@gmail.com>- contribution for bug 151500
@@ -45,7 +45,7 @@
  */
 public class InternalCompletionProposal extends CompletionProposal {
 	private static Object NO_ATTACHED_SOURCE = new Object();
-	
+
 	protected CompletionEngine completionEngine;
 	protected NameLookup nameLookup;
 
@@ -191,7 +191,7 @@
 	 * Indicates whether parameter names have been computed.
 	 */
 	private boolean parameterNamesComputed = false;
-	
+
 	protected char[][] findConstructorParameterNames(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] paramTypeNames){
 		if(paramTypeNames == null || declaringTypeName == null) return null;
 
@@ -281,7 +281,7 @@
 
 		return parameters;
 	}
-	
+
 	protected char[][] findMethodParameterNames(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector, char[][] paramTypeNames){
 		if(paramTypeNames == null || declaringTypeName == null) return null;
 
@@ -343,7 +343,7 @@
 		int startingIndex = 0;
 		String[] args;
 		IType enclosingType = type.getDeclaringType();
-		// If the method is a constructor of a non-static inner type, add the enclosing type as an 
+		// If the method is a constructor of a non-static inner type, add the enclosing type as an
 		// additional parameter to the constructor
 		if (enclosingType != null
 				&& CharOperation.equals(type.getElementName().toCharArray(), selector)
@@ -359,7 +359,7 @@
 			args[i] = new String(paramTypeNames[i-startingIndex]);
 		}
 		method = type.getMethod(new String(selector), args);
-		
+
 		IMethod[] methods = type.findMethods(method);
 		if (methods != null && methods.length > 0) {
 			method = methods[0];
@@ -374,7 +374,7 @@
 	protected char[] getDeclarationTypeName() {
 		return this.declarationTypeName;
 	}
-	
+
 	private int getOpenedBinaryTypesThreshold() {
 		return JavaModelManager.getJavaModelManager().getOpenableCacheSize() / 10;
 	}
@@ -883,7 +883,7 @@
 	public void setFlags(int flags) {
 		this.flags = flags;
 	}
-	
+
 	public void setHasNoParameterNamesFromIndex(boolean hasNoParameterNamesFromIndex) {
 		this.hasNoParameterNamesFromIndex = hasNoParameterNamesFromIndex;
 	}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java
index fce8987..7b87657 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/InternalExtendedCompletionContext.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -178,15 +178,15 @@
 		this.lookupEnvironment.unitBeingCompleted = this.compilationUnitDeclaration;
 		try {
 			this.hasComputedVisibleElementBindings = true;
-	
+
 			Scope scope = this.assistScope;
 			ASTNode astNode = this.assistNode;
 			boolean notInJavadoc = this.completionContext.javadoc == 0;
-	
+
 			this.visibleLocalVariables = new ObjectVector();
 			this.visibleFields = new ObjectVector();
 			this.visibleMethods = new ObjectVector();
-	
+
 			ReferenceContext referenceContext = scope.referenceContext();
 			if (referenceContext instanceof AbstractMethodDeclaration || referenceContext instanceof LambdaExpression) {
 				// completion is inside a method body
@@ -205,7 +205,7 @@
 								break done;
 							}
 						} else {
-							FieldDeclaration fieldDeclaration = fields[i];							
+							FieldDeclaration fieldDeclaration = fields[i];
 							if (fieldDeclaration.initialization != null && fieldDeclaration.binding != null) {
 								boolean isInsideInitializer = false;
 								if (fieldDeclaration.initialization.sourceEnd > 0) {
@@ -770,7 +770,7 @@
 						// If the local variable declaration's initialization statement itself has the completion,
 						// then don't propose the local variable
 						if (local.declaration.initialization != null) {
-							/*(use this if-else block if it is found that local.declaration.initialization != null is not sufficient to 
+							/*(use this if-else block if it is found that local.declaration.initialization != null is not sufficient to
 							  guarantee that proposal is being asked inside a local variable declaration's initializer)
 							 if(local.declaration.initialization.sourceEnd > 0) {
 								if (this.assistNode.sourceEnd <= local.declaration.initialization.sourceEnd
@@ -913,7 +913,7 @@
 		char[][] expectedTypekeys= this.completionContext.getExpectedTypesKeys();
 		if (expectedTypekeys == null || expectedTypekeys.length == 0)
 			return true;
-		// Next, find out whether any of the constructor parameters are the same as one of the 
+		// Next, find out whether any of the constructor parameters are the same as one of the
 		// class type variables. If yes, diamond cannot be used.
 		TypeReference ref;
 		if (cn.length == 1) {
@@ -944,14 +944,14 @@
 		}
 		return false;
 	}
-	
+
 	/**
 	 * @see InternalCompletionContext#getCompletionNode()
 	 */
 	public ASTNode getCompletionNode() {
 		return this.assistNode;
 	}
-	
+
 	/**
 	 * @see InternalCompletionContext#getCompletionNodeParent()
 	 */
@@ -959,21 +959,21 @@
 		// TODO Auto-generated method stub
 		return this.assistNodeParent;
 	}
-	
+
 	public ObjectVector getVisibleLocalVariables() {
 		if (!this.hasComputedVisibleElementBindings) {
 			computeVisibleElementBindings();
 		}
 		return this.visibleLocalVariables;
 	}
-	
+
 	public ObjectVector getVisibleFields() {
 		if (!this.hasComputedVisibleElementBindings) {
 			computeVisibleElementBindings();
 		}
 		return this.visibleFields;
 	}
-	
+
 	public ObjectVector getVisibleMethods() {
 		if (!this.hasComputedVisibleElementBindings) {
 			computeVisibleElementBindings();
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/RelevanceConstants.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/RelevanceConstants.java
index c968294..6e43a84 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/RelevanceConstants.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/RelevanceConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -15,14 +15,14 @@
 
 public interface RelevanceConstants {
 
-	
+
 	/*
 	 * Important: The following rules must be strictly adhered to while declaring new relevance constants or modifying the existing:
 	 * 1. One or more relevance constants are used in combination to form a relevance.
 	 * 2. A particular relevance constant can be added only once to form a relevance.
 	 * 3. A resultant relevance (after combining all the applicable relevance constants) must be a positive number.
 	 * 4. The value of R_DEFAULT is maintained at a positive value such that the sum of all the negative relevance constants
-	 *    and R_DEFAULT must not be negative. 
+	 *    and R_DEFAULT must not be negative.
 	 */
 	int R_DEFAULT = 30;
 	int R_INTERESTING = 5;
@@ -48,6 +48,7 @@
 	int R_NAME_SUFFIX = 3;
 	int R_NAME_LESS_NEW_CHARACTERS = 15;
 	int R_SUBSTRING = -21;
+	int R_SUBWORD = -22;
 	int R_METHOD_OVERIDE = 3;
 	int R_NON_RESTRICTED = 3;
 	int R_TRUE_OR_FALSE = 1;
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java
index b93c595..ebf4a49 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/SelectionEngine.java
@@ -10,7 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     Jesper Steen Møller <jesper@selskabet.org> - contributions for:	
+ *     Jesper Steen Møller <jesper@selskabet.org> - contributions for:
  *         Bug 531046: [10] ICodeAssist#codeSelect support for 'var'
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist;
@@ -48,6 +48,7 @@
 import org.eclipse.jdt.internal.codeassist.select.SelectionNodeFound;
 import org.eclipse.jdt.internal.codeassist.select.SelectionOnPackageVisibilityReference;
 import org.eclipse.jdt.internal.codeassist.select.SelectionOnImportReference;
+import org.eclipse.jdt.internal.codeassist.select.SelectionOnLocalName;
 import org.eclipse.jdt.internal.codeassist.select.SelectionOnPackageReference;
 import org.eclipse.jdt.internal.codeassist.select.SelectionOnQualifiedTypeReference;
 import org.eclipse.jdt.internal.codeassist.select.SelectionOnSingleTypeReference;
@@ -137,16 +138,16 @@
  */
 @SuppressWarnings({"rawtypes", "unchecked"})
 public final class SelectionEngine extends Engine implements ISearchRequestor {
-	
+
 	private static class SelectionTypeNameMatchRequestorWrapper extends TypeNameMatchRequestorWrapper {
-		
+
 		class AcceptedType {
 			public int modifiers;
 			public char[] packageName;
 			public char[] simpleTypeName;
 			public String path;
 			public AccessRestriction access;
-			
+
 			public AcceptedType(int modifiers, char[] packageName, char[] simpleTypeName, String path, AccessRestriction access) {
 				this.modifiers = modifiers;
 				this.packageName = packageName;
@@ -155,63 +156,63 @@
 				this.access = access;
 			}
 		}
-		
+
 		private ImportReference[] importReferences;
-		
+
 		private boolean importCachesNodeInitialized = false;
 		private ImportReference[] onDemandImportsNodeCache;
 		private int onDemandImportsNodeCacheCount;
 		private char[][][] importsNodeCache;
 		private int importsNodeCacheCount;
-		
+
 		private HashtableOfObject onDemandFound = new HashtableOfObject();
 		private ObjectVector notImportedFound = new ObjectVector();
-		
+
 		public SelectionTypeNameMatchRequestorWrapper(TypeNameMatchRequestor requestor, IJavaSearchScope scope, ImportReference[] importReferences) {
 			super(requestor, scope);
 			this.importReferences = importReferences;
 		}
-		
+
 		@Override
 		public void acceptType(int modifiers, char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String path, AccessRestriction access) {
 			if (enclosingTypeNames != null && enclosingTypeNames.length > 0) return;
-			
+
 			if (!this.importCachesNodeInitialized) initializeImportNodeCaches();
-			
+
 			char[] fullyQualifiedTypeName = CharOperation.concat(packageName, simpleTypeName, '.');
-			
+
 			for (int i = 0; i < this.importsNodeCacheCount; i++) {
 				char[][] importName = this.importsNodeCache[i];
 				if (CharOperation.equals(importName[0], simpleTypeName)) {
-					
+
 					if(CharOperation.equals(importName[1], fullyQualifiedTypeName)) {
 						super.acceptType(modifiers, packageName, simpleTypeName, enclosingTypeNames, path, access);
 					}
 					return;
 				}
 			}
-			
+
 			for (int i = 0; i < this.onDemandImportsNodeCacheCount; i++) {
 				char[][] importName = this.onDemandImportsNodeCache[i].tokens;
 				char[] importFlatName = CharOperation.concatWith(importName, '.');
-				
+
 				if (CharOperation.equals(importFlatName, packageName)) {
-					
+
 					this.onDemandFound.put(simpleTypeName, simpleTypeName);
 					super.acceptType(modifiers, packageName, simpleTypeName, enclosingTypeNames, path, access);
 					return;
 				}
 			}
-			
-			
+
+
 			this.notImportedFound.add(new AcceptedType(modifiers, packageName, simpleTypeName, path, access));
 		}
-		
+
 		public void acceptNotImported() {
 			int size = this.notImportedFound.size();
 			for (int i = 0; i < size; i++) {
 				AcceptedType acceptedType = (AcceptedType)this.notImportedFound.elementAt(i);
-				
+
 				if (this.onDemandFound.get(acceptedType.simpleTypeName) == null) {
 					super.acceptType(
 							acceptedType.modifiers,
@@ -223,10 +224,10 @@
 				}
 			}
 		}
-		
+
 		public void initializeImportNodeCaches() {
 			int length = this.importReferences == null ? 0 : this.importReferences.length;
-			
+
 			for (int i = 0; i < length; i++) {
 				ImportReference importReference = this.importReferences[i];
 				if((importReference.bits & ASTNode.OnDemand) != 0) {
@@ -239,15 +240,15 @@
 					if(this.importsNodeCache == null) {
 						this.importsNodeCache = new char[length - i][][];
 					}
-					
-					
+
+
 					this.importsNodeCache[this.importsNodeCacheCount++] = new char[][]{
 							importReference.tokens[importReference.tokens.length - 1],
 							CharOperation.concatWith(importReference.tokens, '.')
 						};
 				}
 			}
-			
+
 			this.importCachesNodeInitialized = true;
 		}
 	}
@@ -348,7 +349,7 @@
 		this.parser = new SelectionParser(problemReporter);
 		this.owner = owner;
 	}
-	
+
 	@Override
 	public void acceptConstructor(
 			int modifiers,
@@ -569,7 +570,7 @@
 				true /*taskCaseSensitive*/,
 				this.compilerOptions.enablePreviewFeatures);
 		scanner.setSource(source);
-		
+
 		int lastIdentifierStart = -1;
 		int lastIdentifierEnd = -1;
 		char[] lastIdentifier = null;
@@ -685,7 +686,7 @@
 			if (selectionStart == selectionEnd) { // Widen the selection to scan -> || :: if needed. No unicode handling for now.
 				if (selectionStart > 0 && selectionEnd < source.length - 1) {
 					if ((source[selectionStart] == '>' && source[selectionStart - 1] == '-') ||
-							source[selectionStart] == ':' && source[selectionStart - 1] == ':') { 
+							source[selectionStart] == ':' && source[selectionStart - 1] == ':') {
 						selectionStart--;
 					} else {
 						if ((source[selectionStart] == '-' && source[selectionEnd + 1] == '>') ||
@@ -693,7 +694,7 @@
 							selectionEnd++;
 						}
 					}
-				}  
+				}
 			} // there could be some innocuous widening, shouldn't matter.
 			scanner.resetTo(selectionStart, selectionEnd, isModuleInfo);
 
@@ -720,12 +721,12 @@
 						}
 						expectingIdentifier = false;
 						break;
-					case TerminalTokens.TokenNameCOLON_COLON:	
+					case TerminalTokens.TokenNameCOLON_COLON:
 						if (selectionStart >= scanner.startPosition && selectionEnd < scanner.currentPosition) {
 							this.actualSelectionStart = selectionStart;
 							this.actualSelectionEnd = selectionEnd;
 							this.selectedIdentifier = CharOperation.NO_CHAR;
-							return true;		
+							return true;
 						}
 						//$FALL-THROUGH$
 					case TerminalTokens.TokenNameDOT :
@@ -750,7 +751,7 @@
 							this.actualSelectionStart = selectionStart;
 							this.actualSelectionEnd = selectionEnd;
 							this.selectedIdentifier = CharOperation.NO_CHAR;
-							return true;		
+							return true;
 						}
 						return false;
 					default :
@@ -836,7 +837,7 @@
 
 		return false;
 	}
-	
+
 	/*
 	 * find all types outside the project scope
 	 */
@@ -877,7 +878,7 @@
 					// implements interface method
 				}
 			};
-			
+
 			TypeNameMatchRequestor typeNameMatchRequestor = new TypeNameMatchRequestor() {
 				@Override
 				public void acceptTypeNameMatch(TypeNameMatch match) {
@@ -887,17 +888,17 @@
 					}
 				}
 			};
-			
+
 			IJavaSearchScope scope = BasicSearchEngine.createWorkspaceScope();
-			
+
 			SelectionTypeNameMatchRequestorWrapper requestorWrapper =
 				new SelectionTypeNameMatchRequestorWrapper(
-						typeNameMatchRequestor, 
+						typeNameMatchRequestor,
 						scope,
 						this.unitScope == null ? null : this.unitScope.referenceContext.imports);
-			
+
 			org.eclipse.jdt.core.ICompilationUnit[] workingCopies = this.owner == null ? null : JavaModelManager.getJavaModelManager().getWorkingCopies(this.owner, true/*add primary WCs*/);
-			
+
 			try {
 				new BasicSearchEngine(workingCopies).searchAllTypeNames(
 					null,
@@ -1097,7 +1098,7 @@
 				// accept qualified types only if no unqualified type was accepted
 				if(!this.acceptedAnswer) {
 					acceptQualifiedTypes();
-					
+
 					// accept types from all the workspace only if no type was found in the project scope
 					if (this.noProposal) {
 						findAllTypes(this.selectedIdentifier);
@@ -1435,6 +1436,9 @@
 			@Override
 			public boolean visit(
 		    		LocalDeclaration localDeclaration, BlockScope scope) {
+				if(localDeclaration instanceof SelectionOnLocalName) {
+					localDeclaration.resolve(scope);
+				}
 				if (localDeclaration.type instanceof SingleTypeReference && ((SingleTypeReference)localDeclaration.type).token == assistIdentifier) {
 					if(localDeclaration.binding != null) {
 						throw new SelectionNodeFound(localDeclaration.binding.type);
@@ -1564,7 +1568,7 @@
 					}
 					// find the type declaration that corresponds to the original source type
 					while (context.isLambda() && context.getParent() != null) {
-						// It is easier to find the first enclosing proper type than the corresponding 
+						// It is easier to find the first enclosing proper type than the corresponding
 						// lambda expression ast to add the selection node to.
 						context = (IType) context.getParent().getAncestor(IJavaElement.TYPE);
 					}
@@ -1596,7 +1600,7 @@
 					CompilationResult result = new CompilationResult(reader.getFileName(), 1, 1, this.compilerOptions.maxProblemsPerUnit);
 					parsedUnit = new CompilationUnitDeclaration(this.parser.problemReporter(), result, 0);
 					HashSetOfCharArrayArray typeNames = new HashSetOfCharArrayArray();
-					
+
 					BinaryTypeConverter converter = new BinaryTypeConverter(this.parser.problemReporter(), result, typeNames);
 					typeDeclaration = converter.buildTypeDeclaration(context, parsedUnit);
 					parsedUnit.imports = converter.buildImports(reader);
@@ -1822,7 +1826,7 @@
 
 		return false;
 	}
-	
+
 	/*
 	 * Returns the correct method binding according to whether the selection is on the method declaration
 	 * or on the inheritDoc tag in its javadoc.
@@ -1842,7 +1846,7 @@
 		}
 		return binding;
 	}
-	
+
 	protected MethodBinding findOverriddenMethodInType(ReferenceBinding overriddenType, MethodBinding overriding) throws JavaModelException {
 		if (overriddenType == null)
 			return null;
@@ -1857,7 +1861,7 @@
 		}
 		return null;
 	}
-	
+
 	private Object findMethodWithAttachedDocInHierarchy(final MethodBinding method) throws JavaModelException {
 		ReferenceBinding type= method.declaringClass;
 		final SelectionRequestor requestor1 = (SelectionRequestor) this.requestor;
@@ -1875,7 +1879,7 @@
 				IMember member = (IMember) requestor1.findMethodFromBinding(overridden, names, overridden.declaringClass);
 				if (member == null)
 					return InheritDocVisitor.CONTINUE;
-				if (member.getAttachedJavadoc(null) != null ) {  
+				if (member.getAttachedJavadoc(null) != null ) {
 					// for binary methods with attached javadoc and no source attached
 					return overridden;
 				}
@@ -1899,7 +1903,7 @@
 			}
 		}.visitInheritDoc(type);
 	}
-	
+
 	/**
 	 * Implements the "Algorithm for Inheriting Method Comments" as specified for
 	 * <a href="http://download.oracle.com/javase/6/docs/technotes/tools/windows/javadoc.html#inheritingcomments">1.6</a>.
@@ -1979,7 +1983,7 @@
 
 		/**
 		 * Visits the super interfaces of the given type in the given hierarchy, thereby skipping already visited types.
-		 * 
+		 *
 		 * @param visited set of visited types
 		 * @param currentType type whose super interfaces should be visited
 		 * @return the result, or {@link #CONTINUE} if no result has been found
@@ -2015,6 +2019,6 @@
 	@Override
 	public void acceptModule(char[] moduleName) {
 		// TODO Auto-generated method stub
-		
+
 	}
 }
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ThrownExceptionFinder.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ThrownExceptionFinder.java
index 5847fba..6ccf8bc 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ThrownExceptionFinder.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/ThrownExceptionFinder.java
@@ -44,7 +44,7 @@
 	 * Finds the thrown exceptions minus the ones that are already caught in previous catch blocks.
 	 * Exception is already caught even if its super type is being caught. Also computes, separately,
 	 * a list comprising of (a)those exceptions that have been caught already and (b)those exceptions that are thrown
-	 * by the method and whose super type has been caught already. 
+	 * by the method and whose super type has been caught already.
 	 * @param tryStatement
 	 * @param scope
 	 */
@@ -107,10 +107,10 @@
 		this.caughtExceptions.asArray(allCaughtExceptions);
 		return allCaughtExceptions;
 	}
-	
+
 	/**
 	 * Returns all the thrown exceptions minus the ones that are already caught in previous catch blocks
-	 * (of the same try), found by the call to 
+	 * (of the same try), found by the call to
 	 * {@link ThrownExceptionFinder#processThrownExceptions(TryStatement, BlockScope)}.
 	 * @return Returns an array of thrown exceptions that are still not caught in any catch block.
 	 */
@@ -119,9 +119,9 @@
 		this.thrownExceptions.asArray(result);
 		return result;
 	}
-	
+
 	/**
-	 * Returns all exceptions that are discouraged to use because (a) they are already caught in some inner try-catch, 
+	 * Returns all exceptions that are discouraged to use because (a) they are already caught in some inner try-catch,
 	 * or (b) their super exception has already been caught.
 	 * @return all discouraged exceptions
 	 */
@@ -174,7 +174,7 @@
 		}
 		return false;
 	}
-	
+
 	private void removeCaughtExceptions(TryStatement tryStatement, boolean recordUncheckedCaughtExceptions) {
 		Argument[] catchArguments = tryStatement.catchArguments;
 		int length = catchArguments == null ? 0 : catchArguments.length;
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java
index 7b839bf..a8f214a 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionNodeDetector.java
@@ -171,7 +171,7 @@
 	}
 	@Override
 	public void endVisit(ReferenceExpression referenceExpression, BlockScope blockScope) {
-		endVisit(referenceExpression);	
+		endVisit(referenceExpression);
 	}
 	@Override
 	public void endVisit(SingleNameReference singleNameReference, BlockScope scope) {
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExportReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExportReference.java
index eb3e281..584a251 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExportReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnExportReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 
 package org.eclipse.jdt.internal.codeassist.complete;
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnJavadocTag.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnJavadocTag.java
index b620240..7b1f581 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnJavadocTag.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnJavadocTag.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -16,6 +16,7 @@
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.JavadocSingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.RecordDeclaration;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
 import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
@@ -86,7 +87,7 @@
 		switch (kind) {
 			case Scope.COMPILATION_UNIT_SCOPE:
 				// bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=255752
-				// Check for FAKE_TYPE_NAME to allow proposals (@see CompletionParser#consumeCompilationUnit)		
+				// Check for FAKE_TYPE_NAME to allow proposals (@see CompletionParser#consumeCompilationUnit)
 				CompilationUnitDeclaration compilationUnit = scope.referenceCompilationUnit();
 				if(compilationUnit != null && compilationUnit.isModuleInfo() ) {
 					specifiedTags = MODULE_TAGS;
@@ -131,7 +132,12 @@
 							switch (scope.kind) {
 								case Scope.CLASS_SCOPE:
 									if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
-										if (((ClassScope)scope).referenceContext.binding.isGenericType()) {
+										boolean isRecordWithComponent = false;
+										if( ((ClassScope)scope).referenceContext instanceof RecordDeclaration) {
+											RecordDeclaration rd = (RecordDeclaration)((ClassScope)scope).referenceContext;
+											isRecordWithComponent = rd.nRecordComponents >0 ;
+										}
+										if (((ClassScope)scope).referenceContext.binding.isGenericType() || isRecordWithComponent) {
 											filteredTags[size++] = possibleTag;
 										}
 									}
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeywordModuleDeclaration.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeywordModuleDeclaration.java
index 9c867b6..95720be 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeywordModuleDeclaration.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeywordModuleDeclaration.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist.complete;
 
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeywordModuleInfo.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeywordModuleInfo.java
index ddb343a..340bce6 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeywordModuleInfo.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnKeywordModuleInfo.java
@@ -18,7 +18,7 @@
 import org.eclipse.jdt.internal.compiler.ast.ImportReference;
 
 /**
- * 
+ *
  * This class is independent of its parent class and is in fact a dummy ExportsStatement. Used to hook
  * into the existing module declaration type and is used as a placeholder for keyword completion. This can
  * be any module keyword completion and not necessarily related to exports statement.
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSendName.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSendName.java
index 2c048f1..e70ec61 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSendName.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMessageSendName.java
@@ -31,7 +31,7 @@
 	public TypeBinding resolveType(BlockScope scope) {
 
 		this.constant = Constant.NotAConstant;
-		
+
 		if (this.receiver.isImplicitThis())
 			throw new CompletionNodeFound();
 
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnModuleDeclaration.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnModuleDeclaration.java
index 548ede6..b17708e 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnModuleDeclaration.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnModuleDeclaration.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist.complete;
 
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnModuleReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnModuleReference.java
index e45032c..3d88012 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnModuleReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnModuleReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist.complete;
 
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesImplementationsQualifiedTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesImplementationsQualifiedTypeReference.java
index 87b59d0..0900dab 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesImplementationsQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesImplementationsQualifiedTypeReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist.complete;
 
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesImplementationsSingleTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesImplementationsSingleTypeReference.java
index bdbe254..6b295cd 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesImplementationsSingleTypeReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesImplementationsSingleTypeReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist.complete;
 
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesInterfacesQualifiedTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesInterfacesQualifiedTypeReference.java
index 9007ee1..eb06589 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesInterfacesQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesInterfacesQualifiedTypeReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist.complete;
 
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesInterfacesSingleTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesInterfacesSingleTypeReference.java
index b89e8e8..d30284e 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesInterfacesSingleTypeReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnProvidesInterfacesSingleTypeReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist.complete;
 
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java
index a6ca507..c69faaf 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedTypeReference.java
@@ -38,9 +38,9 @@
 
 	private int kind = K_TYPE;
 	public char[] completionIdentifier;
-	
+
 	public boolean isConstructorType;
-	
+
 public CompletionOnQualifiedTypeReference(char[][] previousIdentifiers, char[] completionIdentifier, long[] positions) {
 	this(previousIdentifiers, completionIdentifier, positions, K_TYPE);
 }
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnReferenceExpressionName.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnReferenceExpressionName.java
index 377c501..e02edf6 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnReferenceExpressionName.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnReferenceExpressionName.java
@@ -24,14 +24,14 @@
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
 
 public class CompletionOnReferenceExpressionName extends ReferenceExpression {
-	
+
 	public CompletionOnReferenceExpressionName(Scanner scanner) {
 		super(scanner);
 	}
 
 	@Override
 	public TypeBinding resolveType(BlockScope scope) {
-		
+
 		final CompilerOptions compilerOptions = scope.compilerOptions();
 		TypeBinding lhsType;
 		boolean typeArgumentsHaveErrors;
@@ -54,7 +54,7 @@
 			if (typeArgumentsHaveErrors || lhsType == null)
 				throw new CompletionNodeFound();
 		}
-    	
+
 		if (lhsType != null && lhsType.isValidBinding())
 			throw new CompletionNodeFound(this, lhsType, scope);
 		throw new CompletionNodeFound();
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnUsesQualifiedTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnUsesQualifiedTypeReference.java
index 17ab3d3..cbc002e 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnUsesQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnUsesQualifiedTypeReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/package org.eclipse.jdt.internal.codeassist.complete;
 
 public class CompletionOnUsesQualifiedTypeReference extends CompletionOnQualifiedTypeReference {
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnUsesSingleTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnUsesSingleTypeReference.java
index 1185405..9745b0c 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnUsesSingleTypeReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnUsesSingleTypeReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/package org.eclipse.jdt.internal.codeassist.complete;
 
 public class CompletionOnUsesSingleTypeReference extends CompletionOnSingleTypeReference {
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
index 9a0c3d3..0d632f0 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java
@@ -186,7 +186,7 @@
 	private IProgressMonitor monitor;
 	private int resumeOnSyntaxError = 0;
 	private boolean consumedEnhancedFor;
-	
+
 public CompletionParser(ProblemReporter problemReporter, boolean storeExtraSourceEnds) {
 	super(problemReporter);
 	this.reportSyntaxErrorIsRequired = false;
@@ -677,16 +677,16 @@
 		this.parserCursorLocation = parserCursorLocation;
 		this.scannerCursorLocation = scannerCursorLocation;
 		this.assistNodeParent = assistNodeParent;
-	}	
+	}
 }
 @Override
 public Object becomeSimpleParser() {
 	CompletionScanner completionScanner = (CompletionScanner)this.scanner;
 	SavedState parserState = new SavedState(this.cursorLocation, completionScanner.cursorLocation, this.assistNodeParent);
-	
+
 	this.cursorLocation = Integer.MAX_VALUE;
 	completionScanner.cursorLocation = Integer.MAX_VALUE;
-	
+
 	return parserState;
 }
 private void buildMoreAnnotationCompletionContext(MemberValuePair memberValuePair) {
@@ -1155,10 +1155,10 @@
 	IfStatement ifStatement = null;
 	int index = -1;
 	/*
-	 * What happens here? When we have an "instanceof" after the last 
-	 * K_CONTROL_STATEMENT_DELIMITER (which represents if or else-if), the former 
+	 * What happens here? When we have an "instanceof" after the last
+	 * K_CONTROL_STATEMENT_DELIMITER (which represents if or else-if), the former
 	 * is taken to be the current point. Otherwise, the standard rule applies: i.e.
-	 * pick the block if it comes after the K_CONTROL_STATEMENT_DELIMITER, otherwise pick the 
+	 * pick the block if it comes after the K_CONTROL_STATEMENT_DELIMITER, otherwise pick the
 	 * K_BLOCK_DELIMITER.
 	 */
 	int blockIndex = lastIndexOfElement(K_BLOCK_DELIMITER);
@@ -1175,7 +1175,7 @@
 		// Try to find an enclosing if statement even if one is not found immediately preceding the completion node.
 		if (index != -1 && this.elementInfoStack[index] == IF && this.elementObjectInfoStack[index] != null) {
 			Expression condition = (Expression)this.elementObjectInfoStack[index];
-	
+
 			// If currentElement is a RecoveredLocalVariable then it can be contained in the if statement
 			if (this.currentElement instanceof RecoveredLocalVariable &&
 					this.currentElement.parent instanceof RecoveredBlock) {
@@ -1184,15 +1184,15 @@
 						statement instanceof Expression && ((Expression) statement).isTrulyExpression() &&
 						condition.sourceStart < recoveredLocalVariable.localDeclaration.sourceStart) {
 					this.currentElement.add(statement, 0);
-	
+
 					statement = recoveredLocalVariable.updatedStatement(0, new HashSet<TypeDeclaration>());
-	
+
 					// RecoveredLocalVariable must be removed from its parent because the IfStatement will be added instead
 					RecoveredBlock recoveredBlock =  (RecoveredBlock) recoveredLocalVariable.parent;
 					recoveredBlock.statements[--recoveredBlock.statementCount] = null;
-	
+
 					this.currentElement = recoveredBlock;
-	
+
 				}
 			}
 			if (statement instanceof AND_AND_Expression && this.assistNode instanceof Statement) {
@@ -1257,12 +1257,12 @@
 						}
 						if(this.currentElement instanceof RecoveredType) {
 							this.currentElement = this.currentElement.add(new CompletionOnFieldType(ref, false), 0);
-						} else {							
-							
+						} else {
+
 							if (prevKind == K_BETWEEN_NEW_AND_LEFT_BRACKET) {
-								
+
 								AllocationExpression exp;
-								if (this.expressionPtr > -1 && this.expressionStack[this.expressionPtr] instanceof AllocationExpression 
+								if (this.expressionPtr > -1 && this.expressionStack[this.expressionPtr] instanceof AllocationExpression
 										&& this.invocationType == QUALIFIED_ALLOCATION) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=361963
 									exp = new QualifiedAllocationExpression();
 									exp.type = ref;
@@ -1559,12 +1559,12 @@
 					&& (this.lastModifiers & ClassFileConstants.AccFinal) == 0) {
 					keywords[count++] = Keywords.FINAL;
 				}
-	
+
 				keywords[count++] = Keywords.CLASS;
 				if (this.options.complianceLevel >= ClassFileConstants.JDK1_5) {
 					keywords[count++] = Keywords.ENUM;
 				}
-	
+
 				if((this.lastModifiers & ClassFileConstants.AccFinal) == 0) {
 					keywords[count++] = Keywords.INTERFACE;
 				}
@@ -1609,7 +1609,7 @@
 
 	int index = -1;
 	if ((index = this.indexOfAssistIdentifier()) <= -1) return false;
-	
+
 	if (this.currentElement instanceof RecoveredModule) {
 		RecoveredModule module = (RecoveredModule) this.currentElement;
 		if (checkModuleInfoKeyword(module, index)) return true;
@@ -1620,13 +1620,13 @@
 			if (foundToken(K_AFTER_NAME_IN_PROVIDES_STATEMENT)) keyword = ModuleKeyword.PROVIDES_WITH;
 		}
 		if (keyword == ModuleKeyword.NOT_A_KEYWORD) return false;
-		
+
 		int length = this.identifierLengthStack[this.identifierLengthPtr];
 		int ptr = this.identifierPtr - length + index + 1;
-		
+
 		char[] ident = this.identifierStack[ptr];
-		long pos = this.identifierPositionStack[ptr];		
-		char[][] keywords = getModuleKeywords(keyword);		
+		long pos = this.identifierPositionStack[ptr];
+		char[][] keywords = getModuleKeywords(keyword);
 		if (this.currentElement instanceof RecoveredPackageVisibilityStatement) {
 			RecoveredPackageVisibilityStatement rPvs = (RecoveredPackageVisibilityStatement) this.currentElement;
 			rPvs.add(new CompletionOnKeywordModule2(ident, pos, keywords), 0);
@@ -1636,7 +1636,7 @@
 			rPs.add(new CompletionOnKeyword1(ident, pos, keywords), 0);
 			return true;
 		}
-	} 
+	}
 	return false;
 }
 private boolean checkModuleInfoKeyword(RecoveredModule module, int index) {
@@ -2116,7 +2116,7 @@
 	}
 	return false;
 }
-private void classHeaderExtendsOrImplements(boolean isInterface) {
+private void classHeaderExtendsOrImplements(boolean isInterface, boolean isRecord) {
 	if (this.currentElement != null
 			&& this.currentToken == TokenNameIdentifier
 			&& this.cursorLocation+1 >= this.scanner.startPosition
@@ -2136,8 +2136,10 @@
 
 
 					if(type.superInterfaces == null) {
-						if(type.superclass == null) {
-							keywords[count++] = Keywords.EXTENDS;
+						if(!isRecord) {
+							if(type.superclass == null) {
+								keywords[count++] = Keywords.EXTENDS;
+							}
 						}
 						keywords[count++] = Keywords.IMPLEMENTS;
 					}
@@ -2431,7 +2433,18 @@
 		this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
 		this.pendingAnnotation = null;
 	}
-	classHeaderExtendsOrImplements(false);
+	classHeaderExtendsOrImplements(false,false);
+}
+
+@Override
+protected void consumeRecordHeaderPart() {
+	super.consumeRecordHeaderPart();
+	this.hasUnusedModifiers = false;
+	if (this.pendingAnnotation != null) {
+		this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
+		this.pendingAnnotation = null;
+	}
+	classHeaderExtendsOrImplements(false,true);
 }
 
 @Override
@@ -2484,7 +2497,7 @@
 			for (int i = 0; i < length; i++) {
 				if (superInterfaces[i] == this.assistNode) {
 					this.assistNodeParent = typeDecl;
-				}	
+				}
 			}
 		}
 	}
@@ -2614,9 +2627,9 @@
 @Override
 protected void consumeEmptyStatement() {
 	super.consumeEmptyStatement();
-	/* Sneak in the assist node. The reason we can't do that when we see the assist node is that 
+	/* Sneak in the assist node. The reason we can't do that when we see the assist node is that
 	   we don't know whether it is the first or subsequent statement in a block to be able to
-	   decide whether to call contactNodeLists. See Parser.consumeBlockStatement(s) 
+	   decide whether to call contactNodeLists. See Parser.consumeBlockStatement(s)
 	*/
 	if (this.shouldStackAssistNode && this.assistNode != null)
 		this.astStack[this.astPtr] = this.assistNodeParent instanceof MessageSend ? this.assistNodeParent : this.assistNode;
@@ -2882,10 +2895,10 @@
 }
 @Override
 protected void consumeFormalParameter(boolean isVarArgs) {
-	
+
 	this.invocationType = NO_RECEIVER;
 	this.qualifier = -1;
-	
+
 	if (this.indexOfAssistIdentifier() < 0) {
 		super.consumeFormalParameter(isVarArgs);
 		if (this.pendingAnnotation != null) {
@@ -2915,14 +2928,14 @@
 					varArgsAnnotations = new Annotation[length],
 					0,
 					length);
-			} 
+			}
 		}
 		int firstDimensions = this.intStack[this.intPtr--];
 		TypeReference type = getTypeReference(firstDimensions);
-		
+
 		if (isVarArgs || extendedDimensions != 0) {
 			if (isVarArgs) {
-				type = augmentTypeWithAdditionalDimensions(type, 1, varArgsAnnotations != null ? new Annotation[][] { varArgsAnnotations } : null, true);	
+				type = augmentTypeWithAdditionalDimensions(type, 1, varArgsAnnotations != null ? new Annotation[][] { varArgsAnnotations } : null, true);
 			}
 			if (extendedDimensions != 0) { // combination illegal.
 				type = augmentTypeWithAdditionalDimensions(type, extendedDimensions, annotationsOnExtendedDimensions, false);
@@ -2972,7 +2985,7 @@
 	super.consumeGenericTypeWithDiamond();
 	// we need to pop the <> of the diamond from the stack.
 	// This is not required in usual case when the type argument isn't elided
-	// since the < and > get popped while parsing the type argument. 
+	// since the < and > get popped while parsing the type argument.
 	popElement(K_BINARY_OPERATOR); // pop >
 	popElement(K_BINARY_OPERATOR); // pop <
 }
@@ -3009,7 +3022,7 @@
 		this.genericsPtr -= additionalBoundsLength;
 		System.arraycopy(this.genericsStack, this.genericsPtr + 1, bounds, 1, additionalBoundsLength);
 	}
-	
+
 	int end = this.intStack[this.intPtr--];
 	boolean isParameterized =(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_PARAMETERIZED_CAST);
 	if(isParameterized) {
@@ -3027,7 +3040,7 @@
 	Expression castType = getTypeReference(this.intStack[this.intPtr--]);
 	if (additionalBoundsLength > 0) {
 		bounds[0] = (TypeReference) castType;
-		castType = createIntersectionCastTypeReference(bounds); 
+		castType = createIntersectionCastTypeReference(bounds);
 	}
 	if(isParameterized) {
 		this.intPtr--;
@@ -3098,7 +3111,7 @@
 
 	int dim = this.intStack[this.intPtr--];
 	Annotation[][] annotationsOnDimensions = dim == 0 ? null : getAnnotationsOnDimensions(dim);
-	
+
 	TypeReference[] bounds = null;
 	int additionalBoundsLength = this.genericsLengthStack[this.genericsLengthPtr--];
 	if (additionalBoundsLength > 0) {
@@ -3106,14 +3119,14 @@
 		this.genericsPtr -= additionalBoundsLength;
 		System.arraycopy(this.genericsStack, this.genericsPtr + 1, bounds, 1, additionalBoundsLength);
 	}
-	
+
 	TypeReference rightSide = getTypeReference(0);
 
 	castType = computeQualifiedGenericsFromRightSide(rightSide, dim, annotationsOnDimensions);
 	if (additionalBoundsLength > 0) {
 		bounds[0] = (TypeReference) castType;
-		castType = createIntersectionCastTypeReference(bounds); 
-	} 
+		castType = createIntersectionCastTypeReference(bounds);
+	}
 	this.intPtr--;
 	castType.sourceEnd = end - 1;
 	castType.sourceStart = this.intStack[this.intPtr--] + 1;
@@ -3153,7 +3166,7 @@
 		this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
 		this.pendingAnnotation = null;
 	}
-	classHeaderExtendsOrImplements(true);
+	classHeaderExtendsOrImplements(true, false);
 }
 @Override
 protected void consumeInterfaceHeaderExtends() {
@@ -3828,7 +3841,7 @@
 	int prevIdentifierPtr = this.previousIdentifierPtr;
 
 	isInsideEnhancedForLoopWithoutBlock(token);
-	
+
 	if (isInsideMethod() || isInsideFieldInitialization() || isInsideAnnotation() || isInsideEnumConstantnitialization()) {
 		switch(token) {
 			case TokenNameLPAREN:
@@ -3939,7 +3952,7 @@
 					pushOnElementStack(K_YIELD_KEYWORD);
 					// Take the short cut here.
 					// Instead of injecting the TokenNameRestrictedIdentifierYield, totally ignore it
-					// and let completion take it course. We will not be constructing the 
+					// and let completion take it course. We will not be constructing the
 					// YieldStatement and thus not producing accurate completion, but completion doesn't have
 					// enough information anyway about the LHS anyway.
 					token = this.currentToken = this.getNextToken();
@@ -4422,7 +4435,7 @@
 		consumeOpenFakeBlock();
 	}
 	this.consumedEnhancedFor = false;
-	
+
 }
 @Override
 protected void consumeInvocationExpression() { // on error, a message send's error reductions will take the expression path rather than the statement path since that is a dead end.
@@ -4505,7 +4518,7 @@
 	super.consumeTypeHeaderNameWithTypeParameters();
 
 	TypeDeclaration typeDecl = (TypeDeclaration)this.astStack[this.astPtr];
-	classHeaderExtendsOrImplements((typeDecl.modifiers & ClassFileConstants.AccInterface) != 0);
+	classHeaderExtendsOrImplements((typeDecl.modifiers & ClassFileConstants.AccInterface) != 0, false);
 }
 @Override
 protected void consumeTypeImportOnDemandDeclarationName() {
@@ -5204,9 +5217,9 @@
 public void copyState(Parser from) {
 
 	super.copyState(from);
-	
+
 	CompletionParser parser = (CompletionParser) from;
-	
+
 	this.invocationType = parser.invocationType;
 	this.qualifier = parser.qualifier;
 	this.inReferenceExpression = parser.inReferenceExpression;
@@ -5505,12 +5518,12 @@
 		// To make sure the array initializer is popped when the focus is shifted to the parent
 		// in case we're restarting recovery inside an array initializer
 		RecoveredElement oldElement = this.currentElement;
-		super.recoveryExitFromVariable();	
-		if(oldElement != this.currentElement) {	
-			if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_ARRAY_INITIALIZER) {	
-				popElement(K_ARRAY_INITIALIZER);	
-				popElement(K_FIELD_INITIALIZER_DELIMITER);	
-			} 	
+		super.recoveryExitFromVariable();
+		if(oldElement != this.currentElement) {
+			if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_ARRAY_INITIALIZER) {
+				popElement(K_ARRAY_INITIALIZER);
+				popElement(K_FIELD_INITIALIZER_DELIMITER);
+			}
 		}
 	} else {
 		super.recoveryExitFromVariable();
@@ -5586,11 +5599,11 @@
 	flushAssistState();
 }
 @Override
-public void restoreAssistParser(Object parserState) { 	
+public void restoreAssistParser(Object parserState) {
 	SavedState state = (SavedState) parserState;
-	
+
 	CompletionScanner completionScanner = (CompletionScanner)this.scanner;
-	
+
 	this.cursorLocation = state.parserCursorLocation;
 	completionScanner.cursorLocation = state.scannerCursorLocation;
 	this.assistNodeParent = state.assistNodeParent;
@@ -5600,7 +5613,7 @@
 	if (this.monitor != null) {
 		if (++this.resumeOnSyntaxError > 100) {
 			this.resumeOnSyntaxError = 0;
-			if (this.monitor.isCanceled()) 
+			if (this.monitor.isCanceled())
 				return HALT;
 		}
 	}
@@ -5617,14 +5630,14 @@
 protected int resumeAfterRecovery() {
 	this.hasUnusedModifiers = false;
 	if (this.assistNode != null) {
-		
+
 		if (requireExtendedRecovery()) {
 			if (this.unstackedAct != ERROR_ACTION) {
 				return RESUME;
 			}
 			return super.resumeAfterRecovery();
 		}
-		
+
 		/* if reached [eof] inside method body, but still inside nested type,
 			or inside a field initializer, should continue in diet mode until
 			the end of the method body or compilation unit */
@@ -5723,7 +5736,7 @@
 		parser = createSnapShotParser();
 		parser.copyState(this);
 	}
-	
+
 	/* may be able to retrieve completionNode as an orphan, and then attach it */
 	completionIdentifierCheck();
 	attachOrphanCompletionNode();
@@ -5796,7 +5809,7 @@
 	if (i > -1 && this.elementKindStack[i] == K_ARRAY_INITIALIZER) {
 		return true;
 	}
-	return false;	
+	return false;
 }
 private boolean foundToken(int token) {
 	int i = this.elementPtr;
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java
index 840bcae..1e7190b 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionScanner.java
@@ -8,7 +8,6 @@
  *
  * SPDX-License-Identifier: EPL-2.0
  *
- *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -759,7 +758,7 @@
 												pushLineSeparator();
 											}
 										}
-									}									
+									}
 									switch (this.currentCharacter) {
 										case '*':
 											star = true;
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java
index 53bc140..92a40a3 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -57,6 +57,8 @@
 		"org.eclipse.jdt.core.codeComplete.camelCaseMatch"; 	//$NON-NLS-1$
 	public static final String OPTION_SubstringMatch =
 			"org.eclipse.jdt.core.codeComplete.substringMatch"; 	//$NON-NLS-1$
+	public static final String OPTION_SubwordMatch =
+			"org.eclipse.jdt.core.codeComplete.subwordMatch"; 	//$NON-NLS-1$
 	public static final String OPTION_SuggestStaticImports =
 		"org.eclipse.jdt.core.codeComplete.suggestStaticImports"; 	//$NON-NLS-1$
 
@@ -70,6 +72,7 @@
 	public boolean forceImplicitQualification = false;
 	public boolean camelCaseMatch = true;
 	public boolean substringMatch = true;
+	public boolean subwordMatch = true;
 	public boolean suggestStaticImport = true;
 	public char[][] fieldPrefixes = null;
 	public char[][] staticFieldPrefixes = null;
@@ -243,6 +246,13 @@
 				this.substringMatch = false;
 			}
 		}
+		if ((optionValue = optionsMap.get(OPTION_SubwordMatch)) != null) {
+			if (ENABLED.equals(optionValue)) {
+				this.subwordMatch = true;
+			} else if (DISABLED.equals(optionValue)) {
+				this.subwordMatch = false;
+			}
+		}
 		if ((optionValue = optionsMap.get(OPTION_PerformDeprecationCheck)) != null) {
 			if (ENABLED.equals(optionValue)) {
 				this.checkDeprecation = true;
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
index 7d5db3e..3a1c337 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
@@ -78,7 +78,7 @@
 
 	// the index in the identifier stack of the previous identifier
 	protected int previousIdentifierPtr;
-	
+
 	// depth of '(', '{' and '[]'
 	protected int bracketDepth;
 
@@ -143,26 +143,26 @@
 
 @Override
 public void copyState(Parser from) {
-	
+
 	super.copyState(from);
 
 	AssistParser parser = (AssistParser) from;
-	
+
 	this.previousToken = parser.previousToken;
 	this.previousIdentifierPtr = parser.previousIdentifierPtr;
-	
+
 	this.lastModifiers = parser.lastModifiers;
 	this.lastModifiersStart = parser.lastModifiersStart;
-	
+
 	this.bracketDepth = parser.bracketDepth;
 	this.elementPtr = parser.elementPtr;
-	
+
 	int length;
 	System.arraycopy(parser.blockStarts, 0, this.blockStarts = new int [length = parser.blockStarts.length], 0, length);
 	System.arraycopy(parser.elementKindStack, 0, this.elementKindStack = new int [length = parser.elementKindStack.length], 0, length);
 	System.arraycopy(parser.elementInfoStack, 0, this.elementInfoStack = new int [length = parser.elementInfoStack.length], 0, length);
 	System.arraycopy(parser.elementObjectInfoStack, 0, this.elementObjectInfoStack = new Object [length = parser.elementObjectInfoStack.length], 0, length);
-	
+
 	this.previousKind = parser.previousKind;
 	this.previousInfo = parser.previousInfo;
 	this.previousObjectInfo = parser.previousObjectInfo;
@@ -267,7 +267,7 @@
 			}
 			blockIndex = j+1; // shift the index to the new block
 		}
-		
+
 		if (node instanceof LocalDeclaration){
 			LocalDeclaration local = (LocalDeclaration) node;
 			if (local.declarationSourceEnd == 0){
@@ -359,7 +359,7 @@
 	if (this.currentToken == TokenNameRBRACE) {
 		 if (isIndirectlyInsideLambdaExpression())
 			 this.ignoreNextClosingBrace = true;
-		 else 
+		 else
 			 this.currentToken = 0; // closing brace has already been taken care of
 	}
 
@@ -395,7 +395,7 @@
 			int i = 0;
 			for (; i <= this.astPtr; i++) {
 				if ((node = this.astStack[i]) instanceof ModuleDeclaration) {
-					unit.add((ModuleDeclaration) node, this.bracketDepth); 
+					unit.add((ModuleDeclaration) node, this.bracketDepth);
 					break;
 				}
 			}
@@ -539,7 +539,7 @@
 			   See also that this concern does not arise in the case of field/local initialization since the initializer is replaced with full tree by consumeExitVariableWithInitialization.
 			*/
 			/*
-			 * All the above comments will not work if the assist node is buried deeper. This happens when there the 
+			 * All the above comments will not work if the assist node is buried deeper. This happens when there the
 			 * lambda was part of a complex statement, such as it was one of the arguments to a method invocation. In which case,
 			 * we start from the topmost recovery element and look for assist nodes. If the operation is successful, the method
 			 * replaceAssistStatement() returns null. Else, it returns the original statement, thus falling back to replacing the
@@ -547,10 +547,10 @@
 			 */
 			statement = replaceAssistStatement(this.currentElement.topElement(),
 					this.assistNodeParent(), statementStart, statementEnd, statement);
-			
+
 			if (statement != null) {
-				RecoveredBlock recoveredBlock = (RecoveredBlock) (this.currentElement instanceof RecoveredBlock ? this.currentElement : 
-					(this.currentElement.parent instanceof RecoveredBlock) ? this.currentElement.parent : 
+				RecoveredBlock recoveredBlock = (RecoveredBlock) (this.currentElement instanceof RecoveredBlock ? this.currentElement :
+					(this.currentElement.parent instanceof RecoveredBlock) ? this.currentElement.parent :
 						this.currentElement instanceof RecoveredMethod ? ((RecoveredMethod) this.currentElement).methodBody : null);
 				if (recoveredBlock != null) {
 					RecoveredStatement recoveredStatement = recoveredBlock.statementCount > 0 ? recoveredBlock.statements[recoveredBlock.statementCount - 1] : null;
@@ -563,7 +563,7 @@
 								((Expression) statement).isTrulyExpression()) {
 							RecoveredLocalVariable local = (RecoveredLocalVariable) recoveredStatement;
 							if (local.localDeclaration != null && local.localDeclaration.initialization != null) {
-								if ((local.localDeclaration.initialization.sourceStart == 0 || local.localDeclaration.initialization.sourceEnd == 0) || 
+								if ((local.localDeclaration.initialization.sourceStart == 0 || local.localDeclaration.initialization.sourceEnd == 0) ||
 								        (local.localDeclaration.initialization.sourceStart >= statementStart && local.localDeclaration.initialization.sourceEnd <= statementEnd) ){
 									local.localDeclaration.initialization = (Expression) statement;
 									local.localDeclaration.declarationSourceEnd = statement.sourceEnd;
@@ -860,7 +860,7 @@
 						stackLength);
 			}
 			this.stack[this.stateStackTop++] = this.unstackedAct; // transition to Block ::= OpenBlock  .LBRACE BlockStatementsopt RBRACE
-			this.stack[this.stateStackTop] = tAction(this.unstackedAct, this.currentToken); // transition to Block ::= OpenBlock LBRACE  .BlockStatementsopt RBRACE 
+			this.stack[this.stateStackTop] = tAction(this.unstackedAct, this.currentToken); // transition to Block ::= OpenBlock LBRACE  .BlockStatementsopt RBRACE
 			commit(true);
 			this.stateStackTop -= 2;
 		}
@@ -1323,7 +1323,7 @@
 				}
 				break;
 		}
-	} else if (isInsideModuleInfo()) { 
+	} else if (isInsideModuleInfo()) {
 		adjustBracket(token);
 	} else {
 		switch (token) {
@@ -1596,7 +1596,7 @@
 	}
 
 	consumeNonTypeUseName();
-	
+
 	/* retrieve identifiers subset and whole positions, the completion node positions
 		should include the entire replaced source. */
 	int length = this.identifierLengthStack[this.identifierLengthPtr];
@@ -1792,7 +1792,7 @@
 		switch (this.elementKindStack[i]) {
 			case K_TYPE_DELIMITER : return false;
 			case K_METHOD_DELIMITER : return false;
-			case K_FIELD_INITIALIZER_DELIMITER : 
+			case K_FIELD_INITIALIZER_DELIMITER :
 				return true;
 		}
 		i--;
@@ -1816,9 +1816,9 @@
 	int i = this.elementPtr;
 	while(i > -1) {
 		switch (this.elementKindStack[i]) {
-			case K_TYPE_DELIMITER : 
+			case K_TYPE_DELIMITER :
 			case K_METHOD_DELIMITER :
-			case K_FIELD_INITIALIZER_DELIMITER : 
+			case K_FIELD_INITIALIZER_DELIMITER :
 				return false;
 			case K_MODULE_INFO_DELIMITER:
 				return true;
@@ -2055,12 +2055,12 @@
 
 }
 
-// the name is a misnomer, we allow "pop"s not just at the TOS. Lambda wants to be sticky till fully reduced, however we do want other elements popped at the right point, so ... 
+// the name is a misnomer, we allow "pop"s not just at the TOS. Lambda wants to be sticky till fully reduced, however we do want other elements popped at the right point, so ...
 protected void popElement(int kind) {
-	
+
 	if (this.elementPtr < 0)
 		return;
-	
+
 	int stackPointer = this.elementPtr;
 
 	if (kind != K_LAMBDA_EXPRESSION_DELIMITER) {
@@ -2070,7 +2070,7 @@
 	}
 	if (stackPointer < 0 || this.elementKindStack[stackPointer] != kind)
 		return;
-	
+
 	this.previousKind = this.elementKindStack[stackPointer];
 	this.previousInfo = this.elementInfoStack[stackPointer];
 	this.previousObjectInfo = this.elementObjectInfoStack[stackPointer];
@@ -2285,7 +2285,7 @@
 protected int fallBackToSpringForward(Statement unused) {
 	int nextToken;
 	int automatonState = automatonState();
-			
+
 	// If triggered fake EOF at completion site, see if the real next token would have passed muster.
 	if (this.currentToken == TokenNameEOF) {
 		int extendedEnd = this.scanner.source.length;
@@ -2307,7 +2307,7 @@
 		nextToken = this.currentToken;
 		this.scanner.ungetToken(nextToken);
 		if (nextToken == TokenNameRBRACE)
-			ignoreNextClosingBrace(); // having ungotten it, recoveryTokenCheck will see this again. 
+			ignoreNextClosingBrace(); // having ungotten it, recoveryTokenCheck will see this again.
 	}
 	// OK, next token is no good to resume "in place", attempt some local repair. FIXME: need to make sure we don't get stuck keep reducing empty statements !!
 	for (int i = 0, length = RECOVERY_TOKENS.length; i < length; i++) {
@@ -2352,7 +2352,7 @@
 			return RESUME;
 		}
 	}
-		
+
 	// reset internal stacks
 	this.astPtr = -1;
 	this.astLengthPtr = -1;
@@ -2360,19 +2360,19 @@
 	this.expressionLengthPtr = -1;
 	this.typeAnnotationLengthPtr = -1;
 	this.typeAnnotationPtr = -1;
-	
+
 	this.identifierPtr = -1;
 	this.identifierLengthPtr	= -1;
 	this.intPtr = -1;
-	
-	
+
+
 	this.dimensions = 0 ;
 	this.recoveredStaticInitializerStart = 0;
 
 	this.genericsIdentifiersLengthPtr = -1;
 	this.genericsLengthPtr = -1;
 	this.genericsPtr = -1;
-	
+
 	this.valueLambdaNestDepth = -1;
 
 	this.modifiers = ClassFileConstants.AccDefault;
@@ -2488,7 +2488,7 @@
 protected ASTNode wrapWithExplicitConstructorCallIfNeeded(ASTNode ast) {
 	int selector;
 	if (ast != null && topKnownElementKind(ASSIST_PARSER) == K_SELECTOR && ast instanceof Expression &&
-			((Expression) ast).isTrulyExpression() && 
+			((Expression) ast).isTrulyExpression() &&
 			(((selector = topKnownElementInfo(ASSIST_PARSER)) == THIS_CONSTRUCTOR) ||
 			(selector == SUPER_CONSTRUCTOR))) {
 		ExplicitConstructorCall call = new ExplicitConstructorCall(
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java
index d10547f..02c6c18 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/Engine.java
@@ -75,13 +75,13 @@
 	@Override
 	public void accept(ICompilationUnit sourceUnit, AccessRestriction accessRestriction) {
 		CompilationResult result = new CompilationResult(sourceUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit);
-		
+
 		AssistParser assistParser = getParser();
 		Object parserState = assistParser.becomeSimpleParser();
-		
+
 		CompilationUnitDeclaration parsedUnit =
 			assistParser.dietParse(sourceUnit, result);
-		
+
 		assistParser.restoreAssistParser(parserState);
 
 		this.lookupEnvironment.buildTypeBindings(parsedUnit, accessRestriction);
@@ -148,7 +148,7 @@
 		if (this.currentPackageName == null) {
 			initializePackageCache();
 		}
-		
+
 		ImportBinding[] importBindings = this.unitScope.imports;
 		int length = importBindings == null ? 0 : importBindings.length;
 
@@ -176,7 +176,7 @@
 
 		this.importCachesInitialized = true;
 	}
-	
+
 	public void initializePackageCache() {
 		if (this.unitScope.fPackage != null) {
 			this.currentPackageName = CharOperation.concatWith(this.unitScope.fPackage.compoundName, '.');
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadocParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadocParser.java
index d11db50..22226f3 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadocParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionJavadocParser.java
@@ -204,7 +204,7 @@
 			((SelectionJavadoc) this.docComment).inheritDocSelected = true;
 		}
 	}
-	
+
 	/*
 	 * Sets a flag to denote that selection has taken place on an inheritDoc tag
 	 */
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnArgumentName.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnArgumentName.java
index 2aab501..5634b5b 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnArgumentName.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnArgumentName.java
@@ -58,7 +58,7 @@
 		super.resolve(scope);
 		throw new SelectionNodeFound(this.binding);
 	}
-	
+
 	@Override
 	public TypeBinding resolveForCatch(BlockScope scope) {
 		super.resolveForCatch(scope);
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLambdaExpression.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLambdaExpression.java
index f248f58..833b0da 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLambdaExpression.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLambdaExpression.java
@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2014, 2015 IBM Corporation and others.
- * 
+ *
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLocalName.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLocalName.java
index ce48fe7..867db74 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLocalName.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLocalName.java
@@ -33,7 +33,7 @@
 		if (isTypeNameVar(scope)) {
 			if ((this.bits & ASTNode.IsForeachElementVariable) != 0 && scope.blockStatement instanceof ForeachStatement) {
 				// small version extracted from ForeachStatement.resolve():
-				
+
 				ForeachStatement stat = (ForeachStatement) scope.blockStatement;
 				TypeBinding collectionType = stat.collection == null ? null : stat.collection.resolveType((BlockScope) scope.parent);
 
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnModuleDeclaration.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnModuleDeclaration.java
index a67a354..1b91450 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnModuleDeclaration.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnModuleDeclaration.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist.select;
 
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnModuleReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnModuleReference.java
index 44d51e3..6770d99 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnModuleReference.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnModuleReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist.select;
 
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnReferenceExpression.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnReferenceExpression.java
index 2838a8f..064cc13 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnReferenceExpression.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnReferenceExpression.java
@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2014, 2017 IBM Corporation and others.
- * 
+ *
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -21,12 +21,12 @@
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
 
 public class SelectionOnReferenceExpression extends ReferenceExpression {
-	
+
 	public SelectionOnReferenceExpression(ReferenceExpression referenceExpression, Scanner scanner) {
 		super(scanner);
 		initialize(referenceExpression.compilationResult, referenceExpression.lhs, referenceExpression.typeArguments, referenceExpression.selector, referenceExpression.sourceEnd);
 	}
-	
+
 	@Override
 	public TypeBinding resolveType(BlockScope scope) {
 		TypeBinding resolveType = super.resolveType(scope);
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnReferenceExpressionName.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnReferenceExpressionName.java
index 22a5552..7e68324 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnReferenceExpressionName.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnReferenceExpressionName.java
@@ -34,13 +34,13 @@
 		super.printExpression(indent, output);
 		return output.append('>');
 	}
-	
+
 	// See SelectionScanner#scanIdentifierOrKeyword
 	@Override
 	public boolean isConstructorReference() {
 		return CharOperation.equals(this.selector, "new".toCharArray()); //$NON-NLS-1$
 	}
-	
+
 	// See SelectionScanner#scanIdentifierOrKeyword
 	@Override
 	public boolean isMethodReference() {
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java
index d994e69..fea7d23 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionParser.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -10,7 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     Jesper Steen Møller <jesper@selskabet.org> - contributions for:	
+ *     Jesper Steen Møller <jesper@selskabet.org> - contributions for:
  *         Bug 531046: [10] ICodeAssist#codeSelect support for 'var'
  *******************************************************************************/
 package org.eclipse.jdt.internal.codeassist.select;
@@ -41,6 +41,7 @@
 import org.eclipse.jdt.internal.compiler.ast.Expression;
 import org.eclipse.jdt.internal.compiler.ast.FieldReference;
 import org.eclipse.jdt.internal.compiler.ast.ImportReference;
+import org.eclipse.jdt.internal.compiler.ast.InstanceOfExpression;
 import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation;
@@ -567,7 +568,7 @@
 			0,
 			argumentLength);
 	}
-	
+
 	if (qualified) {
 		this.expressionLengthPtr--;
 		alloc.enclosingInstance = this.expressionStack[this.expressionPtr--];
@@ -588,7 +589,7 @@
 		this.lastIgnoredToken = -1;
 		if (isIndirectlyInsideLambdaExpression())
 			this.ignoreNextOpeningBrace = true;
-		else 
+		else
 			this.currentToken = 0; // opening brace already taken into account.
 		this.hasReportedError = true;
 	}
@@ -601,7 +602,7 @@
 		this.currentElement = this.currentElement.add(anonymousType, 0);
 		if (isIndirectlyInsideLambdaExpression())
 			this.ignoreNextOpeningBrace = true;
-		else 
+		else
 			this.currentToken = 0; // opening brace already taken into account.
 		this.lastIgnoredToken = -1;
 	}
@@ -708,15 +709,15 @@
 					varArgsAnnotations = new Annotation[length],
 					0,
 					length);
-			} 
+			}
 		}
 		int firstDimensions = this.intStack[this.intPtr--];
 		TypeReference type = getTypeReference(firstDimensions);
 
 		if (isVarArgs || extendedDimensions != 0) {
 			if (isVarArgs) {
-				type = augmentTypeWithAdditionalDimensions(type, 1, varArgsAnnotations != null ? new Annotation[][] { varArgsAnnotations } : null, true);	
-			} 
+				type = augmentTypeWithAdditionalDimensions(type, 1, varArgsAnnotations != null ? new Annotation[][] { varArgsAnnotations } : null, true);
+			}
 			if (extendedDimensions != 0) { // combination illegal.
 				type = augmentTypeWithAdditionalDimensions(type, extendedDimensions, annotationsOnExtendedDimensions, false);
 			}
@@ -791,6 +792,14 @@
 protected void consumeInstanceOfExpression() {
 	if (indexOfAssistIdentifier() < 0) {
 		super.consumeInstanceOfExpression();
+		int length = this.expressionLengthPtr >= 0 ?
+				this.expressionLengthStack[this.expressionLengthPtr] : 0;
+		if (length > 0) {
+			InstanceOfExpression exp = (InstanceOfExpression) this.expressionStack[this.expressionPtr];
+			if (exp.elementVariable != null) {
+				pushOnAstStack(exp.elementVariable);
+			}
+		}
 	} else {
 		getTypeReference(this.intStack[this.intPtr--]);
 		this.isOrphanCompletionNode = true;
@@ -1679,7 +1688,7 @@
 	char[] selector = this.identifierStack[this.identifierPtr];
 	if (selector != assistIdentifier()){
 		return super.typeElidedArgument();
-	}	
+	}
 	this.identifierLengthPtr--;
 	char[] identifierName = this.identifierStack[this.identifierPtr];
 	long namePositions = this.identifierPositionStack[this.identifierPtr--];
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CategorizedProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CategorizedProblem.java
index c162e3e..425a8e2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CategorizedProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CategorizedProblem.java
@@ -107,7 +107,7 @@
 	 * @since 3.18
 	 */
 	public static final int CAT_COMPLIANCE = 170;
-	/** Category for problems related to preview features 
+	/** Category for problems related to preview features
 	 * @since 3.20*/
 	public static final int CAT_PREVIEW_RELATED = 180;
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java
index 25b704f..7c3ff68 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Luiz-Otavio Zorzella <zorzella at gmail dot com> - Improve CamelCase algorithm
@@ -57,6 +57,8 @@
 	 */
 	public static final char[] COMMA_SEPARATOR = new char[] {','};
 
+	private static final int[] EMPTY_REGIONS = new int[0];
+
 /**
  * Answers a new array with appending the suffix character at the end of the array.
  * <br>
@@ -745,6 +747,71 @@
 
 /**
  * Answers true if the characters of the pattern are contained in the
+ * name as a subword, in a case-insensitive way.
+ *
+ * @param pattern the given pattern
+ * @param name the given name
+ * @return true if the pattern matches the given name, false otherwise
+ * @since 3.21
+ */
+public static final boolean subWordMatch(char[] pattern, char[] name) {
+	if (name == null)
+		return false; // null name cannot match
+	if (pattern == null)
+		return true; // null pattern is equivalent to '*'
+
+	int[] matchingRegions = getSubWordMatchingRegions(new String(pattern), new String(name));
+	return matchingRegions != null;
+}
+
+/**
+ * Answers all the regions in a given name matching a subword pattern.
+ * <p>
+ * Each of these regions is made of its starting index and its length in the given
+ * name. They are all concatenated in a single array of <code>int</code>
+ * which therefore always has an even length.
+ * <p>
+ * Note that each region is disjointed from the following one.<br>
+ * E.g. if the regions are <code>{ start1, length1, start2, length2 }</code>,
+ * then <code>start1+length1</code> will always be smaller than
+ * <code>start2</code>.
+ * <p>
+ * Examples:
+ * <ol>
+ * <li><pre>
+ *    pattern = "linkedmap"
+ *    name = LinkedHashMap
+ *    result:  { 0, 6, 10, 3 }
+ * </pre></li>
+ * </ol>
+ *
+ * @see CharOperation#subWordMatch(char[], char[])
+ * 	for more details on the subword behavior
+ *
+ * @param pattern the given pattern
+ * @param name the given name
+ * @return an array of <code>int</code> having two slots per returned
+ * 	regions (first one is the starting index of the region and the second
+ * 	one the length of the region).<br>
+ * 	Note that it may be <code>null</code> if the given name does not match
+ * 	the pattern
+ * @since 3.21
+ */
+public static final int[] getSubWordMatchingRegions(String pattern, String name) {
+
+	if (name == null)
+		return null; // null name cannot match
+	if (pattern == null) {
+		// null pattern cannot match any region
+		// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=264816
+		return EMPTY_REGIONS;
+	}
+
+	return new SubwordMatcher(name).getMatchingRegions(pattern);
+}
+
+/**
+ * Answers true if the characters of the pattern are contained in the
  * name as a substring, in a case-insensitive way.
  *
  * @param pattern the given pattern
@@ -865,7 +932,7 @@
 /**
  * Converts the given list of strings to an array of equal size,
  * containing the individual strings converted to char[] each.
- * 
+ *
  * @param stringList
  * @return an array of char[], representing the elements in the input list, or {@code null} if the list was {@code null}.
  * @since 3.14
@@ -958,7 +1025,7 @@
  * @param array2 the second given array
  * @param start the starting position to compare (inclusive)
  * @param end the ending position to compare (exclusive)
- * 
+ *
  * @return the returned value of the comparison between array1 and array2
  * @throws NullPointerException if one of the arrays is null
  * @since 3.7.1
@@ -1750,7 +1817,7 @@
 }
 
 /**
- * Answers the concatenation of the given array parts using the given separator between each part 
+ * Answers the concatenation of the given array parts using the given separator between each part
  * irrespective of whether an element is a zero length array or not.
  * <br>
  * <br>
@@ -3014,7 +3081,7 @@
 		if (iPattern == patternEnd) {
 			if (iName == nameEnd) return true; // the chars match
 			return false; // pattern has ended but not the name, no match
-		} 
+		}
 		if ((patternChar = pattern[iPattern]) == '*') {
 			break;
 		}
@@ -4027,13 +4094,13 @@
 		int enclCount = 0;
 		for (int i = start; i < end; i++) {
 			if (array[i] == openEncl)
-				enclCount++; 
+				enclCount++;
 			else if (array[i] == divider)
 				wordCount++;
 		}
 		if (enclCount == 0)
 			return CharOperation.splitOn(divider, array, start, end);
-		
+
 		int nesting = 0;
 		if (openEncl == divider || closeEncl == divider) // divider should be distinct
 			return CharOperation.NO_CHAR_CHAR;
@@ -4046,7 +4113,7 @@
 				continue;
 			}
 			if (array[i] == closeEncl) {
-				if (nesting > 0) 
+				if (nesting > 0)
 					--nesting;
 				continue;
 			}
@@ -4233,7 +4300,7 @@
  *
  * @param chars the chars to convert
  * @return the result of a char[] conversion to uppercase
- * 
+ *
  * @since 3.5
  */
 final static public char[] toUpperCase(char[] chars) {
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 d2bdeae..b9d220d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -1,6 +1,6 @@
 // AspectJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -224,7 +224,7 @@
  *									VarLocalWithoutInitizalier
  *									VarLocalInitializedToNull
  *									VarLocalCannotBeArrayInitalizers
- *									VarLocalCannotBeLambda 
+ *									VarLocalCannotBeLambda
  *									VarLocalCannotBeMethodReference
  *									VarIsReserved
  *									VarIsReservedInFuture
@@ -1219,6 +1219,29 @@
 	int JavadocUnexpectedText = Javadoc + Internal + 518;
 	/** @since 3.1 */
 	int JavadocInvalidParamTagName = Javadoc + Internal + 519;
+	/*
+	 * IDs for module errors in Javadoc
+	 */
+	/** @since 3.20 */
+	int JavadocMissingUsesTag = Javadoc + Internal + 1800;
+	/** @since 3.20 */
+	int JavadocDuplicateUsesTag = Javadoc + Internal + 1801;
+	/** @since 3.20 */
+	int JavadocMissingUsesClassName = Javadoc + Internal + 1802;
+	/** @since 3.20 */
+	int JavadocInvalidUsesClassName = Javadoc + Internal + 1803;
+	/** @since 3.20 */
+	int JavadocInvalidUsesClass = Javadoc + Internal + 1804;
+	/** @since 3.20 */
+	int JavadocMissingProvidesTag = Javadoc + Internal + 1805;
+	/** @since 3.20 */
+	int JavadocDuplicateProvidesTag = Javadoc + Internal + 1806;
+	/** @since 3.20 */
+	int JavadocMissingProvidesClassName = Javadoc + Internal + 1807;
+	/** @since 3.20 */
+	int JavadocInvalidProvidesClassName = Javadoc + Internal + 1808;
+	/** @since 3.20 */
+	int JavadocInvalidProvidesClass = Javadoc + Internal + 1809;
 
 	/**
 	 * Generics
@@ -1489,7 +1512,11 @@
     int ConstructorReferenceNotBelow18 = Internal + Syntax + 647;
     /** @since 3.10 */
     int ExplicitThisParameterNotInLambda = Internal + Syntax + 648;
-    /** @since 3.10 */
+    /**
+     * @since 3.10
+     * @deprecated Per https://bugs.openjdk.java.net/browse/JDK-8231435 this problem is no longer raised
+     */
+    @Deprecated
     int ExplicitAnnotationTargetRequired = TypeRelated + 649;
     /** @since 3.10 */
     int IllegalTypeForExplicitThis = Internal + Syntax + 650;
@@ -1837,6 +1864,8 @@
 	int RedundantNullCheckOnConstNonNullField = Internal + 944;
 	/** @since 3.20 */
 	int ConstNonNullFieldComparisonYieldsFalse = Internal + 945;
+	/** @since 3.21 */
+	int InheritedParameterLackingNonNullAnnotation = MethodRelated + 946;
 
 	/** @since 3.10 */
 	int ArrayReferencePotentialNullReference = Internal + 951;
@@ -1900,6 +1929,12 @@
 	int NonNullTypeVariableFromLegacyMethod = TypeRelated + 980;
 	/** @since 3.12 */
 	int NonNullMethodTypeVariableFromLegacyMethod = TypeRelated + 981;
+	/** @since 3.21 */
+	int MissingNullAnnotationImplicitlyUsed = Internal + 982;
+	/** @since 3.21 */
+	int AnnotatedTypeArgumentToUnannotated = Internal + 983;
+	/** @since 3.21 */
+	int AnnotatedTypeArgumentToUnannotatedSuperHint = Internal + 984;
 
 
 	// Java 8 work
@@ -2176,61 +2211,142 @@
 	 * @deprecated preview related error - will be removed
 	 * @noreference preview related error */
 	int SwitchExpressionIllegalLastStatement = Internal + 1612;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldIncompatibleResultExpressionTypes = PreviewRelated + 1700;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldEmptySwitchBlock = PreviewRelated + 1701;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldNoResultExpression = PreviewRelated + 1702;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionaYieldSwitchLabeledBlockCompletesNormally = PreviewRelated + 1703;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldLastStatementCompletesNormally = PreviewRelated + 1704;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldTrailingSwitchLabels = PreviewRelated + 1705;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchPreviewMixedCase = PreviewRelated + 1706;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldMissingDefaultCase = PreviewRelated + 1707;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldMissingValue = PreviewRelated + 1708;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldMissingEnumConstantCase = PreviewRelated + 1709;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldIllegalLastStatement = PreviewRelated + 1710;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldBreakNotAllowed = PreviewRelated + 1711;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldUnqualifiedMethodWarning = PreviewRelated + 1712;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldUnqualifiedMethodError = PreviewRelated + 1713;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldOutsideSwitchExpression = PreviewRelated + 1714;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldRestrictedGeneralWarning = PreviewRelated + 1715;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldIllegalStatement = PreviewRelated + 1716;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldTypeDeclarationWarning = PreviewRelated + 1717;
-	/** @since 3.20
-	 * @noreference preview related error */
-	int SwitchExpressionsYieldTypeDeclarationError = PreviewRelated + 1718;
+
+	/* Java14 errors - begin */
+	/** @since 3.21  */
+	int SwitchExpressionsYieldIncompatibleResultExpressionTypes = TypeRelated + 1700;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldEmptySwitchBlock = Syntax + 1701;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldNoResultExpression = Internal + 1702;
+	/** @since 3.21  */
+	int SwitchExpressionaYieldSwitchLabeledBlockCompletesNormally = Internal + 1703;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldLastStatementCompletesNormally = Internal + 1704;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldTrailingSwitchLabels = Internal + 1705;
+	/** @since 3.21  */
+	int SwitchPreviewMixedCase = Syntax + 1706;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldMissingDefaultCase = Syntax + 1707;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldMissingValue = Syntax + 1708;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldMissingEnumConstantCase = Syntax + 1709;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldIllegalLastStatement = Internal + 1710;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldBreakNotAllowed = Syntax + 1711;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldUnqualifiedMethodWarning = Syntax + 1712;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldUnqualifiedMethodError = Syntax + 1713;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldOutsideSwitchExpression = Syntax + 1714;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldRestrictedGeneralWarning = Internal + 1715;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldIllegalStatement = Internal + 1716;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldTypeDeclarationWarning = Internal + 1717;
+	/** @since 3.21  */
+	int SwitchExpressionsYieldTypeDeclarationError = Internal + 1718;
+	/** @since 3.22 */
+	int MultiConstantCaseLabelsNotSupported = Syntax + 1719;
+	/** @since 3.22*/
+	int ArrowInCaseStatementsNotSupported = Syntax + 1720;
+	/** @since 3.22 */
+	int SwitchExpressionsNotSupported = Syntax + 1721;
+	/** @since 3.22 */
+	int SwitchExpressionsBreakOutOfSwitchExpression  = Syntax + 1722;
+	/** @since 3.22 */
+	int SwitchExpressionsContinueOutOfSwitchExpression  = Syntax + 1723;
+	/* records - begin */
+
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordIllegalModifierForInnerRecord = PreviewRelated + 1730;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordIllegalModifierForRecord = PreviewRelated + 1731;
+	/** @since 3.22
+	 * JLS 14 Sec 8.10.1
+	 * it is always a compile-time error for a record header to declare a record component with the name
+	 * finalize, getClass, hashCode, notify, notifyAll, or toString. */
+	int RecordIllegalComponentNameInRecord = PreviewRelated + 1732;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordNonStaticFieldDeclarationInRecord = PreviewRelated + 1733;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordAccessorMethodHasThrowsClause = PreviewRelated + 1734;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordCanonicalConstructorHasThrowsClause = PreviewRelated + 1735;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordCanonicalConstructorShouldBePublic = PreviewRelated + 1736;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordMultipleCanonicalConstructors = PreviewRelated + 1737;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordCompactConstructorHasReturnStatement = PreviewRelated + 1738;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordDuplicateComponent = PreviewRelated + 1739;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordIllegalNativeModifierInRecord = PreviewRelated + 1740;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordInstanceInitializerBlockInRecord = PreviewRelated + 1741;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordIsAReservedTypeName = PreviewRelated + 1742;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordIllegalAccessorReturnType = PreviewRelated + 1743;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordAccessorMethodShouldNotBeGeneric = PreviewRelated + 1744;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordAccessorMethodShouldBePublic = PreviewRelated + 1745;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordCanonicalConstructorShouldNotBeGeneric = PreviewRelated + 1746;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordCanonicalConstructorHasReturnStatement = PreviewRelated + 1747;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordCanonicalConstructorHasExplicitConstructorCall = PreviewRelated + 1748;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordCompactConstructorHasExplicitConstructorCall = PreviewRelated + 1749;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordNestedRecordInherentlyStatic = PreviewRelated + 1750;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordAccessorMethodShouldNotBeStatic= PreviewRelated + 1751;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordCannotExtendRecord= PreviewRelated + 1752;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordComponentCannotBeVoid= PreviewRelated + 1753;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordIllegalVararg= PreviewRelated + 1754;
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int RecordStaticReferenceToOuterLocalVariable= PreviewRelated + 1755;
+	/* records - end */
+	/* instanceof pattern: */
+	/** @since 3.22
+	 * @noreference preview feature error */
+	int PatternVariableNotInScope = PreviewRelated + 1760;
+	/* Java14 errors - end */
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/SubwordMatcher.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/SubwordMatcher.java
new file mode 100644
index 0000000..806091f
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/SubwordMatcher.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Julian Honnen.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ * Contributors:
+ *     Julian Honnen - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.compiler;
+
+import java.util.Arrays;
+import java.util.BitSet;
+
+import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
+
+class SubwordMatcher {
+
+	private static final int[] EMPTY_REGIONS = new int[0];
+
+	private final char[] name;
+	private final BitSet wordBoundaries;
+
+	public SubwordMatcher(String name) {
+		this.name = name.toCharArray();
+		this.wordBoundaries = new BitSet(name.length());
+
+		BoundaryState state = BoundaryState.SEPARATOR;
+		for (int i = 0; i < this.name.length; i++) {
+			char c = this.name[i];
+			if (state.isWordBoundary(c)) {
+				this.wordBoundaries.set(i);
+			}
+			state = state.next(c);
+		}
+	}
+
+	public int[] getMatchingRegions(String pattern) {
+		int segmentStart = 0;
+		int[] segments = EMPTY_REGIONS;
+
+		// Main loop is on pattern characters
+		int iName = -1;
+		int iPatternWordStart = 0;
+		for (int iPattern = 0; iPattern < pattern.length(); iPattern++) {
+			iName++;
+			if (iName == this.name.length) {
+				// We have exhausted the name (and not the pattern), so it's not a match
+				return null;
+			}
+
+			char patternChar = pattern.charAt(iPattern);
+			char nameChar = this.name[iName];
+
+			// For as long as we're exactly matching, bring it on
+			if (patternChar == nameChar) {
+				continue;
+			}
+			if (!isWordBoundary(iName) && equalsIgnoreCase(patternChar, nameChar)) {
+				// we're not at a word boundary, case-insensitive match is fine
+				continue;
+			}
+
+			// not matching, record previous segment and find next word match in name
+			if (iName > segmentStart) {
+				segments = Arrays.copyOf(segments, segments.length + 2);
+				segments[segments.length - 2] = segmentStart;
+				segments[segments.length - 1] = iName - segmentStart;
+			}
+
+			int wordStart = indexOfWordStart(iName, patternChar);
+			if (wordStart < 0) {
+				// no matching word found, backtrack and try to find next occurrence of current word
+				int next = indexOfWordStart(iName, pattern.charAt(iPatternWordStart));
+				if (next > 0) {
+					wordStart = next;
+					iPattern = iPatternWordStart;
+					// last recorded segment was invalid -> drop it
+					segments = Arrays.copyOfRange(segments, 0, segments.length - 2);
+				}
+			}
+
+			if (wordStart < 0) {
+				// We have exhausted name (and not pattern), so it's not a match
+				return null;
+			}
+
+			segmentStart = wordStart;
+			iName = wordStart;
+			iPatternWordStart = iPattern;
+		}
+
+		// we have exhausted pattern, record final segment
+		segments = Arrays.copyOf(segments, segments.length + 2);
+		segments[segments.length - 2] = segmentStart;
+		segments[segments.length - 1] = iName - segmentStart + 1;
+
+		return segments;
+	}
+
+	/**
+	 * Returns the index of the first word after nameStart, beginning with patternChar. Returns -1 if no matching word
+	 * is found.
+	 */
+	private int indexOfWordStart(int nameStart, char patternChar) {
+
+		for (int iName = nameStart; iName < this.name.length; iName++) {
+			char nameChar = this.name[iName];
+			if (isWordBoundary(iName) && equalsIgnoreCase(nameChar, patternChar)) {
+				return iName;
+			}
+
+			// don't match across identifiers (e.g. "index" should not match "substring(int beginIndex)")
+			if (!ScannerHelper.isJavaIdentifierPart(nameChar)) {
+				return -1;
+			}
+		}
+
+		// We have exhausted name
+		return -1;
+	}
+
+	private boolean equalsIgnoreCase(char a, char b) {
+		return ScannerHelper.toLowerCase(a) == ScannerHelper.toLowerCase(b);
+	}
+
+	private boolean isWordBoundary(int iName) {
+		return this.wordBoundaries.get(iName);
+	}
+
+	private enum BoundaryState {
+		SEPARATOR() {
+			@Override
+			public BoundaryState next(char c) {
+				if (c == '_')
+					return SEPARATOR;
+
+				return ScannerHelper.isUpperCase(c) ? CAPS_WORD : WORD;
+			}
+			@Override
+			public boolean isWordBoundary(char c) {
+				return true;
+			}
+		},
+		WORD() {
+			@Override
+			public BoundaryState next(char c) {
+				if (c == '_')
+					return SEPARATOR;
+
+				return WORD;
+			}
+
+			@Override
+			public boolean isWordBoundary(char c) {
+				return ScannerHelper.isUpperCase(c);
+			}
+		},
+		CAPS_WORD() {
+			@Override
+			public BoundaryState next(char c) {
+				if (c == '_')
+					return SEPARATOR;
+
+				return ScannerHelper.isUpperCase(c) ? CAPS_WORD : WORD;
+			}
+
+			@Override
+			public boolean isWordBoundary(char c) {
+				return next(c) == SEPARATOR;
+			}
+		};
+
+		public abstract boolean isWordBoundary(char c);
+
+		public abstract BoundaryState next(char c);
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ASTVisitor.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ASTVisitor.java
index 8665c8a..31f3dff 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ASTVisitor.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ASTVisitor.java
@@ -106,6 +106,9 @@
 	public void endVisit(Clinit clinit, ClassScope scope) {
 		// do nothing by default
 	}
+	public void endVisit(CompactConstructorDeclaration ccd, ClassScope scope) {
+		// do nothing by default
+	}
 	public void endVisit(
 		CompilationUnitDeclaration compilationUnitDeclaration,
 		CompilationUnitScope scope) {
@@ -503,7 +506,7 @@
 		// do nothing by default
 	}
 	public void endVisit(ReferenceExpression referenceExpression, BlockScope blockScope) {
-		// do nothing by default	
+		// do nothing by default
 	}
 	public void endVisit(IntersectionCastTypeReference intersectionCastTypeReference, ClassScope scope) {
 		// do nothing by default
@@ -596,6 +599,9 @@
 	public boolean visit(ModuleDeclaration module, CompilationUnitScope scope) {
 		return true;
 	}
+	public boolean visit(CompactConstructorDeclaration ccd, ClassScope scope) {
+		return true; // do nothing by default, keep traversing
+	}
 	public boolean visit(
 		CompilationUnitDeclaration compilationUnitDeclaration,
 		CompilationUnitScope scope) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
index 529b39b..61f040d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ClassFile.java
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -161,6 +161,7 @@
 	public int headerOffset;
 	public Map<TypeBinding, Boolean> innerClassesBindings;
 	public List bootstrapMethods = null;
+	public List<TypeBinding> recordBootstrapMethods = null;
 	public int methodCount;
 	public int methodCountOffset;
 	// pool managment
@@ -427,9 +428,10 @@
 			}
 			attributesNumber += generateHierarchyInconsistentAttribute();
 		}
-		// Functional expression and lambda bootstrap methods
-		if (this.bootstrapMethods != null && !this.bootstrapMethods.isEmpty()) {
-			attributesNumber += generateBootstrapMethods(this.bootstrapMethods);
+		// Functional expression, lambda bootstrap methods and record bootstrap methods
+		if ((this.bootstrapMethods != null && !this.bootstrapMethods.isEmpty()) ||
+				(this.recordBootstrapMethods != null && !this.recordBootstrapMethods.isEmpty())) {
+			attributesNumber += generateBootstrapMethods(this.bootstrapMethods, this.recordBootstrapMethods);
 		}
 		// Inner class attribute
 		int numberOfInnerClasses = this.innerClassesBindings == null ? 0 : this.innerClassesBindings.size();
@@ -479,6 +481,10 @@
 			// add nestMember and nestHost attributes
 			attributesNumber += generateNestAttributes();
 		}
+		if (this.targetJDK >= ClassFileConstants.JDK14) {
+			// add record attributes
+			attributesNumber += generateRecordAttributes();
+		}
 		// update the number of attributes
 		if (attributeOffset + 2 >= this.contents.length) {
 			resizeContents(2);
@@ -561,18 +567,26 @@
 		}
 	}
 
+	private int addComponentAttributes(FieldBinding fieldBinding, int fieldAttributeOffset) {
+		// almost mirrors with field_info
+		// TODO: watch out for spec changes once preview to standard of records
+		return addFieldAttributes(fieldBinding, fieldAttributeOffset, true);
+	}
 	private int addFieldAttributes(FieldBinding fieldBinding, int fieldAttributeOffset) {
+		return addFieldAttributes(fieldBinding, fieldAttributeOffset, false);
+	}
+	private int addFieldAttributes(FieldBinding fieldBinding, int fieldAttributeOffset, boolean isComponent) {
 		int attributesNumber = 0;
 		// 4.7.2 only static constant fields get a ConstantAttribute
 		// Generate the constantValueAttribute
 		Constant fieldConstant = fieldBinding.constant();
-		if (fieldConstant != Constant.NotAConstant){
+		if (fieldConstant != Constant.NotAConstant && !isComponent){
 			attributesNumber += generateConstantValueAttribute(fieldConstant, fieldBinding, fieldAttributeOffset);
 		}
-		if (this.targetJDK < ClassFileConstants.JDK1_5 && fieldBinding.isSynthetic()) {
+		if (this.targetJDK < ClassFileConstants.JDK1_5 && fieldBinding.isSynthetic() && !isComponent) {
 			attributesNumber += generateSyntheticAttribute();
 		}
-		if (fieldBinding.isDeprecated()) {
+		if (fieldBinding.isDeprecated() && !isComponent) {
 			attributesNumber += generateDeprecatedAttribute();
 		}
 		// add signature attribute
@@ -585,7 +599,9 @@
 			if (fieldDeclaration != null) {
 				Annotation[] annotations = fieldDeclaration.annotations;
 				if (annotations != null) {
-					attributesNumber += generateRuntimeAnnotations(annotations, TagBits.AnnotationForField);
+					long allowedTargets = TagBits.AnnotationForField | (fieldDeclaration.isARecordComponent ?
+							TagBits.AnnotationForRecordComponent : 0);
+					attributesNumber += generateRuntimeAnnotations(annotations, allowedTargets);
 				}
 
 				if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) {
@@ -633,6 +649,42 @@
 
 	/**
 	 * INTERNAL USE-ONLY
+	 * This methods generates the bytes for the given record component given by field binding
+	 * @param fieldBinding the given field binding of the record component
+	 */
+	private void addComponentInfo(FieldBinding fieldBinding) {
+		// check that there is enough space to write all the bytes for the field info corresponding
+		// to the @fieldBinding sans accessflags for component
+		/* component_info {
+    	 *	u2 name_index;
+    	 *	u2 descriptor_index;
+    	 *	u2 attributes_count;
+    	 *	attribute_info attributes[attributes_count];
+		} */
+		if (this.contentsOffset + 6 >= this.contents.length) {
+			resizeContents(6);
+		}
+		// Now we can generate all entries into the byte array
+		int nameIndex = this.constantPool.literalIndex(fieldBinding.name);
+		this.contents[this.contentsOffset++] = (byte) (nameIndex >> 8);
+		this.contents[this.contentsOffset++] = (byte) nameIndex;
+		// Then the descriptorIndex
+		int descriptorIndex = this.constantPool.literalIndex(fieldBinding.type);
+		this.contents[this.contentsOffset++] = (byte) (descriptorIndex >> 8);
+		this.contents[this.contentsOffset++] = (byte) descriptorIndex;
+		int componentAttributeOffset = this.contentsOffset;
+		int attributeNumber = 0;
+		// leave some space for the number of attributes
+		this.contentsOffset += 2;
+		attributeNumber += addComponentAttributes(fieldBinding, componentAttributeOffset);
+		if (this.contentsOffset + 2 >= this.contents.length) {
+			resizeContents(2);
+		}
+		this.contents[componentAttributeOffset++] = (byte) (attributeNumber >> 8);
+		this.contents[componentAttributeOffset] = (byte) attributeNumber;
+	}
+	/**
+	 * INTERNAL USE-ONLY
 	 * This methods generates the bytes for the given field binding
 	 * @param fieldBinding the given field binding
 	 */
@@ -1070,6 +1122,11 @@
 						case SyntheticMethodBinding.SerializableMethodReference:
 							// Nothing to be done
 							break;
+						case SyntheticMethodBinding.RecordOverrideEquals:
+						case SyntheticMethodBinding.RecordOverrideHashCode:
+						case SyntheticMethodBinding.RecordOverrideToString:
+							addSyntheticRecordOverrideMethods(syntheticMethod, syntheticMethod.purpose);
+							break;
 					}
 				}
 				emittedSyntheticsCount = currentSyntheticsCount;
@@ -1100,6 +1157,48 @@
 		}
 	}
 
+	private void addSyntheticRecordOverrideMethods(SyntheticMethodBinding methodBinding, int purpose) {
+		if (this.recordBootstrapMethods == null)
+			this.recordBootstrapMethods = new ArrayList<>(3);
+		if (!this.recordBootstrapMethods.contains(methodBinding.declaringClass))
+			this.recordBootstrapMethods.add(methodBinding.declaringClass);
+		int index = this.bootstrapMethods != null ? this.bootstrapMethods.size() +
+				this.recordBootstrapMethods.size() - 1 : 0;
+		generateMethodInfoHeader(methodBinding);
+		int methodAttributeOffset = this.contentsOffset;
+		// this will add exception attribute, synthetic attribute, deprecated attribute,...
+		int attributeNumber = generateMethodInfoAttributes(methodBinding);
+		// Code attribute
+		int codeAttributeOffset = this.contentsOffset;
+		attributeNumber++; // add code attribute
+		generateCodeAttributeHeader();
+		this.codeStream.init(this);
+		switch (purpose) {
+			case SyntheticMethodBinding.RecordOverrideEquals:
+				this.codeStream.generateSyntheticBodyForRecordEquals(methodBinding, index);
+				break;
+			case SyntheticMethodBinding.RecordOverrideHashCode:
+				this.codeStream.generateSyntheticBodyForRecordHashCode(methodBinding, index);
+				break;
+			case SyntheticMethodBinding.RecordOverrideToString:
+				this.codeStream.generateSyntheticBodyForRecordToString(methodBinding, index);
+				break;
+			default:
+				break;
+		}
+		completeCodeAttributeForSyntheticMethod(
+			methodBinding,
+			codeAttributeOffset,
+			((SourceTypeBinding) methodBinding.declaringClass)
+				.scope
+				.referenceCompilationUnit()
+				.compilationResult
+				.getLineSeparatorPositions());
+		// update the number of attributes
+		this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8);
+		this.contents[methodAttributeOffset] = (byte) attributeNumber;
+	}
+
 	public void addSyntheticArrayConstructor(SyntheticMethodBinding methodBinding) {
 		generateMethodInfoHeader(methodBinding);
 		int methodAttributeOffset = this.contentsOffset;
@@ -2780,6 +2879,50 @@
 		nAttrs += generateNestHostAttribute();
 		return nAttrs;
 	}
+	private int generateRecordAttributes() {
+		SourceTypeBinding record = this.referenceBinding;
+		if (record == null || !record.isRecord())
+			return 0;
+		int localContentsOffset = this.contentsOffset;
+		FieldBinding[] recordComponents = this.referenceBinding.getRecordComponents();
+		if (recordComponents == null)
+			return 0;
+		// could be an empty record also, account for zero components as well.
+
+		int numberOfRecordComponents = recordComponents.length;
+
+		int exSize = 8 + 2 * numberOfRecordComponents;
+		if (exSize + localContentsOffset >= this.contents.length) {
+			resizeContents(exSize);
+		}
+		/*
+		 * Record_attribute {
+    	 *  u2 attribute_name_index;
+    	 *	u4 attribute_length;
+    	 *	u2 components_count;
+    	 *	component_info components[components_count];
+		 *	}*/
+		int attributeNameIndex =
+			this.constantPool.literalIndex(AttributeNamesConstants.RecordClass);
+		this.contents[localContentsOffset++] = (byte) (attributeNameIndex >> 8);
+		this.contents[localContentsOffset++] = (byte) attributeNameIndex;
+		int attrLengthOffset = localContentsOffset;
+		localContentsOffset += 4;
+		int base = localContentsOffset;
+		this.contents[localContentsOffset++] = (byte) (numberOfRecordComponents >> 8);
+		this.contents[localContentsOffset++] = (byte) numberOfRecordComponents;
+		this.contentsOffset = localContentsOffset;
+		for (int i = 0; i < numberOfRecordComponents; i++) {
+			addComponentInfo(recordComponents[i]);
+		}
+		int attrLength = this.contentsOffset - base;
+		this.contents[attrLengthOffset++] = (byte) (attrLength >> 24);
+		this.contents[attrLengthOffset++] = (byte) (attrLength >> 16);
+		this.contents[attrLengthOffset++] = (byte) (attrLength >> 8);
+		this.contents[attrLengthOffset++] = (byte) attrLength;
+		return 1;
+	}
+
 	private int generateModuleAttribute(ModuleDeclaration module) {
 		ModuleBinding binding = module.binding;
 		int localContentsOffset = this.contentsOffset;
@@ -3396,7 +3539,7 @@
 		return 1;
 	}
 
-	private int generateBootstrapMethods(List functionalExpressionList) {
+	private int generateBootstrapMethods(List functionalExpressionList, List<TypeBinding> recordBootstrapMethods2) {
 		/* See JVM spec 4.7.21
 		   The BootstrapMethods attribute has the following format:
 		   BootstrapMethods_attribute {
@@ -3413,13 +3556,10 @@
 		ReferenceBinding methodHandlesLookup = this.referenceBinding.scope.getJavaLangInvokeMethodHandlesLookup();
 		if (methodHandlesLookup == null) return 0; // skip bootstrap section, class path problem already reported, just avoid NPE.
 		recordInnerClasses(methodHandlesLookup); // Should be done, it's what javac does also
-		ReferenceBinding javaLangInvokeLambdaMetafactory = this.referenceBinding.scope.getJavaLangInvokeLambdaMetafactory(); 
 		
-		// Depending on the complexity of the expression it may be necessary to use the altMetafactory() rather than the metafactory()
-		int indexForMetaFactory = 0;
-		int indexForAltMetaFactory = 0;
-
-		int numberOfBootstraps = functionalExpressionList.size();
+		int nfunctionalExpressions = functionalExpressionList != null ? functionalExpressionList.size() : 0;
+		int nRecordBootStraps = recordBootstrapMethods2 != null ? recordBootstrapMethods2.size() : 0;
+		int numberOfBootstraps = nfunctionalExpressions + nRecordBootStraps;
 		int localContentsOffset = this.contentsOffset;
 		// Generate the boot strap attribute - since we are only making lambdas and
 		// functional expressions, we know the size ahead of time - this less general
@@ -3440,6 +3580,32 @@
 		localContentsOffset += 4;
 		this.contents[localContentsOffset++] = (byte) (numberOfBootstraps >> 8);
 		this.contents[localContentsOffset++] = (byte) numberOfBootstraps;
+
+		if (nfunctionalExpressions > 0)
+			localContentsOffset = generateLambdaMetaFactoryBootStrapMethods(functionalExpressionList,
+					localContentsOffset, contentsEntries);
+		if (nRecordBootStraps > 0)
+			localContentsOffset = generateObjectMethodsBootStrapMethods(recordBootstrapMethods2, localContentsOffset,
+					contentsEntries);
+
+		int attributeLength = localContentsOffset - attributeLengthPosition - 4;
+		this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 24);
+		this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 16);
+		this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 8);
+		this.contents[attributeLengthPosition++] = (byte) attributeLength;
+		this.contentsOffset = localContentsOffset;
+		return 1;
+	}
+
+	private int generateLambdaMetaFactoryBootStrapMethods(List functionalExpressionList,
+			int localContentsOffset, final int contentsEntries) {
+		ReferenceBinding javaLangInvokeLambdaMetafactory = this.referenceBinding.scope.getJavaLangInvokeLambdaMetafactory();
+		int numberOfBootstraps = functionalExpressionList.size();
+
+		// Depending on the complexity of the expression it may be necessary to use the altMetafactory() rather than the metafactory()
+		int indexForMetaFactory = 0;
+		int indexForAltMetaFactory = 0;
+
 		for (int i = 0; i < numberOfBootstraps; i++) {
 			FunctionalExpression functional = (FunctionalExpression) functionalExpressionList.get(i);
 			MethodBinding [] bridges = functional.getRequiredBridges();
@@ -3552,14 +3718,65 @@
 				this.contents[localContentsOffset++] = (byte) methodTypeIndex;				
 			}
 		}
+		return localContentsOffset;
+	}
+	private int generateObjectMethodsBootStrapMethods(List<TypeBinding> recordList,
+			int localContentsOffset, final int contentsEntries) {
+		ReferenceBinding javaLangRuntimeObjectMethods = this.referenceBinding.scope.getJavaLangRuntimeObjectMethods();
+		int numberOfBootstraps = recordList.size();
+		int indexForObjectMethodBootStrap = 0;
+		for (int i = 0; i < numberOfBootstraps; i++) {
+			if (contentsEntries + localContentsOffset >= this.contents.length) {
+				resizeContents(contentsEntries);
+			}
+			if (indexForObjectMethodBootStrap == 0) {
+				indexForObjectMethodBootStrap = this.constantPool.literalIndexForMethodHandle(ClassFileConstants.MethodHandleRefKindInvokeStatic, javaLangRuntimeObjectMethods,
+						ConstantPool.BOOTSTRAP, ConstantPool.JAVA_LANG_RUNTIME_OBJECTMETHOD_BOOTSTRAP_SIGNATURE, false);
+			}
+			this.contents[localContentsOffset++] = (byte) (indexForObjectMethodBootStrap >> 8);
+			this.contents[localContentsOffset++] = (byte) indexForObjectMethodBootStrap;
 
-		int attributeLength = localContentsOffset - attributeLengthPosition - 4;
-		this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 24);
-		this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 16);
-		this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 8);
-		this.contents[attributeLengthPosition++] = (byte) attributeLength;
-		this.contentsOffset = localContentsOffset;
-		return 1;
+			// u2 num_bootstrap_arguments
+			int numArgsLocation = localContentsOffset;
+			localContentsOffset += 2;
+
+			TypeBinding type = recordList.get(i);
+			assert type.isRecord(); // sanity check
+			char[] recordName = type.constantPoolName();
+			int recordIndex = this.constantPool.literalIndexForType(recordName);
+			this.contents[localContentsOffset++] = (byte) (recordIndex >> 8);
+			this.contents[localContentsOffset++] = (byte) recordIndex;
+
+			assert type instanceof SourceTypeBinding;
+			SourceTypeBinding sourceType = (SourceTypeBinding) type;
+			FieldBinding[] recordComponents = sourceType.getRecordComponents();
+
+			int numArgs = 2 + recordComponents.length;
+			this.contents[numArgsLocation++] = (byte) (numArgs >> 8);
+			this.contents[numArgsLocation] = (byte) numArgs;
+
+			String names =
+				Arrays.stream(recordComponents)
+				.map(f -> new String(f.name))
+				.reduce((s1, s2) -> { return s1 + ";" + s2;}) //$NON-NLS-1$
+				.orElse(Util.EMPTY_STRING);
+			int namesIndex = this.constantPool.literalIndex(names);
+			this.contents[localContentsOffset++] = (byte) (namesIndex >> 8);
+			this.contents[localContentsOffset++] = (byte) namesIndex;
+
+			if (recordComponents.length * 2 + localContentsOffset >= this.contents.length) {
+				resizeContents(recordComponents.length * 2);
+			}
+			for (FieldBinding field : recordComponents) {
+				int methodHandleIndex = this.constantPool.literalIndexForMethodHandleFieldRef(
+						ClassFileConstants.MethodHandleRefKindGetField,
+						recordName, field.name, field.type.signature());
+
+				this.contents[localContentsOffset++] = (byte) (methodHandleIndex >> 8);
+				this.contents[localContentsOffset++] = (byte) methodHandleIndex;
+			}
+		}
+		return localContentsOffset;
 	}
 	private int generateLineNumberAttribute() {
 		int localContentsOffset = this.contentsOffset;
@@ -5844,6 +6061,9 @@
 		if (this.bootstrapMethods != null) {
 			this.bootstrapMethods.clear();
 		}
+		if (this.recordBootstrapMethods != null) {
+			this.recordBootstrapMethods.clear();
+		}
 		this.missingTypes = null;
 		this.visitedTypes = null;
 	}
@@ -6039,23 +6259,32 @@
 
 	private TypeBinding getNewTypeBinding(char[] typeConstantPoolName, Scope scope) {
 		char[] typeName = typeConstantPoolName;
+		if (this.innerClassesBindings != null && isLikelyLocalTypeName(typeName)) {
+			// find local type in innerClassesBindings:
+			Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet();
+			for (TypeBinding binding : innerTypeBindings) {
+				if (CharOperation.equals(binding.constantPoolName(), typeName))
+					return binding;
+			}
+		}
 		TypeBinding type = (TypeBinding) scope.getTypeOrPackage(CharOperation.splitOn('/', typeName));
 		if (!type.isValidBinding()) {
 			ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type;
 			if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0) {
 				type = problemReferenceBinding.closestMatch();
-			} else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) {
-				// check local inner types to see if this is a anonymous type
-				Set<TypeBinding> innerTypeBindings = this.innerClassesBindings.keySet();
-				for (TypeBinding binding : innerTypeBindings) {
-					if (CharOperation.equals(binding.constantPoolName(), typeName)) {
-						type = binding;
-						break;
 					}
 				}
-			}
-		}
 		return type;
+			}
+
+	private boolean isLikelyLocalTypeName(char[] typeName) {
+		int dollarPos = CharOperation.lastIndexOf('$', typeName);
+		while (dollarPos != -1 && dollarPos+1 < typeName.length) {
+			if (Character.isDigit(typeName[dollarPos+1]))
+				return true; // name segment starts with a digit => likely a local type (but still "$0" etc. could be part of the source name)
+			dollarPos = CharOperation.lastIndexOf('$', typeName, 0, dollarPos-1);
+		}
+		return false;
 	}
 
 	private TypeBinding getANewArrayTypeBinding(char[] typeConstantPoolName, Scope scope) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
index b54b374..7e2ce21 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java
@@ -11,7 +11,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     Stephan Herrmann - contributions for 
+ *     Stephan Herrmann - contributions for
  *     							bug 337868 - [compiler][model] incomplete support for package-info.java when using SearchableEnvironment
  *     							bug 186342 - [compiler][null] Using annotations for null checking
  *******************************************************************************/
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java
index 66a6adb..422cc44 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -70,6 +70,7 @@
 				rightInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
 			}
 		}
+		this.left.updateFlowOnBooleanResult(rightInfo, true);
 		rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo);
 		if ((flowContext.tagBits & FlowContext.INSIDE_NEGATION) != 0)
 			flowContext.expireNullCheckedFieldInfo();
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 eb3f1ab..aae6a68 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -12,7 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Matt McCutchen - partial fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=122995
  *     Karen Moore - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=207411
- *     Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for 
+ *     Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for
  *     							bug 185682 - Increment/decrement operators mark local variables as read
  *     							bug 186342 - [compiler][null] Using annotations for null checking
  *								bug 365519 - editorial cleanup after bug 186342 and bug 365387
@@ -36,7 +36,7 @@
  *								Bug 441693 - [1.8][null] Bogus warning for type argument annotated with @NonNull
  *								Bug 434483 - [1.8][compiler][inference] Type inference not picked up with method reference
  *								Bug 446442 - [1.8] merge null annotations from super methods
- *								Bug 437072 - [compiler][null] Null analysis emits possibly incorrect warning for new int[][] despite @NonNullByDefault 
+ *								Bug 437072 - [compiler][null] Null analysis emits possibly incorrect warning for new int[][] despite @NonNullByDefault
  *     Jesper S Moller - Contributions for
  *								bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
  *								bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
@@ -93,12 +93,12 @@
 	public final static int Bit2 = 0x2;					// return type (operator) | name reference kind (name ref) | has local type (type, method, field decl) | if type elided (local)
 	public final static int Bit3 = 0x4;					// return type (operator) | name reference kind (name ref) | implicit this (this ref) | is argument(local)
 	public final static int Bit4 = 0x8;					// return type (operator) | first assignment to local (name ref,local decl) | undocumented empty block (block, type and method decl)
-	public final static int Bit5 = 0x10;					// value for return (expression) | has all method bodies (unit) | supertype ref (type ref) | resolved (field decl)
+	public final static int Bit5 = 0x10;					// value for return (expression) | has all method bodies (unit) | supertype ref (type ref) | resolved (field decl)| name ref (yield result value)
 	public final static int Bit6 = 0x20;					// depth (name ref, msg) | ignore need cast check (cast expression) | error in signature (method declaration/ initializer) | is recovered (annotation reference)
 	public final static int Bit7 = 0x40;					// depth (name ref, msg) | operator (operator) | need runtime checkcast (cast expression) | label used (labelStatement) | needFreeReturn (AbstractMethodDeclaration)
 	public final static int Bit8 = 0x80;					// depth (name ref, msg) | operator (operator) | unsafe cast (cast expression) | is default constructor (constructor declaration) | isElseStatementUnreachable (if statement)
 	public final static int Bit9 = 0x100;				// depth (name ref, msg) | operator (operator) | is local type (type decl) | isThenStatementUnreachable (if statement) | can be static
-	public final static int Bit10= 0x200;				// depth (name ref, msg) | operator (operator) | is anonymous type (type decl)
+	public final static int Bit10= 0x200;				// depth (name ref, msg) | operator (operator) | is anonymous type (type decl) | is implicit constructor (constructor)
 	public final static int Bit11 = 0x400;				// depth (name ref, msg) | operator (operator) | is member type (type decl)
 	public final static int Bit12 = 0x800;				// depth (name ref, msg) | operator (operator) | has abstract methods (type decl)
 	public final static int Bit13 = 0x1000;			// depth (name ref, msg) | is secondary type (type decl)
@@ -182,13 +182,14 @@
 	public static final int IsForeachElementVariable = Bit5;
 	public static final int ShadowsOuterLocal = Bit22;
 	public static final int IsAdditionalDeclarator = Bit23;
+	public static final int IsRecordComponent = Bit30;
 
 	// for name refs or local decls
 	public static final int FirstAssignmentToLocal = Bit4;
 
 	// for msg or field references
 	public static final int NeedReceiverGenericCast = Bit19;
-	
+
 	// for this reference
 	public static final int IsImplicitThis = Bit3;
 
@@ -196,8 +197,10 @@
 	public static final int DepthSHIFT = 5;	// Bit6 -> Bit13
 	public static final int DepthMASK = Bit6|Bit7|Bit8|Bit9|Bit10|Bit11|Bit12|Bit13; // 8 bits for actual depth value (max. 255)
 	public static final int IsCapturedOuterLocal = Bit20;
+	public static final int IsSecretYieldValueUsage = Bit5;
 
 	// for statements
+//	public static final int IsImplicit = Bit11; // record declaration
 	public static final int IsReachable = Bit32;
 	public static final int LabelUsed = Bit7;
 	public static final int DocumentedFallthrough = Bit30; // switch statement
@@ -235,10 +238,10 @@
 
 	// for all method/constructor invocations (msg, alloc, expl. constr call)
 	public static final int Unchecked = Bit17;
-	
+
 	// for javadoc - used to indicate whether the javadoc has to be resolved
 	public static final int ResolveJavadoc = Bit17;
-	
+
 	// for empty statement
 	public static final int IsUsefulEmptyStatement = Bit1;
 
@@ -255,6 +258,8 @@
 
 	// for constructor declaration
 	public static final int IsDefaultConstructor = Bit8;
+	public static final int IsCanonicalConstructor = Bit10; // record declaration
+	public static final int IsImplicit = Bit11; // record declaration / generated statements in compact constructor
 
 	// for compilation unit
 	public static final int HasAllMethodBodies = Bit5;
@@ -317,7 +322,7 @@
 
 	// for all declarations that can contain type references that have type annotations
 	public static final int HasTypeAnnotations = Bit21;
-	
+
 	// for type reference (diamond case) - Java 7
 	public static final int IsUnionType = Bit30;
 	// Used to tag ParameterizedSingleTypeReference or ParameterizedQualifiedTypeReference when they are
@@ -329,11 +334,12 @@
 	public static final int InsideExpressionStatement = Bit21;
 
 	// for annotation reference, signal if annotation was created from a default:
+	// also used for implicit method creation of records Java 14
 	public static final int IsSynthetic = ASTNode.Bit7;
-	
+
 	// for all reference context entries.
 	public static final int HasFunctionalInterfaceTypes = ASTNode.Bit22;
-	
+
 	public static final Argument [] NO_ARGUMENTS = new Argument [0];
 
 	public ASTNode() {
@@ -409,7 +415,7 @@
 					for (int i = lastIndex; i < argLength; i++) {
 						invocationStatus |= checkInvocationArgument(scope, arguments[i], parameterType, argumentTypes[i], originalRawParam);
 					}
-				} 
+				}
 				if (paramLength == argLength) { // 70056
 					int varargsIndex = paramLength - 1;
 					ArrayBinding varargsType = (ArrayBinding) params[varargsIndex];
@@ -449,7 +455,7 @@
 			if (scope.compilerOptions().reportUnavoidableGenericTypeProblems || receiver == null || !receiver.forcedToBeRaw(scope.referenceContext())) {
 				scope.problemReporter().unsafeRawInvocation((ASTNode)invocationSite, method);
 			}
-		} else if (rawOriginalGenericMethod != null 
+		} else if (rawOriginalGenericMethod != null
 				|| uncheckedBoundCheck
 				|| ((invocationStatus & INVOCATION_ARGUMENT_UNCHECKED) != 0)) {
 			if (method instanceof ParameterizedGenericMethodBinding) {
@@ -466,11 +472,11 @@
 	}
 
 	public final boolean isFieldUseDeprecated(FieldBinding field, Scope scope, int filteredBits) {
-		if ((this.bits & ASTNode.InsideJavadoc) == 0			// ignore references inside Javadoc comments 
+		if ((this.bits & ASTNode.InsideJavadoc) == 0			// ignore references inside Javadoc comments
 				&& (filteredBits & IsStrictlyAssigned) == 0 	// ignore write access
-				&& field.isOrEnclosedByPrivateType() 
-				&& !scope.isDefinedInField(field)) 				// ignore cases where field is used from inside itself 
-		{		
+				&& field.isOrEnclosedByPrivateType()
+				&& !scope.isDefinedInField(field)) 				// ignore cases where field is used from inside itself
+		{
 			if (((filteredBits & IsCompoundAssigned) != 0))
 				// used, but usage may not be relevant
 				field.original().compoundUseFlag++;
@@ -567,7 +573,7 @@
 
 		return false;
 	}
-	
+
 	public boolean isUnqualifiedSuper() {
 		return false;
 	}
@@ -673,7 +679,7 @@
 	 * After method lookup has produced 'methodBinding' but when poly expressions have been seen as arguments,
 	 * inspect the arguments to trigger another round of resolving with improved target types from the methods parameters.
 	 * If this resolving produces better types for any arguments, update the 'argumentTypes' array in-place as an
-	 * intended side effect that will feed better type information in checkInvocationArguments() and others. 
+	 * intended side effect that will feed better type information in checkInvocationArguments() and others.
 	 * @param invocation the outer invocation which is being resolved
 	 * @param method the method produced by lookup (possibly involving type inference).
 	 * @param argumentTypes the argument types as collected from first resolving the invocation arguments and as used for the method lookup.
@@ -700,7 +706,7 @@
 				continue; // not much we can do without a target type, assume it only happens after some resolve error
 			if (argumentTypes[i] != null && argumentTypes[i].isPolyType()) {
 				argument.setExpectedType(parameterType);
-				TypeBinding updatedArgumentType; 
+				TypeBinding updatedArgumentType;
 				if (argument instanceof LambdaExpression) {
 					LambdaExpression lambda = (LambdaExpression) argument;
 					// avoid complaining about non-kosher descriptor as secondary problem
@@ -748,7 +754,7 @@
 		if (recipient instanceof SourceTypeBinding)
 			((SourceTypeBinding) recipient).evaluateNullAnnotations();
 	}
-	
+
 	/**
 	 * Resolve annotations, and check duplicates, answers combined tagBits
 	 * for recognized standard annotations. Return null if nothing new is
@@ -893,9 +899,9 @@
 			}
 		}
 
-		/* See if the recipient is meta-annotated with @Repeatable and if so validate constraints. We can't do this during resolution of @Repeatable itself as @Target and 
+		/* See if the recipient is meta-annotated with @Repeatable and if so validate constraints. We can't do this during resolution of @Repeatable itself as @Target and
 		   @Retention etc could come later
-		*/   
+		*/
 		if (recipient != null && recipient.isTaggedRepeatable()) {
 			for (int i = 0; i < length; i++) {
 				Annotation annotation = sourceAnnotations[i];
@@ -904,7 +910,7 @@
 					annotation.checkRepeatableMetaAnnotation(scope);
 			}
 		}
-		
+
 		// check duplicate annotations
 		if (annotations != null && length > 1) {
 			AnnotationBinding[] distinctAnnotations = annotations; // only copy after 1st duplicate is detected
@@ -964,12 +970,12 @@
 			copySE8AnnotationsToType(scope, recipient, sourceAnnotations, false);
 		return annotations;
 	}
-	
+
 	/**	Resolve JSR308 annotations on a type reference, array creation expression or a wildcard. Type parameters go directly to the subroutine,
 	    By construction the bindings associated with QTR, PQTR etc get resolved first and then annotations for different levels get resolved
 	    and applied at one go. Likewise for multidimensional arrays.
-	    
-	    @Returns the annotated type binding. 
+
+	    @Returns the annotated type binding.
 	*/
 	public static TypeBinding resolveAnnotations(BlockScope scope, Annotation[][] sourceAnnotations, TypeBinding type) {
 		int levels = sourceAnnotations == null ? 0 : sourceAnnotations.length;
@@ -989,7 +995,7 @@
 	/**
 	 * "early" handling of NonNullByDefault because for local variables annotations are resolved after their type because of bug
 	 * 96991.
-	 * @param localDeclaration 
+	 * @param localDeclaration
 	 */
 	public static void handleNonNullByDefault(BlockScope scope, Annotation[] sourceAnnotations, LocalDeclaration localDeclaration) {
 		if (sourceAnnotations == null || sourceAnnotations.length == 0) {
@@ -1023,13 +1029,13 @@
 	}
 
 
-	
+
 	// When SE8 annotations feature in SE7 locations, they get attributed to the declared entity. Copy/move these to the type of the declared entity (field, local, argument etc.)
 	public static void copySE8AnnotationsToType(BlockScope scope, Binding recipient, Annotation[] annotations, boolean annotatingEnumerator) {
-		
+
 		if (annotations == null || annotations.length == 0 || recipient == null)
 			return;
-		
+
 		long recipientTargetMask = 0;
 		switch (recipient.kind()) {
 			case Binding.LOCAL:
@@ -1045,7 +1051,7 @@
 			default:
 				return;
 		}
-		
+
 		AnnotationBinding [] se8Annotations = null;
 		int se8count = 0;
 		long se8nullBits = 0;
@@ -1144,11 +1150,11 @@
 	}
 
 	private static TypeBinding mergeAnnotationsIntoType(BlockScope scope, AnnotationBinding[] se8Annotations, long se8nullBits, Annotation se8NullAnnotation,
-			TypeReference typeRef, TypeBinding existingType) 
+			TypeReference typeRef, TypeBinding existingType)
 	{
 		if (existingType == null || !existingType.isValidBinding()) return existingType;
 		TypeReference unionRef = typeRef.isUnionType() ? ((UnionTypeReference) typeRef).typeReferences[0] : null;
-		
+
 		// for arrays: @T X[] SE7 associates @T to the type, but in SE8 it affects the leaf component type
 		TypeBinding oldLeafType = (unionRef == null) ? existingType.leafComponentType() : unionRef.resolvedType;
 		if (se8nullBits != 0) {
@@ -1302,12 +1308,12 @@
 	public boolean checkingPotentialCompatibility() {
 		return false;
 	}
-	
+
 	public void acceptPotentiallyCompatibleMethods(MethodBinding [] methods) {
-		// Discard. Interested subclasses should override and grab these goodies. 
+		// Discard. Interested subclasses should override and grab these goodies.
 	}
 	// --- "default methods" for InvocationSite
-	
+
 	public int sourceStart() {
 		return this.sourceStart;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
index 17c903c..318593d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -77,9 +77,11 @@
 	public int bodyStart;
 	public int bodyEnd = -1;
 	public CompilationResult compilationResult;
+	public boolean containsSwitchWithTry = false;
 
 	AbstractMethodDeclaration(CompilationResult compilationResult){
 		this.compilationResult = compilationResult;
+		this.containsSwitchWithTry = false;
 	}
 
 	/*
@@ -345,8 +347,9 @@
 				}
 			}
 			if (this.statements != null) {
-				for (int i = 0, max = this.statements.length; i < max; i++)
-					this.statements[i].generateCode(this.scope, codeStream);
+				for (Statement stmt : this.statements) {
+					stmt.generateCode(this.scope, codeStream);
+				}
 			}
 			// if a problem got reported during code gen, then trigger problem method creation
 			if (this.ignoreFurtherInvestigation) {
@@ -454,6 +457,10 @@
 		return (this.modifiers & ClassFileConstants.AccNative) != 0;
 	}
 
+	public Argument getRecordComponent() {
+		return null;
+	}
+
 	public boolean isStatic() {
 
 		if (this.binding != null)
@@ -643,7 +650,8 @@
 
 		if (this.statements != null) {
 			for (int i = 0, length = this.statements.length; i < length; i++) {
-				this.statements[i].resolve(this.scope);
+ 				Statement stmt = this.statements[i];
+ 				stmt.resolve(this.scope);
 			}
 		} else if ((this.bits & UndocumentedEmptyBlock) != 0) {
 			if (!this.isConstructor() || this.arguments != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=319626
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
index b96a3a8..092bcc0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
@@ -1,6 +1,6 @@
 //AspectJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -536,12 +536,13 @@
  	}
 	if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) {
 		ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(this.binding, scope);
-		if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) {
+		if (scope.environment().usesNullTypeAnnotations()) {
 			if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) {
 				TypeVariableBinding[] typeVariables = this.binding.original().typeVariables();
 				for (int i = 0; i < this.typeArguments.length; i++)
 					this.typeArguments[i].checkNullConstraints(scope, (ParameterizedGenericMethodBinding) this.binding, typeVariables, i);
 			}
+			this.resolvedType = scope.environment().createAnnotatedType(this.resolvedType, new AnnotationBinding[] {scope.environment().getNonNullAnnotation()});
 }
 	}
 	if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8 &&
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 d26acfc..2ed99c8 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -24,7 +24,7 @@
  *								Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
  *								Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
  *								Bug 457210 - [1.8][compiler][null] Wrong Nullness errors given on full build build but not on incremental build?
- *								Bug 469584 - ClassCastException in Annotation.detectStandardAnnotation (320) 
+ *								Bug 469584 - ClassCastException in Annotation.detectStandardAnnotation (320)
  *        Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
  *                          Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work)
  *                          Bug 409517 - [1.8][compiler] Type annotation problems on more elaborate array references
@@ -55,28 +55,28 @@
  */
 @SuppressWarnings({"rawtypes", "unchecked"})
 public abstract class Annotation extends Expression {
-	
+
 	Annotation persistibleAnnotation = this;  // Emit this into class file, unless this is a repeating annotation, in which case package this into the designated container.
-	
+
 	/**
 	 * Return the location for the corresponding annotation inside the type reference, <code>null</code> if none.
 	 */
 	public static int[] getLocations(
 			final Expression reference,
 			final Annotation annotation) {
-	
+
 		class LocationCollector extends ASTVisitor {
 			Stack typePathEntries;
 			Annotation searchedAnnotation;
 			boolean continueSearch = true;
-			
+
 			public LocationCollector(Annotation currentAnnotation) {
 				this.typePathEntries = new Stack();
 				this.searchedAnnotation = currentAnnotation;
 			}
-			
+
 			private int[] computeNestingDepth(TypeReference typeReference) {
-				TypeBinding type = typeReference.resolvedType == null ? null : typeReference.resolvedType.leafComponentType(); 
+				TypeBinding type = typeReference.resolvedType == null ? null : typeReference.resolvedType.leafComponentType();
 				int[] nestingDepths = new int[typeReference.getAnnotatableLevels()];
 				if (type != null && type.isNestedType()) {
 					int depth = 0;
@@ -95,7 +95,7 @@
 				}
 				return nestingDepths;
 			}
-			
+
 
 			private void inspectAnnotations(Annotation [] annotations) {
 				for (int i = 0, length = annotations == null ? 0 : annotations.length; this.continueSearch && i < length; i++) {
@@ -112,7 +112,7 @@
 					this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY);
 				}
 			}
-			
+
 			private void inspectTypeArguments(TypeReference[] typeReferences) {
 				for (int i = 0, length = typeReferences == null ? 0 : typeReferences.length; this.continueSearch && i < length; i++) {
 					int size = this.typePathEntries.size();
@@ -122,7 +122,7 @@
 					this.typePathEntries.setSize(size);
 				}
 			}
-			
+
 			public boolean visit(TypeReference typeReference, BlockScope scope) {
 				if (this.continueSearch) {
 					inspectArrayDimensions(typeReference.getAnnotationsOnDimensions(), typeReference.dimensions());
@@ -144,18 +144,18 @@
 						}
 					}
 				}
-				return false; // if annotation is not found in the type reference, it must be one from SE7 location, typePathEntries captures the proper path entries for them. 
-			}	
+				return false; // if annotation is not found in the type reference, it must be one from SE7 location, typePathEntries captures the proper path entries for them.
+			}
 			@Override
 			public boolean visit(SingleTypeReference typeReference, BlockScope scope) {
 				return visit((TypeReference) typeReference, scope);
 			}
-			
+
 			@Override
 			public boolean visit(ArrayTypeReference typeReference, BlockScope scope) {
 				return visit((TypeReference) typeReference, scope);
 			}
-			
+
 			@Override
 			public boolean visit(ParameterizedSingleTypeReference typeReference, BlockScope scope) {
 				return visit((TypeReference) typeReference, scope);
@@ -165,17 +165,17 @@
 			public boolean visit(QualifiedTypeReference typeReference, BlockScope scope) {
 				return visit((TypeReference) typeReference, scope);
 			}
-			
+
 			@Override
 			public boolean visit(ArrayQualifiedTypeReference typeReference, BlockScope scope) {
 				return visit((TypeReference) typeReference, scope);
 			}
-			
+
 			@Override
 			public boolean visit(ParameterizedQualifiedTypeReference typeReference, BlockScope scope) {
 				return visit((TypeReference) typeReference, scope);
 			}
-			
+
 			@Override
 			public boolean visit(Wildcard typeReference, BlockScope scope) {
 				visit((TypeReference) typeReference, scope);
@@ -203,7 +203,7 @@
 				}
 				return false;
 			}
-						
+
 			@Override
 			public String toString() {
 				StringBuffer buffer = new StringBuffer();
@@ -245,7 +245,7 @@
 	static final int[] TYPE_PATH_ELEMENT_ARRAY = new int[]{0,0};
 	static final int[] TYPE_PATH_INNER_TYPE = new int[]{1,0};
 	static final int[] TYPE_PATH_ANNOTATION_ON_WILDCARD_BOUND = new int[]{2,0};
-	
+
 	public int declarationSourceEnd;
 	public Binding recipient;
 
@@ -307,6 +307,10 @@
 				else if (CharOperation.equals(elementName, TypeConstants.UPPER_PACKAGE))
 					return TagBits.AnnotationForPackage;
 				break;
+			case 'R' :
+				if (CharOperation.equals(elementName, TypeConstants.UPPER_RECORD_COMPONENT))
+					return TagBits.AnnotationForRecordComponent;
+				break;
 			case 'T' :
 				if (CharOperation.equals(elementName, TypeConstants.TYPE))
 					return TagBits.AnnotationForType;
@@ -419,7 +423,7 @@
 		} else if (annotationType.hasNullBit(TypeIds.BitNonNullByDefaultAnnotation)) {
 			tagBits |= determineNonNullByDefaultTagBits(annotationType, valueAttribute);
 		}
-		
+
 		return tagBits;
 	}
 
@@ -454,7 +458,7 @@
 	/**
 	 * Convert the value() attribute of @NonNullByDefault into a bitvector a la {@link Binding#NullnessDefaultMASK}.
 	 * This method understands value encodings from source and binary types.
-	 * 
+	 *
 	 * <b>pre:</b> null annotation analysis is enabled
 	 */
 	public static int nullLocationBitsFromAnnotationValue(Object value) {
@@ -515,7 +519,7 @@
 		}
 		return 0;
 	}
-	
+
 	public static int nullLocationBitsFromElementTypeAnnotationValue(Object value) {
 		if (value instanceof Object[]) {
 			if (((Object[]) value).length == 0) {					// ({})
@@ -559,7 +563,7 @@
 		return 0;
 	}
 
-	
+
 	static String getRetentionName(long tagBits) {
 		if ((tagBits & TagBits.AnnotationRuntimeRetention) == TagBits.AnnotationRuntimeRetention) {
 			// TagBits.AnnotationRuntimeRetention combines both TagBits.AnnotationClassRetention & TagBits.AnnotationSourceRetention
@@ -578,22 +582,22 @@
 	}
 
 	public void checkRepeatableMetaAnnotation(BlockScope scope) {
-		
+
 		// `this' is the @Repeatable meta annotation, its recipient is the *repeatable* annotation type - we are at the declaration site, not the repeating use site.
-		
+
 		ReferenceBinding repeatableAnnotationType = (ReferenceBinding) this.recipient; // know it to be an annotation type. On target miss we don't get here
-		
+
 		MemberValuePair[] valuePairs = this.memberValuePairs();
 		if (valuePairs == null || valuePairs.length != 1)
 			return;
-		
+
 		Object value = valuePairs[0].compilerElementPair.value;
 		if (!(value instanceof ReferenceBinding))
 			return; // Has deeper problems, will bark elsewhere.
 		ReferenceBinding containerAnnotationType = (ReferenceBinding) value;
 		if (!containerAnnotationType.isAnnotationType())
 			return; // Has deeper problems, will bark elsewhere.
-		
+
 		repeatableAnnotationType.setContainerAnnotationType(containerAnnotationType); // For now. May be reset later to PRB in case of problems.
 		checkContainerAnnotationType(valuePairs[0], scope, containerAnnotationType, repeatableAnnotationType, false); // false => not use site, i.e declaration site error reporting requested.
 	}
@@ -626,34 +630,34 @@
 
 		if (useSite)
 			checkContainingAnnotationTargetAtUse((Annotation) culpritNode, scope, containerAnnotationType, repeatableAnnotationType);
-		else 
+		else
 			checkContainerAnnotationTypeTarget(culpritNode, scope, containerAnnotationType, repeatableAnnotationType);
-		
+
 		long annotationTypeBits = getAnnotationRetention(repeatableAnnotationType);
-		long containerTypeBits = getAnnotationRetention(containerAnnotationType); 
+		long containerTypeBits = getAnnotationRetention(containerAnnotationType);
 		// Due to clever layout of the bits, we can compare the absolute value directly
 		if (containerTypeBits < annotationTypeBits) {
 			repeatableAnnotationType.tagAsHavingDefectiveContainerType();
 			scope.problemReporter().containerAnnotationTypeHasShorterRetention(culpritNode, repeatableAnnotationType, getRetentionName(annotationTypeBits), containerAnnotationType, getRetentionName(containerTypeBits));
 		}
-		
+
 		if ((repeatableAnnotationType.getAnnotationTagBits() & TagBits.AnnotationDocumented) != 0 && (containerAnnotationType.getAnnotationTagBits() & TagBits.AnnotationDocumented) == 0) {
 			repeatableAnnotationType.tagAsHavingDefectiveContainerType();
 			scope.problemReporter().repeatableAnnotationTypeIsDocumented(culpritNode, repeatableAnnotationType, containerAnnotationType);
 		}
-		
+
 		if ((repeatableAnnotationType.getAnnotationTagBits() & TagBits.AnnotationInherited) != 0 && (containerAnnotationType.getAnnotationTagBits() & TagBits.AnnotationInherited) == 0) {
 			repeatableAnnotationType.tagAsHavingDefectiveContainerType();
 			scope.problemReporter().repeatableAnnotationTypeIsInherited(culpritNode, repeatableAnnotationType, containerAnnotationType);
 		}
 	}
-	
+
 	// This is for error reporting for bad targets at annotation type declaration site (as opposed to the repeat site)
 	private static void checkContainerAnnotationTypeTarget(ASTNode culpritNode, Scope scope, ReferenceBinding containerType, ReferenceBinding repeatableAnnotationType) {
 		long tagBits = repeatableAnnotationType.getAnnotationTagBits();
 		if ((tagBits & TagBits.AnnotationTargetMASK) == 0)
 			tagBits = TagBits.SE7AnnotationTargetMASK; // absence of @Target meta-annotation implies all SE7 targets not all targets.
-		
+
 		long containerAnnotationTypeTypeTagBits = containerType.getAnnotationTagBits();
 		if ((containerAnnotationTypeTypeTagBits & TagBits.AnnotationTargetMASK) == 0)
 			containerAnnotationTypeTypeTagBits = TagBits.SE7AnnotationTargetMASK;
@@ -708,13 +712,14 @@
 			builder.check(TagBits.AnnotationForTypeParameter, TypeConstants.TYPE_PARAMETER_TARGET);
 			builder.check(TagBits.AnnotationForTypeUse, TypeConstants.TYPE_USE_TARGET);
 			builder.check(TagBits.AnnotationForModule, TypeConstants.UPPER_MODULE);
+			builder.check(TagBits.AnnotationForRecordComponent, TypeConstants.UPPER_RECORD_COMPONENT);
 			if (builder.hasError()) {
 				repeatableAnnotationType.tagAsHavingDefectiveContainerType();
 				scope.problemReporter().repeatableAnnotationTypeTargetMismatch(culpritNode, repeatableAnnotationType, containerType, builder.toString());
 			}
 		}
 	}
-	
+
 	// This is for error reporting for bad targets at the repeated annotation use site (as opposed to repeatable annotation type declaration site) - Leads to better message.
 	public static void checkContainingAnnotationTargetAtUse(Annotation repeatingAnnotation, BlockScope scope, TypeBinding containerAnnotationType, TypeBinding repeatingAnnotationType) {
 		// check (meta)target compatibility
@@ -740,7 +745,7 @@
 
 		// we need to filter out only "pure" type use and type parameter annotations, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=392119
 		if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) {
-			if ((metaTagBits & TagBits.SE7AnnotationTargetMASK) == 0) {  // not a hybrid target. 
+			if ((metaTagBits & TagBits.SE7AnnotationTargetMASK) == 0) {  // not a hybrid target.
 				return false;
 			}
 		}
@@ -758,12 +763,11 @@
 		}
 		long metaTagBits = annotationBinding.getAnnotationTagBits(); // could be forward reference
 
-		if ((metaTagBits & (TagBits.AnnotationTargetMASK)) == 0) { // explicit target required for JSR308 style annotations.
-			return false;
-		}
-		if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) == 0) {
-			return false;
-		}
+		if ((metaTagBits & (TagBits.AnnotationTargetMASK)) != 0) {
+			if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) == 0) {
+				return false;
+			}
+		} // else: no-@Target always applicable
 
 		if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
 			return true; // by default the retention is CLASS
@@ -778,12 +782,11 @@
 		}
 		long metaTagBits = annotationBinding.getAnnotationTagBits();
 
-		if ((metaTagBits & (TagBits.AnnotationTargetMASK)) == 0) { // explicit target required for JSR308 style annotations.
-			return false;
-		}
-		if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) == 0) {
-			return false;
-		}
+		if ((metaTagBits & (TagBits.AnnotationTargetMASK)) != 0) {
+			if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) == 0) {
+				return false;
+			}
+		} // else: no-@Target always applicable
 		if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0)
 			return false; // by default the retention is CLASS
 
@@ -1059,10 +1062,10 @@
 							LocalDeclaration localDeclaration = variable.declaration;
 							recordSuppressWarnings(scope, localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd, compilerOptions.suppressWarnings);
 						}
-						// note: defaultNullness for local declarations has been already been handled earlier by handleNonNullByDefault() 
+						// note: defaultNullness for local declarations has been already been handled earlier by handleNonNullByDefault()
 						break;
 				}
-			} 
+			}
 			if (kind == Binding.TYPE) {
 				SourceTypeBinding sourceType = (SourceTypeBinding) this.recipient;
 				if (CharOperation.equals(sourceType.sourceName, TypeConstants.PACKAGE_INFO_NAME))
@@ -1087,7 +1090,7 @@
 		}
 
 		ReferenceBinding annotationType = (ReferenceBinding) typeBinding;
-		
+
 		if (!annotationType.hasNullBit(TypeIds.BitNonNullByDefaultAnnotation)) {
 			return 0;
 		}
@@ -1118,11 +1121,11 @@
 		long tagBits = determineNonNullByDefaultTagBits(annotationType, valueAttribute);
 		return (int) (tagBits & Binding.NullnessDefaultMASK);
 	}
-	
+
 	public enum AnnotationTargetAllowed {
 		YES, TYPE_ANNOTATION_ON_QUALIFIED_NAME, NO;
 	}
-	
+
 	private static AnnotationTargetAllowed isAnnotationTargetAllowed(Binding recipient, BlockScope scope, TypeBinding annotationType, int kind, long metaTagBits) {
 		switch (kind) {
 			case Binding.PACKAGE :
@@ -1176,6 +1179,12 @@
 			case Binding.FIELD :
 				if ((metaTagBits & TagBits.AnnotationForField) != 0) {
 					return AnnotationTargetAllowed.YES;
+				} else if (((FieldBinding) recipient).isRecordComponent()){
+					long recordComponentMask = TagBits.AnnotationForRecordComponent |
+							TagBits.AnnotationForMethod |
+							TagBits.AnnotationForParameter |
+							TagBits.AnnotationForTypeUse;
+					return (metaTagBits & recordComponentMask) != 0 ? AnnotationTargetAllowed.YES : AnnotationTargetAllowed.NO;
 				} else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
 					FieldBinding sourceField = (FieldBinding) recipient;
 					SourceTypeBinding sourceType = (SourceTypeBinding) sourceField.declaringClass;
@@ -1238,12 +1247,7 @@
 
 		long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference
 		if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) {
-			// does not specify any target restriction - all locations supported in Java 7 and before are possible
-			// TBD - revisit for modules - as per 9.6.4.1, annotation without target is applicable for module declaration
-			// which is listed as a declaration context, but javac does not allow this
-			if (kind == Binding.TYPE_PARAMETER || kind == Binding.TYPE_USE) {
-				scope.problemReporter().explitAnnotationTargetRequired(annotation);
-			}
+			// does not specify any target restriction - all locations are possible
 			return AnnotationTargetAllowed.YES;
 		}
 
@@ -1274,7 +1278,7 @@
 	AnnotationTargetAllowed annotationTargetAllowed = isAnnotationTargetAllowed(annotation, scope, annotationType, kind);
 	if (annotationTargetAllowed != AnnotationTargetAllowed.YES) {
 		if(annotationTargetAllowed == AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME) {
-			scope.problemReporter().typeAnnotationAtQualifiedName(annotation);			
+			scope.problemReporter().typeAnnotationAtQualifiedName(annotation);
 		} else {
 			scope.problemReporter().disallowedTargetForAnnotation(annotation);
 		}
@@ -1293,15 +1297,15 @@
 		// Fail fast if the repeating annotation type can't be a container, anyway
 		MethodBinding[] valueMethods = repeatedAnnotationType.getMethods(TypeConstants.VALUE);
 		if (valueMethods.length != 1) return; // No violations possible
-		
+
 		TypeBinding methodReturnType = valueMethods[0].returnType;
-		// value must be an array 
+		// value must be an array
 		if (! methodReturnType.isArrayType() || methodReturnType.dimensions() != 1) return;
-		
+
 		ArrayBinding array = (ArrayBinding) methodReturnType;
 		TypeBinding elementsType = array.elementsType();
 		if (! elementsType.isRepeatableAnnotationType()) return; // Can't be a problem, then
-		
+
 		for (int i= 0; i < sourceAnnotations.length; ++i) {
 			Annotation annotation = sourceAnnotations[i];
 			if (TypeBinding.equalsEquals(elementsType, annotation.resolvedType)) {
@@ -1322,7 +1326,7 @@
 		}
 		return true;
 	}
-	
+
 	// Complain if an attempt to annotate the enclosing type of a static member type is being made.
 	public static void isTypeUseCompatible(TypeReference reference, Scope scope, Annotation[] annotations) {
 		if (annotations == null || reference == null || reference.getAnnotatableLevels() == 1)
@@ -1369,7 +1373,7 @@
 	public Annotation getPersistibleAnnotation() {
 		return this.persistibleAnnotation;      // will be this for non-repeating annotation, the container for the first of the repeating ones and null for the followers.
 	}
-	
+
 	public void setPersistibleAnnotation(ContainerAnnotation container) {
 		this.persistibleAnnotation = container; // will be a legitimate container for the first of the repeating ones and null for the followers.
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AnnotationMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AnnotationMethodDeclaration.java
index 0189469..b75eae8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AnnotationMethodDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AnnotationMethodDeclaration.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
index 093233e..707f99c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Argument.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -58,7 +58,7 @@
 		}
 		this.bits |= (IsLocalDeclarationReachable | IsArgument | IsTypeElided);
 	}
-	
+
 	@Override
 	public boolean isRecoveredFromLoneIdentifier() {
 		return false;
@@ -66,7 +66,7 @@
 
 	public TypeBinding createBinding(MethodScope scope, TypeBinding typeBinding) {
 		if (this.binding == null) {
-			// for default constructors and fake implementation of abstract methods 
+			// for default constructors and fake implementation of abstract methods
 			this.binding = new LocalVariableBinding(this, typeBinding, this.modifiers, scope);
 		} else if (!this.binding.type.isValidBinding()) {
 			AbstractMethodDeclaration methodDecl = scope.referenceMethod();
@@ -98,6 +98,8 @@
 			if (localExists && this.hiddenVariableDepth == 0) {
 				if ((this.bits & ASTNode.ShadowsOuterLocal) != 0 && scope.isLambdaSubscope()) {
 					scope.problemReporter().lambdaRedeclaresArgument(this);
+				} else if ((this.bits & ASTNode.IsRecordComponent) != 0) {
+					scope.problemReporter().recordDuplicateComponent(this);
 				} else {
 					scope.problemReporter().redefineArgument(this);
 				}
@@ -137,14 +139,14 @@
 	public boolean isVarArgs() {
 		return this.type != null &&  (this.type.bits & IsVarArgs) != 0;
 	}
-	
+
 	public boolean hasElidedType() {
 		return (this.bits & IsTypeElided) != 0;
 	}
 
 	public boolean hasNullTypeAnnotation(AnnotationPosition position) {
 		// parser associates SE8 annotations to the declaration
-		return TypeReference.containsNullAnnotation(this.annotations) || 
+		return TypeReference.containsNullAnnotation(this.annotations) ||
 				(this.type != null && this.type.hasNullTypeAnnotation(position)); // just in case
 	}
 
@@ -211,7 +213,7 @@
 				scope.problemReporter().localVariableHiding(this, existingVariable, false);
 			}
 		}
-		
+
 		if ((this.type.bits & ASTNode.IsUnionType) != 0) {
 			this.binding = new CatchParameterBinding(this, exceptionType, this.modifiers | ClassFileConstants.AccFinal, false); // argument decl, but local var  (where isArgument = false)
 			this.binding.tagBits |= TagBits.MultiCatchParameter;
@@ -220,7 +222,7 @@
 		}
 		resolveAnnotations(scope, this.annotations, this.binding, true);
 		Annotation.isTypeUseCompatible(this.type, scope, this.annotations);
-		if (scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled && 
+		if (scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled &&
 				(this.type.hasNullTypeAnnotation(AnnotationPosition.ANY) || TypeReference.containsNullAnnotation(this.annotations)))
 		{
 			scope.problemReporter().nullAnnotationUnsupportedLocation(this.type);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java
index ccee99f..dd48533 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java
@@ -10,7 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     Stephan Herrmann - Contributions for 
+ *     Stephan Herrmann - Contributions for
  *								bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK
  *								bug 370639 - [compiler][resource] restore the default for resource leak warnings
  *								bug 388996 - [compiler][resource] Incorrect 'potential resource leak'
@@ -69,7 +69,7 @@
 	public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
 		generateCode(null, null, currentScope, codeStream, valueRequired);
 	}
-	
+
 	/**
 	 * Code generation for a array initializer
 	 */
@@ -198,7 +198,7 @@
 				if (TypeBinding.notEquals(elementType, expressionType)) // must call before computeConversion() and typeMismatchError()
 					scope.compilationUnitScope().recordTypeConversion(elementType, expressionType);
 
-				if (expression.isConstantValueOfTypeAssignableToType(expressionType, elementType) 
+				if (expression.isConstantValueOfTypeAssignableToType(expressionType, elementType)
 						|| expressionType.isCompatibleWith(elementType)) {
 					expression.computeConversion(scope, elementType, expressionType);
 				} else if (isBoxingCompatible(expressionType, elementType, expression, scope)) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java
index 43795dc..ffe0fff 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java
@@ -29,7 +29,7 @@
 
 		super( sources , poss);
 		this.dimensions = dim ;
-		this.annotationsOnDimensions = null; 
+		this.annotationsOnDimensions = null;
 	}
 
 	public ArrayQualifiedTypeReference(char[][] sources, int dim, Annotation[][] annotationsOnDimensions, long[] poss) {
@@ -44,7 +44,7 @@
 
 		return this.dimensions;
 	}
-	
+
 	@Override
 	public int extraDimensions() {
 		return this.extendedDimensions;
@@ -63,7 +63,7 @@
 		System.arraycopy(this.annotationsOnDimensions, 0, externalAnnotations, this.extendedDimensions, baseDimensions);
 		return externalAnnotations;
 	}
-	
+
 	@Override
 	public void setAnnotationsOnDimensions(Annotation [][] annotationsOnDimensions) {
 		this.annotationsOnDimensions = annotationsOnDimensions;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java
index 37773b3..9fe6a31 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java
@@ -65,7 +65,7 @@
 
 		return this.dimensions;
 	}
-	
+
 	@Override
 	public int extraDimensions() {
 		return this.extendedDimensions;
@@ -84,7 +84,7 @@
 		System.arraycopy(this.annotationsOnDimensions, 0, externalAnnotations, this.extendedDimensions, baseDimensions);
 		return externalAnnotations;
 	}
-	
+
 	@Override
 	public void setAnnotationsOnDimensions(Annotation [][] annotationsOnDimensions) {
 		this.annotationsOnDimensions = annotationsOnDimensions;
@@ -268,7 +268,7 @@
 		}
 		return scope.environment().createAnnotatedType(typeBinding, newAnnots);
 	}
-	
+
 	@Override
 	public boolean hasNullTypeAnnotation(AnnotationPosition position) {
 		switch (position) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
index 8afbaaa..4dfb485 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java
@@ -65,7 +65,7 @@
 // just a local variable.
 	LocalVariableBinding local = this.lhs.localVariableBinding();
 	this.expression.checkNPEbyUnboxing(currentScope, flowContext, flowInfo);
-	
+
 	FlowInfo preInitInfo = null;
 	CompilerOptions compilerOptions = currentScope.compilerOptions();
 	boolean shouldAnalyseResource = local != null
@@ -78,7 +78,7 @@
 		// analysis of resource leaks needs additional context while analyzing the RHS:
 		FakedTrackingVariable.preConnectTrackerAcrossAssignment(this, local, this.expression, flowInfo);
 	}
-	
+
 	flowInfo = ((Reference) this.lhs)
 		.analyseAssignment(currentScope, flowContext, flowInfo, this, false)
 		.unconditionalInits();
@@ -208,7 +208,7 @@
 		this.resolvedType = lhsType.capture(scope, this.lhs.sourceStart, this.lhs.sourceEnd); // make it unique, `this' shares source end with 'this.expression'.
 	}
 	LocalVariableBinding localVariableBinding = this.lhs.localVariableBinding();
-	if (localVariableBinding != null && (localVariableBinding.isCatchParameter() || localVariableBinding.isParameter())) { 
+	if (localVariableBinding != null && (localVariableBinding.isCatchParameter() || localVariableBinding.isParameter())) {
 		localVariableBinding.tagBits &= ~TagBits.IsEffectivelyFinal;  // as it is already definitely assigned, we can conclude already. Also note: catch parameter cannot be compound assigned.
 	}
 	TypeBinding rhsType = this.expression.resolveType(scope);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java
index c0c41ae..4a38f32 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -90,6 +90,15 @@
 	}
 }
 
+@Override
+protected void updateFlowOnBooleanResult(FlowInfo flowInfo, boolean result) {
+	int operator = (this.bits & OperatorMASK) >> OperatorSHIFT;
+	if (result ? operator == AND_AND : operator == OR_OR) {
+		this.left.updateFlowOnBooleanResult(flowInfo, result);
+		this.right.updateFlowOnBooleanResult(flowInfo, result);
+	}
+}
+
 public void computeConstant(BlockScope scope, int leftId, int rightId) {
 	//compute the constant when valid
 	if ((this.left.constant != Constant.NotAConstant)
@@ -1803,6 +1812,15 @@
 }
 
 @Override
+public void initializePatternVariables(BlockScope scope, CodeStream codeStream) {
+	this.left.initializePatternVariables(scope, codeStream);
+	this.right.initializePatternVariables(scope, codeStream);
+}
+@Override
+public boolean containsPatternVariable() {
+	return this.left.containsPatternVariable() || this.right.containsPatternVariable();
+}
+@Override
 public TypeBinding resolveType(BlockScope scope) {
 	// keep implementation in sync with CombinedBinaryExpression#resolveType
 	// and nonRecursiveResolveTypeUpwards
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
index 8ae3201..70ee4f9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -23,6 +23,7 @@
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.codegen.*;
 import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.lookup.*;
 
 public class Block extends Statement {
@@ -41,7 +42,8 @@
 	// empty block
 	if (this.statements == null)	return flowInfo;
 	int complaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
-	boolean enableSyntacticNullAnalysisForFields = currentScope.compilerOptions().enableSyntacticNullAnalysisForFields;
+	CompilerOptions compilerOptions = currentScope.compilerOptions();
+	boolean enableSyntacticNullAnalysisForFields = compilerOptions.enableSyntacticNullAnalysisForFields;
 	for (int i = 0, max = this.statements.length; i < max; i++) {
 		Statement stat = this.statements[i];
 		if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) {
@@ -52,6 +54,9 @@
 		if (enableSyntacticNullAnalysisForFields) {
 			flowContext.expireNullCheckedFieldInfo();
 		}
+		if (compilerOptions.analyseResourceLeaks) {
+			FakedTrackingVariable.cleanUpUnassigned(this.scope, stat, flowInfo);
+		}
 	}
 	if (this.scope != currentScope) {
 		// if block is tracking any resources other than the enclosing 'currentScope', analyse them now:
@@ -79,8 +84,8 @@
 	}
 	int pc = codeStream.position;
 	if (this.statements != null) {
-		for (int i = 0, max = this.statements.length; i < max; i++) {
-			this.statements[i].generateCode(this.scope, codeStream);
+		for (Statement stmt : this.statements) {
+			stmt.generateCode(this.scope, codeStream);
 		}
 	} // for local variable debug attributes
 	if (this.scope != currentScope) { // was really associated with its own scope
@@ -122,7 +127,8 @@
 				? upperScope
 				: new BlockScope(upperScope, this.explicitDeclarations);
 		for (int i = 0, length = this.statements.length; i < length; i++) {
-			this.statements[i].resolve(this.scope);
+			final Statement stmt = this.statements[i];
+			stmt.resolve(this.scope);
 		}
 	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java
index 33df5a7..62904f9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java
@@ -38,6 +38,12 @@
 protected void adjustStackSize(BlockScope currentScope, CodeStream codeStream) {
 	// do nothing here
 }
+protected void setSubroutineSwitchExpression(SubRoutineStatement sub) {
+	// Do nothing
+}
+protected void restartExceptionLabels(CodeStream codeStream) {
+	// do nothing
+}
 /**
  * Branch code generation
  *
@@ -56,7 +62,10 @@
 	if (this.subroutines != null){
 		for (int i = 0, max = this.subroutines.length; i < max; i++){
 			SubRoutineStatement sub = this.subroutines[i];
+			SwitchExpression se = sub.getSwitchExpression();
+			setSubroutineSwitchExpression(sub);
 			boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel, this.initStateIndex, null);
+			sub.setSwitchExpression(se);
 			if (didEscape) {
 					codeStream.recordPositionsFrom(pc, this.sourceStart);
 					SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream);
@@ -64,10 +73,12 @@
 						codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex);
 						codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex);
 					}
+					restartExceptionLabels(codeStream);
 					return;
 			}
 		}
 	}
+//	checkAndLoadSyntheticVars(codeStream);
 	codeStream.goto_(this.targetLabel);
 	adjustStackSize(currentScope, codeStream);
 	codeStream.recordPositionsFrom(pc, this.sourceStart);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
index bada77a..9853097 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java
@@ -64,7 +64,7 @@
 private void analyseConstantExpression(
 		BlockScope currentScope,
 		FlowContext flowContext,
-		FlowInfo flowInfo, 
+		FlowInfo flowInfo,
 		Expression e) {
 	if (e.constant == Constant.NotAConstant
 			&& !e.resolvedType.isEnum()) {
@@ -171,12 +171,12 @@
 	}
 	return Constant.NotAConstantList;
 }
-public Constant resolveConstantExpression(BlockScope scope, 
-											TypeBinding caseType, 
-											TypeBinding switchExpressionType, 
-											SwitchStatement switchStatement, 
+public Constant resolveConstantExpression(BlockScope scope,
+											TypeBinding caseType,
+											TypeBinding switchExpressionType,
+											SwitchStatement switchStatement,
 											Expression expression) {
-	
+
 	if (expression.isConstantValueOfTypeAssignableToType(caseType, switchExpressionType)
 			|| caseType.isCompatibleWith(switchExpressionType)) {
 		if (caseType.isEnum()) {
@@ -216,7 +216,7 @@
 		} else {
 			if (this.constantExpression != null) this.constantExpression.traverse(visitor, blockScope);
 		}
-		
+
 	}
 	visitor.endVisit(this, blockScope);
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
index bf216e5..aad157f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -116,13 +116,31 @@
 
 	CastExpression nestedCast = (CastExpression) enclosingCast.expression;
 	if ((nestedCast.bits & ASTNode.UnnecessaryCast) == 0) return;
+	if (nestedCast.losesPrecision(scope)) return;
 	// check if could cast directly to enclosing cast type, without intermediate type cast
 	CastExpression alternateCast = new CastExpression(null, enclosingCast.type);
 	alternateCast.resolvedType = enclosingCast.resolvedType;
-	if (!alternateCast.checkCastTypesCompatibility(scope, enclosingCast.resolvedType, nestedCast.expression.resolvedType, null /* no expr to avoid side-effects*/)) return;
+	if (!alternateCast.checkCastTypesCompatibility(scope, enclosingCast.resolvedType, nestedCast.expression.resolvedType, null /* no expr to avoid side-effects*/, true)) return;
 	scope.problemReporter().unnecessaryCast(nestedCast);
 }
 
+private boolean losesPrecision(Scope scope) {
+	// implements the following from JLS §5.1.2:
+	// "A widening primitive conversion from int to float, or from long to float, or from long to double, may result in loss of precision [...]"
+	// (extended to boxed types)
+	TypeBinding exprType = this.expression.resolvedType;
+	if (exprType.isBoxedPrimitiveType())
+		exprType = scope.environment().computeBoxingType(exprType);
+	switch (this.resolvedType.id) {
+		case TypeIds.T_JavaLangFloat:
+		case TypeIds.T_float: 	// (float)myInt , (float)myLong need rounding
+			return exprType.id == TypeIds.T_int || exprType.id == TypeIds.T_long;
+		case TypeIds.T_JavaLangDouble:
+		case TypeIds.T_double:	// (double)myLong needs rounding
+			return exprType.id == TypeIds.T_long;
+	}
+	return false;
+}
 
 /**
  * Casting an enclosing instance will considered as useful if removing it would actually bind to a different type
@@ -214,6 +232,7 @@
 public static void checkNeedForArgumentCasts(BlockScope scope, int operator, int operatorSignature, Expression left, int leftTypeId, boolean leftIsCast, Expression right, int rightTypeId, boolean rightIsCast) {
 	if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return;
 
+	boolean useAutoBoxing = operator != OperatorIds.EQUAL_EQUAL && operator != OperatorIds.NOT_EQUAL;
 	// check need for left operand cast
 	int alternateLeftTypeId = leftTypeId;
 	if (leftIsCast) {
@@ -223,7 +242,10 @@
 		} else  {
 			TypeBinding alternateLeftType = ((CastExpression)left).expression.resolvedType;
 			if (alternateLeftType == null) return; // cannot do better
-			if ((alternateLeftTypeId = alternateLeftType.id) == leftTypeId || scope.environment().computeBoxingType(alternateLeftType).id == leftTypeId) { // obvious identity cast
+			if ((alternateLeftTypeId = alternateLeftType.id) == leftTypeId
+					|| (useAutoBoxing
+							? scope.environment().computeBoxingType(alternateLeftType).id == leftTypeId
+							: TypeBinding.equalsEquals(alternateLeftType, left.resolvedType))) { // obvious identity cast
 				scope.problemReporter().unnecessaryCast((CastExpression)left);
 				leftIsCast = false;
 			} else if (alternateLeftTypeId == TypeIds.T_null) {
@@ -241,7 +263,10 @@
 		} else {
 			TypeBinding alternateRightType = ((CastExpression)right).expression.resolvedType;
 			if (alternateRightType == null) return; // cannot do better
-			if ((alternateRightTypeId = alternateRightType.id) == rightTypeId || scope.environment().computeBoxingType(alternateRightType).id == rightTypeId) { // obvious identity cast
+			if ((alternateRightTypeId = alternateRightType.id) == rightTypeId
+					|| (useAutoBoxing
+							? scope.environment().computeBoxingType(alternateRightType).id == rightTypeId
+							: TypeBinding.equalsEquals(alternateRightType, right.resolvedType))) { // obvious identity cast
 				scope.problemReporter().unnecessaryCast((CastExpression)right);
 				rightIsCast = false;
 			} else if (alternateRightTypeId == TypeIds.T_null) {
@@ -463,7 +488,7 @@
 		case Binding.TYPE_PARAMETER :
 			this.bits |= ASTNode.UnsafeCast;
 			return true;
-//		(disabled) https://bugs.eclipse.org/bugs/show_bug.cgi?id=240807			
+//		(disabled) https://bugs.eclipse.org/bugs/show_bug.cgi?id=240807
 //		case Binding.TYPE :
 //			if (isNarrowing && match == null && expressionType.isParameterizedType()) {
 //				this.bits |= ASTNode.UnsafeCast;
@@ -615,7 +640,7 @@
 					&& expressionType.isProvablyDistinct(this.instanceofType)) {
 				this.bits |= ASTNode.DisableUnnecessaryCastCheck;
 			}
-			boolean isLegal = checkCastTypesCompatibility(scope, castType, expressionType, this.expression);
+			boolean isLegal = checkCastTypesCompatibility(scope, castType, expressionType, this.expression, true);
 			if (isLegal) {
 				this.expression.computeConversion(scope, castType, expressionType);
 				if ((this.bits & ASTNode.UnsafeCast) != 0) { // unsafe cast
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java
index ef62313..6d1846b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java
@@ -20,9 +20,9 @@
 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
 
 public class CharLiteral extends NumberLiteral {
-	
+
 	char value;
-	
+
 public CharLiteral(char[] token, int s, int e) {
 	super(token, s, e);
 	computeValue();
@@ -44,6 +44,9 @@
 		return;
 	char digit;
 	switch (digit = this.source[2]) {
+		case 's' :
+			this.value = ' ';
+			break;
 		case 'b' :
 			this.value = '\b';
 			break;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompactConstructorDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompactConstructorDeclaration.java
new file mode 100644
index 0000000..e9a2150
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompactConstructorDeclaration.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2019 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
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.ast;
+
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.flow.FlowContext;
+import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.parser.Parser;
+
+public class CompactConstructorDeclaration extends ConstructorDeclaration {
+
+	public RecordDeclaration recordDeclaration;
+
+	public CompactConstructorDeclaration(CompilationResult compilationResult) {
+		super(compilationResult);
+	}
+	@Override
+	public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
+		parser.parse(this, unit, false);
+		this.containsSwitchWithTry = parser.switchWithTry;
+	}
+	@Override
+	protected void checkAndGenerateFieldAssignment(FlowContext flowContext, FlowInfo flowInfo, FieldBinding field) {
+		if (field.isStatic() ||
+				flowInfo.isDefinitelyAssigned(field) || flowInfo.isPotentiallyAssigned(field))
+			return;
+		assert field.isFinal();
+		/* JLS 14 8.10.5 Compact Record Constructor Declarations
+		 * In addition, at the end of the body of the compact constructor, all the fields
+		 * corresponding to the record components of R that are definitely unassigned
+		 * (16 (Definite Assignment)) are implicitly initialized to the value of the
+		 * corresponding formal parameter. These fields are implicitly initialized in the
+		 * order that they are declared in the record component list.
+		 */
+		FieldReference lhs = new FieldReference(field.name,0);
+		lhs.receiver = new ThisReference(0, 0);
+		//TODO: Check whether anything has to be done for null analysis.
+		Assignment assignment = new Assignment(lhs, new SingleNameReference(field.name, 0), 0);
+		assignment.resolveType(this.scope);
+		assignment.analyseCode(this.scope, flowContext, flowInfo);
+		assignment.bits |= ASTNode.IsImplicit;
+		assert flowInfo.isDefinitelyAssigned(field);
+		Statement[] stmts = this.statements;
+		if (this.statements == null) {
+			this.statements = new Statement[] { assignment };
+		} else {
+			int len = this.statements.length;
+			System.arraycopy(
+					this.statements,
+					0,
+					stmts = new Statement[len + 1],
+					0,
+					len);
+			stmts[len] = assignment;
+			this.statements = stmts;
+		}
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java
index 3e17e15..4c3c0c3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java
@@ -13,7 +13,8 @@
  *     Stephan Herrmann  - Contribution for bug 295551
  *     Jesper S Moller   - Contributions for
  *							  Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335
- *     Frits Jalvingh    - contributions for bug 533830.             
+ *     Frits Jalvingh    - contributions for bug 533830.
+ *     Red Hat Inc.	     - add module-info Javadoc support
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
@@ -22,6 +23,7 @@
 
 import org.eclipse.jdt.core.compiler.CategorizedProblem;
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.ClassFile;
 import org.eclipse.jdt.internal.compiler.CompilationResult;
@@ -173,6 +175,7 @@
 		classFile.referenceBinding = null;
 		classFile.innerClassesBindings = null;
 		classFile.bootstrapMethods = null;
+		classFile.recordBootstrapMethods = null;
 		classFile.missingTypes = null;
 		classFile.visitedTypes = null;
 	}
@@ -345,7 +348,7 @@
 														String key = CompilerOptions.optionKeyFromIrritant(id);
 														this.scope.problemReporter().problemNotAnalysed(inits[iToken], key);
 													} else {
-														this.scope.problemReporter().unusedWarningToken(inits[iToken]);														
+														this.scope.problemReporter().unusedWarningToken(inits[iToken]);
 													}
 												}
 											}
@@ -557,7 +560,7 @@
 	if (context instanceof LambdaExpression && context != ((LambdaExpression) context).original())
 		return true; // Do not record from copies. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=441929
 	Scope cScope = context instanceof AbstractMethodDeclaration ? ((AbstractMethodDeclaration) context).scope :
-		context instanceof TypeDeclaration ? ((TypeDeclaration) context).scope : 
+		context instanceof TypeDeclaration ? ((TypeDeclaration) context).scope :
 		context instanceof LambdaExpression ? ((LambdaExpression) context).scope :
 			null;
 	return cScope != null ? isLambdaExpressionCopyContext(cScope.parent.referenceContext()) : false;
@@ -565,7 +568,7 @@
 public void recordSuppressWarnings(IrritantSet irritants, Annotation annotation, int scopeStart, int scopeEnd, ReferenceContext context) {
 	if (isLambdaExpressionCopyContext(context))
 		return; // Do not record from copies. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=441929
-		
+
 	if (this.suppressWarningIrritants == null) {
 		this.suppressWarningIrritants = new IrritantSet[3];
 		this.suppressWarningAnnotations = new Annotation[3];
@@ -603,7 +606,7 @@
 }
 
 /*
- * Keep track of all lambda/method reference expressions, so as to be able to look it up later without 
+ * Keep track of all lambda/method reference expressions, so as to be able to look it up later without
  * having to traverse AST. Return the "ordinal" returned by the enclosing type.
  */
 public int record(FunctionalExpression expression) {
@@ -619,6 +622,7 @@
 public void resolve() {
 	int startingTypeIndex = 0;
 	boolean isPackageInfo = isPackageInfo();
+	boolean isModuleInfo = isModuleInfo();
 	if (this.types != null && isPackageInfo) {
 		// resolve synthetic type declaration
 		final TypeDeclaration syntheticTypeDeclaration = this.types[0];
@@ -637,6 +641,17 @@
 			this.javadoc.resolve(syntheticTypeDeclaration.staticInitializerScope);
 		}
 		startingTypeIndex = 1;
+	} else if (this.moduleDeclaration != null && isModuleInfo) {
+		if (this.javadoc != null) {
+			this.javadoc.resolve(this.moduleDeclaration.scope);
+		} else if (this.moduleDeclaration.binding != null) {
+			ProblemReporter reporter = this.scope.problemReporter();
+			int severity = reporter.computeSeverity(IProblem.JavadocMissing);
+			if (severity != ProblemSeverities.Ignore) {
+				reporter.javadocModuleMissing(this.moduleDeclaration.declarationSourceStart, this.moduleDeclaration.bodyStart,
+						severity);
+			}
+		}
 	} else {
 		// resolve compilation unit javadoc package if any
 		if (this.javadoc != null) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java
index 9ad11a6..e98fa2f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -200,7 +200,7 @@
 		TypeBinding resultType = TypeBinding.wellKnownType(scope, result & 0x0000F);
 		if (checkCastCompatibility()) {
 			if (originalLhsType.id != T_JavaLangString && resultType.id != T_JavaLangString) {
-				if (!checkCastTypesCompatibility(scope, originalLhsType, resultType, null)) {
+				if (!checkCastTypesCompatibility(scope, originalLhsType, resultType, null, true)) {
 					scope.problemReporter().invalidOperator(this, originalLhsType, expressionType);
 					return null;
 				}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
index c3d9573..3f9d3cf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -51,7 +51,7 @@
 	int trueInitStateIndex = -1;
 	int falseInitStateIndex = -1;
 	int mergedInitStateIndex = -1;
-	
+
 	// we compute and store the null status during analyseCode (https://bugs.eclipse.org/324178):
 	private int nullStatus = FlowInfo.UNKNOWN;
 	int ifFalseNullStatus;
@@ -96,6 +96,7 @@
 			}
 		}
 		this.trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo);
+		this.condition.updateFlowOnBooleanResult(trueFlowInfo, true);
 		trueFlowInfo = this.valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo);
 		this.valueIfTrue.checkNPEbyUnboxing(currentScope, flowContext, trueFlowInfo);
 
@@ -118,18 +119,19 @@
 			}
 		}
 		this.falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo);
+		this.condition.updateFlowOnBooleanResult(falseFlowInfo, false);
 		falseFlowInfo = this.valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo);
 		this.valueIfFalse.checkNPEbyUnboxing(currentScope, flowContext, falseFlowInfo);
 
 		flowContext.conditionalLevel--;
-		
+
 		// merge if-true & if-false initializations
 		FlowInfo mergedInfo;
 		if (isConditionOptimizedTrue){
 			mergedInfo = trueFlowInfo.addPotentialInitializationsFrom(falseFlowInfo);
 			if (this.ifTrueNullStatus != -1) {
 				this.nullStatus = this.ifTrueNullStatus;
-			} else { 
+			} else {
 				this.nullStatus = this.valueIfTrue.nullStatus(trueFlowInfo, flowContext);
 			}
 		} else if (isConditionOptimizedFalse) {
@@ -143,12 +145,12 @@
 			// (2) For definite assignment analysis (JLS 16.1.5) of boolean conditional expressions of the form
 			//     "if (c1 ? expr1 : expr2) use(v);" we need to check whether any variable v will be definitely
 			//     assigned whenever the entire conditional expression evaluates to true (to reach the then branch).
-			//     I.e., we need to collect flowInfo *towards* the overall outcome true/false 
+			//     I.e., we need to collect flowInfo *towards* the overall outcome true/false
 			//     (regardless of the evaluation of the condition).
-			
+
 			// to support (1) use the infos of both branches originating from the condition for computing the nullStatus:
 			computeNullStatus(trueFlowInfo, falseFlowInfo, flowContext);
-			
+
 			// to support (2) we split the true/false branches according to their inner structure. Consider this:
 			// if (b ? false : (true && (v = false))) return v; -- ok
 			// - expr1 ("false") has no path towards true (mark as unreachable)
@@ -168,16 +170,16 @@
 			UnconditionalFlowInfo trueFlowTowardsFalse = trueFlowInfo.initsWhenFalse().unconditionalInits();
 			UnconditionalFlowInfo falseFlowTowardsFalse = falseFlowInfo.initsWhenFalse().unconditionalInits();
 			if (isValueIfTrueOptimizedFalse) {
-				trueFlowTowardsTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);				
+				trueFlowTowardsTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
 			}
 			if (isValueIfFalseOptimizedFalse) {
-				falseFlowTowardsTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);	
+				falseFlowTowardsTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
 			}
 			if (isValueIfTrueOptimizedTrue) {
-				trueFlowTowardsFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);	
+				trueFlowTowardsFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
 			}
 			if (isValueIfFalseOptimizedTrue) {
-				falseFlowTowardsFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);	
+				falseFlowTowardsFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
 			}
 			mergedInfo =
 				FlowInfo.conditional(
@@ -187,7 +189,7 @@
 		this.mergedInitStateIndex =
 			currentScope.methodScope().recordInitializationStates(mergedInfo);
 		mergedInfo.setReachMode(mode);
-		
+
 		return mergedInfo;
 	}
 
@@ -201,7 +203,7 @@
 	}
 
 	private void computeNullStatus(FlowInfo trueBranchInfo, FlowInfo falseBranchInfo, FlowContext flowContext) {
-		// given that the condition cannot be optimized to a constant 
+		// given that the condition cannot be optimized to a constant
 		// we now merge the nullStatus from both branches:
 		if (this.ifTrueNullStatus == -1) { // has this status been pre-computed?
 			this.ifTrueNullStatus = this.valueIfTrue.nullStatus(trueBranchInfo, flowContext);
@@ -255,7 +257,8 @@
 			cst = this.condition.optimizedNullComparisonConstant();
 		}
 		boolean needTruePart = !(cst != Constant.NotAConstant && cst.booleanValue() == false);
-		boolean needFalsePart = 	!(cst != Constant.NotAConstant && cst.booleanValue() == true);
+		boolean needFalsePart = !(cst != Constant.NotAConstant && cst.booleanValue() == true);
+
 		endifLabel = new BranchLabel(codeStream);
 
 		// Generate code for the condition
@@ -445,13 +448,20 @@
 	}
 
 	@Override
+	public void initializePatternVariables(BlockScope scope, CodeStream codeStream) {
+		this.condition.initializePatternVariables(scope, codeStream);
+		this.valueIfTrue.initializePatternVariables(scope, codeStream);
+		this.valueIfFalse.initializePatternVariables(scope, codeStream);
+	}
+
+	@Override
 	public TypeBinding resolveType(BlockScope scope) {
 		// JLS3 15.25
 		LookupEnvironment env = scope.environment();
 		final long sourceLevel = scope.compilerOptions().sourceLevel;
 		boolean use15specifics = sourceLevel >= ClassFileConstants.JDK1_5;
 		this.use18specifics = sourceLevel >= ClassFileConstants.JDK1_8;
-		
+
 		if (this.use18specifics) {
 			if (this.expressionContext == ASSIGNMENT_CONTEXT || this.expressionContext == INVOCATION_CONTEXT) {
 				this.valueIfTrue.setExpressionContext(this.expressionContext);
@@ -460,10 +470,9 @@
 				this.valueIfFalse.setExpectedType(this.expectedType);
 			}
 		}
-		
+
 		if (this.constant != Constant.NotAConstant) {
 			this.constant = Constant.NotAConstant;
-
 			TypeBinding conditionType = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
 			this.condition.computeConversion(scope, TypeBinding.BOOLEAN, conditionType);
 
@@ -480,7 +489,7 @@
 				this.originalValueIfTrueType = this.valueIfTrue.resolveType(scope);
 			if (this.originalValueIfFalseType.kind() == Binding.POLY_TYPE)
 				this.originalValueIfFalseType = this.valueIfFalse.resolveType(scope);
-			
+
 			if (this.originalValueIfTrueType == null || !this.originalValueIfTrueType.isValidBinding())
 				return this.resolvedType = null;
 			if (this.originalValueIfFalseType == null || !this.originalValueIfFalseType.isValidBinding())
@@ -719,7 +728,7 @@
 	public void setExpectedType(TypeBinding expectedType) {
 		this.expectedType = expectedType;
 	}
-	
+
 	@Override
 	public void setExpressionContext(ExpressionContext context) {
 		this.expressionContext = context;
@@ -729,7 +738,7 @@
 	public ExpressionContext getExpressionContext() {
 		return this.expressionContext;
 	}
-	
+
 	@Override
 	public Expression[] getPolyExpressions() {
 		Expression [] truePolys = this.valueIfTrue.getPolyExpressions();
@@ -746,65 +755,65 @@
 
 	@Override
 	public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) {
-		return this.valueIfTrue.isPertinentToApplicability(targetType, method) 
+		return this.valueIfTrue.isPertinentToApplicability(targetType, method)
 				&& this.valueIfFalse.isPertinentToApplicability(targetType, method);
 	}
-	
+
 	@Override
 	public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope) {
-		return this.valueIfTrue.isPotentiallyCompatibleWith(targetType, scope) 
+		return this.valueIfTrue.isPotentiallyCompatibleWith(targetType, scope)
 				&& this.valueIfFalse.isPotentiallyCompatibleWith(targetType, scope);
 	}
-	
+
 	@Override
 	public boolean isFunctionalType() {
 		return this.valueIfTrue.isFunctionalType() || this.valueIfFalse.isFunctionalType(); // Even if only one arm is functional type, this will require a functional interface target
 	}
-	
+
 	@Override
 	public boolean isPolyExpression() throws UnsupportedOperationException {
-		
+
 		if (!this.use18specifics)
 			return false;
-		
+
 		if (this.isPolyExpression)
 			return true;
 
 		if (this.expressionContext != ASSIGNMENT_CONTEXT && this.expressionContext != INVOCATION_CONTEXT)
 			return false;
-		
+
 		if (this.originalValueIfTrueType == null || this.originalValueIfFalseType == null) // resolution error.
 			return false;
-		
+
 		if (this.valueIfTrue.isPolyExpression() || this.valueIfFalse.isPolyExpression())
 			return true;
-		
+
 		// "... unless both operands produce primitives (or boxed primitives)":
 		if (this.originalValueIfTrueType.isBaseType() || (this.originalValueIfTrueType.id >= TypeIds.T_JavaLangByte && this.originalValueIfTrueType.id <= TypeIds.T_JavaLangBoolean)) {
 			if (this.originalValueIfFalseType.isBaseType() || (this.originalValueIfFalseType.id >= TypeIds.T_JavaLangByte && this.originalValueIfFalseType.id <= TypeIds.T_JavaLangBoolean))
 				return false;
 		}
-		
-		// clause around generic method's return type prior to instantiation needs double check. 
+
+		// clause around generic method's return type prior to instantiation needs double check.
 		return this.isPolyExpression = true;
 	}
-	
+
 	@Override
 	public boolean isCompatibleWith(TypeBinding left, Scope scope) {
 		return isPolyExpression() ? this.valueIfTrue.isCompatibleWith(left, scope) && this.valueIfFalse.isCompatibleWith(left, scope) :
 			super.isCompatibleWith(left, scope);
 	}
-	
+
 	@Override
 	public boolean isBoxingCompatibleWith(TypeBinding targetType, Scope scope) {
 		// Note: compatibility check may have failed in just one arm and we may have reached here.
-		return isPolyExpression() ? (this.valueIfTrue.isCompatibleWith(targetType, scope) || 
-				                     this.valueIfTrue.isBoxingCompatibleWith(targetType, scope)) && 
-				                    (this.valueIfFalse.isCompatibleWith(targetType, scope) || 
+		return isPolyExpression() ? (this.valueIfTrue.isCompatibleWith(targetType, scope) ||
+				                     this.valueIfTrue.isBoxingCompatibleWith(targetType, scope)) &&
+				                    (this.valueIfFalse.isCompatibleWith(targetType, scope) ||
 				                     this.valueIfFalse.isBoxingCompatibleWith(targetType, scope)) :
 			super.isBoxingCompatibleWith(targetType, scope);
-	}	
-	
+	}
+
 	@Override
 	public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope scope) {
 		if (super.sIsMoreSpecific(s, t, scope))
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
index b230ad3..263a1dc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java
@@ -1,6 +1,6 @@
 // AspectJ
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -40,6 +40,7 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.codegen.*;
 import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.lookup.*;
 import org.eclipse.jdt.internal.compiler.parser.*;
 import org.eclipse.jdt.internal.compiler.problem.*;
@@ -137,7 +138,7 @@
 
 		// anonymous constructor can gain extra thrown exceptions from unhandled ones
 		if (this.binding.declaringClass.isAnonymousType()) {
-			ArrayList computedExceptions = constructorContext.extendedExceptions;
+			List computedExceptions = constructorContext.extendedExceptions;
 			if (computedExceptions != null){
 				int size;
 				if ((size = computedExceptions.size()) > 0){
@@ -172,7 +173,8 @@
 
 		// propagate to statements
 		if (this.statements != null) {
-			boolean enableSyntacticNullAnalysisForFields = this.scope.compilerOptions().enableSyntacticNullAnalysisForFields;
+			CompilerOptions compilerOptions = this.scope.compilerOptions();
+			boolean enableSyntacticNullAnalysisForFields = compilerOptions.enableSyntacticNullAnalysisForFields;
 			int complaintLevel = (nonStaticFieldInfoReachMode & FlowInfo.UNREACHABLE) == 0 ? Statement.NOT_COMPLAINED : Statement.COMPLAINED_FAKE_REACHABLE;
 			for (int i = 0, count = this.statements.length; i < count; i++) {
 				Statement stat = this.statements[i];
@@ -182,6 +184,9 @@
 				if (enableSyntacticNullAnalysisForFields) {
 					constructorContext.expireNullCheckedFieldInfo();
 				}
+				if (compilerOptions.analyseResourceLeaks) {
+					FakedTrackingVariable.cleanUpUnassigned(this.scope, stat, flowInfo);
+				}
 			}
 		}
 		// check for missing returning path
@@ -201,6 +206,7 @@
 			FieldBinding[] fields = this.binding.declaringClass.fields();
 			for (int i = 0, count = fields.length; i < count; i++) {
 				FieldBinding field = fields[i];
+				checkAndGenerateFieldAssignment(initializerFlowContext, flowInfo, field);
 				if (!field.isStatic() && !flowInfo.isDefinitelyAssigned(field)) {
 					if (field.isFinal()) {
 						this.scope.problemReporter().uninitializedBlankFinalField(
@@ -230,6 +236,9 @@
 	}
 }
 
+protected void checkAndGenerateFieldAssignment(FlowContext flowContext, FlowInfo flowInfo, FieldBinding field) {
+	return;
+}
 boolean isValueProvidedUsingAnnotation(FieldDeclaration fieldDecl) {
 	// a member field annotated with @Inject is considered to be initialized by the injector 
 	if (fieldDecl.annotations != null) {
@@ -541,7 +550,7 @@
 		return;
 	}
 	parser.parse(this, unit, false);
-
+	this.containsSwitchWithTry = parser.switchWithTry;
 }
 
 @Override
@@ -567,6 +576,7 @@
 	if (this.binding == null || this.javadoc != null) {
 		super.resolveJavadoc();
 	} else if ((this.bits & ASTNode.IsDefaultConstructor) == 0) {
+		if((this.bits & ASTNode.IsImplicit) != 0 ) return;
 		if (this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) {
 			// Set javadoc visibility
 			int javadocVisibility = this.binding.modifiers & ExtraCompilerModifiers.AccVisibilityMASK;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContainerAnnotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContainerAnnotation.java
index 32f3281..b865829 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContainerAnnotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContainerAnnotation.java
@@ -22,29 +22,29 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 
 public class ContainerAnnotation extends SingleMemberAnnotation {
-	
+
 	private Annotation [] containees;
 	private ArrayInitializer memberValues;
-	
+
 	public ContainerAnnotation(Annotation repeatingAnnotation, ReferenceBinding containerAnnotationType, BlockScope scope) {
-		
+
 		char [][] containerTypeName = containerAnnotationType.compoundName;
 		if (containerTypeName.length == 1) {
 			this.type = new SingleTypeReference(containerTypeName[0], 0);
 		} else {
 			this.type = new QualifiedTypeReference(containerTypeName, new long [containerTypeName.length]);
 		}
-		
+
 		this.sourceStart = repeatingAnnotation.sourceStart;
 		this.sourceEnd = repeatingAnnotation.sourceEnd;
-		
+
 		this.resolvedType = containerAnnotationType;
 		this.recipient = repeatingAnnotation.recipient;
 		this.containees = new Annotation[0];
 		this.memberValue = this.memberValues = new ArrayInitializer();
 		addContainee(repeatingAnnotation);
 	}
-	
+
 	public void addContainee(Annotation repeatingAnnotation) {
 		final int length = this.containees.length;
 		System.arraycopy(this.containees, 0, this.containees = new Annotation[length + 1], 0, length);
@@ -52,7 +52,7 @@
 		this.memberValues.expressions = this.containees;
 		repeatingAnnotation.setPersistibleAnnotation(length == 0 ? this : null);
 	}
-	
+
 	// Resolve the compiler synthesized container annotation.
 	@Override
 	public TypeBinding resolveType(BlockScope scope) {
@@ -74,11 +74,11 @@
 		this.resolvedType = containerAnnotationType = repeatingAnnotationType.containerAnnotationType();
 		if (!this.resolvedType.isValidBinding())
 			return this.resolvedType;
-		
-		// OK, the declaration site of the repeating annotation type as well as the use site where the annotations actually repeat pass muster. 
+
+		// OK, the declaration site of the repeating annotation type as well as the use site where the annotations actually repeat pass muster.
 		MethodBinding[] methods = containerAnnotationType.methods();
 		MemberValuePair pair = memberValuePairs()[0];
-		
+
 		for (int i = 0, length = methods.length; i < length; i++) {
 			MethodBinding method = methods[i];
 			if (CharOperation.equals(method.selector, TypeConstants.VALUE)) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java
index 3b7c102..548bedd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoStatement.java
@@ -107,7 +107,7 @@
 			(this.action == null
 				? actionInfo
 				: (actionInfo.mergedWith(loopingContext.initsOnContinue))).copy());
-	/* https://bugs.eclipse.org/bugs/show_bug.cgi?id=367023, we reach the condition at the bottom via two arcs, 
+	/* https://bugs.eclipse.org/bugs/show_bug.cgi?id=367023, we reach the condition at the bottom via two arcs,
 	   one by free fall and another by continuing... Merge initializations propagated through the two pathways,
 	   cf, while and for loops.
 	*/
@@ -136,7 +136,7 @@
 		loopingContext.simulateThrowAfterLoopBack(loopbackFlowInfo);
 	}
 	// end of loop
-	FlowInfo mergedInfo = 
+	FlowInfo mergedInfo =
 		FlowInfo.mergedOptimizedBranches(
 						(loopingContext.initsOnBreak.tagBits & FlowInfo.UNREACHABLE) != 0
 								? loopingContext.initsOnBreak
@@ -250,7 +250,7 @@
 	boolean isConditionTrue = cst == null || cst != Constant.NotAConstant && cst.booleanValue() == true;
 	cst = this.condition.optimizedBooleanConstant();
 	boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true;
-	
+
 	if (isConditionTrue || isConditionOptimizedTrue)
 		return this.action == null || !this.action.breaksOut(null);
 	if (this.action == null || this.action.breaksOut(null))
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java
index a012723..87c58ad 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java
@@ -21,9 +21,9 @@
 import org.eclipse.jdt.internal.compiler.util.FloatUtil;
 
 public class DoubleLiteral extends NumberLiteral {
-	
+
 	double value;
-	
+
 public DoubleLiteral(char[] token, int s, int e) {
 	super(token, s, e);
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
index 0bdcfe6..53f60af 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -52,7 +52,7 @@
 				rightNonNullChecked = scope.problemReporter().expressionNonNullComparison(this.right, checkEquality);
 			}
 		}
-		
+
 		boolean contextualCheckEquality = checkEquality ^ ((flowContext.tagBits & FlowContext.INSIDE_NEGATION) != 0);
 		// perform flowInfo-based checks for variables and record info for syntactic null analysis for fields:
 		if (!leftNonNullChecked) {
@@ -62,7 +62,7 @@
 					checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, rightStatus, this.left);
 				}
 			} else if (this.left instanceof Reference
-							&& ((!contextualCheckEquality && rightStatus == FlowInfo.NULL) 
+							&& ((!contextualCheckEquality && rightStatus == FlowInfo.NULL)
 									|| (contextualCheckEquality && rightStatus == FlowInfo.NON_NULL))
 							&& scope.compilerOptions().enableSyntacticNullAnalysisForFields)
 			{
@@ -74,19 +74,19 @@
 		}
 		if (!rightNonNullChecked) {
 			LocalVariableBinding local = this.right.localVariableBinding();
-			if (local != null) { 
+			if (local != null) {
 				if ((local.type.tagBits & TagBits.IsBaseType) == 0) {
 					checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, leftStatus, this.right);
 				}
 			} else if (this.right instanceof Reference
-							&& ((!contextualCheckEquality && leftStatus == FlowInfo.NULL) 
+							&& ((!contextualCheckEquality && leftStatus == FlowInfo.NULL)
 									|| (contextualCheckEquality && leftStatus == FlowInfo.NON_NULL))
-							&& scope.compilerOptions().enableSyntacticNullAnalysisForFields) 
+							&& scope.compilerOptions().enableSyntacticNullAnalysisForFields)
 			{
 				FieldBinding field = ((Reference)this.right).lastFieldBinding();
 				if (field != null && (field.type.tagBits & TagBits.IsBaseType) == 0) {
 					flowContext.recordNullCheckedFieldReference((Reference) this.right, 1);
-				}				
+				}
 			}
 		}
 
@@ -934,8 +934,8 @@
 		// spec 15.20.3
 		if ((!leftType.isBaseType() || leftType == TypeBinding.NULL) // cannot compare: Object == (int)0
 				&& (!rightType.isBaseType() || rightType == TypeBinding.NULL)
-				&& (checkCastTypesCompatibility(scope, leftType, rightType, null)
-						|| checkCastTypesCompatibility(scope, rightType, leftType, null))) {
+				&& (checkCastTypesCompatibility(scope, leftType, rightType, null, true)
+						|| checkCastTypesCompatibility(scope, rightType, leftType, null, true))) {
 
 			// (special case for String)
 			if ((rightType.id == T_JavaLangString) && (leftType.id == T_JavaLangString)) {
@@ -954,8 +954,8 @@
 				TypeBinding alternateRightType = unnecessaryRightCast ? ((CastExpression)this.right).expression.resolvedType : rightType;
 				// Bug 543727 - check if either cast is really needed
 				if (!isCastNeeded(alternateLeftType, alternateRightType)) {
-					if (checkCastTypesCompatibility(scope, alternateLeftType, alternateRightType, null)
-							|| checkCastTypesCompatibility(scope, alternateRightType, alternateLeftType, null)) {
+					if (checkCastTypesCompatibility(scope, alternateLeftType, alternateRightType, null, false)
+							|| checkCastTypesCompatibility(scope, alternateRightType, alternateLeftType, null, false)) {
 						if (unnecessaryLeftCast) scope.problemReporter().unnecessaryCast((CastExpression)this.left);
 						if (unnecessaryRightCast) scope.problemReporter().unnecessaryCast((CastExpression)this.right);
 					}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExportsStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExportsStatement.java
index b641512..932435c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExportsStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExportsStatement.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
index d7bf39d..0828b50 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -10,7 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     Stephan Herrmann - Contributions for 
+ *     Stephan Herrmann - Contributions for
  *								bug 292478 - Report potentially null across variable assignment
  *								bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null"
  *								bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types
@@ -78,9 +78,9 @@
 
 	public int implicitConversion;
 	public TypeBinding resolvedType;
-	
+
 	public static Expression [] NO_EXPRESSIONS = new Expression[0];
-	
+
 
 public static final boolean isConstantValueRepresentable(Constant constant, int constantTypeID, int targetTypeID) {
 	//true if there is no loss of precision while casting.
@@ -257,9 +257,19 @@
 }
 
 /**
+ * Back-propagation of flow info: before analysing a branch where a given condition is known to hold true/false respectively,
+ * ask the condition to contribute its information to the given flowInfo.
+ * @param flowInfo the info to be used for analysing the branch
+ * @param result condition result that would cause entering the branch
+ */
+protected void updateFlowOnBooleanResult(FlowInfo flowInfo, boolean result) {
+	// nop
+}
+
+/**
  * Returns false if cast is not legal.
  */
-public final boolean checkCastTypesCompatibility(Scope scope, TypeBinding castType, TypeBinding expressionType, Expression expression) {
+public final boolean checkCastTypesCompatibility(Scope scope, TypeBinding castType, TypeBinding expressionType, Expression expression, boolean useAutoBoxing) {
 	// see specifications 5.5
 	// handle errors and process constant when needed
 
@@ -273,6 +283,7 @@
 	// like constant propagation
 	boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
 	boolean use17specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_7;
+	useAutoBoxing &= use15specifics;
 	if (castType.isBaseType()) {
 		if (expressionType.isBaseType()) {
 			if (TypeBinding.equalsEquals(expressionType, castType)) {
@@ -295,18 +306,18 @@
 				return true;
 
 			}
-		} else if (use17specifics && castType.isPrimitiveType() && expressionType instanceof ReferenceBinding && 
-				!expressionType.isBoxedPrimitiveType() && checkCastTypesCompatibility(scope, scope.boxing(castType), expressionType, expression)) {
+		} else if (useAutoBoxing && use17specifics && castType.isPrimitiveType() && expressionType instanceof ReferenceBinding &&
+				!expressionType.isBoxedPrimitiveType() && checkCastTypesCompatibility(scope, scope.boxing(castType), expressionType, expression, useAutoBoxing)) {
 			// cast from any reference type (other than boxing types) to base type allowed from 1.7, see JLS $5.5
 			// by our own interpretation (in accordance with javac) we reject arays, though.
 			return true;
-		} else if (use15specifics
+		} else if (useAutoBoxing
 							&& scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) { // unboxing - only widening match is allowed
 			tagAsUnnecessaryCast(scope, castType);
 			return true;
 		}
 		return false;
-	} else if (use15specifics
+	} else if (useAutoBoxing
 						&& expressionType.isBaseType()
 						&& scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) { // boxing - only widening match is allowed
 		tagAsUnnecessaryCast(scope, castType);
@@ -316,12 +327,12 @@
 	if (castType.isIntersectionType18()) {
 		ReferenceBinding [] intersectingTypes = castType.getIntersectingTypes();
 		for (int i = 0, length = intersectingTypes.length; i < length; i++) {
-			if (!checkCastTypesCompatibility(scope, intersectingTypes[i], expressionType, expression))
+			if (!checkCastTypesCompatibility(scope, intersectingTypes[i], expressionType, expression, useAutoBoxing))
 				return false;
 		}
 		return true;
 	}
-	
+
 	switch(expressionType.kind()) {
 		case Binding.BASE_TYPE :
 			//-----------cast to something which is NOT a base type--------------------------
@@ -349,7 +360,7 @@
 						return false;
 					}
 					// recurse on array type elements
-					return checkCastTypesCompatibility(scope, castElementType, exprElementType, expression);
+					return checkCastTypesCompatibility(scope, castElementType, exprElementType, expression, useAutoBoxing);
 
 				case Binding.TYPE_PARAMETER :
 					// ( TYPE_PARAMETER ) ARRAY
@@ -358,7 +369,7 @@
 						checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true);
 					}
 					for (TypeBinding bound : ((TypeVariableBinding) castType).allUpperBounds()) {
-						if (!checkCastTypesCompatibility(scope, bound, expressionType, expression))
+						if (!checkCastTypesCompatibility(scope, bound, expressionType, expression, useAutoBoxing))
 							return false;
 					}
 					return true;
@@ -385,12 +396,12 @@
 				if (castType instanceof TypeVariableBinding) {
 					// prefer iterating over required types, not provides
 					for (TypeBinding bound : ((TypeVariableBinding)castType).allUpperBounds()) {
-						if (!checkCastTypesCompatibility(scope, bound, expressionType, expression))
+						if (!checkCastTypesCompatibility(scope, bound, expressionType, expression, useAutoBoxing))
 							return false;
 					}
 				} else {
 					for (TypeBinding bound : ((TypeVariableBinding)expressionType).allUpperBounds()) {
-						if (!checkCastTypesCompatibility(scope, castType, bound, expression))
+						if (!checkCastTypesCompatibility(scope, castType, bound, expression, useAutoBoxing))
 							return false;
 					}
 				}
@@ -407,11 +418,11 @@
 			TypeBinding bound = ((WildcardBinding)expressionType).bound;
 			if (bound == null) bound = scope.getJavaLangObject();
 			// recursively on the type variable upper bound
-			return checkCastTypesCompatibility(scope, castType, bound, expression);
+			return checkCastTypesCompatibility(scope, castType, bound, expression, useAutoBoxing);
 		case Binding.INTERSECTION_TYPE18:
 			ReferenceBinding [] intersectingTypes = expressionType.getIntersectingTypes();
 			for (int i = 0, length = intersectingTypes.length; i < length; i++) {
-				if (checkCastTypesCompatibility(scope, castType, intersectingTypes[i], expression))
+				if (checkCastTypesCompatibility(scope, castType, intersectingTypes[i], expression, useAutoBoxing))
 					return true;
 			}
 			return false;
@@ -437,7 +448,7 @@
 						}
 						// recursively on the type variable upper bounds
 						for (TypeBinding upperBound : ((TypeVariableBinding)castType).allUpperBounds()) {
-							if (!checkCastTypesCompatibility(scope, upperBound, expressionType, expression))
+							if (!checkCastTypesCompatibility(scope, upperBound, expressionType, expression, useAutoBoxing))
 								return false;
 						}
 						return true;
@@ -534,7 +545,7 @@
 						}
 						// recursively on the type variable upper bounds
 						for (TypeBinding upperBound : ((TypeVariableBinding)castType).allUpperBounds()) {
-							if (!checkCastTypesCompatibility(scope, upperBound, expressionType, expression))
+							if (!checkCastTypesCompatibility(scope, upperBound, expressionType, expression, useAutoBoxing))
 								return false;
 						}
 						return true;
@@ -774,7 +785,12 @@
 		throw new ShouldNotImplement(Messages.ast_missingCode);
 	}
 }
-
+public void initializePatternVariables(BlockScope scope, CodeStream codeStream) {
+	// Nothing by default
+}
+public boolean containsPatternVariable() {
+	return false;
+}
 /**
  * Default generation of a boolean value
  * @param currentScope
@@ -1131,7 +1147,7 @@
 			if (field.type.isRawType()) {
 				if (referenceContext instanceof AbstractMethodDeclaration) {
 					AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration) referenceContext;
-					ReferenceBinding declaringClass = methodDecl.binding != null 
+					ReferenceBinding declaringClass = methodDecl.binding != null
 							? methodDecl.binding.declaringClass
 							: methodDecl.scope.enclosingReceiverType();
 					if (TypeBinding.notEquals(field.declaringClass, declaringClass)) { // inherited raw field, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=337962
@@ -1229,9 +1245,9 @@
 }
 
 /* Answer if the receiver is a poly expression in the prevailing context. Caveat emptor: Some constructs (notably method calls)
-   cannot answer this question until after resolution is over and may throw unsupported operation exception if queried ahead of 
+   cannot answer this question until after resolution is over and may throw unsupported operation exception if queried ahead of
    resolution. Default implementation here returns false which is true for vast majority of AST nodes. The ones that are poly
-   expressions under one or more contexts should override and return suitable value.  
+   expressions under one or more contexts should override and return suitable value.
  */
 public boolean isPolyExpression() throws UnsupportedOperationException {
 	return false;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExpressionContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExpressionContext.java
index 07a84ce..9050a3c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExpressionContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExpressionContext.java
@@ -16,14 +16,14 @@
 package org.eclipse.jdt.internal.compiler.ast;
 
 public enum ExpressionContext {
-	
-	/** Assignment context: potential poly-expressions are: method invocations, lambdas, reference expressions, 
+
+	/** Assignment context: potential poly-expressions are: method invocations, lambdas, reference expressions,
 	   conditional expressions and allocation expressions. This is the only Java 7 context where target type
 	   influenced evaluation of some expression.
-	   
-	   Context induced by: ReturnStatement, ArrayInitializer, Assignment, FieldDeclaration and LocalDeclaration. 
+
+	   Context induced by: ReturnStatement, ArrayInitializer, Assignment, FieldDeclaration and LocalDeclaration.
 	*/
-	ASSIGNMENT_CONTEXT { 
+	ASSIGNMENT_CONTEXT {
 		@Override
 		public String toString() {
 			return "assignment context"; //$NON-NLS-1$
@@ -33,14 +33,14 @@
 			return true;
 		}
 	},
-	
-	/** Invocation context: potential poly-expressions are: method invocations, lambdas, reference expressions, 
-	   conditional expressions and allocation expressions. At this point, we don't distinguish between strict 
+
+	/** Invocation context: potential poly-expressions are: method invocations, lambdas, reference expressions,
+	   conditional expressions and allocation expressions. At this point, we don't distinguish between strict
 	   and loose invocation contexts - we may have to cross the bridge some day.
-	   
+
 	   Context induced by: AllocationExpression, QualifiedAllocationExpression, ExplicitConstructorCall, MessageSend
 	   CodeSnippetAllocationExpression and CodeSnippetMessageSend.
-	*/													
+	*/
 	INVOCATION_CONTEXT {
 		@Override
 		public String toString() {
@@ -51,7 +51,7 @@
 			return true;
 		}
 	},
-	
+
 	/** Casting context: potential poly-expressions are: lambdas and reference expressions
 	   Context induced by: CastExpression.
 	*/
@@ -65,9 +65,9 @@
 			return false;
 		}
 	},
-	
-	/** Vanilla context (string, numeric): potential poly-expressions are: NONE. This is the nonpoly context in which 
-	   expressions get evaluated, unless they feature in one of the above contexts. 
+
+	/** Vanilla context (string, numeric): potential poly-expressions are: NONE. This is the nonpoly context in which
+	   expressions get evaluated, unless they feature in one of the above contexts.
 	*/
 	VANILLA_CONTEXT {
 		@Override
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java
index 5736ac4..ff213b9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2019 GK Software AG and others.
+ * Copyright (c) 2011, 2020 GK Software AG and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -24,6 +24,7 @@
 import java.util.Set;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.CompilationResult;
 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
 import org.eclipse.jdt.internal.compiler.flow.FinallyFlowContext;
@@ -49,7 +50,7 @@
  * A faked local variable declaration used for keeping track of data flows of a
  * special variable. Certain events will be recorded by changing the null info
  * for this variable.
- * 
+ *
  * See bug 349326 - [1.7] new warning for missing try-with-resources
  */
 @SuppressWarnings({"rawtypes", "unchecked"})
@@ -66,10 +67,10 @@
 	// - obtaining this from a method call or array reference
 	// Interpret that we may or may not be responsible for closing
 	private static final int SHARED_WITH_OUTSIDE = 2;
-	// the resource is likely owned by outside code (owner has responsibility to close): 
+	// the resource is likely owned by outside code (owner has responsibility to close):
 	// - obtained as argument of the current method, or via a field read
 	// - stored into a field
-	// - returned as the result of this method 
+	// - returned as the result of this method
 	private static final int OWNED_BY_OUTSIDE = 4;
 	// If close() is invoked from a nested method (inside a local type) report remaining problems only as potential:
 	private static final int CLOSED_IN_NESTED_METHOD = 8;
@@ -81,6 +82,7 @@
 	private static final int REPORTED_DEFINITIVE_LEAK = 64;
 	// a local declarations that acts as the element variable of a foreach loop (should never suggest to use t-w-r):
 	private static final int FOREACH_ELEMENT_VAR = 128;
+	public MessageSend acquisition;
 
 	public static boolean TEST_372319 = false; // see https://bugs.eclipse.org/372319
 
@@ -90,7 +92,7 @@
 	private int globalClosingState = 0;
 
 	public LocalVariableBinding originalBinding; // the real local being tracked, can be null for preliminary track vars for allocation expressions
-	
+
 	public FakedTrackingVariable innerTracker; // chained tracking variable of a chained (wrapped) resource
 	public FakedTrackingVariable outerTracker; // inverse of 'innerTracker'
 
@@ -100,7 +102,7 @@
 
 	// temporary storage while analyzing "res = new Res();":
 	private ASTNode currentAssignment; // temporarily store the assignment as the location for error reporting
-	
+
 	// if tracking var was allocated from a finally context, record here the flow context of the corresponding try block
 	private FlowContext tryContext;
 
@@ -137,7 +139,12 @@
 		if (nullStatus != 0)
 			flowInfo.markNullStatus(this.binding, nullStatus); // mark that this flow has seen the resource
 	}
-	
+
+	private void attachTo(LocalVariableBinding local) {
+		local.closeTracker = this;
+		this.originalBinding = local;
+	}
+
 	@Override
 	public void generateCode(BlockScope currentScope, CodeStream codeStream)
 	{ /* NOP - this variable is completely dummy, ie. for analysis only. */ }
@@ -213,9 +220,12 @@
 				return local.closeTracker;
 			}
 		} else if (expression instanceof AllocationExpression) {
-			// return any preliminary tracking variable from analyseCloseableAllocation 
+			// return any preliminary tracking variable from analyseCloseableAllocation
 			return ((AllocationExpression) expression).closeTracker;
-		}		
+		} else if (expression instanceof MessageSend) {
+			// return any preliminary tracking variable from analyseCloseableAcquisition
+			return ((MessageSend) expression).closeTracker;
+		}
 		return null;
 	}
 
@@ -225,13 +235,13 @@
 	 * Also the assignment is temporarily stored in the tracking variable in case we need to
 	 * report errors because the assignment leaves the old LHS value unclosed.
 	 * In this case the assignment should be used as the error location.
-	 * 
+	 *
 	 * @param location the assignment/local declaration being analyzed
 	 * @param local the local variable being assigned to
 	 * @param rhs the rhs of the assignment resp. the initialization of the local variable declaration.
 	 * 		<strong>Precondition:</strong> client has already checked that the resolved type of this expression is either a closeable type or NULL.
 	 */
-	public static void preConnectTrackerAcrossAssignment(ASTNode location, LocalVariableBinding local, Expression rhs, FlowInfo flowInfo) {
+	public static FakedTrackingVariable preConnectTrackerAcrossAssignment(ASTNode location, LocalVariableBinding local, Expression rhs, FlowInfo flowInfo) {
 		FakedTrackingVariable closeTracker = null;
 		if (containsAllocation(rhs)) {
 			closeTracker = local.closeTracker;
@@ -241,13 +251,24 @@
 					if (local.isParameter()) {
 						closeTracker.globalClosingState |= OWNED_BY_OUTSIDE;
 					}
-				}					
+				}
 			}
 			if (closeTracker != null) {
 				closeTracker.currentAssignment = location;
 				preConnectTrackerAcrossAssignment(location, local, flowInfo, closeTracker, rhs);
 			}
+		} else if (rhs instanceof MessageSend) {
+			closeTracker = local.closeTracker;
+			if (closeTracker != null) {
+				handleReassignment(flowInfo, closeTracker, location);
+			}
+			if (rhs.resolvedType != TypeBinding.NULL) { // not NULL means valid closeable as per method precondition
+				closeTracker = new FakedTrackingVariable(local, location, flowInfo, null, FlowInfo.UNKNOWN);
+				closeTracker.currentAssignment = location;
+				((MessageSend) rhs).closeTracker = closeTracker;
+			}
 		}
+		return closeTracker;
 	}
 
 	private static boolean containsAllocation(SwitchExpression location) {
@@ -258,16 +279,19 @@
 		return false;
 	}
 	private static boolean containsAllocation(ASTNode location) {
-		if (location instanceof AllocationExpression)
+		if (location instanceof AllocationExpression) {
 			return true;
-		if (location instanceof ConditionalExpression) {
+		} else if (location instanceof ConditionalExpression) {
 			ConditionalExpression conditional = (ConditionalExpression) location;
 			return containsAllocation(conditional.valueIfTrue) || containsAllocation(conditional.valueIfFalse);
 		} else if (location instanceof SwitchExpression) {
 			return containsAllocation((SwitchExpression) location);
-		}
-		if (location instanceof CastExpression)
+		} else if (location instanceof CastExpression) {
 			return containsAllocation(((CastExpression) location).expression);
+		} else if (location instanceof MessageSend) {
+			if (isFluentMethod(((MessageSend) location).binding))
+				return containsAllocation(((MessageSend) location).receiver);
+		}
 		return false;
 	}
 
@@ -281,6 +305,9 @@
 			preConnectTrackerAcrossAssignment(location, local, flowInfo, (SwitchExpression) expression, closeTracker);
 		} else if (expression instanceof CastExpression) {
 			preConnectTrackerAcrossAssignment(location, local, ((CastExpression) expression).expression, flowInfo);
+		} else if (expression instanceof MessageSend) {
+			if (isFluentMethod(((MessageSend) expression).binding))
+				preConnectTrackerAcrossAssignment(location, local, ((MessageSend) expression).receiver, flowInfo);
 		}
 	}
 
@@ -302,13 +329,15 @@
 		allocationExpression.closeTracker = closeTracker;
 		if (allocationExpression.arguments != null && allocationExpression.arguments.length > 0) {
 			// also push into nested allocations, see https://bugs.eclipse.org/368709
-			preConnectTrackerAcrossAssignment(location, local, allocationExpression.arguments[0], flowInfo);
+			FakedTrackingVariable inner = preConnectTrackerAcrossAssignment(location, local, allocationExpression.arguments[0], flowInfo);
+			if (inner != closeTracker && closeTracker.innerTracker == null)
+				closeTracker.innerTracker = inner;
 		}
 	}
 
-	/** 
+	/**
 	 * Compute/assign a tracking variable for a freshly allocated closeable value, using information from our white lists.
-	 * See  Bug 358903 - Filter practically unimportant resource leak warnings 
+	 * See  Bug 358903 - Filter practically unimportant resource leak warnings
 	 */
 	public static void analyseCloseableAllocation(BlockScope scope, FlowInfo flowInfo, AllocationExpression allocation) {
 		// client has checked that the resolvedType is an AutoCloseable, hence the following cast is safe:
@@ -342,7 +371,7 @@
 								newStatus = finallyStatus;
 						}
 					}
-					if (allocation.closeTracker.innerTracker != null) {
+					if (allocation.closeTracker.innerTracker != null && allocation.closeTracker.innerTracker != innerTracker) {
 						innerTracker = pickMoreUnsafe(allocation.closeTracker.innerTracker, innerTracker, scope, flowInfo);
 					}
 					allocation.closeTracker.innerTracker = innerTracker;
@@ -382,6 +411,56 @@
 		}
 	}
 
+	/**
+	 * Check if a message send acquires a closeable from its receiver, see:
+	 * Bug 463320 - [compiler][resource] potential "resource leak" problem disappears when local variable inlined
+	 */
+	public static FlowInfo analyseCloseableAcquisition(BlockScope scope, FlowInfo flowInfo, MessageSend acquisition) {
+		if (isFluentMethod(acquisition.binding)) {
+			// share the existing close tracker of the receiver (if any):
+			acquisition.closeTracker = findCloseTracker(scope, flowInfo, acquisition.receiver);
+			return flowInfo;
+		}
+		// client has checked that the resolvedType is an AutoCloseable, hence the following cast is safe:
+		if (((ReferenceBinding)acquisition.resolvedType).hasTypeBit(TypeIds.BitResourceFreeCloseable)) {
+			// remove unnecessary attempts (closeable is not relevant)
+			if (acquisition.closeTracker != null) {
+				acquisition.closeTracker.withdraw();
+				acquisition.closeTracker = null;
+			}
+			return flowInfo;
+		} else { // regular resource
+			FakedTrackingVariable tracker = acquisition.closeTracker;
+			if (tracker != null) {
+				// pre-connected tracker means: directly assigning the acquisition to a local, forget special treatment:
+				tracker.withdraw();
+				acquisition.closeTracker = null;
+				return flowInfo;
+			} else {
+				tracker = new FakedTrackingVariable(scope, acquisition, flowInfo, FlowInfo.UNKNOWN); // no local available, closeable is unassigned
+				acquisition.closeTracker = tracker;
+			}
+			tracker.acquisition = acquisition;
+			FlowInfo outsideInfo = flowInfo.copy();
+			outsideInfo.markAsDefinitelyNonNull(tracker.binding);
+			flowInfo.markAsDefinitelyNull(tracker.binding);
+			return FlowInfo.conditional(outsideInfo, flowInfo);
+		}
+	}
+
+	private static boolean isFluentMethod(MethodBinding binding) {
+		if (binding.isStatic())
+			return false;
+		ReferenceBinding declaringClass = binding.declaringClass;
+		if (declaringClass.equals(binding.returnType)) {
+			for (char[][] compoundName : TypeConstants.FLUENT_RESOURCE_CLASSES) {
+				if (CharOperation.equals(compoundName, declaringClass.compoundName))
+					return true;
+			}
+		}
+		return false;
+	}
+
 	private static FakedTrackingVariable pickMoreUnsafe(FakedTrackingVariable tracker1, FakedTrackingVariable tracker2, BlockScope scope, FlowInfo info) {
 		// whichever of the two trackers has stronger indication to be leaking will be returned,
 		// the other one will be removed from the scope (considered to be merged into the former).
@@ -404,18 +483,22 @@
 		if (presetTracker != null && presetTracker.originalBinding != null) {
 			// the current assignment forgets a previous resource in the LHS, may cause a leak
 			// report now because handleResourceAssignment can't distinguish this from a self-wrap situation
-			int closeStatus = flowInfo.nullStatus(presetTracker.binding);
-			if (closeStatus != FlowInfo.NON_NULL		// old resource was not closed
-					&& closeStatus != FlowInfo.UNKNOWN	// old resource had some flow information
-					&& !flowInfo.isDefinitelyNull(presetTracker.originalBinding)		// old resource was not null
-					&& !(presetTracker.currentAssignment instanceof LocalDeclaration))	// forgetting old val in local decl is syntactically impossible
-				allocation.closeTracker.recordErrorLocation(presetTracker.currentAssignment, closeStatus);
+			handleReassignment(flowInfo, presetTracker, presetTracker.currentAssignment);
 		} else {
 			allocation.closeTracker = new FakedTrackingVariable(scope, allocation, flowInfo, FlowInfo.UNKNOWN); // no local available, closeable is unassigned
 		}
 		flowInfo.markAsDefinitelyNull(allocation.closeTracker.binding);
 	}
 
+	private static void handleReassignment(FlowInfo flowInfo, FakedTrackingVariable existingTracker, ASTNode location) {
+		int closeStatus = flowInfo.nullStatus(existingTracker.binding);
+		if (closeStatus != FlowInfo.NON_NULL		// old resource was not closed
+				&& closeStatus != FlowInfo.UNKNOWN	// old resource had some flow information
+				&& !flowInfo.isDefinitelyNull(existingTracker.originalBinding)		// old resource was not null
+				&& !(location instanceof LocalDeclaration))	// forgetting old val in local decl is syntactically impossible
+			existingTracker.recordErrorLocation(location, closeStatus);
+	}
+
 	/** Find an existing tracking variable for the argument of an allocation for a resource wrapper. */
 	private static FakedTrackingVariable findCloseTracker(BlockScope scope, FlowInfo flowInfo, Expression arg)
 	{
@@ -438,17 +521,19 @@
 		} else if (arg instanceof AllocationExpression) {
 			// nested allocation
 			return ((AllocationExpression)arg).closeTracker;
+		} else if (arg instanceof MessageSend) {
+			return ((MessageSend) arg).closeTracker;
 		}
 		return null; // not a tracked expression
 	}
 
-	/** 
+	/**
 	 * Given the rhs of an assignment or local declaration has a (Auto)Closeable type (or null), setup for leak analysis now:
 	 * Create or re-use a tracking variable, and wire and initialize everything.
 	 * @param scope scope containing the assignment
 	 * @param upstreamInfo info without analysis of the rhs, use this to determine the status of a resource being disconnected
 	 * @param flowInfo info with analysis of the rhs, use this for recording resource status because this will be passed downstream
-	 * @param flowContext 
+	 * @param flowContext
 	 * @param location where to report warnigs/errors against
 	 * @param rhs the right hand side of the assignment, this expression is to be analyzed.
 	 *			The caller has already checked that the rhs is either of a closeable type or null.
@@ -482,19 +567,19 @@
 						rhsTrackVar.globalClosingState &= ~(SHARED_WITH_OUTSIDE|OWNED_BY_OUTSIDE|FOREACH_ELEMENT_VAR);
 					}
 				} else {
-					if (rhs instanceof AllocationExpression || rhs instanceof ConditionalExpression || rhs instanceof SwitchExpression) {
+					if (rhs instanceof AllocationExpression || rhs instanceof ConditionalExpression || rhs instanceof SwitchExpression || rhs instanceof MessageSend) {
 						if (rhsTrackVar == disconnectedTracker)
 							return;									// 		b.: self wrapper: res = new Wrap(res); -> done!
-						if (local.closeTracker == rhsTrackVar 
+						if (local.closeTracker == rhsTrackVar
 								&& ((rhsTrackVar.globalClosingState & OWNED_BY_OUTSIDE) != 0)) {
-																	// 		c.: assigning a fresh resource (pre-connected alloc) 
+																	// 		c.: assigning a fresh resource (pre-connected alloc)
 																	//			to a local previously holding an alien resource -> start over
 							local.closeTracker = new FakedTrackingVariable(local, location, flowInfo, flowContext, FlowInfo.NULL);
 							// still check disconnectedTracker below
 							break rhsAnalyis;
 						}
 					}
-					local.closeTracker = rhsTrackVar;				//		d.: conflicting LHS and RHS, proceed with recordErrorLocation below
+					rhsTrackVar.attachTo(local);					//		d.: conflicting LHS and RHS, proceed with recordErrorLocation below
 				}
 				// keep close-status of RHS unchanged across this assignment
 			} else if (previousTracker != null) {					// 2. re-use tracking variable from the LHS?
@@ -520,11 +605,11 @@
 			} else {												// 3. no re-use, create a fresh tracking variable:
 				rhsTrackVar = analyseCloseableExpression(flowInfo, flowContext, local, location, rhs, null);
 				if (rhsTrackVar != null) {
-					local.closeTracker = rhsTrackVar;
+					rhsTrackVar.attachTo(local);
 					// a fresh resource, mark as not-closed:
 					if ((rhsTrackVar.globalClosingState & (SHARED_WITH_OUTSIDE|OWNED_BY_OUTSIDE|FOREACH_ELEMENT_VAR)) == 0)
 						flowInfo.markAsDefinitelyNull(rhsTrackVar.binding);
-// TODO(stephan): this might be useful, but I could not find a test case for it: 
+// TODO(stephan): this might be useful, but I could not find a test case for it:
 //					if (flowContext.initsOnFinally != null)
 //						flowContext.initsOnFinally.markAsDefinitelyNonNull(trackerBinding);
 				}
@@ -553,8 +638,8 @@
 	 *  		which we should then re-use
 	 * @return a tracking variable associated with local or null if no need to track
 	 */
-	private static FakedTrackingVariable analyseCloseableExpression(FlowInfo flowInfo, FlowContext flowContext, LocalVariableBinding local, 
-									ASTNode location, Expression expression, FakedTrackingVariable previousTracker) 
+	private static FakedTrackingVariable analyseCloseableExpression(FlowInfo flowInfo, FlowContext flowContext, LocalVariableBinding local,
+									ASTNode location, Expression expression, FakedTrackingVariable previousTracker)
 	{
 		// unwrap uninteresting nodes:
 		while (true) {
@@ -586,8 +671,8 @@
 				return null;
 			}
 			return tracker;
-		} else if (expression instanceof MessageSend 
-				|| expression instanceof ArrayReference) 
+		} else if (expression instanceof MessageSend
+				|| expression instanceof ArrayReference)
 		{
 			// we *might* be responsible for the resource obtained
 			FakedTrackingVariable tracker = new FakedTrackingVariable(local, location, flowInfo, flowContext, FlowInfo.POTENTIALLY_NULL); // shed some doubt
@@ -603,7 +688,7 @@
 			FakedTrackingVariable tracker = new FakedTrackingVariable(local, location, flowInfo, flowContext, FlowInfo.UNKNOWN);
 			tracker.globalClosingState |= OWNED_BY_OUTSIDE;
 			// leave state as UNKNOWN, the bit OWNED_BY_OUTSIDE will prevent spurious warnings
-			return tracker;			
+			return tracker;
 		}
 
 		if (local.closeTracker != null)
@@ -645,6 +730,12 @@
 				tracker.withdraw();
 				((AllocationExpression) expression).closeTracker = null;
 			}
+		} else if (expression instanceof MessageSend) {
+			FakedTrackingVariable tracker = ((MessageSend) expression).closeTracker;
+			if (tracker != null && tracker.originalBinding == null) {
+				tracker.withdraw();
+				((MessageSend) expression).closeTracker = null;
+			}
 		} else {
 			// assignment passing a local into a field?
 			LocalVariableBinding local = expression.localVariableBinding();
@@ -653,6 +744,28 @@
 		}
 	}
 
+	/** Unassigned closeables are not visible beyond their enclosing statement, immediately report & remove after each statement. */
+	public static void cleanUpUnassigned(BlockScope scope, ASTNode location, FlowInfo flowInfo) {
+		if (!scope.hasResourceTrackers()) return;
+		location.traverse(new ASTVisitor() {
+				@Override
+				public boolean visit(MessageSend messageSend, BlockScope skope) {
+					FakedTrackingVariable closeTracker = messageSend.closeTracker;
+					if (closeTracker != null) {
+						if (closeTracker.originalBinding == null) {
+							int nullStatus = flowInfo.nullStatus(closeTracker.binding);
+							if ((nullStatus & (FlowInfo.POTENTIALLY_NULL | FlowInfo.NULL)) != 0) {
+								closeTracker.reportError(skope.problemReporter(), messageSend, nullStatus);
+							}
+							closeTracker.withdraw();
+						}
+					}
+					return true;
+				}
+			},
+			scope);
+	}
+
 	/** Answer wither the given type binding is a subtype of java.lang.AutoCloseable. */
 	public static boolean isAnyCloseable(TypeBinding typeBinding) {
 		return typeBinding instanceof ReferenceBinding
@@ -714,8 +827,13 @@
 			if ((status & FlowInfo.POTENTIALLY_NULL) != 0)
 				return FlowInfo.POTENTIALLY_NULL;	// non-null + doubt = pot null
 			return FlowInfo.NON_NULL;
-		} else if ((status & FlowInfo.POTENTIALLY_NULL) != 0)
+		} else if ((status & FlowInfo.POTENTIALLY_NULL) != 0) {
 			return FlowInfo.POTENTIALLY_NULL;
+		} else if (status == FlowInfo.UNKNOWN) {
+			// if unassigned resource (not having an originalBinding) is not withdrawn it is unclosed:
+			if (this.originalBinding == null)
+				return FlowInfo.NULL;
+		}
 		return status;
 	}
 
@@ -753,14 +871,14 @@
 		this.globalClosingState |= CLOSED_IN_NESTED_METHOD;
 	}
 
-	/** 
+	/**
 	 * Mark that this resource is passed to some outside code
-	 * (as argument to a method/ctor call or as a return value from the current method), 
+	 * (as argument to a method/ctor call or as a return value from the current method),
 	 * and thus should be considered as potentially closed.
 	 * @param owned should the resource be considered owned by some outside?
 	 */
-	public static FlowInfo markPassedToOutside(BlockScope scope, Expression expression, FlowInfo flowInfo, FlowContext flowContext, boolean owned) {	
-		
+	public static FlowInfo markPassedToOutside(BlockScope scope, Expression expression, FlowInfo flowInfo, FlowContext flowContext, boolean owned) {
+
 		FakedTrackingVariable trackVar = getCloseTrackingVariable(expression, flowInfo, flowContext);
 		if (trackVar != null) {
 			// insert info that the tracked resource *may* be closed (by the target method, i.e.)
@@ -775,7 +893,7 @@
 			if (owned) {
 				return infoResourceIsClosed; // don't let downstream signal any problems on this flow
 			} else {
-				return FlowInfo.conditional(flowInfo, infoResourceIsClosed); // only report potential problems on this flow
+				return FlowInfo.conditional(flowInfo, infoResourceIsClosed).unconditionalCopy(); // only report potential problems on this flow
 			}
 		}
 		return flowInfo;
@@ -788,7 +906,7 @@
 	}
 
 	/**
-	 * Iterator for a set of FakedTrackingVariable, which dispenses the elements 
+	 * Iterator for a set of FakedTrackingVariable, which dispenses the elements
 	 * according to the priorities defined by enum {@link Stage}.
 	 * Resources whose outer is owned by an enclosing scope are never answered,
 	 * unless we are analysing on behalf of an exit (return/throw).
@@ -802,7 +920,7 @@
 		private Stage stage;
 		private Iterator<FakedTrackingVariable> iterator;
 		private FakedTrackingVariable next;
-		
+
 		enum Stage {
 			/** 1. prio: all top-level resources, ie., resources with no outer. */
 			OuterLess,
@@ -885,14 +1003,14 @@
 
 	/**
 	 * Answer true if we know for sure that no resource is bound to this variable
-	 * at the point of 'flowInfo'. 
+	 * at the point of 'flowInfo'.
 	 */
 	public boolean hasDefinitelyNoResource(FlowInfo flowInfo) {
 		if (this.originalBinding == null) return false; // shouldn't happen but keep quiet.
 		if (flowInfo.isDefinitelyNull(this.originalBinding)) {
 			return true;
 		}
-		if (!(flowInfo.isDefinitelyAssigned(this.originalBinding) 
+		if (!(flowInfo.isDefinitelyAssigned(this.originalBinding)
 				|| flowInfo.isPotentiallyAssigned(this.originalBinding))) {
 			return true;
 		}
@@ -901,7 +1019,7 @@
 
 	public boolean isClosedInFinallyOfEnclosing(BlockScope scope) {
 		BlockScope currentScope = scope;
-		while (true) {			
+		while (true) {
 			if (currentScope.finallyInfo != null
 					&& currentScope.finallyInfo.isDefinitelyNonNull(this.binding)) {
 				return true; // closed in enclosing finally
@@ -910,9 +1028,9 @@
 				return false;
 			}
 			currentScope = (BlockScope) currentScope.parent;
-		} 
+		}
 	}
-	/** 
+	/**
 	 * If current is the same as 'returnedResource' or a wrapper thereof,
 	 * mark as reported and return true, otherwise false.
 	 */
@@ -977,7 +1095,7 @@
 		}
 		return hasReported;
 	}
-	
+
 	private boolean neverClosedAtLocations() {
 		if (this.recordedLocations != null) {
 			for (Object value : this.recordedLocations.values())
@@ -1003,15 +1121,19 @@
 		if (isPotentialProblem) {
 			if ((this.globalClosingState & (REPORTED_POTENTIAL_LEAK|REPORTED_DEFINITIVE_LEAK)) != 0)
 				return 0;
-			problemReporter.potentiallyUnclosedCloseable(this, location);	
+//			if ((this.globalClosingState & (ACQUIRED_FROM_OUTSIDE)) != 0
+//					&& location instanceof ReturnStatement
+//					&& ((ReturnStatement) location).expression == this.acquisition)
+//				return 0; // directly returning a resource acquired from a message send: don't assume responsibility
+			problemReporter.potentiallyUnclosedCloseable(this, location);
 		} else {
 			if ((this.globalClosingState & (REPORTED_DEFINITIVE_LEAK)) != 0)
 				return 0;
-			problemReporter.unclosedCloseable(this, location);			
+			problemReporter.unclosedCloseable(this, location);
 		}
 		// propagate flag to inners:
 		int reportFlag = isPotentialProblem ? REPORTED_POTENTIAL_LEAK : REPORTED_DEFINITIVE_LEAK;
-		if (location == null) { // if location != null flags will be set after the loop over locations 
+		if (location == null) { // if location != null flags will be set after the loop over locations
 			FakedTrackingVariable current = this;
 			do {
 				current.globalClosingState |= reportFlag;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java
index 14a0d10..0f99458 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java
@@ -21,9 +21,9 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 
 public class FalseLiteral extends MagicLiteral {
-	
+
 	static final char[] source = {'f', 'a', 'l', 's', 'e'};
-	
+
 public FalseLiteral(int s , int e) {
 	super(s,e);
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java
index 902ae09..d57623a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -55,6 +55,7 @@
 
 	public int endPart1Position;
 	public int endPart2Position;
+	public boolean isARecordComponent; // used in record components
 
 public FieldDeclaration() {
 	// for subtypes or conversion
@@ -72,7 +73,8 @@
 public FlowInfo analyseCode(MethodScope initializationScope, FlowContext flowContext, FlowInfo flowInfo) {
 	if (this.binding != null && !this.binding.isUsed() && this.binding.isOrEnclosedByPrivateType()) {
 		if (!initializationScope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
-			initializationScope.problemReporter().unusedPrivateField(this);
+			if (!this.isARecordComponent) // record component used by implicit methods
+				initializationScope.problemReporter().unusedPrivateField(this);
 		}
 	}
 	// cannot define static non-constant field inside nested class
@@ -137,6 +139,19 @@
 			codeStream.fieldAccess(Opcodes.OPC_putfield, this.binding, null /* default declaringClass */);
 		}
 	}
+	// The fields escape CodeStream#exitUserScope(), and as a result end PC wouldn't be set.
+	// Set this explicitly (unlike a local declaration)
+	if (this.initialization != null && this.initialization.containsPatternVariable()) {
+		this.initialization.traverse(new ASTVisitor() {
+			@Override
+			public boolean visit(
+		    		InstanceOfExpression instanceOfExpression,
+		    		BlockScope scope) {
+				instanceOfExpression.elementVariable.binding.recordInitializationEndPC(codeStream.position);
+				return true;
+			}
+		}, currentScope);
+	}
 	codeStream.recordPositionsFrom(pc, this.sourceStart);
 }
 public void getAllAnnotationContexts(int targetType, List allAnnotationContexts) {
@@ -245,7 +260,7 @@
 				}
 			}
 		}
-		
+
 		// check @Deprecated annotation presence
 		if ((this.binding.getAnnotationTagBits() & TagBits.AnnotationDeprecated) == 0
 				&& (this.binding.modifiers & ClassFileConstants.AccDeprecated) != 0
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
index b4e2269..5b0b7cd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
@@ -745,7 +745,7 @@
 			scope.problemReporter().indirectAccessToStaticField(this, fieldBinding);
 		}
 		// check if accessing enum static field in initializer
-		if (declaringClass.isEnum() && !scope.isModuleScope()) {
+		if (declaringClass.isEnum() && scope.kind != Scope.MODULE_SCOPE) {
 			MethodScope methodScope = scope.methodScope();
 			SourceTypeBinding sourceType = scope.enclosingSourceType();
 			if (this.constant == Constant.NotAConstant
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java
index 0ea54ee..039e2ad 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java
@@ -22,9 +22,9 @@
 import org.eclipse.jdt.internal.compiler.util.FloatUtil;
 
 public class FloatLiteral extends NumberLiteral {
-	
+
 	float value;
-	
+
 public FloatLiteral(char[] token, int s, int e) {
 	super(token, s, e);
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java
index ebf6475..d600dfb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -10,7 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     Stephan Herrmann - Contributions for 
+ *     Stephan Herrmann - Contributions for
  *     							bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE
  *     							bug 349326 - [1.7] new warning for missing try-with-resources
  *								bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null"
@@ -89,7 +89,7 @@
 		cst = this.condition == null ? null : this.condition.optimizedBooleanConstant();
 		boolean isConditionOptimizedTrue = cst == null ||  (cst != Constant.NotAConstant && cst.booleanValue() == true);
 		boolean isConditionOptimizedFalse = cst != null && (cst != Constant.NotAConstant && cst.booleanValue() == false);
-		
+
 		// process the condition
 		LoopingFlowContext condLoopContext = null;
 		FlowInfo condInfo = flowInfo.nullInfoLessUnconditionalCopy();
@@ -148,6 +148,8 @@
 					}
 				}
 			if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) {
+				if (this.condition != null)
+					this.condition.updateFlowOnBooleanResult(actionInfo, true);
 				actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalInits();
 			}
 
@@ -237,6 +239,9 @@
 			}
 		}
 		this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
+		this.scope.checkUnclosedCloseables(mergedInfo, loopingContext, null, null);
+		if (this.condition != null)
+			this.condition.updateFlowOnBooleanResult(mergedInfo, false);
 		return mergedInfo;
 	}
 
@@ -260,6 +265,9 @@
 				this.initializations[i].generateCode(this.scope, codeStream);
 			}
 		}
+		if (this.condition != null && this.condition.containsPatternVariable()) {
+			this.condition.initializePatternVariables(currentScope, codeStream);
+		}
 		Constant cst = this.condition == null ? null : this.condition.optimizedBooleanConstant();
 		boolean isConditionOptimizedFalse = cst != null && (cst != Constant.NotAConstant && cst.booleanValue() == false);
 		if (isConditionOptimizedFalse) {
@@ -327,6 +335,7 @@
 				}
 			}
 			// May loose some local variable initializations : affecting the local variable attributes
+			// This is causing PatternMatching14Test.test039() to fail
 			if (this.preCondInitStateIndex != -1) {
 				codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preCondInitStateIndex);
 			}
@@ -394,7 +403,6 @@
 
 	@Override
 	public void resolve(BlockScope upperScope) {
-
 		// use the scope that will hold the init declarations
 		this.scope = (this.bits & ASTNode.NeededScope) != 0 ? new BlockScope(upperScope) : upperScope;
 		if (this.initializations != null)
@@ -444,10 +452,10 @@
 		boolean isConditionTrue = cst == null || cst != Constant.NotAConstant && cst.booleanValue() == true;
 		cst = this.condition == null ? null : this.condition.optimizedBooleanConstant();
 		boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true;
-		
+
 		return (isConditionTrue || isConditionOptimizedTrue) && (this.action == null || !this.action.breaksOut(null));
 	}
-	
+
 	@Override
 	public boolean completesByContinue() {
 		return this.action.continuesAtOuterLabel();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
index 402260c..5abbd8a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
@@ -132,11 +132,10 @@
 
 			if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) {
 				actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalCopy();
-				if (this.action instanceof Block) {
 					FakedTrackingVariable.markForeachElementVar(this.elementVariable);
-					// action.analyseCode() missed the following check due to identical scopes of ForeachStatement and Block:
-					this.scope.checkUnclosedCloseables(actionInfo, loopingContext, null, null);
-				}
+				// action.analyseCode() missed the following check due to identical scopes of ForeachStatement and action:
+				FlowInfo actionNullInfo = condInfo.copy().addNullInfoFrom(actionInfo); // previously action did not see nullinfo from condInfo
+				this.scope.checkUnclosedCloseables(actionNullInfo, loopingContext, null, null);
 			}
 
 			// code generation can be optimized when no need to continue in the loop
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
index ec81052..c52104e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
@@ -54,7 +54,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
 
 public abstract class FunctionalExpression extends Expression {
-	
+
 	protected TypeBinding expectedType;
 	public MethodBinding descriptor;
 	public MethodBinding binding;                 // Code generation binding. May include synthetics. See getMethodBinding()
@@ -74,20 +74,20 @@
 	public FunctionalExpression(CompilationResult compilationResult) {
 		this.compilationResult = compilationResult;
 	}
-	
+
 	public FunctionalExpression() {
 		super();
 	}
-	
+
 	@Override
 	public boolean isBoxingCompatibleWith(TypeBinding targetType, Scope scope) {
 		return false;
 	}
-	
+
 	public void setCompilationResult(CompilationResult compilationResult) {
 		this.compilationResult = compilationResult;
 	}
-	
+
 	// Return the actual (non-code generation) method binding that is void of synthetics.
 	public MethodBinding getMethodBinding() {
 		return null;
@@ -97,7 +97,7 @@
 	public void setExpectedType(TypeBinding expectedType) {
 		this.expectedType = expectedType;
 	}
-	
+
 	@Override
 	public void setExpressionContext(ExpressionContext context) {
 		this.expressionContext = context;
@@ -121,7 +121,7 @@
 	public boolean isFunctionalType() {
 		return true;
 	}
-	
+
 	@Override
 	public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) {
 		if (targetType instanceof TypeVariableBinding) {
@@ -159,7 +159,7 @@
 	public TypeBinding expectedType() {
 		return this.expectedType;
 	}
-	
+
 	public boolean argumentsTypeElided() { return true; /* only exception: lambda with explicit argument types. */ }
 
 	// Notify the compilation unit that it contains some functional types, taking care not to add any transient copies. this is assumed not to be a copy
@@ -173,7 +173,7 @@
 						if (expression != expression.original) // fake universe.
 							return 0;
 					}
-					break; 
+					break;
 				case Scope.COMPILATION_UNIT_SCOPE :
 					CompilationUnitDeclaration unit = ((CompilationUnitScope) scope).referenceContext;
 					return unit.record(this);
@@ -199,7 +199,7 @@
 		if (!sam.isValidBinding() && sam.problemId() != ProblemReasons.ContradictoryNullAnnotations) {
 			return reportSamProblem(blockScope, sam);
 		}
-		
+
 		this.descriptor = sam;
 		if (skipKosherCheck || kosherDescriptor(blockScope, sam, true)) {
 			if (this.expectedType instanceof IntersectionTypeBinding18) {
@@ -217,9 +217,9 @@
 			if (environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
 				NullAnnotationMatching.checkForContradictions(sam, this, blockScope);
 			}
-			return this.resolvedType = this.expectedType;		
+			return this.resolvedType = this.expectedType;
 		}
-		
+
 		return this.resolvedType = null;
 	}
 
@@ -245,7 +245,7 @@
 		private boolean shouldChatter;
         private boolean visible = true;
 		private FunctionalExpression expression;
-        
+
 		public VisibilityInspector(FunctionalExpression expression, Scope scope, boolean shouldChatter) {
 			this.scope = scope;
 			this.shouldChatter = shouldChatter;
@@ -259,20 +259,20 @@
 					this.scope.problemReporter().descriptorHasInvisibleType(this.expression, referenceBinding);
 			}
 		}
-		
+
 		@Override
 		public boolean visit(ReferenceBinding referenceBinding) {
 			checkVisibility(referenceBinding);
 			return true;
 		}
 
-		
+
 		@Override
 		public boolean visit(ParameterizedTypeBinding parameterizedTypeBinding) {
 			checkVisibility(parameterizedTypeBinding);
 			return true;
 		}
-		
+
 		@Override
 		public boolean visit(RawTypeBinding rawTypeBinding) {
 			checkVisibility(rawTypeBinding);
@@ -288,13 +288,13 @@
 			TypeBindingVisitor.visit(this, types);
 			return this.visible;
 		}
-		
+
 	}
 
 	public boolean kosherDescriptor(Scope scope, MethodBinding sam, boolean shouldChatter) {
-	
+
 		VisibilityInspector inspector = new VisibilityInspector(this, scope, shouldChatter);
-		
+
 		boolean status = true;
 		if (!inspector.visible(sam.returnType))
 			status = false;
@@ -319,7 +319,7 @@
 	public MethodBinding[] getRequiredBridges() {
 
 		class BridgeCollector {
-			
+
 			MethodBinding [] bridges;
 			MethodBinding method;
 			char [] selector;
@@ -333,19 +333,19 @@
 				this.scope = FunctionalExpression.this.enclosingScope;
 				collectBridges(new ReferenceBinding[]{functionalType});
 			}
-			
+
 			void collectBridges(ReferenceBinding[] interfaces) {
 				int length = interfaces == null ? 0 : interfaces.length;
 				for (int i = 0; i < length; i++) {
 					ReferenceBinding superInterface = interfaces[i];
-					if (superInterface == null) 
+					if (superInterface == null)
 						continue;
 					MethodBinding [] methods = superInterface.getMethods(this.selector);
 					for (int j = 0, count = methods == null ? 0 : methods.length; j < count; j++) {
 						MethodBinding inheritedMethod = methods[j];
 						if (inheritedMethod == null || this.method == inheritedMethod)  // descriptor declaring class may not be same functional interface target type.
 							continue;
-						if (inheritedMethod.isStatic() || inheritedMethod.redeclaresPublicObjectMethod(this.scope)) 
+						if (inheritedMethod.isStatic() || inheritedMethod.redeclaresPublicObjectMethod(this.scope))
 							continue;
 						inheritedMethod = MethodVerifier.computeSubstituteMethod(inheritedMethod, this.method, this.environment);
 						if (inheritedMethod == null || !MethodVerifier.isSubstituteParameterSubsignature(this.method, inheritedMethod, this.environment) ||
@@ -376,7 +376,7 @@
 				return this.bridges;
 			}
 		}
-		
+
 		ReferenceBinding functionalType;
 		if (this.expectedType instanceof IntersectionTypeBinding18) {
 			functionalType = (ReferenceBinding) ((IntersectionTypeBinding18)this.expectedType).getSAMType(this.enclosingScope);
@@ -386,7 +386,7 @@
 		return new BridgeCollector(functionalType, this.descriptor).getBridges();
 	}
 	boolean requiresBridges() {
-		return getRequiredBridges() != null; 
+		return getRequiredBridges() != null;
 	}
 	public void cleanUp() {
 		// to be overridden by sub-classes
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IJavadocTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IJavadocTypeReference.java
new file mode 100644
index 0000000..c21cdae
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IJavadocTypeReference.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Red Hat Inc. and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Red Hat Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.ast;
+
+/**
+ * Interface to allow Javadoc parser to collect both JavaSingleTypeReference and JavaQualifiedTypeReferences
+ *
+ * @author jjohnstn
+ *
+ */
+public interface IJavadocTypeReference {
+
+	public int getTagSourceStart();
+	public int getTagSourceEnd();
+
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IPolyExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IPolyExpression.java
index 62af557..8bd42cc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IPolyExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IPolyExpression.java
@@ -25,9 +25,9 @@
 
 /**
  	Contract to be implemented by all poly expressions and potential poly expressions for uniform integration into overload resolution and type inference.
-	Additional contracts may be imposed by {@link Invocation} and {@link InvocationSite}. For most contracts "default" implementations are furnished by 
+	Additional contracts may be imposed by {@link Invocation} and {@link InvocationSite}. For most contracts "default" implementations are furnished by
 	{@link Expression} or {@link Statement} or by {@link ASTNode} and the poly expression should suitably override where required.
-	
+
 	@see PolyTypeBinding
 	@see ExpressionContext
 */
@@ -36,17 +36,17 @@
 	// Expression context manipulation
 	public void setExpressionContext(ExpressionContext context);
 	public ExpressionContext getExpressionContext();
-	
+
 	// Target type injection.
 	public void setExpectedType(TypeBinding targetType);
 	public TypeBinding invocationTargetType();
-	
+
 	// Compatibility checks.
 	public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope);
 	public boolean isCompatibleWith(TypeBinding targetType, final Scope scope);
 	public boolean isBoxingCompatibleWith(TypeBinding targetType, Scope scope);
-	public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope skope);	
-	
+	public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope skope);
+
 	// Pertinence checks.
 	public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method);
 
@@ -55,14 +55,14 @@
 	public boolean isPolyExpression();
 	public boolean isFunctionalType();
 	public Expression[] getPolyExpressions();
-	
-	
+
+
 	/* Resolution: A poly expression must be prepared to be resolved multiple times and should manage matters in a side effect free fashion.
 	   Typically, in invocation contexts, there is an initial resolution, multiple tentative resolutions and then a final resolution against
 	   the ultimate target type.
 	*/
 	public TypeBinding resolveType(BlockScope blockScope);
-	// Resolve expression tentatively - should have no lingering side-effects that may impact final resolution ! 
+	// Resolve expression tentatively - should have no lingering side-effects that may impact final resolution !
 	public Expression resolveExpressionExpecting(TypeBinding targetType, Scope scope, InferenceContext18 inferenceContext);
-	
+
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java
index d8373d7..bcb2b53 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -10,7 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     Stephan Herrmann - Contributions for 
+ *     Stephan Herrmann - Contributions for
  *     							bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE
  *     							bug 349326 - [1.7] new warning for missing try-with-resources
  *								bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null"
@@ -82,7 +82,7 @@
 	if (isConditionOptimizedTrue) {
 		elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
 	}
-	if (((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) && 
+	if (((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) &&
 			((thenFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)) {
 		// Mark then block as unreachable
 		// No need if the whole if-else construct itself lies in unreachable code
@@ -106,6 +106,7 @@
 				this.bits &= ~ASTNode.IsThenStatementUnreachable;
 			}
 		}
+		this.condition.updateFlowOnBooleanResult(thenFlowInfo, true);
 		thenFlowInfo = this.thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo);
 		if (!(this.thenStatement instanceof Block))
 			flowContext.expireNullCheckedFieldInfo();
@@ -136,6 +137,7 @@
 				this.bits &= ~ASTNode.IsElseStatementUnreachable;
 			}
 		}
+		this.condition.updateFlowOnBooleanResult(elseFlowInfo, false);
 		elseFlowInfo = this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo);
 		if (!(this.elseStatement instanceof Block))
 			flowContext.expireNullCheckedFieldInfo();
@@ -274,7 +276,6 @@
 	}
 	return output;
 }
-
 @Override
 public void resolve(BlockScope scope) {
 	TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java
index 75ae8d6..9e41ead 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java
@@ -143,7 +143,7 @@
 	public MethodBinding getMethodBinding() {
 		if (this.methodBinding == null) {
 			Scope scope = this.block.scope;
-			this.methodBinding = isStatic() 
+			this.methodBinding = isStatic()
 					? new MethodBinding(ClassFileConstants.AccStatic, CharOperation.NO_CHAR, TypeBinding.VOID, Binding.NO_PARAMETERS, Binding.NO_EXCEPTIONS, scope.enclosingSourceType())
 					: new MethodBinding(0, CharOperation.NO_CHAR, TypeBinding.VOID, Binding.NO_PARAMETERS, Binding.NO_EXCEPTIONS, scope.enclosingSourceType());
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
index 96e2664..3ca65a7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -35,6 +35,8 @@
 
 	public Expression expression;
 	public TypeReference type;
+	public LocalDeclaration elementVariable;
+	boolean isInitialized;
 
 public InstanceOfExpression(Expression expression, TypeReference type) {
 	this.expression = expression;
@@ -44,30 +46,54 @@
 	this.sourceStart = expression.sourceStart;
 	this.sourceEnd = type.sourceEnd;
 }
+public InstanceOfExpression(Expression expression, LocalDeclaration local) {
+	this.expression = expression;
+	this.elementVariable = local;
+	this.type = this.elementVariable.type;
+	this.bits |= INSTANCEOF << OperatorSHIFT;
+	this.elementVariable.sourceStart = local.sourceStart;
+	this.elementVariable.sourceEnd = local.sourceEnd;
+	this.sourceStart = expression.sourceStart;
+	this.sourceEnd = local.declarationSourceEnd;
+}
 
 @Override
 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
 	LocalVariableBinding local = this.expression.localVariableBinding();
+	FlowInfo initsWhenTrue = null;
 	if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
 		flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo).
 			unconditionalInits();
-		FlowInfo initsWhenTrue = flowInfo.copy();
+		initsWhenTrue = flowInfo.copy();
 		initsWhenTrue.markAsComparedEqualToNonNull(local);
 		flowContext.recordUsingNullReference(currentScope, local,
 				this.expression, FlowContext.CAN_ONLY_NULL | FlowContext.IN_INSTANCEOF, flowInfo);
 		// no impact upon enclosing try context
-		return FlowInfo.conditional(initsWhenTrue, flowInfo.copy());
-	}
-	if (this.expression instanceof Reference && currentScope.compilerOptions().enableSyntacticNullAnalysisForFields) {
-		FieldBinding field = ((Reference)this.expression).lastFieldBinding();
-		if (field != null && (field.type.tagBits & TagBits.IsBaseType) == 0) {
-			flowContext.recordNullCheckedFieldReference((Reference) this.expression, 1);
+		flowInfo =  FlowInfo.conditional(initsWhenTrue, flowInfo.copy());
+	} else if (this.expression instanceof Reference) {
+		if (currentScope.compilerOptions().enableSyntacticNullAnalysisForFields) {
+			FieldBinding field = ((Reference)this.expression).lastFieldBinding();
+			if (field != null && (field.type.tagBits & TagBits.IsBaseType) == 0) {
+				flowContext.recordNullCheckedFieldReference((Reference) this.expression, 1);
+			}
 		}
 	}
-	return this.expression.analyseCode(currentScope, flowContext, flowInfo).
-			unconditionalInits();
+	if (initsWhenTrue == null) {
+		flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo).
+				unconditionalInits();
+		if (this.elementVariable != null) {
+			initsWhenTrue = flowInfo.copy();
+		}
+	}
+	if (this.elementVariable != null) {
+		if (this.elementVariable.duplicateCheckObligation != null) {
+			this.elementVariable.duplicateCheckObligation.accept(flowInfo);
+		}
+		initsWhenTrue.markAsDefinitelyAssigned(this.elementVariable.binding);
+	}
+	return (initsWhenTrue == null) ? flowInfo :
+			FlowInfo.conditional(initsWhenTrue, flowInfo.copy());
 }
-
 /**
  * Code generation for instanceOfExpression
  *
@@ -77,9 +103,21 @@
 */
 @Override
 public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
+	initializePatternVariables(currentScope, codeStream);
+
 	int pc = codeStream.position;
 	this.expression.generateCode(currentScope, codeStream, true);
 	codeStream.instance_of(this.type, this.type.resolvedType);
+	if (this.elementVariable != null) {
+		BranchLabel actionLabel = new BranchLabel(codeStream);
+		codeStream.dup();
+		codeStream.ifeq(actionLabel);
+		this.expression.generateCode(currentScope, codeStream, true);
+		codeStream.checkcast(this.type, this.type.resolvedType, codeStream.position);
+		codeStream.store(this.elementVariable.binding, false);
+		codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd);
+		actionLabel.place();
+	}
 	if (valueRequired) {
 		codeStream.generateImplicitConversion(this.implicitConversion);
 	} else {
@@ -91,12 +129,39 @@
 @Override
 public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
 	this.expression.printExpression(indent, output).append(" instanceof "); //$NON-NLS-1$
-	return this.type.print(0, output);
+	return this.elementVariable == null ? this.type.print(0, output) : this.elementVariable.printAsExpression(0, output);
 }
 
 @Override
+public void initializePatternVariables(BlockScope currentScope, CodeStream codeStream) {
+	if (this.elementVariable != null) {
+		if(!this.isInitialized) {
+			this.isInitialized = true;
+			codeStream.aconst_null();
+			codeStream.store(this.elementVariable.binding, false);
+		}
+		int position = codeStream.position;
+		codeStream.addVisibleLocalVariable(this.elementVariable.binding);
+		this.elementVariable.binding.recordInitializationStartPC(position);
+	}
+}
+public void resolvePatternVariable(BlockScope scope) {
+	if (this.elementVariable != null && this.elementVariable.binding == null) {
+		this.elementVariable.resolve(scope, true);
+		this.elementVariable.binding.modifiers |= ExtraCompilerModifiers.AccPatternVariable;
+		this.elementVariable.binding.useFlag = LocalVariableBinding.USED;
+		// Why cant this be done in the constructor?
+		this.type = this.elementVariable.type;
+	}
+}
+@Override
+public boolean containsPatternVariable() {
+	return this.elementVariable != null;
+}
+@Override
 public TypeBinding resolveType(BlockScope scope) {
 	this.constant = Constant.NotAConstant;
+	resolvePatternVariable(scope);
 	TypeBinding checkedType = this.type.resolveType(scope, true /* check bounds*/);
 	if (this.expression instanceof CastExpression) {
 		((CastExpression) this.expression).setInstanceofType(checkedType); // for cast expression we need to know instanceof type to not tag unnecessary when needed
@@ -115,7 +180,8 @@
 	} else if (checkedType.isValidBinding()) {
 		// if not a valid binding, an error has already been reported for unresolved type
 		if ((expressionType != TypeBinding.NULL && expressionType.isBaseType()) // disallow autoboxing
-				|| !checkCastTypesCompatibility(scope, checkedType, expressionType, null)) {
+				|| checkedType.isBaseType()
+				|| !checkCastTypesCompatibility(scope, checkedType, expressionType, null, true)) {
 			scope.problemReporter().notCompatibleTypesError(this, expressionType, checkedType);
 		}
 	}
@@ -136,7 +202,11 @@
 public void traverse(ASTVisitor visitor, BlockScope scope) {
 	if (visitor.visit(this, scope)) {
 		this.expression.traverse(visitor, scope);
-		this.type.traverse(visitor, scope);
+		if (this.elementVariable != null) {
+			this.elementVariable.traverse(visitor, scope);
+		} else {
+			this.type.traverse(visitor, scope);
+		}
 	}
 	visitor.endVisit(this, scope);
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntersectionCastTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntersectionCastTypeReference.java
index 09db50d..0f3676b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntersectionCastTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IntersectionCastTypeReference.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -68,14 +68,14 @@
 	public TypeReference[] getTypeReferences() {
 		return this.typeReferences;
 	}
-	
+
 	@Override
 	public TypeBinding resolveType(BlockScope scope, boolean checkBounds, int location) {
 
 		int length = this.typeReferences.length;
 		ReferenceBinding[] intersectingTypes = new ReferenceBinding[length];
 		boolean hasError = false;
-		
+
 		int typeCount = 0;
 		nextType:
 		for (int i = 0; i < length; i++) {
@@ -138,7 +138,7 @@
 			itsSuperclass = firstType.superclass();
 			System.arraycopy(intersectingTypes, 1, interfaces = new ReferenceBinding[typeCount - 1], 0, typeCount - 1);
 		}
-		
+
 		Map invocations = new HashMap(2);
 		nextInterface: for (int i = 0, interfaceCount = interfaces.length; i < interfaceCount; i++) {
 			ReferenceBinding one = interfaces[i];
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Invocation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Invocation.java
index c20d074..5dc4f1d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Invocation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Invocation.java
@@ -29,7 +29,7 @@
 
 	/** Answer the resolved method binding of this invocation */
 	MethodBinding binding();
-	
+
 	/**
 	 * Register the given inference context, which produced the given method as its intermediate result.
 	 * Later when the same method is selected as the most specific method, the inference context
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Javadoc.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Javadoc.java
index 308c39c..63939ca 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Javadoc.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Javadoc.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -33,6 +33,8 @@
 	public TypeReference[] exceptionReferences; // @throws, @exception
 	public JavadocReturnStatement returnStatement; // @return
 	public Expression[] seeReferences; // @see
+	public IJavadocTypeReference[] usesReferences; // @uses
+	public IJavadocTypeReference[] providesReferences; // @provides
 	public long[] inheritedPositions = null;
 	// bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51600
 	// Store param references for tag with invalid syntax
@@ -211,6 +213,11 @@
 		// @param tags
 		int paramTagsSize = this.paramReferences == null ? 0 : this.paramReferences.length;
 		for (int i = 0; i < paramTagsSize; i++) {
+			if(scope.referenceContext instanceof RecordDeclaration) {
+				RecordDeclaration rd = (RecordDeclaration)scope.referenceContext;
+				if(  rd.nRecordComponents > 0)
+					break;
+			}
 			JavadocSingleNameReference param = this.paramReferences[i];
 			scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
 		}
@@ -262,8 +269,29 @@
 			return;
 		}
 		// Do nothing - This is to mimic the SDK's javadoc tool behavior, which neither
-		// sanity checks nor generates documentation using comments at the CU scope 
-		// (unless the unit happens to be package-info.java - in which case we don't come here.) 
+		// sanity checks nor generates documentation using comments at the CU scope
+		// (unless the unit happens to be package-info.java - in which case we don't come here.)
+	}
+
+	/*
+	 * Resolve module info javadoc
+	 */
+	public void resolve(ModuleScope moduleScope) {
+		if ((this.bits & ASTNode.ResolveJavadoc) == 0) {
+			return;
+		}
+
+		this.bits &= ~ASTNode.ResolveJavadoc;// avoid double resolution
+
+		// @see tags
+		int seeTagsLength = this.seeReferences == null ? 0 : this.seeReferences.length;
+		for (int i = 0; i < seeTagsLength; i++) {
+			// Resolve reference
+			resolveReference(this.seeReferences[i], moduleScope);
+		}
+
+		resolveUsesTags(moduleScope, true);
+		resolveProvidesTags(moduleScope, true);
 	}
 
 	/*
@@ -318,7 +346,7 @@
 								MethodBinding current = methDecl.binding;
 								// work 'against' better inference in 1.8 (otherwise comparing (G<T> with G<Object>) would fail):
 								if (methScope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8
-									&& current.typeVariables != Binding.NO_TYPE_VARIABLES) 
+									&& current.typeVariables != Binding.NO_TYPE_VARIABLES)
 								{
 									current = current.asRawMethod(methScope.environment());
 								}
@@ -326,7 +354,7 @@
 									superRef = true;
 								}
 							}
-						}						
+						}
 					}
 				}
 			}
@@ -416,7 +444,7 @@
 					scope.problemReporter().javadocInvalidValueReference(fieldRef.sourceStart, fieldRef.sourceEnd, scopeModifiers);
 				}
 				else if (fieldRef.actualReceiverType != null) {
-					if (scope.enclosingSourceType().isCompatibleWith(fieldRef.actualReceiverType)) {
+					if (scope.kind != Scope.MODULE_SCOPE && scope.enclosingSourceType().isCompatibleWith(fieldRef.actualReceiverType)) {
 						fieldRef.bits |= ASTNode.SuperAccess;
 					}
 					ReferenceBinding resolvedType = (ReferenceBinding) fieldRef.actualReceiverType;
@@ -561,14 +589,158 @@
 	}
 
 	/*
+	 * Resolve @uses tags while block scope
+	 */
+	private void resolveUsesTags(BlockScope scope, boolean reportMissing) {
+		ModuleDeclaration moduleDecl = (ModuleDeclaration)scope.referenceContext();
+		int usesTagsSize = this.usesReferences == null ? 0 : this.usesReferences.length;
+
+		// If no referenced module then report a problem for each uses tag
+		if (moduleDecl == null) {
+			for (int i = 0; i < usesTagsSize; i++) {
+				IJavadocTypeReference uses = this.usesReferences[i];
+				scope.problemReporter().javadocUnexpectedTag(uses.getTagSourceStart(), uses.getTagSourceEnd());
+			}
+			return;
+		}
+
+		// If no uses tags then report a problem for each uses reference
+		int usesSize = moduleDecl.usesCount;
+		if (usesTagsSize == 0) {
+			if (reportMissing) {
+				for (int i = 0; i < usesSize; i++) {
+					UsesStatement uses = moduleDecl.uses[i];
+					scope.problemReporter().javadocMissingUsesTag(uses.serviceInterface, uses.sourceStart, uses.sourceEnd, moduleDecl.binding.modifiers);
+				}
+			}
+		} else {
+			TypeBinding[] bindings = new TypeBinding[usesTagsSize];
+			int maxBindings = 0;
+
+			// Scan all @uses tags
+			for (int i = 0; i < usesTagsSize; i++) {
+				TypeReference usesRef = (TypeReference)this.usesReferences[i];
+				try {
+					usesRef.resolve(scope);
+					if (usesRef.resolvedType != null && usesRef.resolvedType.isValidBinding()) {
+						// Verify duplicated tags
+						boolean found = false;
+						for (int j = 0; j < maxBindings && !found; j++) {
+							if (bindings[j].equals(usesRef.resolvedType)) {
+								scope.problemReporter().javadocDuplicatedUsesTag(usesRef.sourceStart, usesRef.sourceEnd);
+								found = true;
+							}
+						}
+						if (!found) {
+							bindings[maxBindings++] = usesRef.resolvedType;
+						}
+					}
+				} catch (Exception e) {
+					scope.problemReporter().javadocInvalidUsesClass(usesRef.sourceStart, usesRef.sourceEnd);
+				}
+			}
+
+			// Look for undocumented uses
+			if (reportMissing) {
+				for (int i = 0; i < usesSize; i++) {
+					UsesStatement uses = moduleDecl.uses[i];
+					boolean found = false;
+					for (int j = 0; j < maxBindings && !found; j++) {
+						TypeBinding binding = bindings[j];
+						if (uses.serviceInterface.getTypeBinding(scope).equals(binding)) {
+							found = true;
+						}
+					}
+					if (!found) {
+						scope.problemReporter().javadocMissingUsesTag(uses.serviceInterface, uses.sourceStart, uses.sourceEnd, moduleDecl.binding.modifiers);
+					}
+				}
+			}
+		}
+	}
+
+	/*
+	 * Resolve @provides tags while block scope
+	 */
+	private void resolveProvidesTags(BlockScope scope, boolean reportMissing) {
+		ModuleDeclaration moduleDecl = (ModuleDeclaration)scope.referenceContext();
+		int providesTagsSize = this.providesReferences == null ? 0 : this.providesReferences.length;
+
+		// If no referenced module then report a problem for each uses tag
+		if (moduleDecl == null) {
+			for (int i = 0; i < providesTagsSize; i++) {
+				IJavadocTypeReference provides = this.providesReferences[i];
+				scope.problemReporter().javadocUnexpectedTag(provides.getTagSourceStart(), provides.getTagSourceEnd());
+			}
+			return;
+		}
+
+		// If no uses tags then report a problem for each uses reference
+		int providesSize = moduleDecl.servicesCount;
+		if (providesTagsSize == 0) {
+			if (reportMissing) {
+				for (int i = 0; i < providesSize; i++) {
+					ProvidesStatement provides = moduleDecl.services[i];
+					scope.problemReporter().javadocMissingProvidesTag(provides.serviceInterface, provides.sourceStart, provides.sourceEnd, moduleDecl.binding.modifiers);
+				}
+			}
+		} else {
+			TypeBinding[] bindings = new TypeBinding[providesTagsSize];
+			int maxBindings = 0;
+
+			// Scan all @provides tags
+			for (int i = 0; i < providesTagsSize; i++) {
+				TypeReference providesRef = (TypeReference)this.providesReferences[i];
+				try {
+					providesRef.resolve(scope);
+					if (providesRef.resolvedType != null && providesRef.resolvedType.isValidBinding()) {
+						// Verify duplicated tags
+						boolean found = false;
+						for (int j = 0; j < maxBindings && !found; j++) {
+							if (bindings[j].equals(providesRef.resolvedType)) {
+								scope.problemReporter().javadocDuplicatedProvidesTag(providesRef.sourceStart, providesRef.sourceEnd);
+								found = true;
+							}
+						}
+						if (!found) {
+							bindings[maxBindings++] = providesRef.resolvedType;
+						}
+					}
+				} catch (Exception e) {
+					scope.problemReporter().javadocInvalidProvidesClass(providesRef.sourceStart, providesRef.sourceEnd);
+				}
+			}
+
+			// Look for undocumented uses
+			if (reportMissing) {
+				for (int i = 0; i < providesSize; i++) {
+					ProvidesStatement provides = moduleDecl.services[i];
+					boolean found = false;
+					for (int j = 0; j < maxBindings && !found; j++) {
+						TypeBinding binding = bindings[j];
+						if (provides.serviceInterface.getTypeBinding(scope).equals(binding)) {
+							found = true;
+						}
+					}
+					if (!found) {
+						scope.problemReporter().javadocMissingProvidesTag(provides.serviceInterface, provides.sourceStart, provides.sourceEnd, moduleDecl.binding.modifiers);
+					}
+				}
+			}
+		}
+	}
+
+	/*
 	 * Resolve @param tags for type parameters
 	 */
 	private void resolveTypeParameterTags(Scope scope, boolean reportMissing) {
 		int paramTypeParamLength = this.paramTypeParameters == null ? 0 : this.paramTypeParameters.length;
+		int paramReferencesLength = this.paramReferences == null ? 0 : this.paramReferences.length;
 
 		// Get declaration infos
 		TypeParameter[] parameters = null;
 		TypeVariableBinding[] typeVariables = null;
+		Argument[] recordParameters = null;
 		int modifiers = -1;
 		switch (scope.kind) {
 			case Scope.METHOD_SCOPE:
@@ -590,11 +762,16 @@
 				parameters = typeDeclaration.typeParameters;
 				typeVariables = typeDeclaration.binding.typeVariables;
 				modifiers = typeDeclaration.binding.modifiers;
+				if (typeDeclaration instanceof RecordDeclaration) {
+					RecordDeclaration recordDecl = (RecordDeclaration)typeDeclaration;
+					recordParameters = recordDecl.getArgs();
+				}
 				break;
 		}
 
 		// If no type variables then report a problem for each param type parameter tag
-		if (typeVariables == null || typeVariables.length == 0) {
+		if ((recordParameters == null || recordParameters.length == 0)
+				&& (typeVariables == null || typeVariables.length == 0)) {
 			for (int i = 0; i < paramTypeParamLength; i++) {
 				JavadocSingleTypeReference param = this.paramTypeParameters[i];
 				scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd);
@@ -602,9 +779,73 @@
 			return;
 		}
 
+		// If no param tags then report a problem for each record parameter
+		if (recordParameters != null) {
+			reportMissing = reportMissing && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
+			int recordParametersLength = recordParameters.length;
+			String argNames[] = new String[paramReferencesLength];
+			if (paramReferencesLength == 0) {
+				if (reportMissing) {
+					for (int i = 0, l=recordParametersLength; i<l; i++) {
+						scope.problemReporter().javadocMissingParamTag(recordParameters[i].name, recordParameters[i].sourceStart, recordParameters[i].sourceEnd, modifiers);
+					}
+				}
+			} else {
+				// Otherwise verify that all param tags match record args
+				// Scan all @param tags
+				for (int i = 0; i < paramReferencesLength; ++i) {
+					JavadocSingleNameReference param = this.paramReferences[i];
+					String paramName = new String(param.getName()[0]);
+					// Verify duplicated tags
+					boolean duplicate = false;
+					for (int j = 0; j < i && !duplicate; j++) {
+						if (paramName.equals(argNames[j])) {
+							scope.problemReporter().javadocDuplicatedParamTag(param.token, param.sourceStart, param.sourceEnd, modifiers);
+							duplicate = true;
+						}
+					}
+					if (!duplicate) {
+						argNames[i] = paramName;
+					}
+				}
+				// Look for undocumented arguments
+				if (reportMissing) {
+					for (int i = 0; i < recordParameters.length; i++) {
+						Argument arg = recordParameters[i];
+						boolean found = false;
+						for (int j = 0; j < paramReferencesLength && !found; j++) {
+							JavadocSingleNameReference param = this.paramReferences[j];
+							String paramName = new String(param.getName()[0]);
+							if (paramName.equals(new String(arg.name))) {
+								found = true;
+							}
+						}
+						if (!found) {
+							scope.problemReporter().javadocMissingParamTag(arg.name, arg.sourceStart, arg.sourceEnd, modifiers);
+						}
+					}
+				}
+				// Look for param tags that specify non-existent arguments
+				for (int i = 0; i < paramReferencesLength; i++) {
+					JavadocSingleNameReference param = this.paramReferences[i];
+					String paramName = new String(param.getName()[0]);
+					boolean found = false;
+					for (int j = 0; j < recordParameters.length; j++) {
+						Argument arg = recordParameters[j];
+						if (paramName.equals(new String(arg.name))) {
+							found = true;
+						}
+					}
+					if (!found) {
+						scope.problemReporter().javadocInvalidParamTagName(param.sourceStart, param.sourceEnd);
+					}
+				}
+			}
+		}
+
 		// If no param tags then report a problem for each declaration type parameter
 		if (parameters != null) {
-			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=324850, avoid secondary errors when <= 1.4 
+			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=324850, avoid secondary errors when <= 1.4
 			reportMissing = reportMissing && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
 			int typeParametersLength = parameters.length;
 			if (paramTypeParamLength == 0) {
@@ -813,80 +1054,82 @@
 					computedCompoundName[--idx] = topLevelType.fPackage.compoundName[i];
 				}
 
-				ClassScope topLevelScope = scope.classScope();
-				// when scope is not on compilation unit type, then inner class may not be visible...
-				if (topLevelScope.parent.kind != Scope.COMPILATION_UNIT_SCOPE ||
-					!CharOperation.equals(topLevelType.sourceName, topLevelScope.referenceContext.name)) {
-					topLevelScope = topLevelScope.outerMostClassScope();
-					if (typeReference instanceof JavadocSingleTypeReference) {
-						// inner class single reference can only be done in same unit
-						if ((!source15 && depth == 1) || TypeBinding.notEquals(topLevelType, topLevelScope.referenceContext.binding)) {
-							// search for corresponding import
-							boolean hasValidImport = false;
-							if (source15) {
-								CompilationUnitScope unitScope = topLevelScope.compilationUnitScope();
-								ImportBinding[] imports = unitScope.imports;
-								int length = imports == null ? 0 : imports.length;
-								mainLoop: for (int i=0; i<length; i++) {
-									char[][] compoundName = imports[i].compoundName;
-									int compoundNameLength = compoundName.length;
-									if ((imports[i].onDemand && compoundNameLength == computedCompoundName.length-1) 
-											|| (compoundNameLength == computedCompoundName.length)) {
-										for (int j = compoundNameLength; --j >= 0;) {
-											if (CharOperation.equals(imports[i].compoundName[j], computedCompoundName[j])) {
-												if (j == 0) {
-													hasValidImport = true;
-													ImportReference importReference = imports[i].reference;
-													if (importReference != null) {
-														importReference.bits |= ASTNode.Used;
+				if (scope.kind != Scope.MODULE_SCOPE) {
+					ClassScope topLevelScope = scope.classScope();
+					// when scope is not on compilation unit type, then inner class may not be visible...
+					if (topLevelScope.parent.kind != Scope.COMPILATION_UNIT_SCOPE ||
+						!CharOperation.equals(topLevelType.sourceName, topLevelScope.referenceContext.name)) {
+						topLevelScope = topLevelScope.outerMostClassScope();
+						if (typeReference instanceof JavadocSingleTypeReference) {
+							// inner class single reference can only be done in same unit
+							if ((!source15 && depth == 1) || TypeBinding.notEquals(topLevelType, topLevelScope.referenceContext.binding)) {
+								// search for corresponding import
+								boolean hasValidImport = false;
+								if (source15) {
+									CompilationUnitScope unitScope = topLevelScope.compilationUnitScope();
+									ImportBinding[] imports = unitScope.imports;
+									int length = imports == null ? 0 : imports.length;
+									mainLoop: for (int i=0; i<length; i++) {
+										char[][] compoundName = imports[i].compoundName;
+										int compoundNameLength = compoundName.length;
+										if ((imports[i].onDemand && compoundNameLength == computedCompoundName.length-1)
+												|| (compoundNameLength == computedCompoundName.length)) {
+											for (int j = compoundNameLength; --j >= 0;) {
+												if (CharOperation.equals(imports[i].compoundName[j], computedCompoundName[j])) {
+													if (j == 0) {
+														hasValidImport = true;
+														ImportReference importReference = imports[i].reference;
+														if (importReference != null) {
+															importReference.bits |= ASTNode.Used;
+														}
+														break mainLoop;
 													}
-													break mainLoop;
+												} else {
+													break;
 												}
-											} else {
-												break;
 											}
 										}
 									}
-								}
-								if (!hasValidImport) {
+									if (!hasValidImport) {
+										if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers();
+										scope.problemReporter().javadocInvalidMemberTypeQualification(typeReference.sourceStart, typeReference.sourceEnd, scopeModifiers);
+									}
+								} else {
 									if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers();
 									scope.problemReporter().javadocInvalidMemberTypeQualification(typeReference.sourceStart, typeReference.sourceEnd, scopeModifiers);
+									return;
 								}
-							} else {
-								if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers();
-								scope.problemReporter().javadocInvalidMemberTypeQualification(typeReference.sourceStart, typeReference.sourceEnd, scopeModifiers);
-								return;
 							}
 						}
 					}
-				}
-				if (typeReference instanceof JavadocQualifiedTypeReference && !scope.isDefinedInSameUnit(resolvedType)) {
-					// https://bugs.eclipse.org/bugs/show_bug.cgi?id=222188
-					// partially qualified references from a different CU should be warned
-					char[][] typeRefName = ((JavadocQualifiedTypeReference) typeReference).getTypeName();
-					int skipLength = 0;
-					if (topLevelScope.getCurrentPackage() == resolvedType.getPackage()
-							&& typeRefName.length < computedCompoundName.length) {
-						// https://bugs.eclipse.org/bugs/show_bug.cgi?id=221539: references can be partially qualified
-						// in same package and hence if the package name is not given, ignore package name check
-						skipLength = resolvedType.fPackage.compoundName.length;
-					}
-					boolean valid = true;
-					if (typeRefName.length == computedCompoundName.length - skipLength) {
-						checkQualification: for (int i = 0; i < typeRefName.length; i++) {
-							if (!CharOperation.equals(typeRefName[i], computedCompoundName[i + skipLength])) {
-								valid = false;
-								break checkQualification;
-							}
+					if (typeReference instanceof JavadocQualifiedTypeReference && !scope.isDefinedInSameUnit(resolvedType)) {
+						// https://bugs.eclipse.org/bugs/show_bug.cgi?id=222188
+						// partially qualified references from a different CU should be warned
+						char[][] typeRefName = ((JavadocQualifiedTypeReference) typeReference).getTypeName();
+						int skipLength = 0;
+						if (topLevelScope.getCurrentPackage() == resolvedType.getPackage()
+								&& typeRefName.length < computedCompoundName.length) {
+							// https://bugs.eclipse.org/bugs/show_bug.cgi?id=221539: references can be partially qualified
+							// in same package and hence if the package name is not given, ignore package name check
+							skipLength = resolvedType.fPackage.compoundName.length;
 						}
-					} else {
-						valid = false;
-					}
-					// report invalid reference
-					if (!valid) {
-						if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers();
-						scope.problemReporter().javadocInvalidMemberTypeQualification(typeReference.sourceStart, typeReference.sourceEnd, scopeModifiers);
-						return;
+						boolean valid = true;
+						if (typeRefName.length == computedCompoundName.length - skipLength) {
+							checkQualification: for (int i = 0; i < typeRefName.length; i++) {
+								if (!CharOperation.equals(typeRefName[i], computedCompoundName[i + skipLength])) {
+									valid = false;
+									break checkQualification;
+								}
+							}
+						} else {
+							valid = false;
+						}
+						// report invalid reference
+						if (!valid) {
+							if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers();
+							scope.problemReporter().javadocInvalidMemberTypeQualification(typeReference.sourceStart, typeReference.sourceEnd, scopeModifiers);
+							return;
+						}
 					}
 				}
 			}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java
index 6e3f0cb..093658e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java
@@ -29,7 +29,7 @@
 		this.sourceStart = pos;
 		this.sourceEnd = pos;
 	}
-	
+
 	@Override
 	public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) {
 		return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java
index 3ed38f0..ef06cca 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -25,7 +25,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 
 
-public class JavadocQualifiedTypeReference extends QualifiedTypeReference {
+public class JavadocQualifiedTypeReference extends QualifiedTypeReference implements IJavadocTypeReference {
 
 	public int tagSourceStart, tagSourceEnd;
 	public PackageBinding packageBinding;
@@ -72,7 +72,7 @@
 	protected void reportDeprecatedType(TypeBinding type, Scope scope) {
 		scope.problemReporter().javadocDeprecatedType(type, this, scope.getDeclarationModifiers());
 	}
-	
+
 	@Override
 	protected void reportDeprecatedType(TypeBinding type, Scope scope, int index) {
 		scope.problemReporter().javadocDeprecatedType(type, this, scope.getDeclarationModifiers(), index);
@@ -107,4 +107,14 @@
 		visitor.visit(this, scope);
 		visitor.endVisit(this, scope);
 	}
+
+	@Override
+	public int getTagSourceStart() {
+		return this.tagSourceStart;
+	}
+
+	@Override
+	public int getTagSourceEnd() {
+		return this.tagSourceEnd;
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
index b64689b..8a9ed40 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -29,7 +29,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 
 
-public class JavadocSingleTypeReference extends SingleTypeReference {
+public class JavadocSingleTypeReference extends SingleTypeReference implements IJavadocTypeReference {
 
 	public int tagSourceStart, tagSourceEnd;
 	public PackageBinding packageBinding;
@@ -129,4 +129,14 @@
 		visitor.visit(this, scope);
 		visitor.endVisit(this, scope);
 	}
+
+	@Override
+	public int getTagSourceStart() {
+		return this.tagSourceStart;
+	}
+
+	@Override
+	public int getTagSourceEnd() {
+		return this.tagSourceEnd;
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java
index 74f7893..b252fc8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java
@@ -156,7 +156,7 @@
 			return false;
 		return this.statement.doesNotCompleteNormally();
 	}
-	
+
 	@Override
 	public boolean completesByContinue() {
 		return this.statement instanceof ContinueStatement; // NOT this.statement.continuesAtOuterLabel
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
index e2dd0ed..a099afe 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
@@ -223,7 +223,8 @@
 			signature.append(this.expectedType.signature());
 		}
 		int invokeDynamicNumber = codeStream.classFile.recordBootstrapMethod(this);
-		codeStream.invokeDynamic(invokeDynamicNumber, (this.shouldCaptureInstance ? 1 : 0) + this.outerLocalVariablesSlotSize, 1, this.descriptor.selector, signature.toString().toCharArray());
+		codeStream.invokeDynamic(invokeDynamicNumber, (this.shouldCaptureInstance ? 1 : 0) + this.outerLocalVariablesSlotSize, 1, this.descriptor.selector, signature.toString().toCharArray(),
+				this.resolvedType.id, this.resolvedType);
 		if (!valueRequired)
 			codeStream.pop();
 		codeStream.recordPositionsFrom(pc, this.sourceStart);		
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java
index 7cb9e04..38ad2d8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java
@@ -46,6 +46,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Consumer;
 
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.impl.*;
@@ -61,6 +62,12 @@
 
 	public LocalVariableBinding binding;
 
+	/**
+	 * For pattern variable, resolve() may store here an obligation to be checked when we have
+	 * a flow info that tells us whether a potential duplicates is in fact in scope.
+	 */
+	Consumer<FlowInfo> duplicateCheckObligation;
+
 	public LocalDeclaration(
 		char[] name,
 		int sourceStart,
@@ -268,7 +275,9 @@
 	
 	@Override
 	public void resolve(BlockScope scope) {
-
+		resolve(scope, false);
+	}
+	public void resolve(BlockScope scope, boolean isPatternVariable) {
 		// prescan NNBD
 		handleNonNullByDefault(scope, this.annotations, this);
 
@@ -308,6 +317,15 @@
 		Binding existingVariable = scope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/);
 		if (existingVariable != null && existingVariable.isValidBinding()){
 			boolean localExists = existingVariable instanceof LocalVariableBinding; 
+			if (localExists && isPatternVariable
+					&& (((LocalVariableBinding) existingVariable).modifiers & ExtraCompilerModifiers.AccPatternVariable) != 0)
+			{
+				this.duplicateCheckObligation = (flowInfo) -> {
+					if (flowInfo.isDefinitelyAssigned((LocalVariableBinding) existingVariable)) {
+						scope.problemReporter().redefineLocal(this);
+					}
+				};
+			} else {
 			if (localExists && (this.bits & ASTNode.ShadowsOuterLocal) != 0 && scope.isLambdaSubscope() && this.hiddenVariableDepth == 0) {
 					scope.problemReporter().lambdaRedeclaresLocal(this);
 			} else if (localExists && this.hiddenVariableDepth == 0) {
@@ -316,6 +334,7 @@
 				scope.problemReporter().localVariableHiding(this, existingVariable, false);
 			}
 		}
+		}
 
 		if ((this.modifiers & ClassFileConstants.AccFinal)!= 0 && this.initialization == null) {
 			this.modifiers |= ExtraCompilerModifiers.AccBlankFinal;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java
index b65a667..a217432 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java
@@ -119,7 +119,7 @@
 							&& requiredType.dimensions() == 1
 							&& (MemberValuePair.this.value.isConstantValueOfTypeAssignableToType(valueType, leafType)
 									|| valueType.isCompatibleWith(leafType)))) {
-						
+
 						if (leafType.isAnnotationType() && !valueType.isAnnotationType()) {
 							scope.problemReporter().annotationValueMustBeAnnotation(MemberValuePair.this.binding.declaringClass,
 									MemberValuePair.this.name, MemberValuePair.this.value, leafType);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
index edfe595..580c0ef 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -70,6 +70,7 @@
 import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.*;
 
 import java.util.HashMap;
+import java.util.function.BiConsumer;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
@@ -146,6 +147,9 @@
 	public TypeBinding[] argumentTypes = Binding.NO_PARAMETERS;
 	public boolean argumentsHaveErrors = false;
 	
+	public FakedTrackingVariable closeTracker;
+
+	BiConsumer<FlowInfo, Boolean> flowUpdateOnBooleanResult; // we assume only one arg can be affected, hence no need for a list of updates
 
 @Override
 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
@@ -223,6 +227,18 @@
 				case NULL_ASSERTION:
 					flowInfo = analyseNullAssertion(currentScope, argument, flowContext, flowInfo, true);
 					break;
+				case ARG_NONNULL_IF_TRUE:
+					recordFlowUpdateOnResult(((SingleNameReference) argument).localVariableBinding(), true, false);
+					flowInfo = argument.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
+					break;
+				case ARG_NONNULL_IF_TRUE_NEGATABLE:
+					recordFlowUpdateOnResult(((SingleNameReference) argument).localVariableBinding(), true, true);
+					flowInfo = argument.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
+					break;
+				case ARG_NULL_IF_TRUE:
+					recordFlowUpdateOnResult(((SingleNameReference) argument).localVariableBinding(), false, true);
+					flowInfo = argument.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
+					break;
 				default:
 					flowInfo = argument.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
 			}
@@ -245,19 +261,39 @@
 		//               checkExceptionHandlers; consider protecting there instead of here;
 		//               NullReferenceTest#test0510
 	}
+	// after having analysed exceptions above start tracking newly allocated resource:
+	if (analyseResources && FakedTrackingVariable.isAnyCloseable(this.resolvedType))
+		flowInfo = FakedTrackingVariable.analyseCloseableAcquisition(currentScope, flowInfo, this);
+
 	manageSyntheticAccessIfNecessary(currentScope, flowInfo);
 	// account for pot. exceptions thrown by method execution
 	flowContext.recordAbruptExit();
 	flowContext.expireNullCheckedFieldInfo(); // no longer trust this info after any message send
 	return flowInfo;
 }
+public void recordFlowUpdateOnResult(LocalVariableBinding local, boolean nonNullIfTrue, boolean negatable) {
+	this.flowUpdateOnBooleanResult = (f, result) -> {
+		if (result || negatable) {
+			if (result == nonNullIfTrue)
+				f.markAsDefinitelyNonNull(local);
+			else
+				f.markAsDefinitelyNull(local);
+		}
+	};
+}
+@Override
+protected void updateFlowOnBooleanResult(FlowInfo flowInfo, boolean result) {
+	if (this.flowUpdateOnBooleanResult != null) {
+		this.flowUpdateOnBooleanResult.accept(flowInfo, result);
+	}
+}
 private void yieldQualifiedCheck(BlockScope currentScope) {
 	long sourceLevel = currentScope.compilerOptions().sourceLevel;
-	if (sourceLevel < ClassFileConstants.JDK13 || !this.receiverIsImplicitThis())
+	if (sourceLevel < ClassFileConstants.JDK14 || !this.receiverIsImplicitThis())
 		return;
 	if (this.selector == null || !("yield".equals(new String(this.selector)))) //$NON-NLS-1$
 		return;
-	if (sourceLevel == ClassFileConstants.JDK13 && currentScope.compilerOptions().enablePreviewFeatures) {
+	if (sourceLevel >= ClassFileConstants.JDK14) {
 		currentScope.problemReporter().switchExpressionsYieldUnqualifiedMethodError(this);
 	} else {
 		currentScope.problemReporter().switchExpressionsYieldUnqualifiedMethodWarning(this);
@@ -275,78 +311,93 @@
 }
 
 // classification of well-known assertion utilities:
-private static final int TRUE_ASSERTION = 1;
-private static final int FALSE_ASSERTION = 2;
-private static final int NULL_ASSERTION = 3;
-private static final int NONNULL_ASSERTION = 4;
+private enum AssertUtil { NONE, TRUE_ASSERTION, FALSE_ASSERTION, NULL_ASSERTION, NONNULL_ASSERTION, ARG_NONNULL_IF_TRUE, ARG_NONNULL_IF_TRUE_NEGATABLE, ARG_NULL_IF_TRUE }
 
 // is the argument at the given position being checked by a well-known assertion utility?
 // if so answer what kind of assertion we are facing.
-private int detectAssertionUtility(int argumentIdx) {
+private AssertUtil detectAssertionUtility(int argumentIdx) {
 	TypeBinding[] parameters = this.binding.original().parameters;
 	if (argumentIdx < parameters.length) {
 		TypeBinding parameterType = parameters[argumentIdx];
 		TypeBinding declaringClass = this.binding.declaringClass;
 		if (declaringClass != null && parameterType != null) {
-			switch (declaringClass.id) {
+			switch (declaringClass.original().id) {
 				case TypeIds.T_OrgEclipseCoreRuntimeAssert:
 					if (parameterType.id == TypeIds.T_boolean)
-						return TRUE_ASSERTION;
+						return AssertUtil.TRUE_ASSERTION;
 					if (parameterType.id == TypeIds.T_JavaLangObject && CharOperation.equals(TypeConstants.IS_NOTNULL, this.selector))
-						return NONNULL_ASSERTION;
+						return AssertUtil.NONNULL_ASSERTION;
 					break;
 				case TypeIds.T_JunitFrameworkAssert:
 				case TypeIds.T_OrgJunitAssert:
 					if (parameterType.id == TypeIds.T_boolean) {
 						if (CharOperation.equals(TypeConstants.ASSERT_TRUE, this.selector))
-							return TRUE_ASSERTION;
+							return AssertUtil.TRUE_ASSERTION;
 						if (CharOperation.equals(TypeConstants.ASSERT_FALSE, this.selector))
-							return FALSE_ASSERTION;
+							return AssertUtil.FALSE_ASSERTION;
 					} else if (parameterType.id == TypeIds.T_JavaLangObject) {
 						if (CharOperation.equals(TypeConstants.ASSERT_NOTNULL, this.selector))
-							return NONNULL_ASSERTION;
+							return AssertUtil.NONNULL_ASSERTION;
 						if (CharOperation.equals(TypeConstants.ASSERT_NULL, this.selector))
-							return NULL_ASSERTION;
+							return AssertUtil.NULL_ASSERTION;
 					}
 					break;
 				case TypeIds.T_OrgApacheCommonsLangValidate:
 					if (parameterType.id == TypeIds.T_boolean) {
 						if (CharOperation.equals(TypeConstants.IS_TRUE, this.selector))
-							return TRUE_ASSERTION;
+							return AssertUtil.TRUE_ASSERTION;
 					} else if (parameterType.id == TypeIds.T_JavaLangObject) {
 						if (CharOperation.equals(TypeConstants.NOT_NULL, this.selector))
-							return NONNULL_ASSERTION;
+							return AssertUtil.NONNULL_ASSERTION;
 					}
 					break;
 				case TypeIds.T_OrgApacheCommonsLang3Validate:
 					if (parameterType.id == TypeIds.T_boolean) {
 						if (CharOperation.equals(TypeConstants.IS_TRUE, this.selector))
-							return TRUE_ASSERTION;
+							return AssertUtil.TRUE_ASSERTION;
 					} else if (parameterType.isTypeVariable()) {
 						if (CharOperation.equals(TypeConstants.NOT_NULL, this.selector))
-							return NONNULL_ASSERTION;
+							return AssertUtil.NONNULL_ASSERTION;
 					}
 					break;
 				case TypeIds.T_ComGoogleCommonBasePreconditions:
 					if (parameterType.id == TypeIds.T_boolean) {
 						if (CharOperation.equals(TypeConstants.CHECK_ARGUMENT, this.selector)
 							|| CharOperation.equals(TypeConstants.CHECK_STATE, this.selector))
-							return TRUE_ASSERTION;
+							return AssertUtil.TRUE_ASSERTION;
 					} else if (parameterType.isTypeVariable()) {
 						if (CharOperation.equals(TypeConstants.CHECK_NOT_NULL, this.selector))
-							return NONNULL_ASSERTION;
+							return AssertUtil.NONNULL_ASSERTION;
 					}
 					break;					
 				case TypeIds.T_JavaUtilObjects:
 					if (parameterType.isTypeVariable()) {
 						if (CharOperation.equals(TypeConstants.REQUIRE_NON_NULL, this.selector))
-							return NONNULL_ASSERTION;
+							return AssertUtil.NONNULL_ASSERTION;
+					}
+					if (this.arguments[argumentIdx] instanceof SingleNameReference) {
+						SingleNameReference nameRef = (SingleNameReference) this.arguments[argumentIdx];
+						if (nameRef.binding instanceof LocalVariableBinding) {
+							if (CharOperation.equals(TypeConstants.NON_NULL, this.selector))
+								return AssertUtil.ARG_NONNULL_IF_TRUE_NEGATABLE;
+							if (CharOperation.equals(TypeConstants.IS_NULL, this.selector))
+								return AssertUtil.ARG_NULL_IF_TRUE;
+						}
+					}
+					break;
+				case TypeIds.T_JavaLangClass:
+					if (CharOperation.equals(TypeConstants.IS_INSTANCE, this.selector)) {
+						if (this.arguments[argumentIdx] instanceof SingleNameReference) {
+							SingleNameReference nameRef = (SingleNameReference) this.arguments[argumentIdx];
+							if (nameRef.binding instanceof LocalVariableBinding)
+								return AssertUtil.ARG_NONNULL_IF_TRUE;
+					}
 					}
 					break;					
 			}
 		}
 	}
-	return 0;
+	return AssertUtil.NONE;
 }
 private FlowInfo analyseBooleanAssertion(BlockScope currentScope, Expression argument,
 		FlowContext flowContext, FlowInfo flowInfo, boolean wasInsideAssert, boolean passOnTrue)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java
index b479b92..a811880 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -91,14 +91,14 @@
 			// may be in a non necessary <clinit> for innerclass with static final constant fields
 			if (this.binding.isAbstract() || this.binding.isNative())
 				return;
-			
+
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=385780
 			if (this.typeParameters != null &&
 					!this.scope.referenceCompilationUnit().compilationResult.hasSyntaxError) {
 				for (int i = 0, length = this.typeParameters.length; i < length; ++i) {
 					TypeParameter typeParameter = this.typeParameters[i];
 					if ((typeParameter.binding.modifiers  & ExtraCompilerModifiers.AccLocallyUsed) == 0) {
-						this.scope.problemReporter().unusedTypeParameter(typeParameter);						
+						this.scope.problemReporter().unusedTypeParameter(typeParameter);
 					}
 				}
 			}
@@ -120,7 +120,8 @@
 			}
 			// propagate to statements
 			if (this.statements != null) {
-				boolean enableSyntacticNullAnalysisForFields = this.scope.compilerOptions().enableSyntacticNullAnalysisForFields;
+				CompilerOptions compilerOptions = this.scope.compilerOptions();
+				boolean enableSyntacticNullAnalysisForFields = compilerOptions.enableSyntacticNullAnalysisForFields;
 				int complaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) == 0 ? Statement.NOT_COMPLAINED : Statement.COMPLAINED_FAKE_REACHABLE;
 				for (int i = 0, count = this.statements.length; i < count; i++) {
 					Statement stat = this.statements[i];
@@ -130,6 +131,9 @@
 					if (enableSyntacticNullAnalysisForFields) {
 						methodContext.expireNullCheckedFieldInfo();
 					}
+					if (compilerOptions.analyseResourceLeaks) {
+						FakedTrackingVariable.cleanUpUnassigned(this.scope, stat, flowInfo);
+					}
 				}
 			} else {
 				// method with empty body should not be flagged as static.
@@ -159,7 +163,7 @@
 						this.scope.problemReporter().methodCanBePotentiallyDeclaredStatic(this);
 					}
 				}
-					
+
 			}
 			this.scope.checkUnclosedCloseables(flowInfo, null, null/*don't report against a specific location*/, null);
 		} catch (AbortMethod e) {
@@ -175,10 +179,10 @@
 			annotation.traverse(collector, (BlockScope) null);
 		}
 	}
-	
+
 	public boolean hasNullTypeAnnotation(AnnotationPosition position) {
 		// parser associates SE8 annotations to the declaration
-		return TypeReference.containsNullAnnotation(this.annotations) || 
+		return TypeReference.containsNullAnnotation(this.annotations) ||
 				(this.returnType != null && this.returnType.hasNullTypeAnnotation(position)); // just in case
 	}
 
@@ -193,9 +197,31 @@
 	}
 
 	@Override
+	public Argument getRecordComponent() {
+		if (this.arguments != null && this.arguments.length != 0)
+			return null;
+		ClassScope skope = this.scope.classScope();
+		if (!(skope.referenceContext instanceof RecordDeclaration))
+			return null;
+		RecordDeclaration rd = (RecordDeclaration) skope.referenceContext;
+		Argument[] args = rd.getArgs();
+		if (args == null || args.length == 0)
+			return null;
+		for (Argument arg : rd.getArgs()) {
+			if (arg == null || arg.name == null)
+				continue;
+			if (CharOperation.equals(this.selector, arg.name)) {
+				return arg;
+			}
+		}
+		return null;
+	}
+
+	@Override
 	public void parseStatements(Parser parser, CompilationUnitDeclaration unit) {
 		//fill up the method body with statement
 		parser.parse(this, unit);
+		this.containsSwitchWithTry = parser.switchWithTry;
 	}
 
 	@Override
@@ -212,6 +238,22 @@
 			this.returnType.resolvedType = this.binding.returnType;
 			// record the return type binding
 		}
+		Argument recordComponent = getRecordComponent();
+		if (recordComponent != null) {
+			/* JLS 14 Records Sec 8.10.3 */
+			if (this.returnType != null && TypeBinding.notEquals(this.returnType.resolvedType, recordComponent.type.resolvedType))
+				this.scope.problemReporter().recordIllegalAccessorReturnType(this.returnType, recordComponent.type.resolvedType);
+			if (this.typeParameters != null)
+				this.scope.problemReporter().recordAccessorMethodShouldNotBeGeneric(this);
+			if (this.binding != null) {
+				if ((this.binding.modifiers & ClassFileConstants.AccPublic) == 0)
+					this.scope.problemReporter().recordAccessorMethodShouldBePublic(this);
+				if ((this.binding.modifiers & ClassFileConstants.AccStatic) != 0)
+					this.scope.problemReporter().recordAccessorMethodShouldNotBeStatic(this);
+			}
+			if (this.thrownExceptions != null)
+				this.scope.problemReporter().recordAccessorMethodHasThrowsClause(this);
+		}
 		// check if method with constructor name
 		if (CharOperation.equals(this.scope.enclosingSourceType().sourceName, this.selector)) {
 			this.scope.problemReporter().methodWithConstructorName(this);
@@ -265,7 +307,7 @@
 									// actually overrides, but did not claim to do so
 									this.scope.problemReporter().missingOverrideAnnotationForInterfaceMethodImplementation(this);
 							}
-							
+
 						}
 				}
 				else {	//For 1.6 and above only
@@ -287,6 +329,7 @@
 				if (this.selector == TypeConstants.VALUEOF) break;
 				//$FALL-THROUGH$
 			case TypeDeclaration.CLASS_DECL :
+			case TypeDeclaration.RECORD_DECL:
 				// if a method has an semicolon body and is not declared as abstract==>error
 				// native methods may have a semicolon body
 				if ((this.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java
index 2bc4e22..b6a089d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
@@ -31,12 +31,11 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
-import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
 import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
-import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
 import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
+import org.eclipse.jdt.internal.compiler.lookup.ModuleScope;
 import org.eclipse.jdt.internal.compiler.lookup.PlainPackageBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Scope;
 import org.eclipse.jdt.internal.compiler.lookup.SourceModuleBinding;
@@ -45,7 +44,6 @@
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit;
 import org.eclipse.jdt.internal.compiler.problem.AbortMethod;
 import org.eclipse.jdt.internal.compiler.problem.AbortType;
-import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
 import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
 
 public class ModuleDeclaration extends ASTNode implements ReferenceContext {
@@ -67,7 +65,7 @@
 	public int bodyStart;
 	public int bodyEnd; // doesn't include the trailing comment if any.
 	public int modifiersSourceStart;
-	public BlockScope scope;
+	public ModuleScope scope;
 	public char[][] tokens;
 	public char[] moduleName;
 	public long[] sourcePositions;
@@ -110,21 +108,7 @@
 	}
 
 	public void createScope(final Scope parentScope) {
-		this.scope = new MethodScope(parentScope, null, true) {
-			@Override
-			public ProblemReporter problemReporter() {
-				// this method scope has no reference context so we better deletegate to the 'real' cuScope:
-				return parentScope.problemReporter();
-			}
-			@Override
-			public ReferenceContext referenceContext() {
-				return ModuleDeclaration.this;
-			}
-			@Override
-			public boolean isModuleScope() {
-				return true;
-			}
-		};
+		this.scope = new ModuleScope(parentScope, this);
 	}
 
 	public void generateCode() {
@@ -277,13 +261,13 @@
 			}
 		}
 		this.binding.setUses(allTypes.toArray(new TypeBinding[allTypes.size()]));
-		
+
 		Set<TypeBinding> interfaces = new HashSet<>();
 		for(int i = 0; i < this.servicesCount; i++) {
 			this.services[i].resolve(this.scope);
 			TypeBinding infBinding = this.services[i].serviceInterface.resolvedType;
 			if (infBinding != null && infBinding.isValidBinding()) {
-				if (!interfaces.add(this.services[i].serviceInterface.resolvedType)) { 
+				if (!interfaces.add(this.services[i].serviceInterface.resolvedType)) {
 					cuScope.problemReporter().duplicateTypeReference(IProblem.DuplicateServices,
 							this.services[i].serviceInterface);
 				}
@@ -297,7 +281,7 @@
 		analyseModuleGraph(skope);
 		analyseReferencedPackages(skope);
 	}
-	
+
 	private void analyseReferencedPackages(CompilationUnitScope skope) {
 		if (this.exports != null) {
 			analyseSomeReferencedPackages(this.exports, skope);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleReference.java
index 4f9af71..c8ebf64 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleStatement.java
index a53484f..62c9ac2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ModuleStatement.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java
index 0a5bed7..022279a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NameReference.java
@@ -13,7 +13,7 @@
  *     Stephan Herrmann - Contribution for
  *								bug 331649 - [compiler][null] consider null annotations for fields
  *								Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec)
- *								Bug 426996 - [1.8][inference] try to avoid method Expression.unresolve()? 
+ *								Bug 426996 - [1.8][inference] try to avoid method Expression.unresolve()?
  *     Jesper S Moller - Contributions for
  *							bug 382721 - [1.8][compiler] Effectively final variables needs special treatment
  *******************************************************************************/
@@ -39,7 +39,7 @@
 	this.bits |= Binding.TYPE | Binding.VARIABLE; // restrictiveFlag
 }
 
-/** 
+/**
  * Use this method only when sure that the current reference is <strong>not</strong>
  * a chain of several fields (QualifiedNameReference with more than one field).
  * Otherwise use {@link #lastFieldBinding()}.
@@ -102,7 +102,7 @@
 
 public abstract char[][] getName();
 
-/* Called during code generation to ensure that outer locals's effectively finality is guaranteed. 
+/* Called during code generation to ensure that outer locals's effectively finality is guaranteed.
    Aborts if constraints are violated. Due to various complexities, this check is not conveniently
    implementable in resolve/analyze phases.
 */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java
index bf66588..6a7c710 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2019 GK Software AG and others.
+ * Copyright (c) 2013, 2020 GK Software AG and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -51,7 +51,7 @@
  * @since 3.10
  */
 public class NullAnnotationMatching {
-	
+
 	public static final NullAnnotationMatching NULL_ANNOTATIONS_OK = new NullAnnotationMatching(Severity.OK, FlowInfo.UNKNOWN, null);
 	public static final NullAnnotationMatching NULL_ANNOTATIONS_OK_NONNULL = new NullAnnotationMatching(Severity.OK, FlowInfo.NON_NULL, null);
 	public static final NullAnnotationMatching NULL_ANNOTATIONS_UNCHECKED = new NullAnnotationMatching(Severity.UNCHECKED, FlowInfo.UNKNOWN, null);
@@ -74,7 +74,7 @@
 		OVERRIDE_RETURN {
 			@Override CheckMode toDetail() {
 				return OVERRIDE;
-			}			
+			}
 		},
 		/** in this mode we do not tolerate incompatibly missing annotations on type parameters (for overriding analysis) */
 		OVERRIDE {
@@ -85,7 +85,7 @@
 				return OVERRIDE;
 			}
 		};
-		
+
 		boolean requiredNullableMatchesAll() {
 			return false;
 		}
@@ -101,6 +101,8 @@
 		LEGACY_WARNING,
 		/** Need unchecked conversion from unannotated to annotated. */
 		UNCHECKED,
+		/** Need unchecked conversion to pass type with annotated type arguments into unannotated code. */
+		UNCHECKED_TO_UNANNOTATED,
 		/** Definite nullity mismatch. */
 		MISMATCH;
 
@@ -109,28 +111,37 @@
 				return severity;
 			return this;
 		}
-	
+
 		public boolean isAnyMismatch() {
 			return compareTo(LEGACY_WARNING) > 0;
 		}
 	}
 
 	private final Severity severity;
-	
+
 	/** If non-null this field holds the supertype of the provided type which was used for direct matching. */
 	public final TypeBinding superTypeHint;
 	public final int nullStatus;
-	
+
 	NullAnnotationMatching(Severity severity, int nullStatus, TypeBinding superTypeHint) {
 		this.severity = severity;
 		this.superTypeHint = superTypeHint;
 		this.nullStatus = nullStatus;
 	}
 
-	public boolean isAnyMismatch()      { return this.severity.isAnyMismatch(); }
-	public boolean isUnchecked()        { return this.severity == Severity.UNCHECKED; }
-	public boolean isDefiniteMismatch() { return this.severity == Severity.MISMATCH; }
-	public boolean wantToReport() 		{ return this.severity == Severity.LEGACY_WARNING; }
+	/**
+ 	 * For creating updated status during *FlowContext.complainOnDeferred*Checks() once the actual nullStatus is known
+	 */
+	public NullAnnotationMatching withNullStatus(int updatedNullStatus) {
+		return updatedNullStatus == this.nullStatus ? this
+				: new NullAnnotationMatching(this.severity, updatedNullStatus, this.superTypeHint);
+	}
+
+	public boolean isAnyMismatch()      		{ return this.severity.isAnyMismatch(); }
+	public boolean isUnchecked()        		{ return this.severity == Severity.UNCHECKED || this.severity == Severity.UNCHECKED_TO_UNANNOTATED; }
+	public boolean isAnnotatedToUnannotated() 	{ return this.severity == Severity.UNCHECKED_TO_UNANNOTATED; }
+	public boolean isDefiniteMismatch() 		{ return this.severity == Severity.MISMATCH; }
+	public boolean wantToReport() 				{ return this.severity == Severity.LEGACY_WARNING; }
 
 	public boolean isPotentiallyNullMismatch() {
 		return !isDefiniteMismatch() && this.nullStatus != -1 && (this.nullStatus & FlowInfo.POTENTIALLY_NULL) != 0;
@@ -139,7 +150,7 @@
 	public String superTypeHintName(CompilerOptions options, boolean shortNames) {
 		return String.valueOf(this.superTypeHint.nullAnnotatedReadableName(options, shortNames));
 	}
-	
+
 	/** Check null-ness of 'var' against a possible null annotation */
 	public static int checkAssignment(BlockScope currentScope, FlowContext flowContext,
 									   VariableBinding var, FlowInfo flowInfo, int nullStatus, Expression expression, TypeBinding providedType)
@@ -169,7 +180,7 @@
 				for (int i = 1, l = resExprs.length; i < l; ++i) {
 					re = resExprs[i];
 					int otherStatus = NullAnnotationMatching.checkAssignment(currentScope, flowContext, var, flowInfo,  re.nullStatus(flowInfo, flowContext), re, re.resolvedType);
-					identicalStatus &= status0 == otherStatus;		
+					identicalStatus &= status0 == otherStatus;
 				}
 				return identicalStatus ? status0 : nullStatus; // if not all branches agree use the precomputed & merged nullStatus
 			}
@@ -228,6 +239,7 @@
 		try {
 			Severity severity = Severity.OK;
 			TypeBinding superTypeHint = null;
+			TypeBinding originalRequiredType = requiredType;
 			NullAnnotationMatching okStatus = NullAnnotationMatching.NULL_ANNOTATIONS_OK;
 			if (areSameTypes(requiredType, providedType, providedSubstitute)) {
 				if ((requiredType.tagBits & TagBits.AnnotationNonNull) != 0)
@@ -282,13 +294,13 @@
 							long requiredBits = validNullTagBits(requiredDimsTagBits[i]);
 							long providedBits = validNullTagBits(providedDimsTagBits[i]);
 							if (i == 0 && requiredBits == TagBits.AnnotationNullable && nullStatus != -1 && mode.requiredNullableMatchesAll()) {
-								// toplevel nullable array: no need to check 
+								// toplevel nullable array: no need to check
 								if (nullStatus == FlowInfo.NULL)
 									break; // null value has no details
 							} else {
 								if (i > 0)
 									currentNullStatus = -1; // don't use beyond the outermost dimension
-								Severity dimSeverity = computeNullProblemSeverity(requiredBits, providedBits, currentNullStatus, i == 0 ? mode : mode.toDetail(), false);
+								Severity dimSeverity = computeNullProblemSeverity(requiredBits, providedBits, currentNullStatus, i == 0 ? mode : mode.toDetail(), null);
 								if (i > 0 && dimSeverity == Severity.UNCHECKED
 										&& providedExpression instanceof ArrayAllocationExpression
 										&& providedBits == 0 && requiredBits != 0)
@@ -322,11 +334,14 @@
 					// at toplevel (having a nullStatus) nullable matches all
 				} else {
 					long providedBits = providedNullTagBits(providedType);
-					Severity s = computeNullProblemSeverity(requiredBits, providedBits, nullStatus, mode, requiredType.isTypeVariable());
+					Severity s = computeNullProblemSeverity(requiredBits, providedBits, nullStatus, mode, originalRequiredType);
 					if (s.isAnyMismatch() && requiredType.isWildcard() && requiredBits != 0) {
 						if (((WildcardBinding) requiredType).determineNullBitsFromDeclaration(null, null) == 0) {
-							// wildcard has its nullBits from the type variable: avoid redundant warning.
-							s = Severity.OK;
+							TypeVariableBinding typeVariable = ((WildcardBinding) requiredType).typeVariable();
+							if ((typeVariable.tagBits & TagBits.AnnotationNullMASK) != 0) {
+								// wildcard has its nullBits from the type variable
+								s = Severity.OK; // is already reported as illegal substitution
+							}
 						}
 					}
 					severity = severity.max(s);
@@ -380,7 +395,7 @@
 			if (method != null && method.isValidBinding()) {
 				MethodBinding originalMethod = method.original();
 				TypeBinding originalDeclaringClass = originalMethod.declaringClass;
-				if (originalDeclaringClass instanceof BinaryTypeBinding 
+				if (originalDeclaringClass instanceof BinaryTypeBinding
 						&& ((BinaryTypeBinding) originalDeclaringClass).externalAnnotationStatus.isPotentiallyUnannotatedLib()
 						&& originalMethod.returnType.isTypeVariable()
 						&& (originalMethod.returnType.tagBits & TagBits.AnnotationNullMASK) == 0)
@@ -433,9 +448,22 @@
 			return validNullTagBits(tagBits);
 
 		if (type.isWildcard()) {
+			WildcardBinding wildcardBinding = (WildcardBinding) type;
+			TypeBinding bound = wildcardBinding.bound;
+			tagBits = bound != null ? bound.tagBits & TagBits.AnnotationNullMASK : 0;
+			switch (wildcardBinding.boundKind) {
+				case Wildcard.SUPER:
+					if (tagBits == TagBits.AnnotationNullable)
+						return TagBits.AnnotationNullable; // type cannot require @NonNull
+					break;
+				case Wildcard.EXTENDS:
+					if (tagBits == TagBits.AnnotationNonNull)
+						return tagBits;
+					break;
+			}
 			return TagBits.AnnotationNullMASK;
-		} 
-		
+		}
+
 		if (type.isTypeVariable()) {
 			// assume we must require @NonNull, unless lower @Nullable bound
 			// (annotation directly on the TV has already been checked above)
@@ -468,11 +496,11 @@
 		long tagBits = type.tagBits & TagBits.AnnotationNullMASK;
 		if (tagBits != 0)
 			return validNullTagBits(tagBits);
-		
+
 		if (type.isWildcard()) { // wildcard can be 'provided' during inheritance checks
 			return TagBits.AnnotationNullMASK;
 		}
-	
+
 		if (type.isTypeVariable()) { // incl. captures
 			TypeVariableBinding typeVariable = (TypeVariableBinding)type;
 			boolean haveNullBits = false;
@@ -516,7 +544,7 @@
 		bits &= TagBits.AnnotationNullMASK;
 		return bits == TagBits.AnnotationNullMASK ? 0 : bits;
 	}
-	
+
 	/** Provided that both types are {@link TypeBinding#equalsEquals}, return the one that is more likely to show null at runtime. */
 	public static TypeBinding moreDangerousType(TypeBinding one, TypeBinding two) {
 		if (one == null) return null;
@@ -544,29 +572,44 @@
 	 * @param providedBits null tagBits of the provided type
 	 * @param nullStatus -1 means: don't use, other values see constants in FlowInfo
 	 * @param mode check mode (see {@link CheckMode})
-	 * @param requiredIsTypeVariable is the required type a type variable (possibly: "free type variable")?
+	 * @param requiredType the required type, used, e.g., to check if it is a type variable (possibly: "free type variable")?
 	 * @return see {@link #severity} for interpretation of values
 	 */
-	private static Severity computeNullProblemSeverity(long requiredBits, long providedBits, int nullStatus, CheckMode mode, boolean requiredIsTypeVariable) {
+	private static Severity computeNullProblemSeverity(long requiredBits, long providedBits, int nullStatus, CheckMode mode, TypeBinding requiredType) {
 		if (requiredBits == providedBits)
 			return Severity.OK;
-		if (requiredBits == 0) { 
+		if (requiredBits == 0) {
 			switch (mode) {
+				case EXACT:
+					if (providedBits == TagBits.AnnotationNonNull && !(requiredType instanceof TypeVariableBinding))
+						return Severity.UNCHECKED_TO_UNANNOTATED;
+					return Severity.OK;
 				case COMPATIBLE:
 				case BOUND_CHECK:
 				case BOUND_SUPER_CHECK:
-				case EXACT:
 					return Severity.OK;
 				case OVERRIDE_RETURN:
 					if (providedBits == TagBits.AnnotationNonNull)
 						return Severity.OK; // covariant redefinition to nonnull is good
-					if (!requiredIsTypeVariable)
+					if (!(requiredType instanceof TypeVariableBinding))
 						return Severity.OK; // refining an unconstrained non-TVB return to nullable is also legal
 					return Severity.UNCHECKED;
 				case OVERRIDE:
 					return Severity.UNCHECKED; // warn about dropped annotation
 			}
 		} else if (requiredBits == TagBits.AnnotationNullMASK) {
+			if (mode == CheckMode.EXACT && providedBits == TagBits.AnnotationNonNull) {
+				if (requiredType instanceof WildcardBinding) {
+					WildcardBinding wildcard = (WildcardBinding) requiredType;
+					// passing '@NonNull X' into '? super Y' risks pollution with null
+					if (wildcard.boundKind == Wildcard.SUPER && providedBits == TagBits.AnnotationNonNull) {
+						TypeBinding bound = wildcard.bound;
+						if (bound != null && (bound.tagBits & TagBits.AnnotationNullMASK) != 0)
+							return Severity.OK; // when the wildcard is annotated via its bound, there is not annotated->unannotated conversion
+						return Severity.UNCHECKED_TO_UNANNOTATED;
+					}
+				}
+			}
 			return Severity.OK; // OK since LHS accepts either
 		} else if (requiredBits == TagBits.AnnotationNonNull) {
 			switch (mode) {
@@ -586,7 +629,7 @@
 						return Severity.UNCHECKED;
 					return Severity.MISMATCH;
 			}
-			
+
 		} else if (requiredBits == TagBits.AnnotationNullable) {
 			switch (mode) {
 				case COMPATIBLE:
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java
index b56ad6b..e35c399 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -75,6 +75,7 @@
 				rightInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
 			}
 		}
+		this.left.updateFlowOnBooleanResult(rightInfo, false);
 		rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo);
 		if ((flowContext.tagBits & FlowContext.INSIDE_NEGATION) == 0)
 			flowContext.expireNullCheckedFieldInfo();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PackageVisibilityStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PackageVisibilityStatement.java
index 1ecfec7..ca132c9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PackageVisibilityStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/PackageVisibilityStatement.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
@@ -36,7 +36,7 @@
 	public boolean isQualified() {
 		return this.targets != null && this.targets.length > 0;
 	}
-	
+
 	public ModuleReference[] getTargetedModules() {
 		return this.targets;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
index f980f9c..fdc3e3a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contributions for
@@ -173,7 +173,7 @@
 	public TypeReference[][] getTypeArguments() {
 		return this.typeArguments;
 	}
-	
+
     @Override
 	protected TypeBinding getTypeBinding(Scope scope) {
         return null; // not supported here - combined with resolveType(...)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
index f577693..77ddddd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contributions for
@@ -71,7 +71,7 @@
 			}
 		}
 	}
-	
+
 	@Override
 	public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation [][] additionalAnnotations, boolean isVarargs) {
 		int totalDimensions = this.dimensions() + additionalDimensions;
@@ -111,12 +111,12 @@
 		}
 		return new char[][]{ name };
 	}
-	
+
 	@Override
 	public TypeReference[][] getTypeArguments() {
 		return new TypeReference[][] { this.typeArguments };
 	}
-	
+
 	/**
      * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope)
      */
@@ -124,7 +124,7 @@
 	protected TypeBinding getTypeBinding(Scope scope) {
         return null; // not supported here - combined with resolveType(...)
     }
-    
+
     @Override
 	public boolean isParameterizedTypeReference() {
     	return true;
@@ -299,7 +299,7 @@
 			if (!isDiamond) { // check arity, IsDiamond never set for 1.6-
 				scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes);
 				return null;
-			} 
+			}
 		} else if (!currentType.isStatic()) {
 			ReferenceBinding actualEnclosing = currentType.enclosingType();
 			if (actualEnclosing != null && actualEnclosing.isRawType()){
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ProvidesStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ProvidesStatement.java
index 8a429ad..20eae5c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ProvidesStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ProvidesStatement.java
@@ -59,7 +59,7 @@
 			}
 			int problemId = ProblemReasons.NoError;
 			ModuleBinding declaringModule = impl.module();
-			
+
 			if (declaringModule != src) {
 				problemId = IProblem.ServiceImplNotDefinedByModule;
 			} else if (!impl.isClass() && !impl.isInterface()) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
index 2dd1101..e297663 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contributions for
@@ -49,6 +49,7 @@
 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
+import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
@@ -109,7 +110,7 @@
 					// The corresponding problem (when called from static) is not produced until during code generation
 				}
 			}
-			
+
 		}
 
 		// check captured variables are initialized in current context (26134)
@@ -123,8 +124,8 @@
 		// process arguments
 		if (this.arguments != null) {
 			boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks;
-			boolean hasResourceWrapperType = analyseResources 
-						&& this.resolvedType instanceof ReferenceBinding 
+			boolean hasResourceWrapperType = analyseResources
+						&& this.resolvedType instanceof ReferenceBinding
 						&& ((ReferenceBinding)this.resolvedType).hasTypeBit(TypeIds.BitWrapperCloseable);
 			for (int i = 0, count = this.arguments.length; i < count; i++) {
 				flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo);
@@ -148,7 +149,7 @@
 			if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) {
 				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=277643, align with javac on JLS 15.12.2.6
 				thrownExceptions = currentScope.environment().convertToRawTypes(this.binding.thrownExceptions, true, true);
-			}			
+			}
 			// check exception handling
 			flowContext.checkExceptionHandlers(
 				thrownExceptions,
@@ -305,12 +306,15 @@
 			final CompilerOptions compilerOptions = scope.compilerOptions();
 			if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) {
 				ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(this.binding, scope);
-				if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) {
+				if (scope.environment().usesNullTypeAnnotations()) {
 					if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) {
 						TypeVariableBinding[] typeVariables = this.binding.original().typeVariables();
 						for (int i = 0; i < this.typeArguments.length; i++)
 							this.typeArguments[i].checkNullConstraints(scope, (ParameterizedGenericMethodBinding) this.binding, typeVariables, i);
 					}
+					if (this.resolvedType.isValidBinding()) {
+						this.resolvedType = scope.environment().createAnnotatedType(this.resolvedType, new AnnotationBinding[] {scope.environment().getNonNullAnnotation()});
+					}
 				}
 			}
 			if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8 &&
@@ -320,7 +324,7 @@
 		}
 		return result;
 	}
-	
+
 	private TypeBinding resolveTypeForQualifiedAllocationExpression(BlockScope scope) {
 		// Propagate the type checking to the arguments, and checks if the constructor is defined.
 		// ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
@@ -499,7 +503,7 @@
 						scope.problemReporter().diamondNotWithAnoymousClasses(this.type);
 						return null;
 					}
-				}	
+				}
 				ReferenceBinding superType = (ReferenceBinding) receiverType;
 				if (superType.isTypeVariable()) {
 					superType = new ProblemReferenceBinding(new char[][]{superType.sourceName()}, superType, ProblemReasons.IllegalSuperTypeVariable);
@@ -597,7 +601,7 @@
 			}
 			this.enclosingInstance.computeConversion(scope, targetEnclosing, enclosingInstanceType);
 		}
-		if (!isDiamond && receiverType.isParameterizedTypeWithActualArguments() && 
+		if (!isDiamond && receiverType.isParameterizedTypeWithActualArguments() &&
 				(this.anonymousType == null || sourceLevel >= ClassFileConstants.JDK9)) {
 			checkTypeArgumentRedundancy((ParameterizedTypeBinding) receiverType, scope);
 		}
@@ -650,7 +654,7 @@
 				return this.noErrors;
 			}
 		}
-		
+
 		return new ValidityInspector().isValid();
 	}
 	private MethodBinding getAnonymousConstructorBinding(ReferenceBinding receiverType, BlockScope scope) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
index 2e5c00d..8be256a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
@@ -789,7 +789,7 @@
 			}
 
 			if (field.isStatic()) {
-				if ((field.modifiers & ClassFileConstants.AccEnum) != 0 && !scope.isModuleScope()) {
+				if ((field.modifiers & ClassFileConstants.AccEnum) != 0 && scope.kind != Scope.MODULE_SCOPE) {
 					// enum constants are checked even when qualified -- modules don't contain field declarations
 					ReferenceBinding declaringClass = field.original().declaringClass;
 					MethodScope methodScope = scope.methodScope();
@@ -1084,11 +1084,15 @@
 					this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits
 					this.bits |= Binding.FIELD;
 					FieldBinding fieldBinding = (FieldBinding) this.binding;
-					MethodScope methodScope = scope.methodScope();
 					ReferenceBinding declaringClass = fieldBinding.original().declaringClass;
-					SourceTypeBinding sourceType = methodScope.enclosingSourceType();
+					MethodScope methodScope = null;
+					SourceTypeBinding sourceType = null;
+					if (scope.kind != Scope.MODULE_SCOPE) {
+						methodScope = scope.methodScope();
+						sourceType = methodScope.enclosingSourceType();
+					}
 					// check for forward references
-					if (!scope.isModuleScope()) {
+					if (scope.kind != Scope.MODULE_SCOPE) {
 					if ((this.indexOfFirstFieldBinding == 1 || (fieldBinding.modifiers & ClassFileConstants.AccEnum) != 0 || (!fieldBinding.isFinal() && declaringClass.isEnum())) // enum constants are checked even when qualified
 							&& TypeBinding.equalsEquals(sourceType, declaringClass)
 							&& methodScope.lastVisibleFieldID >= 0
@@ -1107,7 +1111,7 @@
 					if (fieldBinding.isStatic()) {
 						// only last field is actually a write access if any
 						// check if accessing enum static field in initializer
-						if (declaringClass.isEnum() && !scope.isModuleScope()) {
+						if (declaringClass.isEnum() && scope.kind != Scope.MODULE_SCOPE) {
 							if ((TypeBinding.equalsEquals(sourceType, declaringClass) || TypeBinding.equalsEquals(sourceType.superclass, declaringClass)) // enum constant body
 									&& fieldBinding.constant(scope) == Constant.NotAConstant
 									&& !methodScope.isStatic
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java
index 55d12fd..d18aba6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java
@@ -119,7 +119,7 @@
 		if (depth == 0) {
 			checkAccess(scope, null);
 		} // if depth>0, path emulation will diagnose bad scenarii
-		
+
 		MethodScope methodScope = scope.namedMethodScope();
 		if (methodScope != null) {
 			MethodBinding method = methodScope.referenceMethodBinding();
@@ -128,7 +128,7 @@
 				while (receiver != null) {
 					if (TypeBinding.equalsEquals(receiver, this.resolvedType))
 						return this.resolvedType = receiver;
-					receiver = receiver.enclosingType();	
+					receiver = receiver.enclosingType();
 				}
 			}
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
index 8178dec..856fe9c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
@@ -122,7 +122,7 @@
 		}
 	    PackageBinding packageBinding = binding == null ? null : (PackageBinding) binding;
 	    int typeStart = packageBinding == null ? 0 : packageBinding.compoundName.length;
-	    
+
 	    if (packageBinding != null) {
 	    	PackageBinding uniquePackage = packageBinding.getVisibleFor(scope.module(), false);
 	    	if (uniquePackage instanceof SplitPackageBinding) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Receiver.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Receiver.java
index dce07d3..7398886 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Receiver.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Receiver.java
@@ -24,7 +24,7 @@
 	public boolean isReceiver() {
 		return true;
 	}
-	
+
 	@Override
 	public StringBuffer print(int indent, StringBuffer output) {
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/RecordDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/RecordDeclaration.java
new file mode 100644
index 0000000..37470c2
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/RecordDeclaration.java
@@ -0,0 +1,296 @@
+/*******************************************************************************
+ * Copyright (c) 2019, 2020 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
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.ast;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ClassFile;
+import org.eclipse.jdt.internal.compiler.CompilationResult;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
+import org.eclipse.jdt.internal.compiler.lookup.Scope;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
+import org.eclipse.jdt.internal.compiler.parser.Parser;
+
+public class RecordDeclaration extends TypeDeclaration {
+
+	private Argument[] args;
+	public int nRecordComponents;
+	public boolean isLocalRecord;
+	public static Set<String> disallowedComponentNames;
+	static {
+		disallowedComponentNames = new HashSet<>(6);
+		disallowedComponentNames.add("clone"); //$NON-NLS-1$
+		disallowedComponentNames.add("finalize"); //$NON-NLS-1$
+		disallowedComponentNames.add("getClass"); //$NON-NLS-1$
+		disallowedComponentNames.add("hashCode"); //$NON-NLS-1$
+		disallowedComponentNames.add("notify");   //$NON-NLS-1$
+		disallowedComponentNames.add("notifyAll");//$NON-NLS-1$
+		disallowedComponentNames.add("toString"); //$NON-NLS-1$
+		disallowedComponentNames.add("wait"); //$NON-NLS-1$
+	}
+	public RecordDeclaration(CompilationResult compilationResult) {
+		super(compilationResult);
+		this.modifiers |= ExtraCompilerModifiers.AccRecord;
+	}
+	public RecordDeclaration(TypeDeclaration t) {
+		super(t.compilationResult);
+		this.modifiers = t.modifiers | ExtraCompilerModifiers.AccRecord;
+		this.modifiersSourceStart = t.modifiersSourceStart;
+		this.annotations = t.annotations;
+		this.name = t.name;
+		this.superInterfaces = t.superInterfaces;
+		this.fields = t.fields;
+		this.methods = t.methods;
+		this.memberTypes = t.memberTypes;
+		this.binding = t.binding;
+		this.scope = t.scope;
+		this.initializerScope = t.initializerScope;
+		this.staticInitializerScope = t.staticInitializerScope;
+		this.ignoreFurtherInvestigation = t.ignoreFurtherInvestigation;
+		this.maxFieldCount = t.maxFieldCount;
+		this.declarationSourceStart = t.declarationSourceStart;
+		this.declarationSourceEnd = t.declarationSourceEnd;
+		this.bodyStart = t.bodyStart;
+		this.bodyEnd = t.bodyEnd;
+		this.missingAbstractMethods = t.missingAbstractMethods; // TODO: Investigate whether this is relevant.
+		this.javadoc = t.javadoc;
+		this.allocation = t.allocation;
+		this.enclosingType = t.enclosingType;
+		this.typeParameters = t.typeParameters;
+		this.sourceStart = t.sourceStart;
+		this.sourceEnd = t.sourceEnd;
+		this.restrictedIdentifierStart = t.restrictedIdentifierStart;
+	}
+	public ConstructorDeclaration getConstructor(Parser parser) {
+		if (this.methods != null) {
+			for (int i = this.methods.length; --i >= 0;) {
+				AbstractMethodDeclaration am;
+				if ((am = this.methods[i]).isConstructor()) {
+					if (!CharOperation.equals(am.selector, this.name)) {
+						// the constructor was in fact a method with no return type
+						// unless an explicit constructor call was supplied
+						ConstructorDeclaration c = (ConstructorDeclaration) am;
+						if (c.constructorCall == null || c.constructorCall.isImplicitSuper()) { //changed to a method
+							MethodDeclaration m = parser.convertToMethodDeclaration(c, this.compilationResult);
+							this.methods[i] = m;
+						}
+					} else {
+						if (am instanceof CompactConstructorDeclaration) {
+							CompactConstructorDeclaration ccd = (CompactConstructorDeclaration) am;
+							ccd.recordDeclaration = this;
+							if (ccd.arguments == null)
+								ccd.arguments = this.args;
+							return ccd;
+						}
+						// now we are looking at a "normal" constructor
+						if (this.args == null && am.arguments == null)
+							return (ConstructorDeclaration) am;
+					}
+				}
+			}
+		}
+		/* At this point we can only say that there is high possibility that there is a constructor
+		 * If it is a CCD, then definitely it is there (except for empty one); else we need to check
+		 * the bindings to say that there is a canonical constructor. To take care at binding resolution time.
+		 */
+		return null;
+	}
+
+	/** Returns an implicit canonical constructor, if any.
+	 */
+	public static ConstructorDeclaration getImplicitCanonicalConstructor(AbstractMethodDeclaration[] methods) {
+		if (methods == null)
+			return null;
+		for (AbstractMethodDeclaration am : methods) {
+			if (am instanceof ConstructorDeclaration && (am.bits & (ASTNode.IsCanonicalConstructor | ASTNode.IsImplicit)) != 0)
+				return (ConstructorDeclaration) am;
+		}
+		return null;
+	}
+	@Override
+	public ConstructorDeclaration createDefaultConstructor(boolean needExplicitConstructorCall, boolean needToInsert) {
+		//Add to method'set, the default constuctor that just recall the
+		//super constructor with no arguments
+		//The arguments' type will be positionned by the TC so just use
+		//the default int instead of just null (consistency purpose)
+
+		ConstructorDeclaration constructor = new ConstructorDeclaration(this.compilationResult);
+		constructor.bits |= ASTNode.IsCanonicalConstructor | ASTNode.IsImplicit;
+		constructor.selector = this.name;
+//		constructor.modifiers = this.modifiers & ExtraCompilerModifiers.AccVisibilityMASK;
+		constructor.modifiers = this.modifiers & ClassFileConstants.AccPublic;
+		constructor.modifiers |= ClassFileConstants.AccPublic; // JLS 14 8.10.5
+		constructor.arguments = this.args;
+
+		constructor.declarationSourceStart = constructor.sourceStart =
+				constructor.bodyStart = this.sourceStart;
+		constructor.declarationSourceEnd =
+			constructor.sourceEnd = constructor.bodyEnd =  this.sourceStart - 1;
+
+		//the super call inside the constructor
+		if (needExplicitConstructorCall) {
+			constructor.constructorCall = SuperReference.implicitSuperConstructorCall();
+			constructor.constructorCall.sourceStart = this.sourceStart;
+			constructor.constructorCall.sourceEnd = this.sourceEnd;
+		}
+	/* The body of the implicitly declared canonical constructor initializes each field corresponding
+		 * to a record component with the corresponding formal parameter in the order that they appear
+		 * in the record component list.*/
+		List<Statement> statements = new ArrayList<>();
+		int l = this.args != null ? this.args.length : 0;
+		if (l > 0 && this.fields != null) {
+			List<String> fNames = Arrays.stream(this.fields)
+					.filter(f -> f.isARecordComponent)
+					.map(f ->new String(f.name))
+					.collect(Collectors.toList());
+			for (int i = 0; i < l; ++i) {
+				Argument arg = this.args[i];
+				if (!fNames.contains(new String(arg.name)))
+					continue;
+				FieldReference lhs = new FieldReference(arg.name, 0);
+				lhs.receiver = ThisReference.implicitThis();
+				statements.add(new Assignment(lhs, new SingleNameReference(arg.name, 0), 0));
+			}
+		}
+		constructor.statements = statements.toArray(new Statement[0]);
+
+		//adding the constructor in the methods list: rank is not critical since bindings will be sorted
+		if (needToInsert) {
+			if (this.methods == null) {
+				this.methods = new AbstractMethodDeclaration[] { constructor };
+			} else {
+				AbstractMethodDeclaration[] newMethods;
+				System.arraycopy(
+					this.methods,
+					0,
+					newMethods = new AbstractMethodDeclaration[this.methods.length + 1],
+					1,
+					this.methods.length);
+				newMethods[0] = constructor;
+				this.methods = newMethods;
+			}
+		}
+		return constructor;
+	}
+
+	@Override
+	public void generateCode(ClassFile enclosingClassFile) {
+		super.generateCode(enclosingClassFile);
+	}
+	@Override
+	public boolean isRecord() {
+		return true;
+	}
+	@Override
+	public StringBuffer printHeader(int indent, StringBuffer output) {
+		printModifiers(this.modifiers, output);
+		if (this.annotations != null) {
+			printAnnotations(this.annotations, output);
+			output.append(' ');
+		}
+
+		output.append("record "); //$NON-NLS-1$
+		output.append(this.name);
+		output.append('(');
+		if (this.nRecordComponents > 0 && this.fields != null) {
+			for (int i = 0; i < this.nRecordComponents; i++) {
+				if (i > 0) output.append(", "); //$NON-NLS-1$
+				output.append(this.fields[i].type.getTypeName()[0]);
+				output.append(' ');
+				output.append(this.fields[i].name);
+			}
+		}
+		output.append(')');
+		if (this.typeParameters != null) {
+			output.append("<");//$NON-NLS-1$
+			for (int i = 0; i < this.typeParameters.length; i++) {
+				if (i > 0) output.append( ", "); //$NON-NLS-1$
+				this.typeParameters[i].print(0, output);
+			}
+			output.append(">");//$NON-NLS-1$
+		}
+		if (this.superInterfaces != null && this.superInterfaces.length > 0) {
+			output.append(" implements "); //$NON-NLS-1$
+			for (int i = 0; i < this.superInterfaces.length; i++) {
+				if (i > 0) output.append( ", "); //$NON-NLS-1$
+				this.superInterfaces[i].print(0, output);
+			}
+		}
+		return output;
+	}
+	@Override
+	public StringBuffer printBody(int indent, StringBuffer output) {
+		output.append(" {"); //$NON-NLS-1$
+		if (this.memberTypes != null) {
+			for (int i = 0; i < this.memberTypes.length; i++) {
+				if (this.memberTypes[i] != null) {
+					output.append('\n');
+					this.memberTypes[i].print(indent + 1, output);
+				}
+			}
+		}
+		if (this.fields != null) {
+			for (int fieldI = 0; fieldI < this.fields.length; fieldI++) {
+				if (this.fields[fieldI] != null) {
+					output.append('\n');
+					if (fieldI < this.nRecordComponents)
+						output.append("/* Implicit */"); //$NON-NLS-1$ //TODO BETA_JAVA14: Move this to FD?
+					this.fields[fieldI].print(indent + 1, output);
+				}
+			}
+		}
+		if (this.methods != null) {
+			for (int i = 0; i < this.methods.length; i++) {
+				if (this.methods[i] != null) {
+					output.append('\n');
+					AbstractMethodDeclaration amd = this.methods[i];
+					if (amd instanceof MethodDeclaration && (amd.bits & ASTNode.IsImplicit) != 0)
+						output.append("/* Implicit */\n"); //$NON-NLS-1$// TODO BETA_JAVA14: Move this to MD?
+					amd.print(indent + 1, output);
+				}
+			}
+		}
+		output.append('\n');
+		return printIndent(indent, output).append('}');
+	}
+	public Argument[] getArgs() {
+		return this.args;
+	}
+	public void setArgs(Argument[] args) {
+		this.args = args;
+	}
+	public static void checkAndFlagRecordNameErrors(char[] typeName, ASTNode node, Scope skope) {
+		if (CharOperation.equals(typeName, TypeConstants.RECORD_RESTRICTED_IDENTIFIER)) {
+			if (skope.compilerOptions().sourceLevel == ClassFileConstants.JDK14) {
+					skope.problemReporter().recordIsAReservedTypeName(node);
+			}
+		}
+	}
+	AbstractMethodDeclaration[] getMethod(char[] name1) {
+		if (name1 == null || name1.length == 0 || this.methods == null)
+			return null;
+		List<AbstractMethodDeclaration> amList = new ArrayList<>(0);
+		for (AbstractMethodDeclaration amd : this.methods) {
+			if (CharOperation.equals(name1, amd.selector))
+				amList.add(amd);
+		}
+		return amList.toArray(new AbstractMethodDeclaration[0]);
+	}
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
index cebb774..c50f5aa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
@@ -16,7 +16,7 @@
  *								bug 331649 - [compiler][null] consider null annotations for fields
  *								bug 383368 - [compiler][null] syntactic null analysis for field references
  *								bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files
- *								Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis 
+ *								Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
  *								Bug 411964 - [1.8][null] leverage null type annotation in foreach statement
  *								Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null
  *******************************************************************************/
@@ -68,7 +68,7 @@
 		if ((field.type.tagBits & TagBits.AnnotationNullable) != 0) {
 			scope.problemReporter().dereferencingNullableExpression(sourcePosition, scope.environment());
 			return true;
-		} 
+		}
 		if (field.type.isFreeTypeVariable()) {
 			scope.problemReporter().fieldFreeTypeVariableReference(field, sourcePosition);
 			return true;
@@ -96,7 +96,7 @@
 				case TypeIds.T_double :
 					codeStream.dup2();
 					break;
-				default : 
+				default :
 					codeStream.dup();
 					break;
 			}
@@ -114,7 +114,7 @@
 				case TypeIds.T_double :
 					codeStream.dup2_x1();
 					break;
-				default : 
+				default :
 					codeStream.dup_x1();
 					break;
 			}
@@ -135,8 +135,8 @@
 
 public abstract void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired);
 
-/** 
- * Is the given reference equivalent to the receiver, 
+/**
+ * Is the given reference equivalent to the receiver,
  * meaning that both denote the same path of field reads?
  * Used from {@link FlowContext#isNullcheckedFieldAccess(Reference)}.
  */
@@ -184,7 +184,7 @@
 		if (fieldBinding.isUsedOnlyInCompound()) {
 			fieldBinding.compoundUseFlag--; // consume one
 			if (fieldBinding.compoundUseFlag == 0					// report only the last usage
-					&& fieldBinding.isOrEnclosedByPrivateType() 
+					&& fieldBinding.isOrEnclosedByPrivateType()
 					&& (this.implicitConversion & TypeIds.UNBOXING) == 0) // don't report if unboxing is involved (might cause NPE)
 			{
 				// compoundAssignment/postIncrement is the only usage of this field
@@ -219,14 +219,14 @@
 		MethodScope methodScope = currentScope.methodScope();
 		if (methodScope != null && !methodScope.isLambdaScope()) { // lambda must be congruent with the descriptor.
 			MethodBinding method = ((AbstractMethodDeclaration)methodScope.referenceContext()).binding;
-			
+
 			boolean shouldReport = !method.isMain();
 			if (method.isImplementing()) {
 				shouldReport &= currentScope.compilerOptions().reportUnusedParameterWhenImplementingAbstract;
 			} else if (method.isOverriding()) {
 				shouldReport &= currentScope.compilerOptions().reportUnusedParameterWhenOverridingConcrete;
 			}
-			
+
 			if (shouldReport) {
 				// report the case of an argument that is unread except through a special operator
 				currentScope.problemReporter().unusedArgument(localBinding.declaration);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
index cfa3925..3a7bf00 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -15,7 +15,7 @@
  *                          Bug 384687 - [1.8] Wildcard type arguments should be rejected for lambda and reference expressions
  *							Bug 416885 - [1.8][compiler]IncompatibleClassChange error (edit)
  *	   Stephan Herrmann - Contribution for
- *							bug 402028 - [1.8][compiler] null analysis for reference expressions 
+ *							bug 402028 - [1.8][compiler] null analysis for reference expressions
  *							bug 404649 - [1.8][compiler] detect illegal reference to indirect or redundant super via I.super.m() syntax
  *							Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis
  *							Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled
@@ -66,6 +66,7 @@
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.impl.IrritantSet;
+import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
 import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
 import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
@@ -105,14 +106,14 @@
 	public Expression lhs;
 	public TypeReference [] typeArguments;
 	public char [] selector;
-	
+
 	public int nameSourceStart;
 
 	public TypeBinding receiverType;
 	public boolean haveReceiver;
 	public TypeBinding[] resolvedTypeArguments;
 	private boolean typeArgumentsHaveErrors;
-	
+
 	MethodBinding syntheticAccessor;	// synthetic accessor for inner-emulation
 	private int depth;
 	private MethodBinding exactMethodBinding; // != null ==> exact method reference.
@@ -127,14 +128,14 @@
 
 	// the scanner used when creating this expression, may be a RecoveryScanner (with proper RecoveryScannerData),
 	// need to keep it so copy() can parse in the same mode (normal/recovery):
-	private Scanner scanner; 
-	
+	private Scanner scanner;
+
 	public ReferenceExpression(Scanner scanner) {
 		super();
 		this.original = this;
 		this.scanner = scanner;
 	}
-	
+
 	public void initialize(CompilationResult result, Expression expression, TypeReference [] optionalTypeArguments, char [] identifierOrNew, int sourceEndPosition) {
 		super.setCompilationResult(result);
 		this.lhs = expression;
@@ -143,20 +144,20 @@
 		this.sourceStart = expression.sourceStart;
 		this.sourceEnd = sourceEndPosition;
 	}
-	
+
 	private ReferenceExpression copy() {
 		final Parser parser = new Parser(this.enclosingScope.problemReporter(), false);
 		final ICompilationUnit compilationUnit = this.compilationResult.getCompilationUnit();
 		final char[] source = compilationUnit != null ? compilationUnit.getContents() : this.text;
 		parser.scanner = this.scanner;
-		ReferenceExpression copy =  (ReferenceExpression) parser.parseExpression(source, compilationUnit != null ? this.sourceStart : 0, this.sourceEnd - this.sourceStart + 1, 
+		ReferenceExpression copy =  (ReferenceExpression) parser.parseExpression(source, compilationUnit != null ? this.sourceStart : 0, this.sourceEnd - this.sourceStart + 1,
 										this.enclosingScope.referenceCompilationUnit(), false /* record line separators */);
 		copy.original = this;
 		copy.sourceStart = this.sourceStart;
 		copy.sourceEnd = this.sourceEnd;
 		return copy;
 	}
- 
+
 	private boolean shouldGenerateSecretReceiverVariable() {
 		if (isMethodReference() && this.haveReceiver) {
 			if (this.lhs instanceof Invocation)
@@ -187,11 +188,11 @@
 		return false;
 	}
 	public void generateImplicitLambda(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
-		
+
 		ReferenceExpression copy = copy();
-		
+
 		int argc = this.descriptor.parameters.length;
-		
+
 		LambdaExpression implicitLambda = new LambdaExpression(this.compilationResult, false, (this.binding.modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0);
 		Argument [] arguments = new Argument[argc];
 		for (int i = 0; i < argc; i++)
@@ -199,7 +200,7 @@
 		implicitLambda.setArguments(arguments);
 		implicitLambda.setExpressionContext(this.expressionContext);
 		implicitLambda.setExpectedType(this.expectedType);
-		
+
 		int parameterShift = this.receiverPrecedesParameters ? 1 : 0;
 		Expression [] argv = new SingleNameReference[argc - parameterShift];
 		for (int i = 0, length = argv.length; i < length; i++) {
@@ -216,7 +217,7 @@
 			MessageSend message = new MessageSend();
 			message.selector = this.selector;
 			Expression receiver = generateSecretReceiverVariable ? new SingleNameReference(this.receiverVariable.name, 0) : copy.lhs;
-			message.receiver = this.receiverPrecedesParameters ? 
+			message.receiver = this.receiverPrecedesParameters ?
 					new SingleNameReference(CharOperation.append(ImplicitArgName, Integer.toString(0).toCharArray()), 0) : receiver;
 			message.typeArguments = copy.typeArguments;
 			message.arguments = argv;
@@ -227,12 +228,12 @@
 			arrayAllocationExpression.dimensions = new Expression[] { argv[0] };
 			if (this.lhs instanceof ArrayTypeReference) {
 				ArrayTypeReference arrayTypeReference = (ArrayTypeReference) this.lhs;
-				arrayAllocationExpression.type = arrayTypeReference.dimensions == 1 ? new SingleTypeReference(arrayTypeReference.token, 0L) : 
+				arrayAllocationExpression.type = arrayTypeReference.dimensions == 1 ? new SingleTypeReference(arrayTypeReference.token, 0L) :
 																new ArrayTypeReference(arrayTypeReference.token, arrayTypeReference.dimensions - 1, 0L);
 			} else {
 				ArrayQualifiedTypeReference arrayQualifiedTypeReference = (ArrayQualifiedTypeReference) this.lhs;
 				arrayAllocationExpression.type = arrayQualifiedTypeReference.dimensions == 1 ? new QualifiedTypeReference(arrayQualifiedTypeReference.tokens, arrayQualifiedTypeReference.sourcePositions)
-																: new ArrayQualifiedTypeReference(arrayQualifiedTypeReference.tokens, arrayQualifiedTypeReference.dimensions - 1, 
+																: new ArrayQualifiedTypeReference(arrayQualifiedTypeReference.tokens, arrayQualifiedTypeReference.dimensions - 1,
 																		arrayQualifiedTypeReference.sourcePositions);
 			}
 			implicitLambda.setBody(arrayAllocationExpression);
@@ -251,14 +252,14 @@
 			allocation.arguments = argv;
 			implicitLambda.setBody(allocation);
 		}
-		
+
 		// Process the lambda, taking care not to double report diagnostics. Don't expect any from resolve, Any from code generation should surface, but not those from flow analysis.
 		BlockScope lambdaScope = this.receiverVariable != null ? this.receiverVariable.declaringScope : currentScope;
 		IErrorHandlingPolicy oldPolicy = lambdaScope.problemReporter().switchErrorHandlingPolicy(silentErrorHandlingPolicy);
 		try {
 			implicitLambda.resolveType(lambdaScope, true);
-			implicitLambda.analyseCode(lambdaScope, 
-					new FieldInitsFakingFlowContext(null, this, Binding.NO_EXCEPTIONS, null, lambdaScope, FlowInfo.DEAD_END), 
+			implicitLambda.analyseCode(lambdaScope,
+					new FieldInitsFakingFlowContext(null, this, Binding.NO_EXCEPTIONS, null, lambdaScope, FlowInfo.DEAD_END),
 					UnconditionalFlowInfo.fakeInitializedFlowInfo(lambdaScope.outerMostMethodScope().analysisIndex, lambdaScope.referenceType().maxFieldCount));
 		} finally {
 			lambdaScope.problemReporter().switchErrorHandlingPolicy(oldPolicy);
@@ -266,16 +267,16 @@
 		SyntheticArgumentBinding[] outerLocals = this.receiverType.syntheticOuterLocalVariables();
 		for (int i = 0, length = outerLocals == null ? 0 : outerLocals.length; i < length; i++)
 			implicitLambda.addSyntheticArgument(outerLocals[i].actualOuterLocalVariable);
-		
+
 		implicitLambda.generateCode(lambdaScope, codeStream, valueRequired);
 		if (generateSecretReceiverVariable) {
 			codeStream.removeVariable(this.receiverVariable);
 		}
-	}	
-	
+	}
+
 	private boolean shouldGenerateImplicitLambda(BlockScope currentScope) {
-		// these cases are either too complicated, impossible to handle or result in significant code duplication 
-		return (this.binding.isVarargs() || 
+		// these cases are either too complicated, impossible to handle or result in significant code duplication
+		return (this.binding.isVarargs() ||
 				(isConstructorReference() && this.receiverType.syntheticOuterLocalVariables() != null && this.shouldCaptureInstance) ||
 				this.requiresBridges() || // bridges.
 				!isDirectCodeGenPossible());
@@ -287,9 +288,11 @@
 				if (TypeBinding.notEquals(this.binding.declaringClass, this.lhs.resolvedType.erasure())) {
 					// reference to a method declared by an inaccessible type accessed via a
 					// subtype - normally a bridge method would be present to facilitate
-					// this access, unless the method is final/static, in which case, direct access to
+					// this access, unless the method is final/static/default, in which case, direct access to
 					// the method is not possible, an implicit lambda is needed
 					if (!this.binding.declaringClass.canBeSeenBy(this.enclosingScope)) {
+						if (this.binding.isDefaultMethod())
+							return false; // workaround for bug in MethodHandle lookup, see https://bugs.openjdk.java.net/browse/JDK-8068253
 						return !(this.binding.isFinal() || this.binding.isStatic());
 					}
 				}
@@ -301,7 +304,7 @@
 			for (int i = 0; i < descriptorParams.length - offset; i++) {
 				TypeBinding descType = descriptorParams[i + offset];
 				TypeBinding origDescType = origDescParams[i + offset];
-				if (descType.isIntersectionType18() || 
+				if (descType.isIntersectionType18() ||
 						(descType.isTypeVariable() && ((TypeVariableBinding) descType).boundsCount() > 1)) {
 					return CharOperation.equals(origDescType.signature(), origParams[i].signature());
 				}
@@ -328,7 +331,7 @@
 		} else if (this.syntheticAccessor != null) {
 			if (this.lhs.isSuper() || isMethodReference())
 				this.binding = this.syntheticAccessor;
-		} else { // cf. MessageSend.generateCode()'s call to CodeStream.getConstantPoolDeclaringClass. We have extracted the relevant portions sans side effect here. 
+		} else { // cf. MessageSend.generateCode()'s call to CodeStream.getConstantPoolDeclaringClass. We have extracted the relevant portions sans side effect here.
 			if (this.binding != null && isMethodReference()) {
 				if (TypeBinding.notEquals(this.binding.declaringClass, this.lhs.resolvedType.erasure())) {
 					if (!this.binding.declaringClass.canBeSeenBy(currentScope)) {
@@ -359,7 +362,7 @@
 					} else {
 						buffer.append(((QualifiedSuperReference) this.lhs).currentCompatibleType.signature());
 					}
-				} else { 
+				} else {
 					buffer.append(sourceType.signature());
 				}
 			} else {
@@ -406,13 +409,14 @@
 			sourceType.addSyntheticMethod(this);
 		}
 		int invokeDynamicNumber = codeStream.classFile.recordBootstrapMethod(this);
-		codeStream.invokeDynamic(invokeDynamicNumber, argumentsSize, 1, this.descriptor.selector, buffer.toString().toCharArray(), 
-				this.isConstructorReference(), (this.lhs instanceof TypeReference? (TypeReference) this.lhs : null), this.typeArguments);
+		codeStream.invokeDynamic(invokeDynamicNumber, argumentsSize, 1, this.descriptor.selector, buffer.toString().toCharArray(),
+				this.isConstructorReference(), (this.lhs instanceof TypeReference? (TypeReference) this.lhs : null), this.typeArguments,
+				this.resolvedType.id, this.resolvedType);
 		if (!valueRequired)
 			codeStream.pop();
 		codeStream.recordPositionsFrom(pc, this.sourceStart);
 	}
-	
+
 	@Override
 	public void cleanUp() {
 		// no more rescanning needed beyond this point, so free the memory:
@@ -428,16 +432,16 @@
 	}
 
 	public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
-		
-		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 || this.binding == null || !this.binding.isValidBinding()) 
+
+		if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 || this.binding == null || !this.binding.isValidBinding())
 			return;
-		
+
 		MethodBinding codegenBinding = this.binding.original();
 		if (codegenBinding.isVarargs())
 			return; // completely managed by transforming into implicit lambda expression.
-		
+
 		SourceTypeBinding enclosingSourceType = currentScope.enclosingSourceType();
-		
+
 		if (this.isConstructorReference()) {
 			ReferenceBinding allocatedType = codegenBinding.declaringClass;
 			if (codegenBinding.isPrivate() &&
@@ -455,7 +459,7 @@
 			}
 			return;
 		}
-	
+
 		// -----------------------------------   Only method references from now on -----------
 		if (this.binding.isPrivate()) {
 			if (TypeBinding.notEquals(enclosingSourceType, codegenBinding.declaringClass)){
@@ -464,7 +468,7 @@
 			}
 			return;
 		}
-		
+
 		if (this.lhs.isSuper()) {
 			SourceTypeBinding destinationType = enclosingSourceType;
 			if (this.lhs instanceof QualifiedSuperReference) { 	// qualified super
@@ -473,12 +477,12 @@
 				if (!qualification.resolvedType.isInterface()) // we can't drop the bridge in I, it may not even be a source type.
 					destinationType = (SourceTypeBinding) (qualifiedSuperReference.currentCompatibleType);
 			}
-			
+
 			this.syntheticAccessor = destinationType.addSyntheticMethod(codegenBinding, true);
 			currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this);
 			return;
 		}
-		
+
 		if (this.binding.isProtected() && (this.bits & ASTNode.DepthMASK) != 0 && codegenBinding.declaringClass.getPackage() != enclosingSourceType.getPackage()) {
 			SourceTypeBinding currentCompatibleType = (SourceTypeBinding) enclosingSourceType.enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT);
 			this.syntheticAccessor = currentCompatibleType.addSyntheticMethod(codegenBinding, isSuperAccess());
@@ -486,7 +490,7 @@
 			return;
 		}
 	}
-	
+
 	@Override
 	public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
 		// static methods with receiver value never get here
@@ -529,10 +533,10 @@
 				if (argumentCheck != null && argumentCheck.isDangerous(currentScope)) {
 					currentScope.problemReporter().unlikelyArgumentType(this, this.binding, argumentType2,
 							argumentCheck.typeToReport, argumentCheck.dangerousMethod);
-				}			
+				}
 			}
 		}
-		
+
 		if (currentScope.compilerOptions().analyseResourceLeaks) {
 			if (this.haveReceiver && CharOperation.equals(this.selector, TypeConstants.CLOSE)) {
 				FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(this.lhs, flowInfo, flowContext);
@@ -549,16 +553,16 @@
 	public boolean checkingPotentialCompatibility() {
 		return this.checkingPotentialCompatibility;
 	}
-	
+
 	@Override
 	public void acceptPotentiallyCompatibleMethods(MethodBinding[] methods) {
 		if (this.checkingPotentialCompatibility)
 			this.potentialMethods = methods;
 	}
-	
+
 	@Override
 	public TypeBinding resolveType(BlockScope scope) {
-		
+
 		final CompilerOptions compilerOptions = scope.compilerOptions();
 		TypeBinding lhsType;
     	if (this.constant != Constant.NotAConstant) {
@@ -592,12 +596,12 @@
     		}
     		if (this.typeArgumentsHaveErrors || lhsType == null)
 				return this.resolvedType = null;
-	
+
     		if (lhsType.problemId() == ProblemReasons.AttemptToBypassDirectSuper)
     			lhsType = lhsType.closestMatch();	// improve resolving experience
-        	if (lhsType == null || !lhsType.isValidBinding()) 
+        	if (lhsType == null || !lhsType.isValidBinding())
     			return this.resolvedType = null;	// nope, no useful type found
-        	
+
     		this.receiverType = lhsType;
 			this.haveReceiver = true;
 			if (this.lhs instanceof NameReference) {
@@ -623,7 +627,7 @@
     			scope.problemReporter().cannotInstantiate(this.lhs, lhsType);
     			return this.resolvedType = null;
     		}
-    		
+
     		if (this.lhs instanceof TypeReference && ((TypeReference)this.lhs).hasNullTypeAnnotation(AnnotationPosition.ANY)) {
     			scope.problemReporter().nullAnnotationUnsupportedLocation((TypeReference) this.lhs);
     		}
@@ -664,30 +668,30 @@
 
     	super.resolveType(scope);
 
-		/* For Reference expressions unlike other call sites, we always have a receiver _type_ since LHS of :: cannot be empty. 
+		/* For Reference expressions unlike other call sites, we always have a receiver _type_ since LHS of :: cannot be empty.
 		   LHS's resolved type == actual receiver type. All code below only when a valid descriptor is available.
 		*/
     	if (this.descriptor == null || !this.descriptor.isValidBinding())
     		return this.resolvedType =  null;
-     
+
     	// Convert parameters into argument expressions for look up.
 		TypeBinding[] descriptorParameters = descriptorParametersAsArgumentExpressions();
-		
+
 		if (lhsType.isBaseType()) {
 			scope.problemReporter().errorNoMethodFor(this.lhs, lhsType, this.selector, descriptorParameters);
 			return this.resolvedType = null;
 		}
-		
+
 		/* 15.13: "If a method reference expression has the form super :: [TypeArguments] Identifier or TypeName . super :: [TypeArguments] Identifier,
 		   it is a compile-time error if the expression occurs in a static context. ": This is nop since the primary when it resolves
 		   itself will complain automatically.
-		
-		   15.13: "The immediately enclosing instance of an inner class instance (15.9.2) must be provided for a constructor reference by a lexically 
+
+		   15.13: "The immediately enclosing instance of an inner class instance (15.9.2) must be provided for a constructor reference by a lexically
 		   enclosing instance of this (8.1.3)", we will actually implement this check in code generation. Emulation path computation will fail if there
-		   is no suitable enclosing instance. While this could be pulled up to here, leaving it to code generation is more consistent with Java 5,6,7 
+		   is no suitable enclosing instance. While this could be pulled up to here, leaving it to code generation is more consistent with Java 5,6,7
 		   modus operandi.
 		*/
-		
+
 		// handle the special case of array construction first.
 		final int parametersLength = descriptorParameters.length;
         if (isConstructorReference() && lhsType.isArrayType()) {
@@ -725,7 +729,7 @@
     			return this.resolvedType = null;
     		}
         }
-    	
+
     	if (this.lhs.isSuper() && this.lhs.resolvedType.isInterface()) {
     		scope.checkAppropriateMethodAgainstSupers(this.selector, someMethod, this.descriptor.parameters, this);
     	}
@@ -753,12 +757,12 @@
         		this.depth = 0;
         	}
         }
-        
+
         if (someMethod != null && someMethod.isValidBinding() && someMethod.isStatic() && anotherMethod != null && anotherMethod.isValidBinding() && !anotherMethod.isStatic()) {
         	scope.problemReporter().methodReferenceSwingsBothWays(this, anotherMethod, someMethod);
         	return this.resolvedType = null;
         }
-        
+
         if (someMethod != null && someMethod.isValidBinding() && (anotherMethod == null || !anotherMethod.isValidBinding() || anotherMethod.isStatic())) {
         	this.binding = someMethod;
         	this.bits &= ~ASTNode.DepthMASK;
@@ -770,7 +774,7 @@
         			scope.problemReporter().methodMustBeAccessedWithInstance(this, someMethod);
         			return this.resolvedType = null;
         		}
-        	} 
+        	}
         } else if (anotherMethod != null && anotherMethod.isValidBinding() && (someMethod == null || !someMethod.isValidBinding() || !someMethod.isStatic())) {
         	this.binding = anotherMethod;
         	this.receiverPrecedesParameters = true; // 0 is receiver, real parameters start at 1
@@ -792,12 +796,12 @@
         	scope.problemReporter().danglingReference(this, this.receiverType, visibleName, descriptorParameters);
 			return this.resolvedType = null;
         }
-        
+
         // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=382350#c2, I.super::abstractMethod will be handled there.
 
         if (this.binding.isAbstract() && this.lhs.isSuper())
         	scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding);
-        
+
         if (this.binding.isStatic()) {
         	if (TypeBinding.notEquals(this.binding.declaringClass, this.receiverType))
         		scope.problemReporter().indirectAccessToStaticMethod(this, this.binding);
@@ -806,16 +810,16 @@
         	if (srcMethod != null && srcMethod.isMethod())
         		srcMethod.bits &= ~ASTNode.CanBeStatic;
         }
-        
+
     	if (isMethodUseDeprecated(this.binding, scope, true, this))
     		scope.problemReporter().deprecatedMethod(this.binding, this);
 
     	if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES)
     		scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(this.binding, this.resolvedTypeArguments, this.typeArguments);
-    	
+
     	if ((this.binding.tagBits & TagBits.HasMissingType) != 0)
     		scope.problemReporter().missingTypeInMethod(this, this.binding);
-    	
+
 
         // OK, we have a compile time declaration, see if it passes muster.
         TypeBinding [] methodExceptions = this.binding.thrownExceptions;
@@ -832,7 +836,7 @@
         }
         checkNullAnnotations(scope);
         this.freeParameters = null; // not used after method lookup
-        
+
     	if (checkInvocationArguments(scope, null, this.receiverType, this.binding, null, descriptorParameters, false, this))
     		this.bits |= ASTNode.Unchecked;
 
@@ -883,7 +887,7 @@
 		    			final TypeBinding receiver = scope.environment().createAnnotatedType(this.binding.declaringClass,
 								new AnnotationBinding[] { scope.environment().getNonNullAnnotation() });
     					scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, receiver, descriptorParameter, this.descriptor, -1, NullAnnotationMatching.NULL_ANNOTATIONS_MISMATCH);
-	    			}	        		
+	    			}
 	        	}
 	        	boolean isVarArgs = false;
 	        	if (this.binding.isVarargs()) {
@@ -926,10 +930,10 @@
 	}
 
 	private TypeBinding[] descriptorParametersAsArgumentExpressions() {
-		
+
 		if (this.descriptor == null || this.descriptor.parameters == null || this.descriptor.parameters.length == 0)
 			return Binding.NO_PARAMETERS;
-		
+
 		/* 15.13.1, " ... method reference is treated as if it were an invocation with argument expressions of types P1, ..., Pn;"
 		   This implies/requires wildcard capture. This creates interesting complications, we can't just take the descriptor parameters
 		   and apply captures - where a single wildcard type got "fanned out" and propagated into multiple locations through type variable
@@ -940,17 +944,29 @@
 			ParameterizedTypeBinding type = (ParameterizedTypeBinding) this.expectedType;
 			MethodBinding method = type.getSingleAbstractMethod(this.enclosingScope, true, this.sourceStart, this.sourceEnd);
 			return method.parameters;
-		} 
+		}
 		return this.descriptor.parameters;
 	}
 
+	private boolean contextHasSyntaxError() {
+		ReferenceContext referenceContext = this.enclosingScope.referenceContext();
+		if (referenceContext instanceof AbstractMethodDeclaration) {
+			if ((((AbstractMethodDeclaration) referenceContext).bits & ASTNode.HasSyntaxErrors) != 0)
+				return true;
+		}
+		return false;
+	}
+
 	// Cache resolved copies against various target types, so repeat overload resolution and possibly type inference could be avoided.
 	private ReferenceExpression cachedResolvedCopy(TypeBinding targetType) {
 
 		ReferenceExpression copy = this.copiesPerTargetType != null ? this.copiesPerTargetType.get(targetType) : null;
 		if (copy != null)
 			return copy;
-		
+
+		if (contextHasSyntaxError())
+			return null;
+
 		IErrorHandlingPolicy oldPolicy = this.enclosingScope.problemReporter().switchErrorHandlingPolicy(silentErrorHandlingPolicy);
 		try {
 			copy = copy();
@@ -960,29 +976,29 @@
 			copy.setExpressionContext(this.expressionContext);
 			copy.setExpectedType(targetType);
 			copy.resolveType(this.enclosingScope);
-			
+
 			if (this.copiesPerTargetType == null)
 				this.copiesPerTargetType = new HashMap<TypeBinding, ReferenceExpression>();
 			this.copiesPerTargetType.put(targetType, copy);
-			
+
 			return copy;
 		} finally {
 			this.enclosingScope.problemReporter().switchErrorHandlingPolicy(oldPolicy);
 		}
 	}
-	
+
 	public void registerInferenceContext(ParameterizedGenericMethodBinding method, InferenceContext18 context) {
 		if (this.inferenceContexts == null)
 			this.inferenceContexts = new HashMap<ParameterizedGenericMethodBinding, InferenceContext18>();
 		this.inferenceContexts.put(method, context);
 	}
-	
+
 	public InferenceContext18 getInferenceContext(ParameterizedMethodBinding method) {
 		if (this.inferenceContexts == null)
 			return null;
 		return this.inferenceContexts.get(method);
 	}
-	
+
 	@Override
 	public ReferenceExpression resolveExpressionExpecting(TypeBinding targetType, Scope scope, InferenceContext18 inferenceContext) {
 		if (this.exactMethodBinding != null) { // We may see inference variables in target type.
@@ -991,34 +1007,34 @@
 				return null;
 			int n = functionType.parameters.length;
 			int k = this.exactMethodBinding.parameters.length;
-			
+
 			if (!this.haveReceiver && this.isMethodReference() && !this.exactMethodBinding.isStatic()) {
 				k++;
 			}
 			return (n == k) ? this : null;
 		}
 		// descriptors parameters should be free of inference variables.
-		ReferenceExpression copy = cachedResolvedCopy(targetType); 
+		ReferenceExpression copy = cachedResolvedCopy(targetType);
 		return copy != null && copy.resolvedType != null && copy.resolvedType.isValidBinding() && copy.binding != null && copy.binding.isValidBinding() ? copy : null;
 	}
 
 	public boolean isConstructorReference() {
 		return CharOperation.equals(this.selector,  ConstantPool.Init);
 	}
-	
+
 	@Override
 	public boolean isExactMethodReference() {
 		return this.exactMethodBinding != null;
 	}
-	
+
 	public MethodBinding getExactMethod() {
 		return this.exactMethodBinding;
 	}
-	
+
 	public boolean isMethodReference() {
 		return !CharOperation.equals(this.selector,  ConstantPool.Init);
 	}
-	
+
 	@Override
 	public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) {
 		if (!this.isExactMethodReference()) {
@@ -1026,7 +1042,7 @@
 		}
 		return super.isPertinentToApplicability(targetType, method);
 	}
-	
+
 	@Override
 	public TypeBinding[] genericTypeArguments() {
 		return this.resolvedTypeArguments;
@@ -1068,7 +1084,7 @@
 
 	@Override
 	public StringBuffer printExpression(int tab, StringBuffer output) {
-		
+
 		this.lhs.print(0, output);
 		output.append("::"); //$NON-NLS-1$
 		if (this.typeArguments != null) {
@@ -1083,19 +1099,19 @@
 		}
 		if (isConstructorReference())
 			output.append("new"); //$NON-NLS-1$
-		else 
+		else
 			output.append(this.selector);
-		
+
 		return output;
 	}
-		
+
 	@Override
 	public void traverse(ASTVisitor visitor, BlockScope blockScope) {
 
 		if (visitor.visit(this, blockScope)) {
-			
+
 			this.lhs.traverse(visitor, blockScope);
-			
+
 			int length = this.typeArguments == null ? 0 : this.typeArguments.length;
 			for (int i = 0; i < length; i++) {
 				this.typeArguments[i].traverse(visitor, blockScope);
@@ -1105,7 +1121,7 @@
 	}
 
 	public Expression[] createPseudoExpressions(TypeBinding[] p) {
-		// from 15.13.1: 
+		// from 15.13.1:
 		// ... the reference is treated as if it were an invocation with argument expressions of types P1..Pn
 		// ... the reference is treated as if it were an invocation with argument expressions of types P2..Pn
 		// (the different sets of types are passed from our resolveType to scope.getMethod(..), see someMethod, anotherMethod)
@@ -1141,7 +1157,7 @@
 			return false;
 		if (this.typeArgumentsHaveErrors || this.receiverType == null || !this.receiverType.isValidBinding())
 			return false;
-		
+
 		int parametersLength = sam.parameters.length;
 		TypeBinding[] descriptorParameters = new TypeBinding[parametersLength];
 		for (int i = 0; i < parametersLength; i++) {
@@ -1163,7 +1179,7 @@
 				}
 			};
 		}
-		
+
 		// 15.13.1
         this.freeParameters = descriptorParameters;
         this.checkingPotentialCompatibility = true;
@@ -1173,12 +1189,12 @@
         	if (compileTimeDeclaration != null && compileTimeDeclaration.isValidBinding()) // we have the mSMB.
         		this.potentialMethods = new MethodBinding [] { compileTimeDeclaration };
         	else {
-        		/* We EITHER have potential methods that are input to Scope.mSMb already captured in this.potentialMethods 
+        		/* We EITHER have potential methods that are input to Scope.mSMb already captured in this.potentialMethods
         	       OR there is no potentially compatible compile time declaration ...
         		 */
         	}
 
-        	/* 15.12.2.1: A method reference expression (§15.13) is potentially compatible with a functional interface type if, where the type's function type arity is n, 
+        	/* 15.12.2.1: A method reference expression (§15.13) is potentially compatible with a functional interface type if, where the type's function type arity is n,
 		       there exists at least one potentially applicable method for the method reference expression with arity n (§15.13.1), and one of the following is true:
                    – The method reference expression has the form ReferenceType ::[TypeArguments] Identifier and at least one potentially applicable method is
                         i) static and supports arity n, or ii) not static and supports arity n-1.
@@ -1202,11 +1218,11 @@
         	this.freeParameters = descriptorParameters;
         	this.potentialMethods = Binding.NO_METHODS;
         	compileTimeDeclaration = getCompileTimeDeclaration(scope, false, descriptorParameters);
-        
+
         	if (compileTimeDeclaration != null && compileTimeDeclaration.isValidBinding()) // we have the mSMB.
         		this.potentialMethods = new MethodBinding [] { compileTimeDeclaration };
         	else {
-        		/* We EITHER have potential methods that are input to Scope.mSMb already captured in this.potentialMethods 
+        		/* We EITHER have potential methods that are input to Scope.mSMb already captured in this.potentialMethods
               	   OR there is no potentially compatible compile time declaration ...
         		*/
         	}
@@ -1222,7 +1238,7 @@
         }
         return false;
 	}
-	
+
 	MethodBinding getCompileTimeDeclaration(Scope scope, boolean isConstructorRef, TypeBinding[] parameters) {
 		if (this.exactMethodBinding != null)
 			return this.exactMethodBinding;
@@ -1237,24 +1253,28 @@
 	@Override
 	public boolean isCompatibleWith(TypeBinding targetType, Scope scope) {
 		ReferenceExpression copy = cachedResolvedCopy(targetType);
-		return copy != null && copy.resolvedType != null && copy.resolvedType.isValidBinding() && copy.binding != null && copy.binding.isValidBinding();
+		if (copy == null) {
+			return contextHasSyntaxError(); // in case of syntax error avoid secondary errors
+		} else {
+			return copy.resolvedType != null && copy.resolvedType.isValidBinding() && copy.binding != null && copy.binding.isValidBinding();
+		}
 	}
-	
+
 	@Override
 	public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope scope) {
-		
+
 		if (super.sIsMoreSpecific(s, t, scope))
 			return true;
-		
+
 		if (this.exactMethodBinding == null || t.findSuperTypeOriginatingFrom(s) != null)
 			return false;
-		
+
 		s = s.capture(this.enclosingScope, this.sourceStart, this.sourceEnd);
 		MethodBinding sSam = s.getSingleAbstractMethod(this.enclosingScope, true);
 		if (sSam == null || !sSam.isValidBinding())
 			return false;
 		TypeBinding r1 = sSam.returnType;
-		
+
 		MethodBinding tSam = t.getSingleAbstractMethod(this.enclosingScope, true);
 		if (tSam == null || !tSam.isValidBinding())
 			return false;
@@ -1269,14 +1289,14 @@
 		}
 		if (r2.id == TypeIds.T_void)
 			return true;
-		
+
 		if (r1.id == TypeIds.T_void)
 			return false;
-		
+
 		// r1 <: r2
 		if (r1.isCompatibleWith(r2, scope))
 			return true;
-		
+
 		return r1.isBaseType() != r2.isBaseType() && r1.isBaseType() == this.exactMethodBinding.returnType.isBaseType();
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/RequiresStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/RequiresStatement.java
index 110ab4a..ea1b95d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/RequiresStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/RequiresStatement.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.ast;
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
index 4cddf3a..a856cfd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java
@@ -74,12 +74,12 @@
 	// to each of the traversed try statements, so that execution will terminate properly.
 
 	// lookup the label, this should answer the returnContext
-	
+
 	if (this.expression instanceof FunctionalExpression) {
 		if (this.expression.resolvedType == null || !this.expression.resolvedType.isValidBinding()) {
 			/* Don't descend without proper target types. For lambda shape analysis, what is pertinent is value vs void return and the fact that
 			   this constitutes an abrupt exit. The former is already gathered, the latter is handled here.
-			*/ 
+			*/
 			flowContext.recordAbruptExit();
 			return FlowInfo.DEAD_END;
 		}
@@ -99,6 +99,8 @@
 				// by returning the method passes the responsibility to the caller:
 				flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.expression, flowInfo, flowContext, true);
 			}
+			// don't wait till after this statement, because then flowInfo would be DEAD_END & thus cannot serve nullStatus any more:
+			FakedTrackingVariable.cleanUpUnassigned(currentScope, this.expression, flowInfo);
 		}
 	}
 	this.initStateIndex =
@@ -291,7 +293,7 @@
 				: methodBinding.returnType)
 			: TypeBinding.VOID;
 	TypeBinding expressionType;
-	
+
 	if (this.expression != null) {
 		this.expression.setExpressionContext(ASSIGNMENT_CONTEXT);
 		this.expression.setExpectedType(methodType);
@@ -299,7 +301,7 @@
 			this.expression.bits |= ASTNode.DisableUnnecessaryCastCheck;
 		}
 	}
-	
+
 	if (methodType == TypeBinding.VOID) {
 		// the expression should be null, exceptions exist for lambda expressions.
 		if (this.expression == null) {
@@ -322,11 +324,11 @@
 		if (methodType != null) scope.problemReporter().shouldReturn(methodType, this);
 		return;
 	}
-	
+
 	expressionType = this.expression.resolveType(scope);
 	if (lambda != null)
 		lambda.returnsExpression(this.expression, expressionType);
-	
+
 	if (expressionType == null) return;
 	if (expressionType == TypeBinding.VOID) {
 		scope.problemReporter().attemptToReturnVoidValue(this);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java
index 4a5fbb0..1936924 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java
@@ -31,7 +31,7 @@
 		this.sourceStart = sourceStart;
 		this.sourceEnd = type.sourceEnd;
 	}
-	
+
 	public SingleMemberAnnotation() {
 		// for subclasses.
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
index d97c34f..08daf8b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
@@ -226,7 +226,7 @@
 	if (fieldBinding.isStatic()) {
 		// check if accessing enum static field in initializer
 		ReferenceBinding declaringClass = fieldBinding.declaringClass;
-		if (declaringClass.isEnum() && !scope.isModuleScope()) {
+		if (declaringClass.isEnum() && scope.kind != Scope.MODULE_SCOPE) {
 			SourceTypeBinding sourceType = scope.enclosingSourceType();
 			if (this.constant == Constant.NotAConstant
 					&& !methodScope.isStatic
@@ -406,6 +406,9 @@
 
 			// normal local assignment (since cannot store in outer local which are final locations)
 			codeStream.store(localBinding, valueRequired);
+			if ((this.bits & ASTNode.IsSecretYieldValueUsage) != 0) {
+				localBinding.recordInitializationStartPC(codeStream.position);
+			}
 			if ((this.bits & ASTNode.FirstAssignmentToLocal) != 0) { // for local variable debug attributes
 				localBinding.recordInitializationStartPC(codeStream.position);
 			}
@@ -1054,6 +1057,12 @@
 							if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) // for 8, defer till effective finality could be ascertained.
 								scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)variable, this);
 						}
+						if (this.actualReceiverType.isRecord() && this.actualReceiverType.isLocalType()) {// JLS 14 Sec 14.3
+							if ((variable.modifiers & ClassFileConstants.AccStatic) == 0 &&
+									(this.bits & ASTNode.IsCapturedOuterLocal) != 0) {
+								scope.problemReporter().recordStaticReferenceToOuterLocalVariable((LocalVariableBinding)variable, this);
+							}
+						}
 						variableType = variable.type;
 						this.constant = (this.bits & ASTNode.IsStrictlyAssigned) == 0 ? variable.constant(scope) : Constant.NotAConstant;
 					} else {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
index 837edda..ebb8f55 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -55,7 +55,7 @@
 			return this.resolvedType;
 
 		this.resolvedType = scope.getType(this.token);
-		
+
 		if (this.resolvedType instanceof TypeVariableBinding) {
 			TypeVariableBinding typeVariable = (TypeVariableBinding) this.resolvedType;
 			if (typeVariable.declaringElement instanceof SourceTypeBinding) {
@@ -91,9 +91,9 @@
 			   this.token == CHAR    ||
 			   this.token == BOOLEAN ||
 			   this.token == NULL    ||
-			   this.token == VOID;	    
+			   this.token == VOID;
 	}
-	
+
 	@Override
 	public StringBuffer printExpression(int indent, StringBuffer output){
 		if (this.annotations != null && this.annotations[0] != null) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
index 9d386d5..814f8dc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
@@ -73,7 +73,7 @@
 //				case OperatorIds.AND_AND :
 //				case OperatorIds.OR_OR :
 //					break;
-//				default: 
+//				default:
 //					// if (DEBUG_LEVEL > 0) print(); - tolerated
 //					if ((binary.left instanceof Reference) && binary.right.constant != Constant.NotAConstant)
 //						return true;
@@ -88,8 +88,8 @@
 
 /** Lambda shape analysis: *Assuming* this is reachable, analyze if this completes normally i.e control flow can reach the textually next statement.
    For blocks, we don't perform intra-reachability analysis. We assume the lambda body is free of intrinsic control flow errors (if such errors
-   exist they will not be flagged by this analysis, but are guaranteed to surface later on.) 
-   
+   exist they will not be flagged by this analysis, but are guaranteed to surface later on.)
+
    @see Block#doesNotCompleteNormally
 */
 public boolean doesNotCompleteNormally() {
@@ -97,7 +97,7 @@
 }
 
 /** Lambda shape analysis: *Assuming* this is reachable, analyze if this completes by continuing i.e control flow cannot reach the textually next statement.
-    This is necessitated by the fact that continue claims to not complete normally. So this is necessary to discriminate between do { continue; } while (false); 
+    This is necessitated by the fact that continue claims to not complete normally. So this is necessary to discriminate between do { continue; } while (false);
     which completes normally and do { throw new Exception(); } while (false); which does not complete normally.
 */
 public boolean completesByContinue() {
@@ -107,7 +107,7 @@
 	public static final int NOT_COMPLAINED = 0;
 	public static final int COMPLAINED_FAKE_REACHABLE = 1;
 	public static final int COMPLAINED_UNREACHABLE = 2;
-	
+
 
 /** Analysing arguments of MessageSend, ExplicitConstructorCall, AllocationExpression. */
 protected void analyseArguments(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, MethodBinding methodBinding, Expression[] arguments)
@@ -165,7 +165,7 @@
 						flowContext.recordNullityMismatch(currentScope, argument, argument.resolvedType, expectedType, flowInfo, nullStatus, null);
 				}
 			}
-		} 
+		}
 	}
 }
 void analyseOneArgument18(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo,
@@ -191,16 +191,16 @@
 									nullStatus, expectedNonNullness, originalExpected);
 }
 void internalAnalyseOneArgument18(BlockScope currentScope, FlowContext flowContext, TypeBinding expectedType,
-		Expression argument, FlowInfo flowInfo, int nullStatus, Boolean expectedNonNullness, TypeBinding originalExpected) 
+		Expression argument, FlowInfo flowInfo, int nullStatus, Boolean expectedNonNullness, TypeBinding originalExpected)
 {
 	// here we consume special case information generated in the ctor of ParameterizedGenericMethodBinding (see there):
-	int statusFromAnnotatedNull = expectedNonNullness == Boolean.TRUE ? nullStatus : 0;  
-	
+	int statusFromAnnotatedNull = expectedNonNullness == Boolean.TRUE ? nullStatus : 0;
+
 	NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(expectedType, argument.resolvedType, nullStatus);
-	
+
 	if (!annotationStatus.isAnyMismatch() && statusFromAnnotatedNull != 0)
 		expectedType = originalExpected; // to avoid reports mentioning '@NonNull null'!
-	
+
 	if (statusFromAnnotatedNull == FlowInfo.NULL) {
 		// immediate reporting:
 		currentScope.problemReporter().nullityMismatchingTypeAnnotation(argument, argument.resolvedType, expectedType, annotationStatus);
@@ -224,7 +224,7 @@
 	} catch (NullPointerException npe) {
 		// chain of references in try-block has several potential nulls;
 		// any null means we cannot perform the following check
-		return;			
+		return;
 	}
 	if (useTypeAnnotations) {
 		checkAgainstNullTypeAnnotation(scope, methodBinding.returnType, expr, flowContext, flowInfo);
@@ -246,8 +246,8 @@
 	} else 	if (expression instanceof SwitchExpression && expression.isPolyExpression()) {
 		SwitchExpression se = (SwitchExpression) expression;
 		for (int i = 0; i < se.resultExpressions.size(); i++) {
-			internalCheckAgainstNullTypeAnnotation(scope, requiredType, 
-					se.resultExpressions.get(i), 
+			internalCheckAgainstNullTypeAnnotation(scope, requiredType,
+					se.resultExpressions.get(i),
 					se.resultExpressionNullStatus.get(i), flowContext, flowInfo);
 		}
 		return;
@@ -280,7 +280,7 @@
 // Inspect AST nodes looking for a break statement, descending into nested control structures only when necessary (looking for a break with a specific label.)
 public boolean breaksOut(final char[] label) {
 	return new ASTVisitor() {
-		
+
 		boolean breaksOut;
 		@Override
 		public boolean visit(TypeDeclaration type, BlockScope skope) { return label != null; }
@@ -298,7 +298,7 @@
 		public boolean visit(ForStatement forStatement, BlockScope skope) { return label != null; }
 		@Override
 		public boolean visit(SwitchStatement switchStatement, BlockScope skope) { return label != null; }
-		
+
 		@Override
 		public boolean visit(BreakStatement breakStatement, BlockScope skope) {
 			if (label == null || CharOperation.equals(label,  breakStatement.label))
@@ -479,7 +479,7 @@
 public TypeBinding resolveExpressionType(BlockScope scope) {
 	return null;
 }
-/** 
+/**
  * Implementation of {@link org.eclipse.jdt.internal.compiler.lookup.InvocationSite#invocationTargetType}
  * suitable at this level. Subclasses should override as necessary.
  * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#invocationTargetType()
@@ -496,7 +496,7 @@
 	return ExpressionContext.VANILLA_CONTEXT;
 }
 /**
- * For all constructor invocations: find the constructor binding; 
+ * For all constructor invocations: find the constructor binding;
  * if site.innersNeedUpdate() perform some post processing for those and produce
  * any updates as side-effects into 'argumentTypes'.
  */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java
index 32b7c7c..04d4b67 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java
@@ -34,6 +34,7 @@
 	}
 
 	ExceptionLabel anyExceptionLabel;
+	protected SwitchExpression switchExpression = null;
 
 	public ExceptionLabel enterAnyExceptionHandler(CodeStream codeStream) {
 
@@ -75,4 +76,12 @@
 	public void placeAllAnyExceptionHandler() {
 		this.anyExceptionLabel.place();
 	}
+
+	public SwitchExpression getSwitchExpression() {
+		return this.switchExpression;
+	}
+
+	public void setSwitchExpression(SwitchExpression switchExpression) {
+		this.switchExpression = switchExpression;
+	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java
index 6539558..8aaf7a2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java
@@ -44,7 +44,7 @@
 
 		return true;
 	}
-	
+
 	@Override
 	public boolean isUnqualifiedSuper() {
 		return true;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java
index b524448..42b6e63 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2018, 2019 IBM Corporation and others.
+ * Copyright (c) 2018, 2020 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
@@ -18,14 +18,18 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.EmptyStackException;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Stack;
 import java.util.stream.Collectors;
 
+import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ASTVisitor;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
 import org.eclipse.jdt.internal.compiler.flow.FlowContext;
 import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
@@ -34,6 +38,7 @@
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
+import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
 import org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding;
@@ -53,11 +58,17 @@
 	public List<Expression> resultExpressions;
 	public boolean resolveAll;
 	/* package */ List<Integer> resultExpressionNullStatus;
+	LocalVariableBinding hiddenYield;
+	/* package */ int hiddenYieldResolvedPosition = -1;
+	public boolean containsTry = false;
 	private static Map<TypeBinding, TypeBinding[]> type_map;
+	static final char[] SECRET_YIELD_VALUE_NAME = " yieldValue".toCharArray(); //$NON-NLS-1$
+	int yieldResolvedPosition = -1;
+	List<LocalVariableBinding> typesOnStack;
 
 	static {
 		type_map = new HashMap<TypeBinding, TypeBinding[]>();
-		type_map.put(TypeBinding.CHAR, new TypeBinding[] {TypeBinding.CHAR, TypeBinding.BYTE, TypeBinding.INT});
+		type_map.put(TypeBinding.CHAR, new TypeBinding[] {TypeBinding.CHAR, TypeBinding.INT});
 		type_map.put(TypeBinding.SHORT, new TypeBinding[] {TypeBinding.SHORT, TypeBinding.BYTE, TypeBinding.INT});
 		type_map.put(TypeBinding.BYTE, new TypeBinding[] {TypeBinding.BYTE, TypeBinding.INT});
 	}
@@ -88,7 +99,7 @@
 	protected int getFallThroughState(Statement stmt, BlockScope blockScope) {
 		if ((stmt instanceof Expression && ((Expression) stmt).isTrulyExpression())|| stmt instanceof ThrowStatement)
 			return BREAKING;
-		if (this.switchLabeledRules // do this check for every block if '->' (Switch Labeled Rules) 
+		if (this.switchLabeledRules // do this check for every block if '->' (Switch Labeled Rules)
 				&& stmt instanceof Block) {
 			Block block = (Block) stmt;
 			if (block.doesNotCompleteNormally()) {
@@ -160,11 +171,11 @@
 			}
 		}
 		if (firstTrailingCaseStmt != null) {
-			blockScope.problemReporter().switchExpressionTrailingSwitchLabels(firstTrailingCaseStmt);				
+			blockScope.problemReporter().switchExpressionTrailingSwitchLabels(firstTrailingCaseStmt);
 		}
 	}
 	@Override
-	protected boolean needToCheckFlowInAbsenceOfDefaultBranch() { // JLS 12 16.1.8 
+	protected boolean needToCheckFlowInAbsenceOfDefaultBranch() { // JLS 12 16.1.8
 		return !this.switchLabeledRules;
 	}
 	@Override
@@ -219,9 +230,99 @@
 		Expression expression1 = (Expression) statement;
 		expression1.generateCode(currentScope, codeStream, true /* valueRequired */);
 	}
+	private TypeBinding createType(int typeId) {
+		TypeBinding type = TypeBinding.wellKnownType(this.scope, typeId);
+		return type != null ? type : this.scope.getJavaLangObject();
+	}
+	private LocalVariableBinding addTypeStackVariable(CodeStream codeStream, TypeBinding type, int typeId, int index, int resolvedPosition) {
+		char[] name = CharOperation.concat(SECRET_YIELD_VALUE_NAME, String.valueOf(index).toCharArray());
+		type = type != null ? type : createType(typeId);
+		LocalVariableBinding lvb =
+				new LocalVariableBinding(
+					name,
+					type,
+					ClassFileConstants.AccDefault,
+					false);
+		lvb.setConstant(Constant.NotAConstant);
+		lvb.useFlag = LocalVariableBinding.USED;
+		lvb.resolvedPosition = resolvedPosition;
+//		if (this.offset > 0xFFFF) { // no more than 65535 words of locals // TODO - also the cumulative at MethodScope
+//			problemReporter().noMoreAvailableSpaceForLocal(
+//				local,
+//				local.declaration == null ? (ASTNode)methodScope().referenceContext : local.declaration);
+//		}
+		this.scope.addLocalVariable(lvb);
+		lvb.declaration = new LocalDeclaration(name, 0, 0);
+		return lvb;
+	}
+	private int getNextOffset(LocalVariableBinding local) {
+		int delta =  ((TypeBinding.equalsEquals(local.type, TypeBinding.LONG)) || (TypeBinding.equalsEquals(local.type, TypeBinding.DOUBLE))) ?
+				2 : 1;
+		return local.resolvedPosition + delta;
+	}
+	private void processTypesBindingsOnStack(CodeStream codeStream) {
+		int count = 0;
+		int nextResolvedPosition = this.scope.offset;
+		if (!codeStream.switchSaveTypeBindings.empty()) {
+			this.typesOnStack = new ArrayList<>();
+			int index = 0;
+			Stack<TypeBinding> typeStack = new Stack<>();
+			int sz = codeStream.switchSaveTypeBindings.size();
+			for (int i = codeStream.lastSwitchCumulativeSyntheticVars; i < sz; ++i) {
+				typeStack.add(codeStream.switchSaveTypeBindings.get(i));
+			}
+			while (!typeStack.empty()) {
+				TypeBinding type = typeStack.pop();
+				LocalVariableBinding lvb = addTypeStackVariable(codeStream, type, TypeIds.T_undefined, index++, nextResolvedPosition);
+				nextResolvedPosition = getNextOffset(lvb);
+				this.typesOnStack.add(lvb);
+				codeStream.store(lvb, false);
+				codeStream.addVariable(lvb);
+				++count;
+			}
+		}
+		// now keep a position reserved for yield result value
+		this.yieldResolvedPosition = nextResolvedPosition;
+		nextResolvedPosition += ((TypeBinding.equalsEquals(this.resolvedType, TypeBinding.LONG)) ||
+				(TypeBinding.equalsEquals(this.resolvedType, TypeBinding.DOUBLE))) ?
+				2 : 1;
+
+		codeStream.lastSwitchCumulativeSyntheticVars += count + 1; // 1 for yield var
+		int delta = nextResolvedPosition - this.scope.offset;
+		this.scope.adjustLocalVariablePositions(delta, false);
+	}
+	public void loadStoredTypesAndKeep(CodeStream codeStream) {
+		List<LocalVariableBinding> tos = this.typesOnStack;
+		int sz = tos != null ? tos.size() : 0;
+		int index = sz - 1;
+		while (index >= 0) {
+			LocalVariableBinding lvb = tos.get(index--);
+			codeStream.load(lvb);
+//		    lvb.recordInitializationEndPC(codeStream.position);
+//			codeStream.removeVariable(lvb);
+		}
+	}
+	private void removeStoredTypes(CodeStream codeStream) {
+		List<LocalVariableBinding> tos = this.typesOnStack;
+		int sz = tos != null ? tos.size() : 0;
+		int index = sz - 1;
+		while (index >= 0) {
+			LocalVariableBinding lvb = tos.get(index--);
+			codeStream.removeVariable(lvb);
+		}
+	}
 	@Override
 	public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
+		int tmp = 0;
+		if (this.containsTry) {
+			tmp = codeStream.lastSwitchCumulativeSyntheticVars;
+			processTypesBindingsOnStack(codeStream);
+		}
 		super.generateCode(currentScope, codeStream);
+		if (this.containsTry) {
+			removeStoredTypes(codeStream);
+			codeStream.lastSwitchCumulativeSyntheticVars = tmp;
+		}
 		if (!valueRequired) {
 			// switch expression is saved to a variable that is not used. We need to pop the generated value from the stack
 			switch(postConversionType(currentScope).id) {
@@ -271,14 +372,76 @@
 		}
 		return true;
 	}
+	class OOBLFlagger extends ASTVisitor {
+		Set<String> labelDecls;
+		Set<BreakStatement> referencedBreakLabels;
+		Set<ContinueStatement> referencedContinueLabels;
+		public OOBLFlagger(SwitchExpression se) {
+			this.labelDecls = new HashSet<>();
+			this.referencedBreakLabels = new HashSet<>();
+			this.referencedContinueLabels = new HashSet<>();
+		}
+		@Override
+		public boolean visit(SwitchExpression switchExpression, BlockScope blockScope) {
+			return true;
+		}
+		private void checkForOutofBoundLabels(BlockScope blockScope) {
+			try {
+				for (BreakStatement bs : this.referencedBreakLabels) {
+					if (bs.label == null || bs.label.length == 0)
+						continue;
+					if (!this.labelDecls.contains(new String(bs.label)))
+						blockScope.problemReporter().switchExpressionsBreakOutOfSwitchExpression(bs);
+				}
+				for (ContinueStatement cs : this.referencedContinueLabels) {
+					if (cs.label == null || cs.label.length == 0)
+						continue;
+					if (!this.labelDecls.contains(new String(cs.label)))
+						blockScope.problemReporter().switchExpressionsContinueOutOfSwitchExpression(cs);
+				}
+			} catch (EmptyStackException e) {
+				// ignore
+			}
+		}
+
+		@Override
+		public void endVisit(SwitchExpression switchExpression,	BlockScope blockScope) {
+			checkForOutofBoundLabels(blockScope);
+		}
+		@Override
+		public boolean visit(BreakStatement breakStatement, BlockScope blockScope) {
+			if (breakStatement.label != null && breakStatement.label.length != 0)
+				this.referencedBreakLabels.add(breakStatement);
+			return true;
+		}
+		@Override
+		public boolean visit(ContinueStatement continueStatement, BlockScope blockScope) {
+			if (continueStatement.label != null && continueStatement.label.length != 0)
+				this.referencedContinueLabels.add(continueStatement);
+			return true;
+		}
+		@Override
+		public boolean visit(LabeledStatement stmt, BlockScope blockScope) {
+			if (stmt.label != null && stmt.label.length != 0)
+				this.labelDecls.add(new String(stmt.label));
+			return true;
+		}
+		@Override
+		public boolean visit(TypeDeclaration stmt, BlockScope blockScope) {
+			return false;
+		}
+	}
 	@Override
 	public TypeBinding resolveType(BlockScope upperScope) {
+		return resolveTypeInternal(upperScope);
+	}
+	public TypeBinding resolveTypeInternal(BlockScope upperScope) {
 		try {
 			int resultExpressionsCount;
 			if (this.constant != Constant.NotAConstant) {
 				this.constant = Constant.NotAConstant;
-	
-				// A switch expression is a poly expression if it appears in an assignment context or an invocation context (5.2, 5.3). 
+
+				// A switch expression is a poly expression if it appears in an assignment context or an invocation context (5.2, 5.3).
 				// Otherwise, it is a standalone expression.
 				if (this.expressionContext == ASSIGNMENT_CONTEXT || this.expressionContext == INVOCATION_CONTEXT) {
 					for (Expression e : this.resultExpressions) {
@@ -288,23 +451,24 @@
 						e.setExpectedType(this.expectedType);
 					}
 				}
-	
+
 				resolve(upperScope);
-	
+
 				if (this.statements == null || this.statements.length == 0) {
 					//	Report Error JLS 13 15.28.1  The switch block must not be empty.
 					upperScope.problemReporter().switchExpressionEmptySwitchBlock(this);
 					return null;
 				}
-				
+
 				resultExpressionsCount = this.resultExpressions != null ? this.resultExpressions.size() : 0;
 				if (resultExpressionsCount == 0) {
-					//  Report Error JLS 13 15.28.1 
+					//  Report Error JLS 13 15.28.1
 					// It is a compile-time error if a switch expression has no result expressions.
 					upperScope.problemReporter().switchExpressionNoResultExpressions(this);
 					return null;
 				}
-	
+				this.traverse(new OOBLFlagger(this), upperScope);
+
 				if (this.originalValueResultExpressionTypes == null) {
 					this.originalValueResultExpressionTypes = new TypeBinding[resultExpressionsCount];
 					this.finalValueResultExpressionTypes = new TypeBinding[resultExpressionsCount];
@@ -323,10 +487,12 @@
 			} else {
 				// re-resolving of poly expression:
 				resultExpressionsCount = this.resultExpressions != null ? this.resultExpressions.size() : 0;
+				if (resultExpressionsCount == 0)
+					return this.resolvedType = null; // error flagging would have been done during the earlier phase.
 				for (int i = 0; i < resultExpressionsCount; i++) {
 					Expression resultExpr = this.resultExpressions.get(i);
 					if (resultExpr.resolvedType == null || resultExpr.resolvedType.kind() == Binding.POLY_TYPE) {
-						this.finalValueResultExpressionTypes[i] = this.originalValueResultExpressionTypes[i] = 
+						this.finalValueResultExpressionTypes[i] = this.originalValueResultExpressionTypes[i] =
 							resultExpr.resolveTypeExpecting(upperScope, this.expectedType);
 					}
 					// This is a kludge and only way completion can tell this node to resolve all
@@ -352,7 +518,7 @@
 					break;
 				}
 			}
-			// If the result expressions all have the same type (which may be the null type), 
+			// If the result expressions all have the same type (which may be the null type),
 			// then that is the type of the switch expression.
 			if (typeUniformAcrossAllArms) {
 				tmp = this.originalValueResultExpressionTypes[0];
@@ -362,7 +528,7 @@
 				}
 				return this.resolvedType = tmp;
 			}
-			
+
 			boolean typeBbolean = true;
 			for (TypeBinding t : this.originalValueResultExpressionTypes) {
 				if (t != null)
@@ -376,6 +542,7 @@
 			 */
 			if (typeBbolean) {
 				for (int i = 0; i < resultExpressionsCount; ++i) {
+					if (this.originalValueResultExpressionTypes[i] == null) continue;
 					if (this.originalValueResultExpressionTypes[i].id == T_boolean) continue;
 					this.finalValueResultExpressionTypes[i] = env.computeBoxingType(this.originalValueResultExpressionTypes[i]);
 					this.resultExpressions.get(i).computeConversion(this.scope, this.finalValueResultExpressionTypes[i], this.originalValueResultExpressionTypes[i]);
@@ -411,7 +578,7 @@
 				 *  are widened to double.
 				 *  Otherwise, if any result expression is of type float, then other result expressions that are not of
 				 *  type float are widened to float.
-				 *  Otherwise, if any result expression is of type long, then other result expressions that are not of 
+				 *  Otherwise, if any result expression is of type long, then other result expressions that are not of
 				 *  type long are widened to long.
 				 */
 				TypeBinding[] dfl = new TypeBinding[]{// do not change the order JLS 13 5.6
@@ -432,13 +599,13 @@
 				 * a standalone switch expression where all the result expressions are convertible to a numeric type.]
 				 */
 
-				 /*  Otherwise, if any result expression is of type int and is not a constant expression, the other 
+				 /*  Otherwise, if any result expression is of type int and is not a constant expression, the other
 				 *  result expressions that are not of type int are widened to int.
 				 */
 				resultNumeric = resultNumeric != null ? resultNumeric : check_nonconstant_int();
 
 				resultNumeric = resultNumeric != null ? resultNumeric : // one among the first few rules applied.
-					getResultNumeric(typeSet, this.originalValueResultExpressionTypes); // check the rest
+					getResultNumeric(typeSet); // check the rest
 				typeSet = null; // hey gc!
 				for (int i = 0; i < resultExpressionsCount; ++i) {
 					this.resultExpressions.get(i).computeConversion(this.scope,
@@ -507,6 +674,21 @@
 		computeNullStatus(flowInfo, flowContext);
 		return flowInfo;
 	}
+	@Override
+	protected void addSecretTryResultVariable() {
+		if (this.containsTry) {
+			this.hiddenYield =
+					new LocalVariableBinding(
+						SwitchExpression.SECRET_YIELD_VALUE_NAME,
+						null,
+						ClassFileConstants.AccDefault,
+						false);
+			this.hiddenYield.setConstant(Constant.NotAConstant);
+			this.hiddenYield.useFlag = LocalVariableBinding.USED;
+			this.scope.addLocalVariable(this.hiddenYield);
+			this.hiddenYield.declaration = new LocalDeclaration(SECRET_YIELD_VALUE_NAME, 0, 0);
+		}
+	}
 	private TypeBinding check_csb(Set<TypeBinding> typeSet, TypeBinding candidate) {
 		if (!typeSet.contains(candidate))
 			return null;
@@ -520,17 +702,17 @@
 		return areAllIntegerResultExpressionsConvertibleToTargetType(candidate) ?
 				candidate : null;
 	}
-	private TypeBinding getResultNumeric(Set<TypeBinding> typeSet, TypeBinding[] armTypes) {
-		// note: if an expression has a type integer, then it will be a constant 
+	private TypeBinding getResultNumeric(Set<TypeBinding> typeSet) {
+		// note: if an expression has a type integer, then it will be a constant
 		// since non-constant integers are already processed before reaching here.
 
 		/* Otherwise, if any expression is of type short, and every other expression is either of type short,
 		 * or of type byte, or a constant expression of type int with a value that is representable in the
-		 * type short, then T is short, the byte expressions undergo widening primitive conversion to short, 
+		 * type short, then T is short, the byte expressions undergo widening primitive conversion to short,
 		 * and the int expressions undergo narrowing primitive conversion to short.\
 		 *
 		 * Otherwise, if any expression is of type byte, and every other expression is either of type byte or a
-		 * constant expression of type int with a value that is representable in the type byte, then T is byte 
+		 * constant expression of type int with a value that is representable in the type byte, then T is byte
 		 * and the int expressions undergo narrowing primitive conversion to byte.
 		 *
 		 * Otherwise, if any expression is of type char, and every other expression is either of type char or a
@@ -557,7 +739,7 @@
 			return true;
 		// JLS 13 15.28.1 A switch expression is a poly expression if it appears in an assignment context or
 		// an invocation context (5.2, 5.3). Otherwise, it is a standalone expression.
-		return this.isPolyExpression = this.expressionContext == ASSIGNMENT_CONTEXT || 
+		return this.isPolyExpression = this.expressionContext == ASSIGNMENT_CONTEXT ||
 				this.expressionContext == INVOCATION_CONTEXT;
 	}
 	@Override
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
index 2fa9584..30814cc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
@@ -162,7 +162,7 @@
 						fallThroughState = CASE;
 					} else {
 						if (!(this instanceof SwitchExpression) &&
-							currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK13 &&
+							currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK14 &&
 							statement instanceof YieldStatement &&
 							((YieldStatement) statement).isImplicit) {
 							YieldStatement y = (YieldStatement) statement;
@@ -656,6 +656,9 @@
 		}
 		return n;
 	}
+	protected void addSecretTryResultVariable() {
+		// do nothing
+	}
 	@Override
 	public void resolve(BlockScope upperScope) {
 		try {
@@ -702,6 +705,7 @@
 			}
 			if (this.statements != null) {
 				this.scope = new BlockScope(upperScope);
+//				addSecretTryResultVariable();
 				int length;
 				// collection of cases is too big but we will only iterate until caseCount
 				this.cases = new CaseStatement[length = this.statements.length];
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java
index d6465cb..cbc5e91 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java
@@ -113,7 +113,7 @@
 			default :
 				codeStream.dup();
 				break;
-		}		
+		}
 		// only take the lock
 		codeStream.monitorenter();
 		codeStream.monitorexit();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java
index 26d0d82..6aa7a59 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java
@@ -131,7 +131,7 @@
 	public TypeBinding resolveType(BlockScope scope) {
 
 		this.constant = Constant.NotAConstant;
-		
+
 		ReferenceBinding enclosingReceiverType = scope.enclosingReceiverType();
 		if (!isImplicitThis() &&!checkAccess(scope, enclosingReceiverType)) {
 			return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java
index 0cde48c..b1f906d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java
@@ -21,9 +21,9 @@
 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
 
 public class TrueLiteral extends MagicLiteral {
-	
+
 	static final char[] source = {'t' , 'r' , 'u' , 'e'};
-	
+
 public TrueLiteral(int s , int e) {
 	super(s,e);
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java
index 856c6f6..d5fe5dc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java
@@ -93,6 +93,7 @@
 	private ExceptionLabel[] resourceExceptionLabels;
 	private int[] caughtExceptionsCatchBlocks;
 
+	public SwitchExpression enclosingSwitchExpression = null;
 @Override
 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
 
@@ -148,7 +149,7 @@
 
 		FlowInfo tryInfo = flowInfo.copy();
 		for (int i = 0; i < resourcesLength; i++) {
-			final Statement resource = this.resources[i];			
+			final Statement resource = this.resources[i];
 			tryInfo = resource.analyseCode(currentScope, handlingContext, tryInfo);
 			this.postResourcesInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(tryInfo);
 			TypeBinding resolvedType = null;
@@ -247,7 +248,7 @@
 				null,
 				this.scope,
 				flowInfo);
-		insideSubContext.initsOnFinally = handlingContext.initsOnFinally; 
+		insideSubContext.initsOnFinally = handlingContext.initsOnFinally;
 
 		subInfo =
 			this.finallyBlock
@@ -574,7 +575,7 @@
 			for (int i = resourceCount; i >= 0; i--) {
 				BranchLabel exitLabel = new BranchLabel(codeStream);
 				this.resourceExceptionLabels[i].placeEnd(); // outer handler if any is the one that should catch exceptions out of close()
-				
+
 				Statement stmt = i > 0 ? this.resources[i - 1] : null;
 				if ((this.bits & ASTNode.IsTryBlockExiting) == 0) {
 					// inline resource closure
@@ -605,8 +606,8 @@
 
 				codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable());
 				this.resourceExceptionLabels[i].place();
-				if (i == resourceCount) { 
-					// inner most try's catch/finally can be a lot simpler. 
+				if (i == resourceCount) {
+					// inner most try's catch/finally can be a lot simpler.
 					codeStream.store(this.primaryExceptionVariable, false);
 					// fall through, invoke close() and re-throw.
 				} else {
@@ -629,7 +630,7 @@
 				if (i > 0) {
 					// inline resource close here rather than bracketing the current catch block with a try region.
 					BranchLabel postCloseLabel = new BranchLabel(codeStream);
-					generateCodeSnippet(stmt, codeStream, postCloseLabel, true /* record */, i, codeStream.position);						
+					generateCodeSnippet(stmt, codeStream, postCloseLabel, true /* record */, i, codeStream.position);
 					postCloseLabel.place();
 				}
 				codeStream.load(this.primaryExceptionVariable);
@@ -885,8 +886,8 @@
 	codeStream.recordPositionsFrom(pc, this.sourceStart);
 }
 private void generateCodeSnippet(Statement statement, CodeStream codeStream, BranchLabel postCloseLabel, boolean record, int... values) {
-	
-	int i = -1; 
+
+	int i = -1;
 	int invokeCloseStartPc = -1;
 	if (record) {
 		i = values[0];
@@ -927,11 +928,11 @@
 		Binding refBinding =  ref instanceof NameReference ? ((NameReference) ref).binding :
 			ref instanceof FieldReference ? ((FieldReference) ref).binding : null;
 		if (refBinding == null) return false;
-		
+
 		//TODO: For field accesses in the form of a.b.c and b.c - could there be a non-trivial dup - to check?
 		for (int i = 0; i < index; i++) {
 			Statement stmt = this.resources[i];
-			Binding b = stmt instanceof LocalDeclaration ? ((LocalDeclaration) stmt).binding : 
+			Binding b = stmt instanceof LocalDeclaration ? ((LocalDeclaration) stmt).binding :
 				stmt instanceof NameReference ? ((NameReference) stmt).binding :
 						stmt instanceof FieldReference ? ((FieldReference) stmt).binding : null;
 			if (b == refBinding) {
@@ -967,11 +968,17 @@
 	int finallyMode = finallyMode();
 	switch(finallyMode) {
 		case FINALLY_DOES_NOT_COMPLETE :
+			if (this.switchExpression != null) {
+				this.finallyBlock.generateCode(currentScope, codeStream);
+				return true;
+			}
 			codeStream.goto_(this.subRoutineStartLabel);
 			return true;
 
 		case NO_FINALLY :
-			exitDeclaredExceptionHandlers(codeStream);
+			if (this.switchExpression == null) { // already taken care at Yield
+				exitDeclaredExceptionHandlers(codeStream);
+			}
 			return false;
 	}
 	// optimize subroutine invocation sequences, using the targetLocation (if any)
@@ -1163,7 +1170,7 @@
 
 			if (!methodScope.isInsideInitializer()) {
 				MethodBinding methodBinding = methodScope.referenceContext instanceof AbstractMethodDeclaration ?
-					((AbstractMethodDeclaration) methodScope.referenceContext).binding : (methodScope.referenceContext instanceof LambdaExpression ? 
+					((AbstractMethodDeclaration) methodScope.referenceContext).binding : (methodScope.referenceContext instanceof LambdaExpression ?
 							((LambdaExpression)methodScope.referenceContext).binding : null);
 				if (methodBinding != null) {
 					TypeBinding methodReturnType = methodBinding.returnType;
@@ -1333,7 +1340,7 @@
 public boolean completesByContinue() {
 	if (this.tryBlock.completesByContinue()) {
 		return (this.finallyBlock == null) ? true :
-			!this.finallyBlock.doesNotCompleteNormally() || this.finallyBlock.completesByContinue(); 
+			!this.finallyBlock.doesNotCompleteNormally() || this.finallyBlock.completesByContinue();
 	}
 	if (this.catchBlocks != null) {
 		for (int i = 0; i < this.catchBlocks.length; i++) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
index 952b2ed..e4a2b8d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java
@@ -1,6 +1,6 @@
 // AspectJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -43,6 +43,10 @@
 	public static final int INTERFACE_DECL = 2;
 	public static final int ENUM_DECL = 3;
 	public static final int ANNOTATION_TYPE_DECL = 4;
+	/*
+	 * @noreference This field is not intended to be referenced by clients as it is a part of Java preview feature.
+	 */
+	public static final int RECORD_DECL = 5;
 
 	public int modifiers = ClassFileConstants.AccDefault;
 	public int modifiersSourceStart;
@@ -63,6 +67,7 @@
 	public int maxFieldCount;
 	public int declarationSourceStart;
 	public int declarationSourceEnd;
+	public int restrictedIdentifierStart; // used only for records
 	public int bodyStart;
 	public int bodyEnd; // doesn't include the trailing comment if any.
 	public CompilationResult compilationResult;
@@ -813,10 +818,10 @@
 
 private void checkYieldUsage() {
 	long sourceLevel = this.scope.compilerOptions().sourceLevel;
-	if (sourceLevel < ClassFileConstants.JDK13 || this.name == null ||
+	if (sourceLevel < ClassFileConstants.JDK14 || this.name == null ||
 			!("yield".equals(new String(this.name)))) //$NON-NLS-1$
 		return;
-	if (sourceLevel == ClassFileConstants.JDK13 && this.scope.compilerOptions().enablePreviewFeatures) {
+	if (sourceLevel >= ClassFileConstants.JDK14) {
 		this.scope.problemReporter().switchExpressionsYieldTypeDeclarationError(this);
 	} else {
 		this.scope.problemReporter().switchExpressionsYieldTypeDeclarationWarning(this);
@@ -866,18 +871,24 @@
 }
 
 public final static int kind(int flags) {
-	switch (flags & (ClassFileConstants.AccInterface|ClassFileConstants.AccAnnotation|ClassFileConstants.AccEnum)) {
+	switch (flags & (ClassFileConstants.AccInterface|ClassFileConstants.AccAnnotation|ClassFileConstants.AccEnum|ExtraCompilerModifiers.AccRecord)) {
 		case ClassFileConstants.AccInterface :
 			return TypeDeclaration.INTERFACE_DECL;
 		case ClassFileConstants.AccInterface|ClassFileConstants.AccAnnotation :
 			return TypeDeclaration.ANNOTATION_TYPE_DECL;
 		case ClassFileConstants.AccEnum :
 			return TypeDeclaration.ENUM_DECL;
+		case ExtraCompilerModifiers.AccRecord :
+			return TypeDeclaration.RECORD_DECL;
 		default :
 			return TypeDeclaration.CLASS_DECL;
 	}
 }
 
+public boolean isRecord() {
+	return false;
+}
+
 /*
  * Access emulation for a local type
  * force to emulation of access to direct enclosing instance.
@@ -1073,6 +1084,9 @@
 		case TypeDeclaration.ANNOTATION_TYPE_DECL :
 			output.append("@interface "); //$NON-NLS-1$
 			break;
+		case TypeDeclaration.RECORD_DECL :
+			output.append("record "); //$NON-NLS-1$
+			break;
 	}
 	output.append(this.name);
 	if (this.typeParameters != null) {
@@ -1091,6 +1105,7 @@
 		switch (kind(this.modifiers)) {
 			case TypeDeclaration.CLASS_DECL :
 			case TypeDeclaration.ENUM_DECL :
+			case TypeDeclaration.RECORD_DECL :
 				output.append(" implements "); //$NON-NLS-1$
 				break;
 			case TypeDeclaration.INTERFACE_DECL :
@@ -1133,6 +1148,7 @@
 				this.scope.problemReporter().varIsReservedTypeName(this);
 			}
 		}
+		RecordDeclaration.checkAndFlagRecordNameErrors(this.name, this, this.scope);
 		// resolve annotations and check @Deprecated annotation
 		long annotationTagBits = sourceType.getAnnotationTagBits();
 		if ((annotationTagBits & TagBits.AnnotationDeprecated) == 0
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java
index c618954..185dda1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java
@@ -120,6 +120,7 @@
 				scope.problemReporter().varIsNotAllowedHere(this);
 			}
 		}
+		RecordDeclaration.checkAndFlagRecordNameErrors(this.name, this, scope);
 	}
 
 	@Override
@@ -166,7 +167,7 @@
 					this.binding.evaluateNullAnnotations(scope, this);
 				}
 			}
-		}	
+		}
 	}
 
 	@Override
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 38d7609..135754a 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
@@ -355,10 +355,10 @@
 	char [][] qName = getTypeName();
 	String name = qName != null && qName[0] != null ? new String(qName[0]) : null;
 	long sourceLevel = currentScope.compilerOptions().sourceLevel;
-	if (sourceLevel < ClassFileConstants.JDK13 || name == null ||
+	if (sourceLevel < ClassFileConstants.JDK14 || name == null ||
 			!("yield".equals(new String(name)))) //$NON-NLS-1$
 		return;
-	if (sourceLevel == ClassFileConstants.JDK13 && currentScope.compilerOptions().enablePreviewFeatures) {
+	if (sourceLevel >= ClassFileConstants.JDK14) {
 		currentScope.problemReporter().switchExpressionsYieldTypeDeclarationError(this);
 	} else {
 		currentScope.problemReporter().switchExpressionsYieldTypeDeclarationWarning(this);
@@ -388,9 +388,7 @@
 	final int totalDimensions = dimensions + additionalDimensions;
 	Annotation [][] mergedAnnotations = new Annotation[totalDimensions][];
 	if (annotationsOnDimensions != null) {
-		for (int i = 0; i < dimensions; i++) {
-			mergedAnnotations[i] = annotationsOnDimensions[i];
-		} 
+		System.arraycopy(annotationsOnDimensions, 0, mergedAnnotations, 0, dimensions); 
 	}
 	if (additionalAnnotations != null) {
 		for (int i = dimensions, j = 0; i < totalDimensions; i++, j++) {
@@ -543,6 +541,7 @@
 		} else {
 			reportInvalidType(scope);
 		}
+		RecordDeclaration.checkAndFlagRecordNameErrors(getTypeName(0), this, scope);
 		switch (type.problemId()) {
 			case ProblemReasons.NotFound :
 			case ProblemReasons.NotVisible :
@@ -793,6 +792,11 @@
 public boolean isBaseTypeReference() {
 	return false;
 }
+private char[] getTypeName(int index) {
+	char[][] typeName = this.getTypeName();
+	return typeName != null && typeName.length > index ? typeName[index] :
+		CharOperation.NO_CHAR;
+}
 /**
  * Checks to see if the declaration uses 'var' as type name 
  * @param scope Relevant scope, for error reporting
@@ -803,7 +807,6 @@
 	if (compilerOptions != null && compilerOptions.sourceLevel < ClassFileConstants.JDK10) {
 		return false;
 	}
-	char[][] typeName = this.getTypeName();
-	return typeName.length == 1 && CharOperation.equals(typeName[0], TypeConstants.VAR);
+	return CharOperation.equals(getTypeName(0), TypeConstants.VAR);
 }
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java
index b1e8752..2c9904b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -33,24 +33,30 @@
 		this.bits |= operator << OperatorSHIFT; // encode operator
 	}
 
-@Override
-public FlowInfo analyseCode(
-		BlockScope currentScope,
-		FlowContext flowContext,
-		FlowInfo flowInfo) {
-	if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
-		flowContext.tagBits ^= FlowContext.INSIDE_NEGATION;
-		flowInfo = this.expression.
-			analyseCode(currentScope, flowContext, flowInfo).
-			asNegatedCondition();
-		flowContext.tagBits ^= FlowContext.INSIDE_NEGATION;
-	} else {
-		flowInfo = this.expression.
-			analyseCode(currentScope, flowContext, flowInfo);
+	@Override
+	public FlowInfo analyseCode(
+			BlockScope currentScope,
+			FlowContext flowContext,
+			FlowInfo flowInfo) {
+		if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) {
+			flowContext.tagBits ^= FlowContext.INSIDE_NEGATION;
+			flowInfo = this.expression.
+				analyseCode(currentScope, flowContext, flowInfo).
+				asNegatedCondition();
+			flowContext.tagBits ^= FlowContext.INSIDE_NEGATION;
+		} else {
+			flowInfo = this.expression.
+				analyseCode(currentScope, flowContext, flowInfo);
+		}
+		this.expression.checkNPE(currentScope, flowContext, flowInfo);
+		return flowInfo;
 	}
-	this.expression.checkNPE(currentScope, flowContext, flowInfo);
-	return flowInfo;
-}
+
+	@Override
+	protected void updateFlowOnBooleanResult(FlowInfo flowInfo, boolean result) {
+		if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT)
+			this.expression.updateFlowOnBooleanResult(flowInfo, !result);
+	}
 
 	@Override
 	public Constant optimizedBooleanConstant() {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnionTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnionTypeReference.java
index 49e08f0..cb9b2e8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnionTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnionTypeReference.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -49,7 +49,7 @@
 
 	@Override
 	public TypeBinding resolveType(BlockScope scope, boolean checkBounds, int location) {
-		// return the lub (least upper bound of all type binding) 
+		// return the lub (least upper bound of all type binding)
 		int length = this.typeReferences.length;
 		TypeBinding[] allExceptionTypes = new TypeBinding[length];
 		boolean hasError = false;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnlikelyArgumentCheck.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnlikelyArgumentCheck.java
index f8ba8be..7eebf74 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnlikelyArgumentCheck.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/UnlikelyArgumentCheck.java
@@ -133,7 +133,7 @@
 						ReferenceBinding argumentCollectionType = argumentType
 								.findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilCollection, false);
 						if (collectionType != null && argumentCollectionType != null
-								&& argumentCollectionType.isParameterizedTypeWithActualArguments() 
+								&& argumentCollectionType.isParameterizedTypeWithActualArguments()
 								&& collectionType.isParameterizedTypeWithActualArguments()) {
 							return new UnlikelyArgumentCheck(suspect,
 									((ParameterizedTypeBinding) argumentCollectionType).typeArguments()[0],
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
index 06bdcde..3db9b23 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -10,7 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     Stephan Herrmann - Contributions for 
+ *     Stephan Herrmann - Contributions for
  *     							bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE
  *     							bug 349326 - [1.7] new warning for missing try-with-resources
  *								bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null"
@@ -63,7 +63,7 @@
 		this.preCondInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo);
 		LoopingFlowContext condLoopContext;
 		FlowInfo condInfo =	flowInfo.nullInfoLessUnconditionalCopy();
-		
+
 		// we need to collect the contribution to nulls of the coming paths through the
 		// loop, be they falling through normally or branched to break, continue labels
 		// or catch blocks
@@ -123,6 +123,7 @@
 					condInfo.initsWhenTrue());
 
 			if (this.action.complainIfUnreachable(actionInfo, currentScope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) {
+				this.condition.updateFlowOnBooleanResult(actionInfo, true);
 				actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo);
 			}
 
@@ -175,6 +176,7 @@
 				isConditionOptimizedFalse,
 				!isConditionTrue /*while(true); unreachable(); */);
 		this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
+		this.condition.updateFlowOnBooleanResult(mergedInfo, false);
 		return mergedInfo;
 	}
 
@@ -190,6 +192,9 @@
 		if ((this.bits & IsReachable) == 0) {
 			return;
 		}
+		if (this.condition != null && this.condition.containsPatternVariable()) {
+			this.condition.initializePatternVariables(currentScope, codeStream);
+		}
 		int pc = codeStream.position;
 		Constant cst = this.condition.optimizedBooleanConstant();
 		boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;
@@ -270,7 +275,6 @@
 
 	@Override
 	public void resolve(BlockScope scope) {
-
 		TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN);
 		this.condition.computeConversion(scope, type, type);
 		if (this.action != null)
@@ -310,7 +314,7 @@
 		boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true;
 		return (isConditionTrue || isConditionOptimizedTrue) && (this.action == null || !this.action.breaksOut(null));
 	}
-	
+
 	@Override
 	public boolean completesByContinue() {
 		return this.action.continuesAtOuterLabel();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Wildcard.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Wildcard.java
index 42fd68e..15caa6a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Wildcard.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Wildcard.java
@@ -79,11 +79,11 @@
 		}
 		this.resolvedType = scope.environment().createWildcard(genericType, rank, boundType, null /*no extra bound*/, this.kind);
 		resolveAnnotations(scope, 0); // no defaultNullness for wildcards
-		
+
 		if(scope.environment().usesNullTypeAnnotations()) {
 			((WildcardBinding)this.resolvedType).evaluateNullAnnotations(scope, this);
 		}
-		
+
 		return this.resolvedType;
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java
index 3479ca6..87b8c86 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java
@@ -17,16 +17,21 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
 import org.eclipse.jdt.internal.compiler.flow.*;
+import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.*;
 
 public class YieldStatement extends BranchStatement {
 
 	public Expression expression;
 	public SwitchExpression switchExpression;
+	public TryStatement tryStatement;
 	/**
 	 * @noreference This field is not intended to be referenced by clients.
 	 */
 	public boolean isImplicit;
+	static final char[] SECRET_YIELD_RESULT_VALUE_NAME = " secretYieldValue".toCharArray(); //$NON-NLS-1$
+	private LocalVariableBinding secretYieldResultValue = null;
+	public BlockScope scope;
 
 public YieldStatement(Expression exp, int sourceStart, int sourceEnd) {
 	super(null, sourceStart, sourceEnd);
@@ -41,7 +46,7 @@
 
 
 	// lookup the null label, this should answer the returnContext - for implicit yields, the nesting
-	// doesn't occur since it immediately follow '->' and hence identical to default break - ie the 
+	// doesn't occur since it immediately follow '->' and hence identical to default break - ie the
 	// immediate breakable context is guaranteed to be the one intended;
 	// while explicit yield should move up the parent to the switch expression.
 	FlowContext targetContext = this.isImplicit ? flowContext.getTargetContextForDefaultBreak() :
@@ -80,8 +85,7 @@
 		if (traversedContext instanceof InsideSubRoutineFlowContext) {
 			ASTNode node = traversedContext.associatedNode;
 			if (node instanceof TryStatement) {
-				TryStatement tryStatement = (TryStatement) node;
-				flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits
+				flowInfo.addInitializationsFrom(((TryStatement) node).subRoutineInits); // collect inits
 			}
 		} else if (traversedContext == targetContext) {
 			// only record break info once accumulated through subroutines, and only against target context
@@ -97,63 +101,104 @@
 	return FlowInfo.DEAD_END;
 }
 @Override
-protected void generateExpressionResultCode(BlockScope currentScope, CodeStream codeStream) {
-	this.expression.generateCode(currentScope, codeStream, this.switchExpression != null);
+protected void setSubroutineSwitchExpression(SubRoutineStatement sub) {
+	sub.setSwitchExpression(this.switchExpression);
+}
+protected void addSecretYieldResultValue(BlockScope scope1) {
+	SwitchExpression se = this.switchExpression;
+	if (se == null || !se.containsTry)
+		return;
+	LocalVariableBinding local = new LocalVariableBinding(
+			YieldStatement.SECRET_YIELD_RESULT_VALUE_NAME,
+			se.resolvedType,
+			ClassFileConstants.AccDefault,
+			false);
+	local.setConstant(Constant.NotAConstant);
+	local.useFlag = LocalVariableBinding.USED;
+	local.declaration = new LocalDeclaration(YieldStatement.SECRET_YIELD_RESULT_VALUE_NAME, 0, 0);
+	assert se.yieldResolvedPosition >= 0;
+	local.resolvedPosition = se.yieldResolvedPosition;
+	assert local.resolvedPosition < this.scope.maxOffset;
+	this.scope.addLocalVariable(local);
+	this.secretYieldResultValue = local;
+}
+
+@Override
+protected void restartExceptionLabels(CodeStream codeStream) {
+	SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream);
 }
 @Override
-protected void adjustStackSize(BlockScope currentScope, CodeStream codeStream) {
-	if (this.label == null && this.expression != null && this.switchExpression != null) {
-		TypeBinding postConversionType = this.expression.postConversionType(currentScope);
-		switch(postConversionType.id) {
-			case TypeIds.T_long :
-			case TypeIds.T_double :
-				codeStream.decrStackSize(2);
-				break;
-			case TypeIds.T_void :
-				break;
-			default :
-				codeStream.decrStackSize(1);
-				break;
+protected void generateExpressionResultCode(BlockScope currentScope, CodeStream codeStream) {
+	SwitchExpression se = this.switchExpression;
+	if (se != null && se.containsTry && se.resolvedType != null ) {
+		addSecretYieldResultValue(this.scope);
+		assert this.secretYieldResultValue != null;
+		codeStream.record(this.secretYieldResultValue);
+		SingleNameReference lhs = new SingleNameReference(this.secretYieldResultValue.name, 0);
+		lhs.binding = this.secretYieldResultValue;
+		lhs.bits &= ~ASTNode.RestrictiveFlagMASK;  // clear bits
+		lhs.bits |= Binding.LOCAL;
+		lhs.bits |= ASTNode.IsSecretYieldValueUsage;
+		((LocalVariableBinding) lhs.binding).markReferenced(); // TODO : Can be skipped?
+		Assignment assignment = new Assignment(lhs, this.expression, 0);
+		assignment.generateCode(this.scope, codeStream);
+		int l = this.subroutines == null ? 0 : this.subroutines.length;
+		boolean foundFinally = false;
+		if (l > 0) {
+			for (int i = 0; i < l; ++i) {
+				SubRoutineStatement srs = this.subroutines[i];
+				srs.exitAnyExceptionHandler();
+				srs.exitDeclaredExceptionHandlers(codeStream);
+				if (srs instanceof TryStatement) {
+					TryStatement ts = (TryStatement) srs;
+					if (ts.finallyBlock != null) {
+						foundFinally = true;
+					}
+				}
+			}
 		}
+		if (!foundFinally) {
+			 // no finally - TODO: Check for SynSta?
+			se.loadStoredTypesAndKeep(codeStream);
+			codeStream.load(this.secretYieldResultValue);
+		}
+		codeStream.removeVariable(this.secretYieldResultValue);
+	} else {
+		this.expression.generateCode(this.scope, codeStream, se != null);
 	}
 }
+private boolean isInsideTry() {
+	return this.switchExpression != null && this.switchExpression.containsTry;
+}
 @Override
-public void resolve(BlockScope scope) {
-	// METHOD IN WORKS - INCOMPLETE
-	super.resolve(scope);
+public void resolve(BlockScope skope) {
+	this.scope = isInsideTry() ? new BlockScope(skope) : skope;
+	super.resolve(this.scope);
 	if (this.expression == null) {
-		//currentScope.problemReporter().switchExpressionYieldMissingExpression(this);
 		return;
-		
+
 	}
 	if (this.switchExpression != null || this.isImplicit) {
 		if (this.switchExpression == null && this.isImplicit && !this.expression.statementExpression()) {
-			if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK12 && scope.compilerOptions().enablePreviewFeatures) {
+			if (this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) {
 				/* JLS 13 14.11.2
 				Switch labeled rules in switch statements differ from those in switch expressions (15.28).
 				In switch statements they must be switch labeled statement expressions, ... */
-				scope.problemReporter().invalidExpressionAsStatement(this.expression);
+				this.scope.problemReporter().invalidExpressionAsStatement(this.expression);
 				return;
 			}
 		}
 	} else {
-		if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK13) {
-			if (scope.compilerOptions().enablePreviewFeatures) {
-				scope.problemReporter().switchExpressionsYieldOutsideSwitchExpression(this);
-			} else {
-				scope.problemReporter().switchExpressionsYieldIllegalStatement(this);
-			}
+		if (this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) {
+			this.scope.problemReporter().switchExpressionsYieldOutsideSwitchExpression(this);
 		}
 	}
-	this.expression.resolveType(scope);
-//	if  (this.expression != null) {
-//		this.expression.resolveType(scope);
-//	}
+	this.expression.resolveType(this.scope);
 }
 
 @Override
-public TypeBinding resolveExpressionType(BlockScope scope) {
-	return this.expression != null ? this.expression.resolveType(scope) : null;
+public TypeBinding resolveExpressionType(BlockScope scope1) {
+	return this.expression != null ? this.expression.resolveType(scope1) : null;
 }
 
 @Override
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java
index dde2308..9cdfe85 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -11,7 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Jesper S Moller - Contributions for
- *							Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335             
+ *							Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335
  *							Bug 406982 - [1.8][compiler] Generation of MethodParameters Attribute in classfile
  *     Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
  *                          Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas
@@ -58,7 +58,7 @@
 	int ACC_TRANSITIVE 		= 0x0020;
 	int ACC_STATIC_PHASE	= 0x0040;
 	int ACC_SYNTHETIC 		= 0x1000;
-	
+
 	/**
 	 * Other VM flags.
 	 */
@@ -130,9 +130,10 @@
 	int MAJOR_VERSION_11 = 55;
 	int MAJOR_VERSION_12 = 56;
 	int MAJOR_VERSION_13 = 57;
+	int MAJOR_VERSION_14 = 58;
 
 	int MAJOR_VERSION_0 = 44;
-	int MAJOR_LATEST_VERSION = MAJOR_VERSION_13;
+	int MAJOR_LATEST_VERSION = MAJOR_VERSION_14;
 
 	int MINOR_VERSION_0 = 0;
 	int MINOR_VERSION_1 = 1;
@@ -156,6 +157,7 @@
 	long JDK11 = ((long)ClassFileConstants.MAJOR_VERSION_11 << 16) + ClassFileConstants.MINOR_VERSION_0;
 	long JDK12 = ((long)ClassFileConstants.MAJOR_VERSION_12 << 16) + ClassFileConstants.MINOR_VERSION_0;
 	long JDK13 = ((long)ClassFileConstants.MAJOR_VERSION_13 << 16) + ClassFileConstants.MINOR_VERSION_0;
+	long JDK14 = ((long)ClassFileConstants.MAJOR_VERSION_14 << 16) + ClassFileConstants.MINOR_VERSION_0;
 
 	public static long getLatestJDKLevel() {
 		return ((long)ClassFileConstants.MAJOR_LATEST_VERSION << 16) + ClassFileConstants.MINOR_VERSION_0;
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 0bec013..3bd74d7 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
@@ -41,8 +41,10 @@
 import org.eclipse.jdt.internal.compiler.env.ITypeAnnotationWalker;
 import org.eclipse.jdt.internal.compiler.impl.Constant;
 import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus;
+import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
 import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
 import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
 import org.eclipse.jdt.internal.compiler.util.JRTUtil;
 import org.eclipse.jdt.internal.compiler.util.Util;
@@ -81,6 +83,9 @@
 	private char[] nestHost;
 	private int nestMembersCount;
 	private char[][] nestMembers;
+	private boolean isRecord;
+	private int recordComponentsCount;
+	private ComponentInfo[] recordComponents;
 
 private static String printTypeModifiers(int modifiers) {
 	java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
@@ -298,6 +303,9 @@
 		// field this.superclassName. null is fine.
 		if (superclassNameIndex != 0) {
 			this.superclassName = getConstantClassNameAt(superclassNameIndex);
+			if (CharOperation.equals(this.superclassName, TypeConstants.CharArray_JAVA_LANG_RECORD_SLASH)) {
+				this.accessFlags |= ExtraCompilerModifiers.AccRecord;
+			}
 		}
 
 		// Read the interfaces, use exception handlers to catch bad format
@@ -418,6 +426,8 @@
 						decodeTypeAnnotations(readOffset, true);
 					} else if (CharOperation.equals(attributeName, AttributeNamesConstants.RuntimeInvisibleTypeAnnotationsName)) {
 						decodeTypeAnnotations(readOffset, false);
+					} 	else if (CharOperation.equals(attributeName, AttributeNamesConstants.RecordClass)) {
+						decodeRecords(readOffset, attributeName);
 					}
 					break;
 				case 'M' :
@@ -480,6 +490,23 @@
 	}
 }
 
+private void decodeRecords(int readOffset, char[] attributeName) {
+	if (CharOperation.equals(attributeName, AttributeNamesConstants.RecordClass)) {
+		this.isRecord = true;
+		int offset = readOffset + 6;
+		this.recordComponentsCount = u2At(offset);
+		if (this.recordComponentsCount != 0) {
+			offset += 2;
+			this.recordComponents = new ComponentInfo[this.recordComponentsCount];
+			for (int j = 0; j < this.recordComponentsCount; j++) {
+				ComponentInfo component = ComponentInfo.createComponent(this.reference, this.constantPoolOffsets, offset, this.version);
+				this.recordComponents[j] = component;
+				offset += component.sizeInBytes();
+			}
+		}
+	}
+}
+
 public char[] getNestHost() {
 	return this.nestHost;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFormatException.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFormatException.java
index 6371a12..8286935 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFormatException.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFormatException.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -45,6 +45,7 @@
 	public static final int ErrIncorrectInterfaceMethods = 26;
 	public static final int ErrInvalidMethodName = 27;
 	public static final int ErrInvalidMethodSignature = 28;
+	public static final int ErrBadComponentInfo = 29;
 
 	private static final long serialVersionUID = 6667458511042774540L; // backward compatible
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ComponentInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ComponentInfo.java
new file mode 100644
index 0000000..f357ad2
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ComponentInfo.java
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * Copyright (c) 2019 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.classfmt;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants;
+import org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation;
+import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
+import org.eclipse.jdt.internal.compiler.env.IComponent;
+import org.eclipse.jdt.internal.compiler.lookup.TagBits;
+
+/*
+ * TODO: Refactor common code from FieldInfo since this mirrors field info mostly except for
+ * the accessflags and the attribute_length size. However, since this is still in preview stage,
+ * it is too early to disturb the field_info code. To be done if this gets standardized.
+ */
+@SuppressWarnings("rawtypes")
+public class ComponentInfo extends ClassFileStruct implements IComponent, Comparable {
+	protected int attributeBytes;
+	protected char[] descriptor;
+	protected char[] name;
+	protected char[] signature;
+	protected int signatureUtf8Offset;
+	protected long tagBits;
+	protected long version;
+
+public static ComponentInfo createComponent(byte classFileBytes[], int offsets[], int offset, long version) {
+	ComponentInfo componentInfo = new ComponentInfo(classFileBytes, offsets, offset, version);
+
+	int attributesCount = componentInfo.u2At(4);
+	int readOffset = 6;
+	AnnotationInfo[] annotations = null;
+	TypeAnnotationInfo[] typeAnnotations = null;
+	for (int i = 0; i < attributesCount; i++) {
+		// check the name of each attribute
+		int utf8Offset = componentInfo.constantPoolOffsets[componentInfo.u2At(readOffset)] - componentInfo.structOffset;
+		char[] attributeName = componentInfo.utf8At(utf8Offset + 3, componentInfo.u2At(utf8Offset + 1));
+		if (attributeName.length > 0) {
+			switch(attributeName[0]) {
+				case 'S' :
+					if (CharOperation.equals(AttributeNamesConstants.SignatureName, attributeName))
+						componentInfo.signatureUtf8Offset = componentInfo.constantPoolOffsets[componentInfo.u2At(readOffset + 6)] - componentInfo.structOffset;
+					break;
+				case 'R' :
+					AnnotationInfo[] decodedAnnotations = null;
+					TypeAnnotationInfo[] decodedTypeAnnotations = null;
+					if (CharOperation.equals(attributeName, AttributeNamesConstants.RuntimeVisibleAnnotationsName)) {
+						decodedAnnotations = componentInfo.decodeAnnotations(readOffset, true);
+					} else if (CharOperation.equals(attributeName, AttributeNamesConstants.RuntimeInvisibleAnnotationsName)) {
+						decodedAnnotations = componentInfo.decodeAnnotations(readOffset, false);
+					} else if (CharOperation.equals(attributeName, AttributeNamesConstants.RuntimeVisibleTypeAnnotationsName)) {
+						decodedTypeAnnotations = componentInfo.decodeTypeAnnotations(readOffset, true);
+					} else if (CharOperation.equals(attributeName, AttributeNamesConstants.RuntimeInvisibleTypeAnnotationsName)) {
+						decodedTypeAnnotations = componentInfo.decodeTypeAnnotations(readOffset, false);
+					}
+					if (decodedAnnotations != null) {
+						if (annotations == null) {
+							annotations = decodedAnnotations;
+						} else {
+							int length = annotations.length;
+							AnnotationInfo[] combined = new AnnotationInfo[length + decodedAnnotations.length];
+							System.arraycopy(annotations, 0, combined, 0, length);
+							System.arraycopy(decodedAnnotations, 0, combined, length, decodedAnnotations.length);
+							annotations = combined;
+						}
+					} else if (decodedTypeAnnotations != null) {
+						if (typeAnnotations == null) {
+							typeAnnotations = decodedTypeAnnotations;
+						} else {
+							int length = typeAnnotations.length;
+							TypeAnnotationInfo[] combined = new TypeAnnotationInfo[length + decodedTypeAnnotations.length];
+							System.arraycopy(typeAnnotations, 0, combined, 0, length);
+							System.arraycopy(decodedTypeAnnotations, 0, combined, length, decodedTypeAnnotations.length);
+							typeAnnotations = combined;
+						}
+					}
+			}
+		}
+		readOffset += (6 + componentInfo.u4At(readOffset + 2));
+	}
+	componentInfo.attributeBytes = readOffset;
+
+	if (typeAnnotations != null)
+		return new ComponentInfoWithTypeAnnotation(componentInfo, annotations, typeAnnotations);
+	if (annotations != null)
+		return new ComponentInfoWithAnnotation(componentInfo, annotations);
+	return componentInfo;
+}
+
+/**
+ * @param classFileBytes byte[]
+ * @param offsets int[]
+ * @param offset int
+ * @param version class file version
+ */
+protected ComponentInfo (byte classFileBytes[], int offsets[], int offset, long version) {
+	super(classFileBytes, offsets, offset);
+	this.signatureUtf8Offset = -1;
+	this.version = version;
+}
+private AnnotationInfo[] decodeAnnotations(int offset, boolean runtimeVisible) {
+	int numberOfAnnotations = u2At(offset + 6);
+	if (numberOfAnnotations > 0) {
+		int readOffset = offset + 8;
+		AnnotationInfo[] newInfos = null;
+		int newInfoCount = 0;
+		for (int i = 0; i < numberOfAnnotations; i++) {
+			// With the last parameter being 'false', the data structure will not be flushed out
+			AnnotationInfo newInfo = new AnnotationInfo(this.reference, this.constantPoolOffsets,
+				readOffset + this.structOffset, runtimeVisible, false);
+			readOffset += newInfo.readOffset;
+			long standardTagBits = newInfo.standardAnnotationTagBits;
+			if (standardTagBits != 0) {
+				this.tagBits |= standardTagBits;
+				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)
+				System.arraycopy(newInfos, 0, newInfos = new AnnotationInfo[newInfoCount], 0, newInfoCount);
+			return newInfos;
+		}
+	}
+	return null; // nothing to record
+}
+
+TypeAnnotationInfo[] decodeTypeAnnotations(int offset, boolean runtimeVisible) {
+	int numberOfAnnotations = u2At(offset + 6);
+	if (numberOfAnnotations > 0) {
+		int readOffset = offset + 8;
+		TypeAnnotationInfo[] typeAnnos = new TypeAnnotationInfo[numberOfAnnotations];
+		for (int i = 0; i < numberOfAnnotations; i++) {
+			TypeAnnotationInfo newInfo = new TypeAnnotationInfo(this.reference, this.constantPoolOffsets, readOffset + this.structOffset, runtimeVisible, false);
+			readOffset += newInfo.readOffset;
+			typeAnnos[i] = newInfo;
+		}
+		return typeAnnos;
+	}
+	return null;
+}
+
+@Override
+public int compareTo(Object o) {
+	return new String(getName()).compareTo(new String(((ComponentInfo) o).getName()));
+}
+@Override
+public boolean equals(Object o) {
+	if (!(o instanceof ComponentInfo)) {
+		return false;
+	}
+	return CharOperation.equals(getName(), ((ComponentInfo) o).getName());
+}
+@Override
+public int hashCode() {
+	return CharOperation.hashCode(getName());
+}
+@Override
+public char[] getGenericSignature() {
+	if (this.signatureUtf8Offset != -1) {
+		if (this.signature == null) {
+			// decode the signature
+			this.signature = utf8At(this.signatureUtf8Offset + 3, u2At(this.signatureUtf8Offset + 1));
+		}
+		return this.signature;
+	}
+	return null;
+}
+/**
+ * Answer the name of the component.
+ * @return char[]
+ */
+@Override
+public char[] getName() {
+	if (this.name == null) {
+		// read the name
+		int utf8Offset = this.constantPoolOffsets[u2At(0)] - this.structOffset;
+		this.name = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+	}
+	return this.name;
+}
+@Override
+public long getTagBits() {
+	return this.tagBits;
+}
+/**
+ * Answer the resolved name of the receiver's type in the
+ * class file format as specified in section 4.3.2 of the Java 2 VM spec.
+ *
+ * For example:
+ *   - java.lang.String is Ljava/lang/String;
+ *   - an int is I
+ *   - a 2 dimensional array of strings is [[Ljava/lang/String;
+ *   - an array of floats is [F
+ * @return char[]
+ */
+@Override
+public char[] getTypeName() {
+	if (this.descriptor == null) {
+		// read the signature
+		int utf8Offset = this.constantPoolOffsets[u2At(2)] - this.structOffset;
+		this.descriptor = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
+	}
+	return this.descriptor;
+}
+/**
+ * @return the annotations or null if there is none.
+ */
+@Override
+public IBinaryAnnotation[] getAnnotations() {
+	return null;
+}
+
+@Override
+public IBinaryTypeAnnotation[] getTypeAnnotations() {
+	return null;
+}
+/**
+ * This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos
+ * will be therefore fully initialized and we can get rid of the bytes.
+ */
+protected void initialize() {
+	getName();
+	getTypeName();
+	getGenericSignature();
+	reset();
+}
+/**
+ * Answer the size of the receiver in bytes.
+ *
+ * @return int
+ */
+public int sizeInBytes() {
+	return this.attributeBytes;
+}
+public void throwFormatException() throws ClassFormatException {
+	throw new ClassFormatException(ClassFormatException.ErrBadComponentInfo);
+}
+@Override
+public String toString() {
+	StringBuffer buffer = new StringBuffer(getClass().getName());
+	toStringContent(buffer);
+	return buffer.toString();
+}
+protected void toStringContent(StringBuffer buffer) {
+	buffer
+		.append('{')
+		.append(getTypeName())
+		.append(' ')
+		.append(getName())
+		.append(' ')
+		.append('}')
+		.toString();
+}
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ComponentInfoWithAnnotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ComponentInfoWithAnnotation.java
new file mode 100644
index 0000000..29414f4
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ComponentInfoWithAnnotation.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2019 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
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.classfmt;
+
+public class ComponentInfoWithAnnotation extends ComponentInfo {
+	private AnnotationInfo[] annotations;
+
+	ComponentInfoWithAnnotation(ComponentInfo info, AnnotationInfo[] annos) {
+	super(info.reference, info.constantPoolOffsets, info.structOffset, info.version);
+	this.attributeBytes = info.attributeBytes;
+	this.constantPoolOffsets = info.constantPoolOffsets;
+	this.descriptor = info.descriptor;
+	this.name = info.name;
+	this.signature = info.signature;
+	this.signatureUtf8Offset = info.signatureUtf8Offset;
+	this.tagBits = info.tagBits;
+	this.annotations = annos;
+}
+@Override
+public org.eclipse.jdt.internal.compiler.env.IBinaryAnnotation[] getAnnotations() {
+	return this.annotations;
+}
+@Override
+protected void initialize() {
+	if (this.annotations != null)
+		for (int i = 0, max = this.annotations.length; i < max; i++)
+			this.annotations[i].initialize();
+	super.initialize();
+}
+@Override
+protected void reset() {
+	if (this.annotations != null)
+		for (int i = 0, max = this.annotations.length; i < max; i++)
+			this.annotations[i].reset();
+	super.reset();
+}
+@Override
+public String toString() {
+	StringBuffer buffer = new StringBuffer(getClass().getName());
+	if (this.annotations != null) {
+		buffer.append('\n');
+		for (int i = 0; i < this.annotations.length; i++) {
+			buffer.append(this.annotations[i]);
+			buffer.append('\n');
+		}
+	}
+	toStringContent(buffer);
+	return buffer.toString();
+}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ComponentInfoWithTypeAnnotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ComponentInfoWithTypeAnnotation.java
new file mode 100644
index 0000000..73441a8
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ComponentInfoWithTypeAnnotation.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2019 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
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.classfmt;
+
+import org.eclipse.jdt.internal.compiler.env.IBinaryTypeAnnotation;
+
+public final class ComponentInfoWithTypeAnnotation extends ComponentInfoWithAnnotation {
+	private TypeAnnotationInfo[] typeAnnotations;
+
+ComponentInfoWithTypeAnnotation(ComponentInfo info, AnnotationInfo[] annos, TypeAnnotationInfo[] typeAnnos) {
+	super(info, annos);
+	this.typeAnnotations = typeAnnos;
+}
+@Override
+public IBinaryTypeAnnotation[] getTypeAnnotations() {
+	return this.typeAnnotations;
+}
+@Override
+protected void initialize() {
+	for (int i = 0, max = this.typeAnnotations.length; i < max; i++)
+		this.typeAnnotations[i].initialize();
+	super.initialize();
+}
+@Override
+protected void reset() {
+	if (this.typeAnnotations != null)
+		for (int i = 0, max = this.typeAnnotations.length; i < max; i++)
+			this.typeAnnotations[i].reset();
+	super.reset();
+}
+@Override
+public String toString() {
+	StringBuffer buffer = new StringBuffer(getClass().getName());
+	if (this.typeAnnotations != null) {
+		buffer.append('\n');
+		buffer.append("type annotations:"); //$NON-NLS-1$
+		for (int i = 0; i < this.typeAnnotations.length; i++) {
+			buffer.append(this.typeAnnotations[i]);
+			buffer.append('\n');
+		}
+	}
+	toStringContent(buffer);
+	return buffer.toString();
+}
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationDecorator.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationDecorator.java
index 0846cf1..afcef9d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationDecorator.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationDecorator.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     Stefan Xenos <sxenos@gmail.com> (Google) - initial API and implementation
  *******************************************************************************/
@@ -17,6 +17,7 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
@@ -225,7 +226,9 @@
 		} else {
 			ZipEntry entry = zipFile.getEntry(qualifiedBinaryFileName);
 			if (entry != null) {
-				return new ExternalAnnotationProvider(zipFile.getInputStream(entry), qualifiedBinaryTypeName);
+				try(InputStream is = zipFile.getInputStream(entry)) {
+					return new ExternalAnnotationProvider(is, qualifiedBinaryTypeName);
+				}
 			}
 		}
 		return null;
@@ -236,7 +239,7 @@
 	 * annotations is associated. This provider is constructed using the given basePath, which is either a directory
 	 * holding .eea text files, or a zip file of entries of the same format. If no such provider could be constructed,
 	 * then the original binary type is returned unchanged.
-	 * 
+	 *
 	 * @param toDecorate
 	 *            the binary type to wrap, if needed
 	 * @param basePath
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java
index a40a380..8dbd7d9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java
@@ -59,7 +59,7 @@
 	Map<String,String> supertypeAnnotationSources;
 	private Map<String,String> methodAnnotationSources;
 	private Map<String,String> fieldAnnotationSources;
-	
+
 	/**
 	 * Create and initialize.
 	 * @param input open input stream to read the annotations from, will be closed by the constructor.
@@ -86,7 +86,7 @@
 					this.typeParametersAnnotationSource = line.substring(TYPE_PARAMETER_PREFIX.length());
 					if ((line = reader.readLine()) == null)
 						return;
-				} 
+				}
 			}
 			String pendingLine;
 			do {
@@ -171,7 +171,7 @@
 		int tail = line.indexOf(' ');
 		if (tail == -1)
 			tail = line.indexOf('\t');
-		if (tail != -1) 
+		if (tail != -1)
 			return line.substring(0, tail);
 		return line;
 	}
@@ -257,7 +257,7 @@
 		public ITypeAnnotationWalker toTypeParameter(boolean isClassTypeParameter, int rank) {
 			String source = ExternalAnnotationProvider.this.typeParametersAnnotationSource;
 			if (source != null) {
-				if (this.typeParametersWalker == null) 
+				if (this.typeParametersWalker == null)
 					this.typeParametersWalker = new TypeParametersAnnotationWalker(source.toCharArray(), 0, 0, null, this.environment);
 				return this.typeParametersWalker.toTypeParameter(isClassTypeParameter, rank);
 			}
@@ -305,7 +305,7 @@
 	}
 
 	abstract class BasicAnnotationWalker implements ITypeAnnotationWalker {
-		
+
 		char[] source;
 		SignatureWrapper wrapper;
 		int pos;
@@ -319,7 +319,7 @@
 			this.environment = environment;
 			initAnnotations(environment);
 		}
-		
+
 		SignatureWrapper wrapperWithStart(int start) {
 			if (this.wrapper == null)
 				this.wrapper = new SignatureWrapper(this.source);
@@ -362,10 +362,10 @@
 			}
 			int next = this.prevTypeArgStart;
 			switch (this.source[next]) {
-				case '*': 
+				case '*':
 					next = skipNullAnnotation(next+1);
 					break;
-				case '-': 
+				case '-':
 				case '+':
 					next = skipNullAnnotation(next+1);
 					//$FALL-THROUGH$
@@ -380,13 +380,13 @@
 		@Override
 		public ITypeAnnotationWalker toWildcardBound() {
 			switch (this.source[this.pos]) {
-				case '-': 
+				case '-':
 				case '+':
 					int newPos = skipNullAnnotation(this.pos+1);
 					return new MethodAnnotationWalker(this.source, newPos, this.environment);
 				default: // includes unbounded '*'
 					return ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER;
-			}			
+			}
 		}
 
 		@Override
@@ -419,7 +419,7 @@
 							case NONNULL:
 								return new IBinaryAnnotation[]{ ExternalAnnotationProvider.this.NONNULL_ANNOTATION };
 						}
-				}				
+				}
 			}
 			return NO_ANNOTATIONS;
 		}
@@ -431,7 +431,7 @@
 				case NULLABLE:
 					return cur+1;
 				default:
-					return cur; 
+					return cur;
 			}
 		}
 	}
@@ -501,7 +501,7 @@
 				System.arraycopy(rankStarts, 0, this.rankStarts = new int[curRank], 0, curRank);
 			}
 		}
-		
+
 		@Override
 		public ITypeAnnotationWalker toTypeParameter(boolean isClassTypeParameter, int rank) {
 			if (rank == this.currentRank)
@@ -564,7 +564,7 @@
 						return new IBinaryAnnotation[]{ ExternalAnnotationProvider.this.NULLABLE_ANNOTATION };
 					case NONNULL:
 						return new IBinaryAnnotation[]{ ExternalAnnotationProvider.this.NONNULL_ANNOTATION };
-				}				
+				}
 			}
 			return super.getAnnotationsAtCursor(currentTypeId, mayApplyArrayContentsDefaultNullness);
 		}
@@ -611,7 +611,7 @@
 		MethodAnnotationWalker(char[] source, int pos, LookupEnvironment environment) {
 			super(source, pos, environment);
 		}
-	
+
 		int typeEnd(int start) {
 			while (this.source[start] == '[') {
 				start++;
@@ -621,7 +621,7 @@
 			int end = wrapper1.skipAngleContents(wrapper1.computeEnd());
 			return end;
 		}
-		
+
 		@Override
 		public ITypeAnnotationWalker toTypeParameter(boolean isClassTypeParameter, int rank) {
 			if (this.source[0] == '<') {
@@ -689,7 +689,7 @@
 			return count;
 		}
 	}
-	
+
 	class FieldAnnotationWalker extends BasicAnnotationWalker {
 		public FieldAnnotationWalker(char[] source, int pos, LookupEnvironment environment) {
 			super(source, pos, environment);
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 46cb846..77cbb64 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
@@ -11,7 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *        Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
- *          Bug 407191 - [1.8] Binary access support for type annotations 
+ *          Bug 407191 - [1.8] Binary access support for type annotations
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.classfmt;
 
@@ -40,7 +40,7 @@
 
 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;
 	AnnotationInfo[] annotations = null;
@@ -93,7 +93,7 @@
 		readOffset += (6 + fieldInfo.u4At(readOffset + 2));
 	}
 	fieldInfo.attributeBytes = readOffset;
-	
+
 	if (typeAnnotations != null)
 		return new FieldInfoWithTypeAnnotation(fieldInfo, annotations, typeAnnotations);
 	if (annotations != null)
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 353edc2..2c4bb07 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
@@ -221,7 +221,7 @@
  * @param classFileBytes byte[]
  * @param offsets int[]
  * @param offset int
- * @param version class file version 
+ * @param version class file version
  */
 protected MethodInfo (byte classFileBytes[], int offsets[], int offset, long version) {
 	super(classFileBytes, offsets, offset);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ModuleInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ModuleInfo.java
index aa091f8..f2807b7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ModuleInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ModuleInfo.java
@@ -280,7 +280,7 @@
 		}
 		@Override
 		public boolean equals(Object o) {
-			if (this == o) 
+			if (this == o)
 				return true;
 			if (!(o instanceof IModule.IModuleReference))
 				return false;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/NonNullDefaultAwareTypeAnnotationWalker.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/NonNullDefaultAwareTypeAnnotationWalker.java
index ad0f050..5cc6128 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/NonNullDefaultAwareTypeAnnotationWalker.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/NonNullDefaultAwareTypeAnnotationWalker.java
@@ -34,12 +34,12 @@
 	private final boolean isEmpty;
 	private final IBinaryAnnotation nonNullAnnotation;
 	private final LookupEnvironment environment;
-	
+
 	private boolean nextIsDefaultLocation;
 	private boolean nextIsTypeBound;
 	private boolean nextArrayContentIsNonNull;
 
-	
+
 	/** Create initial walker with non-empty type annotations. */
 	public NonNullDefaultAwareTypeAnnotationWalker(IBinaryTypeAnnotation[] typeAnnotations,
 						int defaultNullness, LookupEnvironment environment) {
@@ -52,7 +52,7 @@
 		this.isEmpty = false;
 		this.currentArrayContentIsNonNull = false;
 	}
-	
+
 	/** Create an initial walker without 'real' type annotations, but with a nonnull default. */
 	public NonNullDefaultAwareTypeAnnotationWalker(int defaultNullness, LookupEnvironment environment) {
 		this(defaultNullness, getNonNullAnnotation(environment), false, false, environment, false);
@@ -84,7 +84,7 @@
 		this.environment = environment;
 		this.currentArrayContentIsNonNull = this.nextArrayContentIsNonNull = currentArrayContentIsNonNull;
 	}
-	
+
 	private static IBinaryAnnotation getNonNullAnnotation(LookupEnvironment environment) {
 		final char[] nonNullAnnotationName = CharOperation.concat(
 						'L', CharOperation.concatWith(environment.getNonNullAnnotationName(), '/'), ';');
@@ -111,7 +111,7 @@
 				return this;
 			// are we running out of real type annotations?
 			if (newMatches == 0 || this.typeAnnotations == null || this.typeAnnotations.length == 0)
-				return new NonNullDefaultAwareTypeAnnotationWalker(this.defaultNullness, this.nonNullAnnotation, 
+				return new NonNullDefaultAwareTypeAnnotationWalker(this.defaultNullness, this.nonNullAnnotation,
 												this.nextIsDefaultLocation, this.nextIsTypeBound, this.environment, this.nextArrayContentIsNonNull);
 			// proceed as normal, but pass on our specific fields, too:
 			return new NonNullDefaultAwareTypeAnnotationWalker(this.typeAnnotations, newMatches, newPathPtr,
@@ -123,7 +123,7 @@
 			this.nextArrayContentIsNonNull = this.currentArrayContentIsNonNull;
 		}
 	}
-	
+
 	@Override
 	public ITypeAnnotationWalker toSupertype(short index, char[] superTypeSignature) {
 		if (this.isEmpty) return restrict(this.matches, this.pathPtr);
@@ -143,7 +143,7 @@
 		if (this.isEmpty) return restrict(this.matches, this.pathPtr);
 		return super.toField();
 	}
-	
+
 	@Override
 	public ITypeAnnotationWalker toMethodReturn() {
 		// don't set nextIsDefaultLocation, because signature-level nullness is handled by ImplicitNullAnnotationVerifier (triggered per invocation via MessageSend.resolveType() et al)
@@ -225,7 +225,7 @@
 		}
 		return normalAnnotations;
 	}
-	
+
 	@Override
 	public ITypeAnnotationWalker toNextArrayDimension() {
 		boolean hasNNBDForArrayContents = (this.defaultNullness & Binding.DefaultLocationArrayContents) != 0;
@@ -255,12 +255,12 @@
 				} else {
 					if (walker instanceof TypeAnnotationWalker) {
 						TypeAnnotationWalker typeAnnotationWalker = (TypeAnnotationWalker) walker;
-						
+
 						IBinaryAnnotation nonNullAnnotation2;
 						if (walker instanceof NonNullDefaultAwareTypeAnnotationWalker) {
 							NonNullDefaultAwareTypeAnnotationWalker nonNullDefaultAwareTypeAnnotationWalker = (NonNullDefaultAwareTypeAnnotationWalker) walker;
 							if(nonNullDefaultAwareTypeAnnotationWalker.isEmpty) {
-								return new NonNullDefaultAwareTypeAnnotationWalker(defaultNullness, environment);								
+								return new NonNullDefaultAwareTypeAnnotationWalker(defaultNullness, environment);
 							}
 							nonNullAnnotation2 = nonNullDefaultAwareTypeAnnotationWalker.nonNullAnnotation;
 						} else {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationInfo.java
index e0d84a1..ba20fb0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationInfo.java
@@ -22,38 +22,38 @@
 
 /**
  * The TypeAnnotationInfo class does not currently support type annotations within code
- * blocks (those that have a target type of 0x40 and higher) - it is not yet clear that 
+ * blocks (those that have a target type of 0x40 and higher) - it is not yet clear that
  * these need to be accessible.
  */
 public class TypeAnnotationInfo extends ClassFileStruct implements IBinaryTypeAnnotation {
 
 	private AnnotationInfo annotation;
-	
+
 	private int targetType = 0;
-	
+
 	// info is used in different ways:
 	// TargetType 0x00: CLASS_TYPE_PARAMETER: type parameter index
-	// TargetType 0x01: METHOD_TYPE_PARAMETER: type parameter index 
+	// TargetType 0x01: METHOD_TYPE_PARAMETER: type parameter index
 	// TargetType 0x10: CLASS_EXTENDS: supertype index (-1 = superclass, 0..N superinterface)
 	// TargetType 0x11: CLASS_TYPE_PARAMETER_BOUND: type parameter index
 	// TargetType 0x12: METHOD_TYPE_PARAMETER_BOUND: type parameter index
 	// TargetType 0x16: METHOD_FORMAL_PARAMETER: method formal parameter index
 	// TargetType 0x17: THROWS: throws type index
 	private int info;
-	
+
 	// TargetType 0x11: CLASS_TYPE_PARAMETER_BOUND: bound index
 	// TargetType 0x12: METHOD_TYPE_PARAMETER_BOUND: bound index
 	private int info2;
-	
+
 	private int[] typePath; // each pair of ints in the array is a type path entry
-	
+
 	int readOffset = 0;
-	
-	
+
+
 TypeAnnotationInfo(byte[] classFileBytes, int[] contantPoolOffsets, int offset) {
 	super(classFileBytes, contantPoolOffsets, offset);
 }
-	
+
 TypeAnnotationInfo(byte[] classFileBytes, int[] contantPoolOffsets, int offset, boolean runtimeVisible, boolean populate) {
 	this(classFileBytes, contantPoolOffsets, offset);
 	this.readOffset = 0;
@@ -64,30 +64,30 @@
 			this.info = u1At(1); // typeParameterIndex
 			this.readOffset += 2;
 			break;
-			
+
 		case AnnotationTargetTypeConstants.CLASS_EXTENDS:
 			this.info = u2At(1); // supertypeIndex
 			this.readOffset += 3;
 			break;
-			
+
 		case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER_BOUND:
 		case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER_BOUND:
 			this.info = u1At(1); // typeParameterIndex
 			this.info2 = u1At(2); // boundIndex;
 			this.readOffset += 3;
 			break;
-			
+
 		case AnnotationTargetTypeConstants.FIELD:
 		case AnnotationTargetTypeConstants.METHOD_RETURN:
 		case AnnotationTargetTypeConstants.METHOD_RECEIVER:
 			this.readOffset ++;
 			break;
-			
+
 		case AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER :
 			this.info = u1At(1); // methodFormalParameterIndex
 			this.readOffset += 2;
 			break;
-			
+
 		case AnnotationTargetTypeConstants.THROWS :
 			this.info = u2At(1); // throwsTypeIndex
 			this.readOffset += 3;
@@ -204,7 +204,7 @@
 	if (this.targetType != other.targetType) {
 		return false;
 	}
-	
+
 	if (this.info != other.info) {
 		return false;
 	}
@@ -212,11 +212,11 @@
 	if (this.info2 != other.info2) {
 		return false;
 	}
-	
+
 	if (!Arrays.equals(this.typePath, other.typePath)) {
 		return false;
 	}
-	
+
 	return this.annotation.equals(other.annotation);
 }
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java
index 28bfcd8..d5fd769 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/TypeAnnotationWalker.java
@@ -46,7 +46,7 @@
 	}
 
 	// ==== filter by top-level targetType: ====
-	
+
 	@Override
 	public ITypeAnnotationWalker toField() {
 		return toTarget(AnnotationTargetTypeConstants.FIELD);
@@ -92,7 +92,7 @@
 				newMatches &= ~mask;
 			}
 		}
-		return restrict(newMatches, 0);		
+		return restrict(newMatches, 0);
 	}
 
 	@Override
@@ -110,7 +110,7 @@
 				newMatches &= ~mask;
 			}
 		}
-		return restrict(newMatches, 0);	
+		return restrict(newMatches, 0);
 	}
 
 	@Override
@@ -126,10 +126,10 @@
 				newMatches &= ~mask;
 			}
 		}
-		return restrict(newMatches, 0);		
+		return restrict(newMatches, 0);
 	}
-	
-	
+
+
 	/**
 	 * {@inheritDoc}
 	 * <p>(superTypesSignature is ignored in this implementation).</p>
@@ -147,7 +147,7 @@
 				newMatches &= ~mask;
 			}
 		}
-		return restrict(newMatches, 0);		
+		return restrict(newMatches, 0);
 	}
 
 	@Override
@@ -163,7 +163,7 @@
 				newMatches &= ~mask;
 			}
 		}
-		return restrict(newMatches, 0);		
+		return restrict(newMatches, 0);
 	}
 
 	@Override
@@ -179,7 +179,7 @@
 				newMatches &= ~mask;
 			}
 		}
-		return restrict(newMatches, 0);		
+		return restrict(newMatches, 0);
 	}
 
 	// ==== descending into details: ====
@@ -195,13 +195,13 @@
 		for (int i = 0; i < length; i++, mask = mask << 1) {
 			IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
 			int[] path = candidate.getTypePath();
-			if (this.pathPtr >= path.length 
+			if (this.pathPtr >= path.length
 					|| path[this.pathPtr] != AnnotationTargetTypeConstants.TYPE_ARGUMENT
 					|| path[this.pathPtr+1] != rank) {
 				newMatches &= ~mask;
 			}
 		}
-		return restrict(newMatches, this.pathPtr+2);		
+		return restrict(newMatches, this.pathPtr+2);
 	}
 
 	@Override
@@ -214,19 +214,19 @@
 		for (int i = 0; i < length; i++, mask = mask << 1) {
 			IBinaryTypeAnnotation candidate = this.typeAnnotations[i];
 			int[] path = candidate.getTypePath();
-			if (this.pathPtr >= path.length 
+			if (this.pathPtr >= path.length
 					|| path[this.pathPtr] != AnnotationTargetTypeConstants.WILDCARD_BOUND) {
 				newMatches &= ~mask;
 			}
 		}
-		return restrict(newMatches, this.pathPtr+2);		
+		return restrict(newMatches, this.pathPtr+2);
 	}
 
 	@Override
 	public ITypeAnnotationWalker toNextArrayDimension() {
 		return toNextDetail(AnnotationTargetTypeConstants.NEXT_ARRAY_DIMENSION);
 	}
-	
+
 	@Override
 	public ITypeAnnotationWalker toNextNestedType() {
 		return toNextDetail(AnnotationTargetTypeConstants.NEXT_NESTED_TYPE);
@@ -250,9 +250,9 @@
 		}
 		return restrict(newMatches, this.pathPtr+2);
 	}
-	
+
 	// ==== leaves: the actual annotations: ====
-	
+
 	@Override
 	public IBinaryAnnotation[] getAnnotationsAtCursor(int currentTypeId, boolean mayApplyArrayContentsDefaultNullness) {
 		int length = this.typeAnnotations.length;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AttributeNamesConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AttributeNamesConstants.java
index 5426cbc..b069105 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AttributeNamesConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/AttributeNamesConstants.java
@@ -11,7 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Jesper S Moller - Contributions for
- *							Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335             
+ *							Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335
  *							Bug 406973 - [compiler] Parse MethodParameters attribute
  *        Andy Clement - Contributions for
  *                          Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work)
@@ -53,4 +53,6 @@
 	// jep181
 	final char[] NestHost = "NestHost".toCharArray(); //$NON-NLS-1$
 	final char[] NestMembers = "NestMembers".toCharArray(); //$NON-NLS-1$
+	// jep 359 records
+	final char[] RecordClass = "Record".toCharArray(); //$NON-NLS-1$
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
index e08d070..86bc7e5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -35,6 +35,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Stack;
+import java.util.function.Supplier;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ClassFile;
@@ -119,6 +121,9 @@
 	// to handle goto_w
 	public boolean wideMode = false;	
 	
+	public Stack<TypeBinding> switchSaveTypeBindings = new Stack<>();
+	public int lastSwitchCumulativeSyntheticVars = 0;
+
 public CodeStream(ClassFile givenClassFile) {
 	this.targetLevel = givenClassFile.targetJDK;
 	this.generateAttributes = givenClassFile.produceAttributes;
@@ -220,6 +225,7 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aaload;
+	pushTypeBindingArray();
 }
 
 public void aastore() {
@@ -230,6 +236,7 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aastore;
+	popTypeBinding(3);
 }
 
 public void aconst_null() {
@@ -243,6 +250,7 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_aconst_null;
+	pushTypeBinding(TypeBinding.NULL);
 }
 
 public void addDefinitelyAssignedVariables(Scope scope, int initStateIndex) {
@@ -302,6 +310,7 @@
 	if (this.maxLocals <= iArg) {
 		this.maxLocals = iArg + 1;
 	}
+	pushTypeBinding(iArg);
 	if (iArg > 255) { // Widen
 		if (this.classFileOffset + 3 >= this.bCodeStream.length) {
 			resizeByteArray();
@@ -324,6 +333,7 @@
 public void aload_0() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(0);
 	if (this.stackDepth > this.stackMax) {
 		this.stackMax = this.stackDepth;
 	}
@@ -340,6 +350,7 @@
 public void aload_1() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(1);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.maxLocals <= 1) {
@@ -355,6 +366,7 @@
 public void aload_2() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(2);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.maxLocals <= 2) {
@@ -370,6 +382,7 @@
 public void aload_3() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(3);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.maxLocals <= 3) {
@@ -390,11 +403,13 @@
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_anewarray;
 	writeUnsignedShort(this.constantPool.literalIndexForType(typeBinding));
+	pushTypeBinding(1, typeBinding);
 }
 
 public void areturn() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	// the stackDepth should be equal to 0
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
@@ -485,11 +500,13 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_arraylength;
+	pushTypeBinding(1, TypeBinding.INT);
 }
 
 public void astore(int iArg) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= iArg) {
 		this.maxLocals = iArg + 1;
 	}
@@ -514,6 +531,7 @@
 public void astore_0() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals == 0) {
 		this.maxLocals = 1;
 	}
@@ -527,6 +545,7 @@
 public void astore_1() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= 1) {
 		this.maxLocals = 2;
 	}
@@ -540,6 +559,7 @@
 public void astore_2() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= 2) {
 		this.maxLocals = 3;
 	}
@@ -553,6 +573,7 @@
 public void astore_3() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= 3) {
 		this.maxLocals = 4;
 	}
@@ -566,6 +587,7 @@
 public void athrow() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -577,6 +599,7 @@
 public void baload() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBindingArray();
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -587,6 +610,7 @@
 public void bastore() {
 	this.countLabels = 0;
 	this.stackDepth -= 3;
+	popTypeBinding(3);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -597,6 +621,7 @@
 public void bipush(byte b) {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.BYTE);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset + 1 >= this.bCodeStream.length) {
@@ -610,6 +635,7 @@
 public void caload() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBindingArray();
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -620,6 +646,7 @@
 public void castore() {
 	this.countLabels = 0;
 	this.stackDepth -= 3;
+	popTypeBinding(3);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -659,6 +686,7 @@
 		case TypeIds.T_boolean :
 			writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangBooleanConstantPoolName));
 	}
+	pushTypeBinding(1, TypeBinding.wellKnownBaseType(baseId));
 }
 
 public void checkcast(TypeBinding typeBinding) {
@@ -673,11 +701,14 @@
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_checkcast;
 	writeUnsignedShort(this.constantPool.literalIndexForType(typeBinding));
+	pushTypeBinding(1, typeBinding);
+
 }
 
 public void d2f() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(1, TypeBinding.FLOAT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -688,6 +719,7 @@
 public void d2i() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(1, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -702,6 +734,7 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_d2l;
+	pushTypeBinding(1, TypeBinding.LONG);
 }
 
 public void dadd() {
@@ -712,6 +745,7 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dadd;
+	pushTypeBinding(2, TypeBinding.DOUBLE);
 }
 
 public void daload() {
@@ -721,6 +755,7 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_daload;
+	pushTypeBindingArray();
 }
 
 public void dastore() {
@@ -731,6 +766,7 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dastore;
+	popTypeBinding(3);
 }
 
 public void dcmpg() {
@@ -741,6 +777,7 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dcmpg;
+	pushTypeBinding(2, TypeBinding.INT);
 }
 
 public void dcmpl() {
@@ -751,11 +788,13 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dcmpl;
+	pushTypeBinding(2, TypeBinding.INT);
 }
 
 public void dconst_0() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.DOUBLE);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -768,6 +807,7 @@
 public void dconst_1() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.DOUBLE);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -780,6 +820,7 @@
 public void ddiv() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	pushTypeBinding(2, TypeBinding.DOUBLE);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -799,6 +840,7 @@
 	if (this.maxLocals < iArg + 2) {
 		this.maxLocals = iArg + 2; // + 2 because it is a double
 	}
+	pushTypeBinding(TypeBinding.DOUBLE);
 	if (iArg > 255) { // Widen
 		if (this.classFileOffset + 3 >= this.bCodeStream.length) {
 			resizeByteArray();
@@ -821,6 +863,7 @@
 public void dload_0() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.DOUBLE);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.maxLocals < 2) {
@@ -836,6 +879,7 @@
 public void dload_1() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.DOUBLE);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.maxLocals < 3) {
@@ -851,6 +895,7 @@
 public void dload_2() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.DOUBLE);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.maxLocals < 4) {
@@ -866,6 +911,7 @@
 public void dload_3() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.DOUBLE);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.maxLocals < 5) {
@@ -881,6 +927,7 @@
 public void dmul() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	pushTypeBinding(2, TypeBinding.DOUBLE);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -895,10 +942,12 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dneg;
+	pushTypeBinding(1, TypeBinding.DOUBLE);
 }
 
 public void drem() {
 	this.countLabels = 0;
+	pushTypeBinding(2, TypeBinding.DOUBLE);
 	this.stackDepth -= 2;
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
@@ -910,6 +959,7 @@
 public void dreturn() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	// the stackDepth should be equal to 0
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
@@ -922,6 +972,7 @@
 public void dstore(int iArg) {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	if (this.maxLocals <= iArg + 1) {
 		this.maxLocals = iArg + 2;
 	}
@@ -946,6 +997,7 @@
 public void dstore_0() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	if (this.maxLocals < 2) {
 		this.maxLocals = 2;
 	}
@@ -959,6 +1011,7 @@
 public void dstore_1() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	if (this.maxLocals < 3) {
 		this.maxLocals = 3;
 	}
@@ -972,6 +1025,7 @@
 public void dstore_2() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	if (this.maxLocals < 4) {
 		this.maxLocals = 4;
 	}
@@ -985,6 +1039,7 @@
 public void dstore_3() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	if (this.maxLocals < 5) {
 		this.maxLocals = 5;
 	}
@@ -998,6 +1053,7 @@
 public void dsub() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	pushTypeBinding(2, TypeBinding.DOUBLE);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -1008,6 +1064,9 @@
 public void dup() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	if (isSwitchStackTrackingActive()) {
+		pushTypeBinding(this.switchSaveTypeBindings.peek());
+	}
 	if (this.stackDepth > this.stackMax) {
 		this.stackMax = this.stackDepth;
 	}
@@ -1018,9 +1077,19 @@
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dup;
 }
 
+private void adjustTypeBindingStackForDupX1() {
+	if (isSwitchStackTrackingActive()) {
+		TypeBinding[] topStack = { popTypeBinding(), popTypeBinding() };
+		pushTypeBinding(topStack[0]);
+		pushTypeBinding(topStack[1]);
+		pushTypeBinding(topStack[0]);
+	}
+}
+
 public void dup_x1() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	adjustTypeBindingStackForDupX1();
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -1030,9 +1099,31 @@
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dup_x1;
 }
 
+private void adjustTypeBindingStackForDupX2() {
+	if (!isSwitchStackTrackingActive())
+		return;
+	TypeBinding val1 = popTypeBinding();
+	TypeBinding val2 = popTypeBinding();
+	if (TypeIds.getCategory(val1.id) == 1) {
+		if (TypeIds.getCategory(val2.id) == 2) {
+			pushTypeBinding(val1);
+			pushTypeBinding(val2);
+			pushTypeBinding(val1);
+		} else { // 1
+			TypeBinding val3 = popTypeBinding();
+			if (TypeIds.getCategory(val3.id) == 1) {
+				pushTypeBinding(val1);
+				pushTypeBinding(val3);
+				pushTypeBinding(val2);
+				pushTypeBinding(val1);
+			}
+		}
+	}
+}
 public void dup_x2() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	adjustTypeBindingStackForDupX2();
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -1042,9 +1133,27 @@
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dup_x2;
 }
 
+private void adjustTypeBindingStackForDup2() {
+	if (!isSwitchStackTrackingActive())
+		return;
+	TypeBinding val1 = popTypeBinding();
+	if (TypeIds.getCategory(val1.id) == 2) {
+		pushTypeBinding(val1);
+		pushTypeBinding(val1);
+	} else { // val1 category 1
+		TypeBinding val2 = popTypeBinding();
+		if (TypeIds.getCategory(val2.id) == 1) {
+			pushTypeBinding(val2);
+			pushTypeBinding(val1);
+			pushTypeBinding(val2);
+			pushTypeBinding(val1);
+		}
+	}
+}
 public void dup2() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	adjustTypeBindingStackForDup2();
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -1054,9 +1163,34 @@
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dup2;
 }
 
+private void adjustTypeBindingStackForDup2X1() {
+	if (!isSwitchStackTrackingActive())
+		return;
+	TypeBinding val1 = popTypeBinding();
+	TypeBinding val2 = popTypeBinding();
+	if (TypeIds.getCategory(val1.id) == 2) {
+		if (TypeIds.getCategory(val2.id) == 1) {
+			pushTypeBinding(val1);
+			pushTypeBinding(val2);
+			pushTypeBinding(val1);
+		}
+	} else { // val1 cat 1
+		if (TypeIds.getCategory(val2.id) == 1) {
+			TypeBinding val3 = popTypeBinding();
+			if (TypeIds.getCategory(val3.id) == 1) {
+				pushTypeBinding(val2);
+				pushTypeBinding(val1);
+				pushTypeBinding(val3);
+				pushTypeBinding(val2);
+				pushTypeBinding(val1);
+			}
+		}
+	}
+}
 public void dup2_x1() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	adjustTypeBindingStackForDup2X1();
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -1066,9 +1200,55 @@
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_dup2_x1;
 }
 
+private void adjustTypeBindingStackForDup2X2() {
+	if (!isSwitchStackTrackingActive())
+		return;
+	TypeBinding val1 = popTypeBinding();
+	if (TypeIds.getCategory(val1.id) == 2) {
+		TypeBinding val2 = popTypeBinding();
+		if (TypeIds.getCategory(val2.id) == 2) { // Form 4
+			pushTypeBinding(val1);
+			pushTypeBinding(val2);
+			pushTypeBinding(val1);
+		} else {
+			TypeBinding val3 = popTypeBinding();
+			if (TypeIds.getCategory(val3.id) == 1) { // Form 2
+				pushTypeBinding(val1);
+				pushTypeBinding(val3);
+				pushTypeBinding(val2);
+				pushTypeBinding(val1);
+			}
+		}
+		pushTypeBinding(val1);
+		pushTypeBinding(val1);
+	} else { // val1 category 1
+		TypeBinding val2 = popTypeBinding();
+		if (TypeIds.getCategory(val2.id) == 1) {
+			TypeBinding val3 = popTypeBinding();
+			if (TypeIds.getCategory(val3.id) == 2) { // Form 3
+				pushTypeBinding(val2);
+				pushTypeBinding(val1);
+				pushTypeBinding(val3);
+				pushTypeBinding(val2);
+				pushTypeBinding(val1);
+			} else { // val3 cat 1
+				TypeBinding val4 = popTypeBinding();
+				if (TypeIds.getCategory(val4.id) == 1) { // Form 1
+					pushTypeBinding(val2);
+					pushTypeBinding(val1);
+					pushTypeBinding(val4);
+					pushTypeBinding(val3);
+					pushTypeBinding(val2);
+					pushTypeBinding(val1);
+				}
+			}
+		}
+	}
+}
 public void dup2_x2() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	adjustTypeBindingStackForDup2X2();
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -1126,6 +1306,7 @@
 public void f2d() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(1, TypeBinding.DOUBLE);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -1142,11 +1323,13 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_f2i;
+	pushTypeBinding(1, TypeBinding.INT);
 }
 
 public void f2l() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(1, TypeBinding.LONG);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -1159,6 +1342,7 @@
 public void fadd() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.FLOAT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -1169,6 +1353,7 @@
 public void faload() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBindingArray();
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -1179,6 +1364,7 @@
 public void fastore() {
 	this.countLabels = 0;
 	this.stackDepth -= 3;
+	popTypeBinding(3);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -1189,6 +1375,7 @@
 public void fcmpg() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.FLOAT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -1199,6 +1386,7 @@
 public void fcmpl() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.FLOAT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -1209,6 +1397,7 @@
 public void fconst_0() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.FLOAT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -1221,6 +1410,7 @@
 public void fconst_1() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.FLOAT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -1233,6 +1423,7 @@
 public void fconst_2() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.FLOAT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -1245,6 +1436,7 @@
 public void fdiv() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.FLOAT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -1268,36 +1460,46 @@
 			returnTypeSize = 1;
 			break;
 	}
-	this.fieldAccess(opcode, returnTypeSize, declaringClass.constantPoolName(), fieldBinding.name, returnType.signature());
+	this.fieldAccess(opcode, returnTypeSize, declaringClass.constantPoolName(), fieldBinding.name, returnType.signature(), returnType.id, returnType);
 }
 
-private void fieldAccess(byte opcode, int returnTypeSize, char[] declaringClass, char[] fieldName, char[] signature) {
+private void fieldAccess(byte opcode, int returnTypeSize, char[] declaringClass, char[] fieldName, char[] signature, int typeId) {
+	fieldAccess(opcode, returnTypeSize, declaringClass, fieldName, signature, typeId, null);
+}
+private void fieldAccess(byte opcode, int returnTypeSize, char[] declaringClass, char[] fieldName, char[] signature, int typeId, TypeBinding typeBinding) {
 	this.countLabels = 0;
 	switch(opcode) {
 		case Opcodes.OPC_getfield :
 			if (returnTypeSize == 2) {
 				this.stackDepth++;
 			}
+			pushTypeBinding(1, typeBinding);
 			break;
 		case Opcodes.OPC_getstatic :
 			if (returnTypeSize == 2) {
 				this.stackDepth += 2;
+				pushTypeBinding(typeBinding);
 			} else {
 				this.stackDepth++;
+				pushTypeBinding(typeBinding);
 			}
 			break;
 		case Opcodes.OPC_putfield :
 			if (returnTypeSize == 2) {
 				this.stackDepth -= 3;
+				popTypeBinding(2);
 			} else {
 				this.stackDepth -= 2;
+				popTypeBinding(2);
 			}
 			break;
 		case Opcodes.OPC_putstatic :
 			if (returnTypeSize == 2) {
 				this.stackDepth -= 2;
+				popTypeBinding();
 			} else {
 				this.stackDepth--;
+				popTypeBinding();
 			}
 	}
 	if (this.stackDepth > this.stackMax) {
@@ -1317,6 +1519,7 @@
 	if (this.maxLocals <= iArg) {
 		this.maxLocals = iArg + 1;
 	}
+	pushTypeBinding(TypeBinding.FLOAT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (iArg > 255) { // Widen
@@ -1340,6 +1543,7 @@
 public void fload_0() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.FLOAT);
 	if (this.maxLocals == 0) {
 		this.maxLocals = 1;
 	}
@@ -1355,6 +1559,7 @@
 public void fload_1() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.FLOAT);
 	if (this.maxLocals <= 1) {
 		this.maxLocals = 2;
 	}
@@ -1370,6 +1575,7 @@
 public void fload_2() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.FLOAT);
 	if (this.maxLocals <= 2) {
 		this.maxLocals = 3;
 	}
@@ -1385,6 +1591,7 @@
 public void fload_3() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.FLOAT);
 	if (this.maxLocals <= 3) {
 		this.maxLocals = 4;
 	}
@@ -1400,6 +1607,7 @@
 public void fmul() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.FLOAT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -1414,11 +1622,13 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_fneg;
+	pushTypeBinding(1, TypeBinding.FLOAT);
 }
 
 public void frem() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.FLOAT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -1429,6 +1639,7 @@
 public void freturn() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	// the stackDepth should be equal to 0
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
@@ -1441,6 +1652,7 @@
 public void fstore(int iArg) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= iArg) {
 		this.maxLocals = iArg + 1;
 	}
@@ -1465,6 +1677,7 @@
 public void fstore_0() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals == 0) {
 		this.maxLocals = 1;
 	}
@@ -1478,6 +1691,7 @@
 public void fstore_1() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= 1) {
 		this.maxLocals = 2;
 	}
@@ -1491,6 +1705,7 @@
 public void fstore_2() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= 2) {
 		this.maxLocals = 3;
 	}
@@ -1504,6 +1719,7 @@
 public void fstore_3() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= 3) {
 		this.maxLocals = 4;
 	}
@@ -1517,6 +1733,7 @@
 public void fsub() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.FLOAT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -1535,7 +1752,9 @@
                     1, // return type size
                     ConstantPool.JavaLangByteConstantPoolName,
                     ConstantPool.ValueOf,
-                    ConstantPool.byteByteSignature);
+                    ConstantPool.byteByteSignature,
+                    unboxedTypeID,
+                    TypeBinding.BYTE);
             } else {
                // new Byte( byte )
                 newWrapperFor(unboxedTypeID);
@@ -1547,7 +1766,9 @@
                     0, // return type size
                     ConstantPool.JavaLangByteConstantPoolName,
                     ConstantPool.Init,
-                    ConstantPool.ByteConstrSignature);
+                    ConstantPool.ByteConstrSignature,
+                    unboxedTypeID,
+                    TypeBinding.BYTE);
             }
             break;
         case TypeIds.T_short :
@@ -1559,7 +1780,9 @@
                     1, // return type size
                     ConstantPool.JavaLangShortConstantPoolName,
                     ConstantPool.ValueOf,
-                    ConstantPool.shortShortSignature);
+                    ConstantPool.shortShortSignature,
+                    unboxedTypeID,
+                    TypeBinding.SHORT);
             } else {
                 // new Short(short)
             	newWrapperFor(unboxedTypeID);
@@ -1571,7 +1794,9 @@
                     0, // return type size
                     ConstantPool.JavaLangShortConstantPoolName,
                     ConstantPool.Init,
-                    ConstantPool.ShortConstrSignature);
+                    ConstantPool.ShortConstrSignature,
+                    unboxedTypeID,
+                    TypeBinding.SHORT);
             }
             break;
         case TypeIds.T_char :
@@ -1583,7 +1808,9 @@
                     1, // return type size
                     ConstantPool.JavaLangCharacterConstantPoolName,
                     ConstantPool.ValueOf,
-                    ConstantPool.charCharacterSignature);
+                    ConstantPool.charCharacterSignature,
+                    unboxedTypeID,
+                    TypeBinding.CHAR);
             } else {
                 // new Char( char )
                 newWrapperFor(unboxedTypeID);
@@ -1595,7 +1822,9 @@
                     0, // return type size
                     ConstantPool.JavaLangCharacterConstantPoolName,
                     ConstantPool.Init,
-                    ConstantPool.CharConstrSignature);
+                    ConstantPool.CharConstrSignature,
+                    unboxedTypeID,
+                    TypeBinding.CHAR);
             }
             break;
         case TypeIds.T_int :
@@ -1607,7 +1836,9 @@
                     1, // return type size
                     ConstantPool.JavaLangIntegerConstantPoolName,
                     ConstantPool.ValueOf,
-                    ConstantPool.IntIntegerSignature);
+                    ConstantPool.IntIntegerSignature,
+                    unboxedTypeID,
+                    TypeBinding.INT);
             } else {
                 // new Integer(int)
                 newWrapperFor(unboxedTypeID);
@@ -1619,7 +1850,9 @@
                     0, // return type size
                     ConstantPool.JavaLangIntegerConstantPoolName,
                     ConstantPool.Init,
-                    ConstantPool.IntConstrSignature);
+                    ConstantPool.IntConstrSignature,
+                    unboxedTypeID,
+                    TypeBinding.INT);
             }
             break;
         case TypeIds.T_long :
@@ -1631,7 +1864,9 @@
                     1, // return type size
                     ConstantPool.JavaLangLongConstantPoolName,
                     ConstantPool.ValueOf,
-                    ConstantPool.longLongSignature);
+                    ConstantPool.longLongSignature,
+                    unboxedTypeID,
+                    TypeBinding.LONG);
             } else {
                 // new Long( long )
                 newWrapperFor(unboxedTypeID);
@@ -1644,7 +1879,9 @@
                     0, // return type size
                     ConstantPool.JavaLangLongConstantPoolName,
                     ConstantPool.Init,
-                    ConstantPool.LongConstrSignature);
+                    ConstantPool.LongConstrSignature,
+                    unboxedTypeID,
+                    TypeBinding.LONG);
             }
             break;
         case TypeIds.T_float :
@@ -1656,7 +1893,9 @@
                     1, // return type size
                     ConstantPool.JavaLangFloatConstantPoolName,
                     ConstantPool.ValueOf,
-                    ConstantPool.floatFloatSignature);
+                    ConstantPool.floatFloatSignature,
+                    unboxedTypeID,
+                    TypeBinding.FLOAT);
             } else {
                 // new Float(float)
                 newWrapperFor(unboxedTypeID);
@@ -1668,7 +1907,9 @@
                     0, // return type size
                     ConstantPool.JavaLangFloatConstantPoolName,
                     ConstantPool.Init,
-                    ConstantPool.FloatConstrSignature);
+                    ConstantPool.FloatConstrSignature,
+                    unboxedTypeID,
+                    TypeBinding.FLOAT);
             }
             break;
         case TypeIds.T_double :
@@ -1680,7 +1921,9 @@
                     1, // return type size
                     ConstantPool.JavaLangDoubleConstantPoolName,
                     ConstantPool.ValueOf,
-                    ConstantPool.doubleDoubleSignature);
+                    ConstantPool.doubleDoubleSignature,
+                    unboxedTypeID,
+                    TypeBinding.DOUBLE);
             } else {
                 // new Double( double )
             	newWrapperFor(unboxedTypeID);
@@ -1694,7 +1937,9 @@
                     0, // return type size
                     ConstantPool.JavaLangDoubleConstantPoolName,
                     ConstantPool.Init,
-                    ConstantPool.DoubleConstrSignature);
+                    ConstantPool.DoubleConstrSignature,
+                    unboxedTypeID,
+                    TypeBinding.DOUBLE);
             }
 
             break;
@@ -1707,7 +1952,9 @@
                     1, // return type size
                     ConstantPool.JavaLangBooleanConstantPoolName,
                     ConstantPool.ValueOf,
-                    ConstantPool.booleanBooleanSignature);
+                    ConstantPool.booleanBooleanSignature,
+                    unboxedTypeID,
+                    TypeBinding.BOOLEAN);
             } else {
                 // new Boolean(boolean)
                 newWrapperFor(unboxedTypeID);
@@ -1719,7 +1966,9 @@
                     0, // return type size
                     ConstantPool.JavaLangBooleanConstantPoolName,
                     ConstantPool.Init,
-                    ConstantPool.BooleanConstrSignature);
+                    ConstantPool.BooleanConstrSignature,
+                    unboxedTypeID,
+                    TypeBinding.BOOLEAN);
             }
     }
 }
@@ -1786,6 +2035,8 @@
 		goto_(endLabel);
 
 		int savedStackDepth = this.stackDepth;
+		int switchSaveTypeBindingsStackSize = this.switchSaveTypeBindings.size();
+
 		// Generate the body of the exception handler
 		/* ClassNotFoundException on stack -- the class literal could be doing more things
 		on the stack, which means that the stack may not be empty at this point in the
@@ -1809,6 +2060,7 @@
 		athrow();
 		endLabel.place();
 		this.stackDepth = savedStackDepth;
+		popTypeBinding(this.switchSaveTypeBindings.size() - switchSaveTypeBindingsStackSize);
 	}
 }
 
@@ -1864,14 +2116,14 @@
 	generateEmulationForField(fieldBinding);
 	// swap  the field with the receiver
 	this.swap();
-	invokeJavaLangReflectFieldGetter(fieldBinding.type.id);
+	invokeJavaLangReflectFieldGetter(fieldBinding.type);
 	if (!fieldBinding.type.isBaseType()) {
 		this.checkcast(fieldBinding.type);
 	}
 }
 
 public void generateEmulatedWriteAccessForField(FieldBinding fieldBinding) {
-	invokeJavaLangReflectFieldSetter(fieldBinding.type.id);
+	invokeJavaLangReflectFieldSetter(fieldBinding.type);
 }
 
 public void generateEmulationForConstructor(Scope scope, MethodBinding methodBinding) {
@@ -2471,7 +2723,8 @@
 			1, // return type size
 			arrayType.signature(), // declaring class e.g "[I"
 			ConstantPool.Clone,
-			ConstantPool.CloneSignature);
+			ConstantPool.CloneSignature,
+			getPopularBinding(ConstantPool.JavaLangObjectConstantPoolName));
 	checkcast(arrayType);
 	areturn();
 }
@@ -2548,7 +2801,8 @@
 	
 	// Generate the first switch, on method name hashcode
 	aload_0();
-	invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, ConstantPool.GetImplMethodName, ConstantPool.GetImplMethodNameSignature);
+	invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName, ConstantPool.GetImplMethodName, ConstantPool.GetImplMethodNameSignature,
+			getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 	astore_1();
 	LocalVariableBinding lvb1 = new LocalVariableBinding("hashcode".toCharArray(),scope.getJavaLangString(),0,false); //$NON-NLS-1$
 	lvb1.resolvedPosition = 1;
@@ -2644,7 +2898,8 @@
 					: syntheticMethodBinding.serializableMethodRef;
 			MethodBinding mb = funcEx.binding;
 			invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName,
-					ConstantPool.GetImplMethodKind, ConstantPool.GetImplMethodKindSignature);
+					ConstantPool.GetImplMethodKind, ConstantPool.GetImplMethodKindSignature, TypeIds.T_int,
+					TypeBinding.INT);
 			byte methodKind = 0;
 			if (mb.isStatic()) {
 				methodKind = ClassFileConstants.MethodHandleRefKindInvokeStatic;
@@ -2663,7 +2918,8 @@
 			// Compare FunctionalInterfaceClass
 			aload_0();
 			invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName,
-					ConstantPool.GetFunctionalInterfaceClass, ConstantPool.GetFunctionalInterfaceClassSignature);
+					ConstantPool.GetFunctionalInterfaceClass, ConstantPool.GetFunctionalInterfaceClassSignature,
+					getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 			String functionalInterface = null;
 			final TypeBinding expectedType = funcEx.expectedType();
 			if (expectedType instanceof IntersectionTypeBinding18) {
@@ -2680,7 +2936,8 @@
 			aload_0();
 			invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName,
 					ConstantPool.GetFunctionalInterfaceMethodName,
-					ConstantPool.GetFunctionalInterfaceMethodNameSignature);
+					ConstantPool.GetFunctionalInterfaceMethodNameSignature,
+					getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 			ldc(new String(funcEx.descriptor.selector)); // e.g. "m"
 			invokeObjectEquals();
 			ifeq(nextOne);
@@ -2689,7 +2946,8 @@
 			aload_0();
 			invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName,
 					ConstantPool.GetFunctionalInterfaceMethodSignature,
-					ConstantPool.GetFunctionalInterfaceMethodSignatureSignature);
+					ConstantPool.GetFunctionalInterfaceMethodSignatureSignature,
+					getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 			ldc(new String(funcEx.descriptor.original().signature())); // e.g "()I"
 			invokeObjectEquals();
 			ifeq(nextOne);
@@ -2697,7 +2955,8 @@
 			// Compare ImplClass
 			aload_0();
 			invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName,
-					ConstantPool.GetImplClass, ConstantPool.GetImplClassSignature);
+					ConstantPool.GetImplClass, ConstantPool.GetImplClassSignature,
+					getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 			ldc(new String(mb.declaringClass.constantPoolName())); // e.g. "com/foo/X"
 			invokeObjectEquals();
 			ifeq(nextOne);
@@ -2705,7 +2964,8 @@
 			// Compare ImplMethodSignature
 			aload_0();
 			invoke(Opcodes.OPC_invokevirtual, 1, 1, ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName,
-					ConstantPool.GetImplMethodSignature, ConstantPool.GetImplMethodSignatureSignature);
+					ConstantPool.GetImplMethodSignature, ConstantPool.GetImplMethodSignatureSignature,
+					getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 			ldc(new String(mb.signature())); // e.g. "(I)I"
 			invokeObjectEquals();
 			ifeq(nextOne);
@@ -2732,7 +2992,8 @@
 				loadInt(index++);
 				invoke(Opcodes.OPC_invokevirtual, 1, 1,
 						ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName,
-						ConstantPool.GetCapturedArg, ConstantPool.GetCapturedArgSignature);
+						ConstantPool.GetCapturedArg, ConstantPool.GetCapturedArgSignature,
+						getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 				checkcast(receiverType);
 				sig.append(receiverType.signature());
 			}
@@ -2742,7 +3003,8 @@
 				loadInt(index);
 				invoke(Opcodes.OPC_invokevirtual, 1, 1,
 						ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName,
-						ConstantPool.GetCapturedArg, ConstantPool.GetCapturedArgSignature);
+						ConstantPool.GetCapturedArg, ConstantPool.GetCapturedArgSignature,
+						getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 				if (varType.isBaseType()) {
 					checkcast(scope.boxing(varType));
 					generateUnboxingConversion(varType.id);
@@ -2763,7 +3025,7 @@
 			}
 			// Example: invokeDynamic(0, 0, 1, "m".toCharArray(), "()Lcom/foo/X$Foo;".toCharArray());
 			invokeDynamic(funcEx.bootstrapMethodNumber, index, 1, funcEx.descriptor.selector,
-					sig.toString().toCharArray());
+					sig.toString().toCharArray(), funcEx.resolvedType.id, funcEx.resolvedType);
 			areturn();
 			if (j < count - 1) {
 				nextOne.place();
@@ -2787,7 +3049,8 @@
 			0, // return type size
 			ConstantPool.JavaLangIllegalArgumentExceptionConstantPoolName,
 			ConstantPool.Init,
-			ConstantPool.IllegalArgumentExceptionConstructorSignature);
+			ConstantPool.IllegalArgumentExceptionConstructorSignature,
+			null);
 	athrow();
 }
 
@@ -3172,6 +3435,34 @@
 		}
 	}
 }
+public void generateSyntheticBodyForRecordEquals(SyntheticMethodBinding methodBinding, int index) {
+	initializeMaxLocals(methodBinding);
+	aload_0();
+	aload_1();
+	String sig = new String(methodBinding.signature());
+	sig = sig.substring(0, 1)+ new String(methodBinding.declaringClass.signature()) + sig.substring(1);
+	invokeDynamic(index, methodBinding.parameters.length, 1, methodBinding.selector, sig.toCharArray(),
+			TypeIds.T_boolean, TypeBinding.BOOLEAN);
+	ireturn();
+}
+public void generateSyntheticBodyForRecordHashCode(SyntheticMethodBinding methodBinding, int index) {
+	initializeMaxLocals(methodBinding);
+	aload_0();
+	String sig = new String(methodBinding.signature());
+	sig = sig.substring(0, 1)+ new String(methodBinding.declaringClass.signature()) + sig.substring(1);
+	invokeDynamic(index, methodBinding.parameters.length, 1, methodBinding.selector, sig.toCharArray(),
+			TypeIds.T_int, TypeBinding.INT);
+	ireturn();
+}
+public void generateSyntheticBodyForRecordToString(SyntheticMethodBinding methodBinding, int index) {
+	initializeMaxLocals(methodBinding);
+	aload_0();
+	String sig = new String(methodBinding.signature());
+	sig = sig.substring(0, 1)+ new String(methodBinding.declaringClass.signature()) + sig.substring(1);
+	invokeDynamic(index, methodBinding.parameters.length, 1, methodBinding.selector, sig.toCharArray(),
+			TypeIds.T_JavaLangObject, getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
+	areturn();
+}
 
 public void generateUnboxingConversion(int unboxedTypeID) {
 	switch (unboxedTypeID) {
@@ -3183,7 +3474,9 @@
 					1, // return type size
 					ConstantPool.JavaLangByteConstantPoolName,
 					ConstantPool.BYTEVALUE_BYTE_METHOD_NAME,
-					ConstantPool.BYTEVALUE_BYTE_METHOD_SIGNATURE);
+					ConstantPool.BYTEVALUE_BYTE_METHOD_SIGNATURE,
+					unboxedTypeID,
+					TypeBinding.wellKnownBaseType(unboxedTypeID));
 			break;
 		case TypeIds.T_short :
 			// invokevirtual: shortValue()
@@ -3193,7 +3486,9 @@
 					1, // return type size
 					ConstantPool.JavaLangShortConstantPoolName,
 					ConstantPool.SHORTVALUE_SHORT_METHOD_NAME,
-					ConstantPool.SHORTVALUE_SHORT_METHOD_SIGNATURE);
+					ConstantPool.SHORTVALUE_SHORT_METHOD_SIGNATURE,
+					unboxedTypeID,
+					TypeBinding.wellKnownBaseType(unboxedTypeID));
 			break;
 		case TypeIds.T_char :
 			// invokevirtual: charValue()
@@ -3203,7 +3498,9 @@
 					1, // return type size
 					ConstantPool.JavaLangCharacterConstantPoolName,
 					ConstantPool.CHARVALUE_CHARACTER_METHOD_NAME,
-					ConstantPool.CHARVALUE_CHARACTER_METHOD_SIGNATURE);
+					ConstantPool.CHARVALUE_CHARACTER_METHOD_SIGNATURE,
+					unboxedTypeID,
+					TypeBinding.wellKnownBaseType(unboxedTypeID));
 			break;
 		case TypeIds.T_int :
 			// invokevirtual: intValue()
@@ -3213,7 +3510,9 @@
 					1, // return type size
 					ConstantPool.JavaLangIntegerConstantPoolName,
 					ConstantPool.INTVALUE_INTEGER_METHOD_NAME,
-					ConstantPool.INTVALUE_INTEGER_METHOD_SIGNATURE);
+					ConstantPool.INTVALUE_INTEGER_METHOD_SIGNATURE,
+					unboxedTypeID,
+					TypeBinding.wellKnownBaseType(unboxedTypeID));
 			break;
 		case TypeIds.T_long :
 			// invokevirtual: longValue()
@@ -3223,7 +3522,9 @@
 					2, // return type size
 					ConstantPool.JavaLangLongConstantPoolName,
 					ConstantPool.LONGVALUE_LONG_METHOD_NAME,
-					ConstantPool.LONGVALUE_LONG_METHOD_SIGNATURE);
+					ConstantPool.LONGVALUE_LONG_METHOD_SIGNATURE,
+					unboxedTypeID,
+					TypeBinding.wellKnownBaseType(unboxedTypeID));
 			break;
 		case TypeIds.T_float :
 			// invokevirtual: floatValue()
@@ -3233,7 +3534,9 @@
 					1, // return type size
 					ConstantPool.JavaLangFloatConstantPoolName,
 					ConstantPool.FLOATVALUE_FLOAT_METHOD_NAME,
-					ConstantPool.FLOATVALUE_FLOAT_METHOD_SIGNATURE);
+					ConstantPool.FLOATVALUE_FLOAT_METHOD_SIGNATURE,
+					unboxedTypeID,
+					TypeBinding.wellKnownBaseType(unboxedTypeID));
 			break;
 		case TypeIds.T_double :
 			// invokevirtual: doubleValue()
@@ -3243,7 +3546,9 @@
 					2, // return type size
 					ConstantPool.JavaLangDoubleConstantPoolName,
 					ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_NAME,
-					ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_SIGNATURE);
+					ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_SIGNATURE,
+					unboxedTypeID,
+					TypeBinding.wellKnownBaseType(unboxedTypeID));
 			break;
 		case TypeIds.T_boolean :
 			// invokevirtual: booleanValue()
@@ -3253,7 +3558,9 @@
 					1, // return type size
 					ConstantPool.JavaLangBooleanConstantPoolName,
 					ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_NAME,
-					ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_SIGNATURE);
+					ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_SIGNATURE,
+					unboxedTypeID,
+					TypeBinding.wellKnownBaseType(unboxedTypeID));
 	}
 }
 
@@ -3288,7 +3595,9 @@
 					1, // return type size
 					ConstantPool.JavaLangByteConstantPoolName,
 					ConstantPool.BYTEVALUE_BYTE_METHOD_NAME,
-					ConstantPool.BYTEVALUE_BYTE_METHOD_SIGNATURE);
+					ConstantPool.BYTEVALUE_BYTE_METHOD_SIGNATURE,
+					baseTypeID,
+					TypeBinding.wellKnownBaseType(baseTypeID));
 			break;
 		case TypeIds.T_short :
 			// invokevirtual: shortValue()
@@ -3298,7 +3607,9 @@
 					1, // return type size
 					ConstantPool.JavaLangShortConstantPoolName,
 					ConstantPool.SHORTVALUE_SHORT_METHOD_NAME,
-					ConstantPool.SHORTVALUE_SHORT_METHOD_SIGNATURE);
+					ConstantPool.SHORTVALUE_SHORT_METHOD_SIGNATURE,
+					baseTypeID,
+					TypeBinding.wellKnownBaseType(baseTypeID));
 			break;
 		case TypeIds.T_char :
 			// invokevirtual: charValue()
@@ -3308,7 +3619,9 @@
 					1, // return type size
 					ConstantPool.JavaLangCharacterConstantPoolName,
 					ConstantPool.CHARVALUE_CHARACTER_METHOD_NAME,
-					ConstantPool.CHARVALUE_CHARACTER_METHOD_SIGNATURE);
+					ConstantPool.CHARVALUE_CHARACTER_METHOD_SIGNATURE,
+					baseTypeID,
+					TypeBinding.wellKnownBaseType(baseTypeID));
 			break;
 		case TypeIds.T_int :
 			// invokevirtual: intValue()
@@ -3318,7 +3631,9 @@
 					1, // return type size
 					ConstantPool.JavaLangIntegerConstantPoolName,
 					ConstantPool.INTVALUE_INTEGER_METHOD_NAME,
-					ConstantPool.INTVALUE_INTEGER_METHOD_SIGNATURE);
+					ConstantPool.INTVALUE_INTEGER_METHOD_SIGNATURE,
+					baseTypeID,
+					TypeBinding.wellKnownBaseType(baseTypeID));
 			break;
 		case TypeIds.T_long :
 			// invokevirtual: longValue()
@@ -3328,7 +3643,9 @@
 					2, // return type size
 					ConstantPool.JavaLangLongConstantPoolName,
 					ConstantPool.LONGVALUE_LONG_METHOD_NAME,
-					ConstantPool.LONGVALUE_LONG_METHOD_SIGNATURE);
+					ConstantPool.LONGVALUE_LONG_METHOD_SIGNATURE,
+					baseTypeID,
+					TypeBinding.wellKnownBaseType(baseTypeID));
 			break;
 		case TypeIds.T_float :
 			// invokevirtual: floatValue()
@@ -3338,7 +3655,9 @@
 					1, // return type size
 					ConstantPool.JavaLangFloatConstantPoolName,
 					ConstantPool.FLOATVALUE_FLOAT_METHOD_NAME,
-					ConstantPool.FLOATVALUE_FLOAT_METHOD_SIGNATURE);
+					ConstantPool.FLOATVALUE_FLOAT_METHOD_SIGNATURE,
+					baseTypeID,
+					TypeBinding.wellKnownBaseType(baseTypeID));
 			break;
 		case TypeIds.T_double :
 			// invokevirtual: doubleValue()
@@ -3348,7 +3667,9 @@
 					2, // return type size
 					ConstantPool.JavaLangDoubleConstantPoolName,
 					ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_NAME,
-					ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_SIGNATURE);
+					ConstantPool.DOUBLEVALUE_DOUBLE_METHOD_SIGNATURE,
+					baseTypeID,
+					TypeBinding.wellKnownBaseType(baseTypeID));
 			break;
 		case TypeIds.T_boolean :
 			// invokevirtual: booleanValue()
@@ -3358,7 +3679,9 @@
 					1, // return type size
 					ConstantPool.JavaLangBooleanConstantPoolName,
 					ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_NAME,
-					ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_SIGNATURE);
+					ConstantPool.BOOLEANVALUE_BOOLEAN_METHOD_SIGNATURE,
+					baseTypeID,
+					TypeBinding.wellKnownBaseType(baseTypeID));
 	}
 }
 
@@ -3435,6 +3758,10 @@
 						&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(isImplicitThisReceiver && codegenBinding.isStatic()))
 						&& codegenBinding.declaringClass.id != TypeIds.T_JavaLangObject) // no change for Object methods
 					|| !codegenBinding.declaringClass.canBeSeenBy(currentScope)) {
+				TypeBinding erasedReceiverType = actualReceiverType.erasure();
+				if (erasedReceiverType.isIntersectionType18()) {
+					actualReceiverType = erasedReceiverType; // need to peel the intersecting types below
+				}
 				if (actualReceiverType.isIntersectionType18()) {
 					TypeBinding[] intersectingTypes = ((IntersectionTypeBinding18)actualReceiverType).getIntersectingTypes();
 					for(int i = 0; i < intersectingTypes.length; i++) {
@@ -3444,7 +3771,7 @@
 						}
 					}
 				} else {
-					constantPoolDeclaringClass = actualReceiverType.erasure();
+					constantPoolDeclaringClass = erasedReceiverType;
 				}
 			}
 		}				
@@ -3465,7 +3792,8 @@
 					1, // return type size
 					ConstantPool.JavaLangByteConstantPoolName,
 					ConstantPool.TYPE,
-					ConstantPool.JavaLangClassSignature);
+					ConstantPool.JavaLangClassSignature,
+					baseTypeID);
 			break;
 		case TypeIds.T_short :
 			// getstatic: java.lang.Short.TYPE
@@ -3474,7 +3802,8 @@
 					1, // return type size
 					ConstantPool.JavaLangShortConstantPoolName,
 					ConstantPool.TYPE,
-					ConstantPool.JavaLangClassSignature);
+					ConstantPool.JavaLangClassSignature,
+					baseTypeID);
 			break;
 		case TypeIds.T_char :
 			// getstatic: java.lang.Character.TYPE
@@ -3483,7 +3812,8 @@
 					1, // return type size
 					ConstantPool.JavaLangCharacterConstantPoolName,
 					ConstantPool.TYPE,
-					ConstantPool.JavaLangClassSignature);
+					ConstantPool.JavaLangClassSignature,
+					baseTypeID);
 			break;
 		case TypeIds.T_int :
 			// getstatic: java.lang.Integer.TYPE
@@ -3492,7 +3822,8 @@
 					1, // return type size
 					ConstantPool.JavaLangIntegerConstantPoolName,
 					ConstantPool.TYPE,
-					ConstantPool.JavaLangClassSignature);
+					ConstantPool.JavaLangClassSignature,
+					baseTypeID);
 			break;
 		case TypeIds.T_long :
 			// getstatic: java.lang.Long.TYPE
@@ -3501,7 +3832,8 @@
 					1, // return type size
 					ConstantPool.JavaLangLongConstantPoolName,
 					ConstantPool.TYPE,
-					ConstantPool.JavaLangClassSignature);
+					ConstantPool.JavaLangClassSignature,
+					baseTypeID);
 			break;
 		case TypeIds.T_float :
 			// getstatic: java.lang.Float.TYPE
@@ -3510,7 +3842,8 @@
 					1, // return type size
 					ConstantPool.JavaLangFloatConstantPoolName,
 					ConstantPool.TYPE,
-					ConstantPool.JavaLangClassSignature);
+					ConstantPool.JavaLangClassSignature,
+					baseTypeID);
 			break;
 		case TypeIds.T_double :
 			// getstatic: java.lang.Double.TYPE
@@ -3519,7 +3852,8 @@
 					1, // return type size
 					ConstantPool.JavaLangDoubleConstantPoolName,
 					ConstantPool.TYPE,
-					ConstantPool.JavaLangClassSignature);
+					ConstantPool.JavaLangClassSignature,
+					baseTypeID);
 			break;
 		case TypeIds.T_boolean :
 			// getstatic: java.lang.Boolean.TYPE
@@ -3528,7 +3862,8 @@
 					1, // return type size
 					ConstantPool.JavaLangBooleanConstantPoolName,
 					ConstantPool.TYPE,
-					ConstantPool.JavaLangClassSignature);
+					ConstantPool.JavaLangClassSignature,
+					baseTypeID);
 			break;
 		case TypeIds.T_void :
 			// getstatic: java.lang.Void.TYPE
@@ -3537,7 +3872,8 @@
 					1, // return type size
 					ConstantPool.JavaLangVoidConstantPoolName,
 					ConstantPool.TYPE,
-					ConstantPool.JavaLangClassSignature);
+					ConstantPool.JavaLangClassSignature,
+					baseTypeID);
 			break;
 	}
 }
@@ -3605,6 +3941,7 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_i2b;
+	pushTypeBinding(1, TypeBinding.INT);
 }
 
 public void i2c() {
@@ -3614,11 +3951,13 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_i2c;
+	pushTypeBinding(1, TypeBinding.INT);
 }
 
 public void i2d() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(1, TypeBinding.INT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -3635,11 +3974,13 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_i2f;
+	pushTypeBinding(1, TypeBinding.FLOAT);
 }
 
 public void i2l() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(1, TypeBinding.LONG);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -3656,11 +3997,13 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_i2s;
+	pushTypeBinding(1, TypeBinding.INT);
 }
 
 public void iadd() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -3671,6 +4014,7 @@
 public void iaload() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBindingArray();
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -3681,6 +4025,7 @@
 public void iand() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -3691,6 +4036,7 @@
 public void iastore() {
 	this.countLabels = 0;
 	this.stackDepth -= 3;
+	popTypeBinding(3);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -3701,6 +4047,7 @@
 public void iconst_0() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -3713,6 +4060,7 @@
 public void iconst_1() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -3725,6 +4073,7 @@
 public void iconst_2() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -3736,6 +4085,7 @@
 public void iconst_3() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -3748,6 +4098,7 @@
 public void iconst_4() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -3760,6 +4111,7 @@
 public void iconst_5() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -3772,6 +4124,7 @@
 public void iconst_m1() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -3784,6 +4137,7 @@
 public void idiv() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -3794,6 +4148,7 @@
 public void if_acmpeq(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth-=2;
+	popTypeBinding(2);
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_if_acmpne, lbl);
 	} else {
@@ -3809,6 +4164,7 @@
 public void if_acmpne(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth-=2;
+	popTypeBinding(2);
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_if_acmpeq, lbl);
 	} else {
@@ -3824,6 +4180,7 @@
 public void if_icmpeq(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding(2);
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmpne, lbl);
 	} else {
@@ -3839,6 +4196,7 @@
 public void if_icmpge(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding(2);
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmplt, lbl);
 	} else {
@@ -3854,6 +4212,7 @@
 public void if_icmpgt(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding(2);
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmple, lbl);
 	} else {
@@ -3869,6 +4228,7 @@
 public void if_icmple(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding(2);
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmpgt, lbl);
 	} else {
@@ -3884,6 +4244,7 @@
 public void if_icmplt(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding(2);
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmpge, lbl);
 	} else {
@@ -3899,6 +4260,7 @@
 public void if_icmpne(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding(2);
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_if_icmpeq, lbl);
 	} else {
@@ -3914,6 +4276,7 @@
 public void ifeq(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_ifne, lbl);
 	} else {
@@ -3929,6 +4292,7 @@
 public void ifge(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_iflt, lbl);
 	} else {
@@ -3944,6 +4308,7 @@
 public void ifgt(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_ifle, lbl);
 	} else {
@@ -3959,6 +4324,7 @@
 public void ifle(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_ifgt, lbl);
 	} else {
@@ -3974,6 +4340,7 @@
 public void iflt(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_ifge, lbl);
 	} else {
@@ -3989,6 +4356,7 @@
 public void ifne(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_ifeq, lbl);
 	} else {
@@ -4004,6 +4372,7 @@
 public void ifnonnull(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_ifnull, lbl);
 	} else {
@@ -4019,6 +4388,7 @@
 public void ifnull(BranchLabel lbl) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.wideMode) {
 		generateWideRevertedConditionalBranch(Opcodes.OPC_ifnonnull, lbl);
 	} else {
@@ -4059,6 +4429,7 @@
 	if (this.maxLocals <= iArg) {
 		this.maxLocals = iArg + 1;
 	}
+	pushTypeBinding(TypeBinding.INT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (iArg > 255) { // Widen
@@ -4082,6 +4453,7 @@
 public void iload_0() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.maxLocals <= 0) {
 		this.maxLocals = 1;
 	}
@@ -4097,6 +4469,7 @@
 public void iload_1() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.maxLocals <= 1) {
 		this.maxLocals = 2;
 	}
@@ -4112,6 +4485,7 @@
 public void iload_2() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.maxLocals <= 2) {
 		this.maxLocals = 3;
 	}
@@ -4127,6 +4501,7 @@
 public void iload_3() {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.maxLocals <= 3) {
 		this.maxLocals = 4;
 	}
@@ -4142,6 +4517,7 @@
 public void imul() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -4156,6 +4532,7 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_ineg;
+	pushTypeBinding(1, TypeBinding.INT);
 }
 
 public void init(ClassFile targetClassFile) {
@@ -4261,17 +4638,24 @@
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_instanceof;
 	writeUnsignedShort(this.constantPool.literalIndexForType(typeBinding));
+	pushTypeBinding(1, TypeBinding.INT);
 }
 
-protected void invoke(byte opcode, int receiverAndArgsSize, int returnTypeSize, char[] declaringClass, char[] selector, char[] signature) {
-	invoke18(opcode, receiverAndArgsSize, returnTypeSize, declaringClass, opcode == Opcodes.OPC_invokeinterface, selector, signature);
+protected void invoke(byte opcode, int receiverAndArgsSize, int returnTypeSize, char[] declaringClass, char[] selector, char[] signature, TypeBinding type) {
+	invoke(opcode, receiverAndArgsSize, returnTypeSize, declaringClass, selector, signature, TypeIds.T_JavaLangObject, type);
+}
+protected void _invoke(byte opcode, int receiverAndArgsSize, int returnTypeSize, char[] declaringClass, char[] selector, char[] signature, int typeId) {
+//	invoke18(opcode, receiverAndArgsSize, returnTypeSize, declaringClass, opcode == Opcodes.OPC_invokeinterface, selector, signature, typeId);
+}
+protected void invoke(byte opcode, int receiverAndArgsSize, int returnTypeSize, char[] declaringClass, char[] selector, char[] signature, int typeId, TypeBinding type) {
+	invoke18(opcode, receiverAndArgsSize, returnTypeSize, declaringClass, opcode == Opcodes.OPC_invokeinterface, selector, signature, typeId, type);
 }
 
 // Starting with 1.8 we can no longer deduce isInterface from opcode, invokespecial can be used for default methods, too.
 // Hence adding explicit parameter 'isInterface', which is needed only for non-ctor invokespecial invocations
 // (i.e., other clients may still call the shorter overload).
 private void invoke18(byte opcode, int receiverAndArgsSize, int returnTypeSize, char[] declaringClass,
-		boolean isInterface, char[] selector, char[] signature) {	
+		boolean isInterface, char[] selector, char[] signature, int typeId, TypeBinding type) {
 	this.countLabels = 0;
 	if (opcode == Opcodes.OPC_invokeinterface) {
 		// invokeinterface
@@ -4295,16 +4679,22 @@
 		writeUnsignedShort(this.constantPool.literalIndexForMethod(declaringClass, selector, signature, isInterface));
 	}
 	this.stackDepth += returnTypeSize - receiverAndArgsSize;
+	popTypeBinding(receiverAndArgsSize);
+	if (returnTypeSize > 0) {
+		pushTypeBinding(type);
+	}
 	if (this.stackDepth > this.stackMax) {
 		this.stackMax = this.stackDepth;
 	}
 }
 
-public void invokeDynamic(int bootStrapIndex, int argsSize, int returnTypeSize, char[] selector, char[] signature) {
-	this.invokeDynamic(bootStrapIndex, argsSize, returnTypeSize, selector, signature, false, null, null);
+public void invokeDynamic(int bootStrapIndex, int argsSize, int returnTypeSize, char[] selector, char[] signature,
+		int typeId, TypeBinding type) {
+	this.invokeDynamic(bootStrapIndex, argsSize, returnTypeSize, selector, signature, false, null, null, typeId, type);
 }
 
-public void invokeDynamic(int bootStrapIndex, int argsSize, int returnTypeSize, char[] selector, char[] signature, boolean isConstructorReference, TypeReference lhsTypeReference, TypeReference [] typeArguments) {
+public void invokeDynamic(int bootStrapIndex, int argsSize, int returnTypeSize, char[] selector, char[] signature, boolean isConstructorReference, TypeReference lhsTypeReference, TypeReference [] typeArguments,
+		int typeId, TypeBinding type) {
 	if (this.classFileOffset + 4 >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -4315,6 +4705,10 @@
 	this.bCodeStream[this.classFileOffset++] = 0;
 	this.bCodeStream[this.classFileOffset++] = 0;
 	this.stackDepth += returnTypeSize - argsSize;
+	popTypeBinding(argsSize);
+	if (returnTypeSize > 0) {
+		pushTypeBinding(type);
+	}
 	if (this.stackDepth > this.stackMax) {
 		this.stackMax = this.stackDepth;
 	}
@@ -4404,7 +4798,9 @@
 			declaringClass.constantPoolName(),
 			declaringClass.isInterface(),
 			methodBinding.selector, 
-			methodBinding.signature(this.classFile));
+			methodBinding.signature(this.classFile),
+			methodBinding.returnType.id,
+			methodBinding.returnType);
 }
 
 protected void invokeAccessibleObjectSetAccessible() {
@@ -4415,7 +4811,8 @@
 			0, // return type size
 			ConstantPool.JAVALANGREFLECTACCESSIBLEOBJECT_CONSTANTPOOLNAME,
 			ConstantPool.SETACCESSIBLE_NAME,
-			ConstantPool.SETACCESSIBLE_SIGNATURE);
+			ConstantPool.SETACCESSIBLE_SIGNATURE,
+			null);
 }
 
 protected void invokeArrayNewInstance() {
@@ -4426,7 +4823,8 @@
 			1, // return type size
 			ConstantPool.JAVALANGREFLECTARRAY_CONSTANTPOOLNAME,
 			ConstantPool.NewInstance,
-			ConstantPool.NewInstanceSignature);
+			ConstantPool.NewInstanceSignature,
+			getPopularBinding(ConstantPool.JavaLangObjectConstantPoolName));
 }
 public void invokeClassForName() {
 	// invokestatic: java.lang.Class.forName(Ljava.lang.String;)Ljava.lang.Class;
@@ -4436,7 +4834,8 @@
 		1, // return type size
 		ConstantPool.JavaLangClassConstantPoolName,
 		ConstantPool.ForName,
-		ConstantPool.ForNameSignature);
+		ConstantPool.ForNameSignature,
+		getPopularBinding(ConstantPool.JavaLangClassConstantPoolName));
 }
 
 protected void invokeClassGetDeclaredConstructor() {
@@ -4447,7 +4846,8 @@
 			1, // return type size
 			ConstantPool.JavaLangClassConstantPoolName,
 			ConstantPool.GETDECLAREDCONSTRUCTOR_NAME,
-			ConstantPool.GETDECLAREDCONSTRUCTOR_SIGNATURE);
+			ConstantPool.GETDECLAREDCONSTRUCTOR_SIGNATURE,
+			getPopularBinding(ConstantPool.JavaLangReflectConstructorConstantPoolName));
 }
 
 protected void invokeClassGetDeclaredField() {
@@ -4458,7 +4858,8 @@
 			1, // return type size
 			ConstantPool.JavaLangClassConstantPoolName,
 			ConstantPool.GETDECLAREDFIELD_NAME,
-			ConstantPool.GETDECLAREDFIELD_SIGNATURE);
+			ConstantPool.GETDECLAREDFIELD_SIGNATURE,
+			getPopularBinding(ConstantPool.JAVALANGREFLECTFIELD_CONSTANTPOOLNAME));
 }
 
 protected void invokeClassGetDeclaredMethod() {
@@ -4469,7 +4870,8 @@
 			1, // return type size
 			ConstantPool.JavaLangClassConstantPoolName,
 			ConstantPool.GETDECLAREDMETHOD_NAME,
-			ConstantPool.GETDECLAREDMETHOD_SIGNATURE);
+			ConstantPool.GETDECLAREDMETHOD_SIGNATURE,
+			getPopularBinding(ConstantPool.JAVALANGREFLECTMETHOD_CONSTANTPOOLNAME));
 }
 
 public void invokeEnumOrdinal(char[] enumTypeConstantPoolName) {
@@ -4480,7 +4882,9 @@
 			1, // return type size
 			enumTypeConstantPoolName,
 			ConstantPool.Ordinal,
-			ConstantPool.OrdinalSignature);
+			ConstantPool.OrdinalSignature,
+			TypeIds.T_int,
+			TypeBinding.INT);
 }
 
 public void invokeIterableIterator(TypeBinding iterableReceiverType) {
@@ -4494,7 +4898,8 @@
 			1, // returnTypeSize
 			iterableReceiverType.constantPoolName(), 
 			ConstantPool.ITERATOR_NAME, 
-			ConstantPool.ITERATOR_SIGNATURE);
+			ConstantPool.ITERATOR_SIGNATURE,
+			getPopularBinding(ConstantPool.JavaUtilIteratorConstantPoolName));
 }
 
 public void invokeAutoCloseableClose(TypeBinding resourceType) {
@@ -4505,7 +4910,8 @@
 			0, // returnTypeSize
 			resourceType.constantPoolName(), 
 			ConstantPool.Close, 
-			ConstantPool.CloseSignature);
+			ConstantPool.CloseSignature,
+			null);
 }
 
 public void invokeThrowableAddSuppressed() {
@@ -4514,7 +4920,8 @@
 			0, // returnTypeSize
 			ConstantPool.JavaLangThrowableConstantPoolName,
 			ConstantPool.AddSuppressed, 
-			ConstantPool.AddSuppressedSignature);
+			ConstantPool.AddSuppressedSignature,
+			null);
 }
 
 public void invokeJavaLangAssertionErrorConstructor(int typeBindingID) {
@@ -4563,7 +4970,8 @@
 			0, // return type size
 			ConstantPool.JavaLangAssertionErrorConstantPoolName,
 			ConstantPool.Init,
-			signature);
+			signature,
+			null);
 }
 
 public void invokeJavaLangAssertionErrorDefaultConstructor() {
@@ -4574,7 +4982,8 @@
 			0, // return type size
 			ConstantPool.JavaLangAssertionErrorConstantPoolName,
 			ConstantPool.Init,
-			ConstantPool.DefaultConstructorSignature);
+			ConstantPool.DefaultConstructorSignature,
+			null);
 }
 public void invokeJavaLangIncompatibleClassChangeErrorDefaultConstructor() {
 	// invokespecial: java.lang.IncompatibleClassChangeError.<init>()V
@@ -4584,7 +4993,8 @@
 			0, // return type size
 			ConstantPool.JavaLangIncompatibleClassChangeErrorConstantPoolName,
 			ConstantPool.Init,
-			ConstantPool.DefaultConstructorSignature);
+			ConstantPool.DefaultConstructorSignature,
+			null);
 }
 public void invokeJavaLangClassDesiredAssertionStatus() {
 	// invokevirtual: java.lang.Class.desiredAssertionStatus()Z;
@@ -4594,7 +5004,9 @@
 			1, // return type size
 			ConstantPool.JavaLangClassConstantPoolName,
 			ConstantPool.DesiredAssertionStatus,
-			ConstantPool.DesiredAssertionStatusSignature);
+			ConstantPool.DesiredAssertionStatusSignature,
+			TypeIds.T_boolean,
+			TypeBinding.BOOLEAN);
 }
 
 public void invokeJavaLangEnumvalueOf(ReferenceBinding binding) {
@@ -4605,7 +5017,8 @@
 			1, // return type size
 			ConstantPool.JavaLangEnumConstantPoolName,
 			ConstantPool.ValueOf,
-			ConstantPool.ValueOfStringClassSignature);
+			ConstantPool.ValueOfStringClassSignature,
+			getPopularBinding(ConstantPool.JavaLangEnumConstantPoolName));
 }
 
 public void invokeJavaLangEnumValues(TypeBinding enumBinding, ArrayBinding arrayBinding) {
@@ -4617,7 +5030,8 @@
 			1,  // return type size
 			enumBinding.constantPoolName(), 
 			TypeConstants.VALUES, 
-			signature);
+			signature,
+			arrayBinding);
 }
 
 public void invokeJavaLangErrorConstructor() {
@@ -4628,7 +5042,8 @@
 			0, // return type size
 			ConstantPool.JavaLangErrorConstantPoolName,
 			ConstantPool.Init,
-			ConstantPool.StringConstructorSignature);
+			ConstantPool.StringConstructorSignature,
+			null);
 }
 
 public void invokeJavaLangReflectConstructorNewInstance() {
@@ -4639,13 +5054,15 @@
 			1, // return type size
 			ConstantPool.JavaLangReflectConstructorConstantPoolName,
 			ConstantPool.NewInstance,
-			ConstantPool.JavaLangReflectConstructorNewInstanceSignature);
+			ConstantPool.JavaLangReflectConstructorNewInstanceSignature,
+			getPopularBinding(ConstantPool.JavaLangObjectSignature));
 }
 
-protected void invokeJavaLangReflectFieldGetter(int typeID) {
+protected void invokeJavaLangReflectFieldGetter(TypeBinding type) {
 	char[] selector;
 	char[] signature;
 	int returnTypeSize;
+	int typeID = type.id;
 	switch (typeID) {
 		case TypeIds.T_int :
 			selector = ConstantPool.GET_INT_METHOD_NAME;
@@ -4699,13 +5116,16 @@
 			returnTypeSize, // return type size
 			ConstantPool.JAVALANGREFLECTFIELD_CONSTANTPOOLNAME,
 			selector,
-			signature);
+			signature,
+			typeID,
+			type);
 }
 
-protected void invokeJavaLangReflectFieldSetter(int typeID) {
+protected void invokeJavaLangReflectFieldSetter(TypeBinding type) {
 	char[] selector;
 	char[] signature;
 	int receiverAndArgsSize;
+	int typeID = type.id;
 	switch (typeID) {
 		case TypeIds.T_int :
 			selector = ConstantPool.SET_INT_METHOD_NAME;
@@ -4759,7 +5179,9 @@
 			0, // return type size
 			ConstantPool.JAVALANGREFLECTFIELD_CONSTANTPOOLNAME,
 			selector,
-			signature);
+			signature,
+			typeID,
+			type);
 }
 
 public void invokeJavaLangReflectMethodInvoke() {
@@ -4770,7 +5192,8 @@
 			1, // return type size
 			ConstantPool.JAVALANGREFLECTMETHOD_CONSTANTPOOLNAME,
 			ConstantPool.INVOKE_METHOD_METHOD_NAME,
-			ConstantPool.INVOKE_METHOD_METHOD_SIGNATURE);
+			ConstantPool.INVOKE_METHOD_METHOD_SIGNATURE,
+			getPopularBinding(ConstantPool.JavaLangObjectSignature));
 }
 
 public void invokeJavaUtilIteratorHasNext() {
@@ -4781,7 +5204,9 @@
 			1, // return type size
 			ConstantPool.JavaUtilIteratorConstantPoolName,
 			ConstantPool.HasNext,
-			ConstantPool.HasNextSignature);
+			ConstantPool.HasNextSignature,
+			TypeIds.T_boolean,
+			TypeBinding.BOOLEAN);
 }
 
 public void invokeJavaUtilIteratorNext() {
@@ -4792,7 +5217,8 @@
 			1, // return type size
 			ConstantPool.JavaUtilIteratorConstantPoolName,
 			ConstantPool.Next,
-			ConstantPool.NextSignature);
+			ConstantPool.NextSignature,
+			getPopularBinding(ConstantPool.JavaLangObjectSignature));
 }
 
 public void invokeNoClassDefFoundErrorStringConstructor() {
@@ -4803,7 +5229,8 @@
 			0, // return type size
 			ConstantPool.JavaLangNoClassDefFoundErrorConstantPoolName,
 			ConstantPool.Init,
-			ConstantPool.StringConstructorSignature);
+			ConstantPool.StringConstructorSignature,
+			null);
 }
 
 public void invokeObjectGetClass() {
@@ -4814,7 +5241,8 @@
 			1, // return type size
 			ConstantPool.JavaLangObjectConstantPoolName,
 			ConstantPool.GetClass,
-			ConstantPool.GetClassSignature);
+			ConstantPool.GetClassSignature,
+			getPopularBinding(ConstantPool.JavaLangClassConstantPoolName));
 }
 
 /**
@@ -4910,13 +5338,18 @@
 			receiverAndArgsSize = 2;
 			break;
 	}
+	// TODO: revisit after bug 561726 is fixed
+	TypeBinding type = this.targetLevel >= ClassFileConstants.JDK14 ?
+		getPopularBinding(ConstantPool.JavaLangStringBuilderConstantPoolName) : null;
 	invoke(
 			Opcodes.OPC_invokevirtual,
 			receiverAndArgsSize,
 			1, // return type size
 			declaringClass,
 			selector,
-			signature);
+			signature,
+			typeID,
+			type);
 }
 
 public void invokeStringConcatenationDefaultConstructor() {
@@ -4934,7 +5367,8 @@
 			0, // return type size
 			declaringClass,
 			ConstantPool.Init,
-			ConstantPool.DefaultConstructorSignature);
+			ConstantPool.DefaultConstructorSignature,
+			null);
 }
 
 public void invokeStringConcatenationStringConstructor() {
@@ -4954,7 +5388,8 @@
 			0, // return type size
 			declaringClass,
 			ConstantPool.Init,
-			ConstantPool.StringConstructorSignature);
+			ConstantPool.StringConstructorSignature,
+			null);
 }
 
 public void invokeStringConcatenationToString() {
@@ -4974,7 +5409,8 @@
 			1, // return type size
 			declaringClass,
 			ConstantPool.ToString,
-			ConstantPool.ToStringSignature);
+			ConstantPool.ToStringSignature,
+			getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 }
 public void invokeStringEquals() {
 	// invokevirtual: java.lang.String.equals()
@@ -4984,7 +5420,9 @@
 			1, // return type size
 			ConstantPool.JavaLangStringConstantPoolName,
 			ConstantPool.Equals,
-			ConstantPool.EqualsSignature);
+			ConstantPool.EqualsSignature,
+			TypeIds.T_boolean,
+			TypeBinding.BOOLEAN);
 }
 public void invokeObjectEquals() {
 	// invokevirtual: java.lang.Object.equals()
@@ -4994,7 +5432,9 @@
 			1, // return type size
 			ConstantPool.JavaLangObjectConstantPoolName,
 			ConstantPool.Equals,
-			ConstantPool.EqualsSignature);
+			ConstantPool.EqualsSignature,
+			TypeIds.T_boolean,
+			TypeBinding.BOOLEAN);
 }
 public void invokeStringHashCode() {
 	// invokevirtual: java.lang.String.hashCode()
@@ -5004,7 +5444,9 @@
 			1, // return type size
 			ConstantPool.JavaLangStringConstantPoolName,
 			ConstantPool.HashCode,
-			ConstantPool.HashCodeSignature);
+			ConstantPool.HashCodeSignature,
+			TypeIds.T_int,
+			TypeBinding.INT);
 }
 public void invokeStringIntern() {
 	// invokevirtual: java.lang.String.intern()
@@ -5014,7 +5456,8 @@
 			1, // return type size
 			ConstantPool.JavaLangStringConstantPoolName,
 			ConstantPool.Intern,
-			ConstantPool.InternSignature);
+			ConstantPool.InternSignature,
+			getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 }
 public void invokeStringValueOf(int typeID) {
 	// invokestatic: java.lang.String.valueOf(argumentType)
@@ -5063,7 +5506,9 @@
 			1, // return type size
 			ConstantPool.JavaLangStringConstantPoolName,
 			ConstantPool.ValueOf,
-			signature);
+			signature,
+			typeID,
+			getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 }
 
 public void invokeSystemArraycopy() {
@@ -5074,7 +5519,8 @@
 			0, // return type size
 			ConstantPool.JavaLangSystemConstantPoolName,
 			ConstantPool.ArrayCopy,
-			ConstantPool.ArrayCopySignature);
+			ConstantPool.ArrayCopySignature,
+			null);
 }
 
 public void invokeThrowableGetMessage() {
@@ -5085,12 +5531,14 @@
 			1, // return type size
 			ConstantPool.JavaLangThrowableConstantPoolName,
 			ConstantPool.GetMessage,
-			ConstantPool.GetMessageSignature);
+			ConstantPool.GetMessageSignature,
+			getPopularBinding(ConstantPool.JavaLangStringConstantPoolName));
 }
 
 public void ior() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5101,6 +5549,7 @@
 public void irem() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5111,6 +5560,7 @@
 public void ireturn() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	// the stackDepth should be equal to 0
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
@@ -5146,6 +5596,7 @@
 public void ishl() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5156,6 +5607,7 @@
 public void ishr() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5166,6 +5618,7 @@
 public void istore(int iArg) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= iArg) {
 		this.maxLocals = iArg + 1;
 	}
@@ -5190,6 +5643,7 @@
 public void istore_0() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals == 0) {
 		this.maxLocals = 1;
 	}
@@ -5203,6 +5657,7 @@
 public void istore_1() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= 1) {
 		this.maxLocals = 2;
 	}
@@ -5216,6 +5671,7 @@
 public void istore_2() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= 2) {
 		this.maxLocals = 3;
 	}
@@ -5229,6 +5685,7 @@
 public void istore_3() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.maxLocals <= 3) {
 		this.maxLocals = 4;
 	}
@@ -5242,6 +5699,7 @@
 public void isub() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5252,6 +5710,7 @@
 public void iushr() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5262,6 +5721,7 @@
 public void ixor() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5300,11 +5760,13 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_l2d;
+	pushTypeBinding(1, TypeBinding.DOUBLE);
 }
 
 public void l2f() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(1, TypeBinding.FLOAT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5315,6 +5777,7 @@
 public void l2i() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(1, TypeBinding.INT);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5325,6 +5788,7 @@
 public void ladd() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5339,11 +5803,13 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_laload;
+	pushTypeBindingArray();
 }
 
 public void land() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5354,6 +5820,7 @@
 public void lastore() {
 	this.countLabels = 0;
 	this.stackDepth -= 4;
+	popTypeBinding(3);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5364,6 +5831,7 @@
 public void lcmp() {
 	this.countLabels = 0;
 	this.stackDepth -= 3;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5374,6 +5842,7 @@
 public void lconst_0() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.LONG);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -5386,6 +5855,7 @@
 public void lconst_1() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.LONG);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -5399,6 +5869,7 @@
 	this.countLabels = 0;
 	int index = this.constantPool.literalIndex(constant);
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.FLOAT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (index > 255) {
@@ -5424,6 +5895,7 @@
 	this.countLabels = 0;
 	int index = this.constantPool.literalIndex(constant);
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (index > 255) {
@@ -5548,6 +6020,7 @@
 	this.countLabels = 0;
 	int index = this.constantPool.literalIndexForType(typeBinding);
 	this.stackDepth++;
+	pushTypeBinding(typeBinding);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (index > 255) {
@@ -5573,6 +6046,7 @@
 	this.countLabels = 0;
 	int index = this.constantPool.literalIndex(constant);
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.DOUBLE);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	// Generate a ldc2_w
@@ -5588,6 +6062,7 @@
 	this.countLabels = 0;
 	int index = this.constantPool.literalIndex(constant);
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.LONG);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	// Generate a ldc2_w
@@ -5601,6 +6076,7 @@
 
 public void ldcForIndex(int index) {
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.INT);
 	if (this.stackDepth > this.stackMax) {
 		this.stackMax = this.stackDepth;
 	}
@@ -5626,6 +6102,7 @@
 public void ldiv() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5639,6 +6116,7 @@
 	if (this.maxLocals <= iArg + 1) {
 		this.maxLocals = iArg + 2;
 	}
+	pushTypeBinding(TypeBinding.LONG);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (iArg > 255) { // Widen
@@ -5662,6 +6140,7 @@
 public void lload_0() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.LONG);
 	if (this.maxLocals < 2) {
 		this.maxLocals = 2;
 	}
@@ -5677,6 +6156,7 @@
 public void lload_1() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.LONG);
 	if (this.maxLocals < 3) {
 		this.maxLocals = 3;
 	}
@@ -5692,6 +6172,7 @@
 public void lload_2() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.LONG);
 	if (this.maxLocals < 4) {
 		this.maxLocals = 4;
 	}
@@ -5707,6 +6188,7 @@
 public void lload_3() {
 	this.countLabels = 0;
 	this.stackDepth += 2;
+	pushTypeBinding(TypeBinding.LONG);
 	if (this.maxLocals < 5) {
 		this.maxLocals = 5;
 	}
@@ -5722,6 +6204,7 @@
 public void lmul() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5736,6 +6219,7 @@
 	}
 	this.position++;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_lneg;
+	pushTypeBinding(1, TypeBinding.LONG);
 }
 
 public final void load(LocalVariableBinding localBinding) {
@@ -5849,6 +6333,7 @@
 public void lookupswitch(CaseLabel defaultLabel, int[] keys, int[] sortedIndexes, CaseLabel[] casesLabel) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	int length = keys.length;
 	int pos = this.position;
 	defaultLabel.placeInstruction();
@@ -5878,6 +6363,7 @@
 public void lor() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5888,6 +6374,7 @@
 public void lrem() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5898,6 +6385,7 @@
 public void lreturn() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	// the stackDepth should be equal to 0
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
@@ -5910,6 +6398,7 @@
 public void lshl() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5920,6 +6409,7 @@
 public void lshr() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -5930,6 +6420,7 @@
 public void lstore(int iArg) {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	if (this.maxLocals <= iArg + 1) {
 		this.maxLocals = iArg + 2;
 	}
@@ -5954,6 +6445,7 @@
 public void lstore_0() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	if (this.maxLocals < 2) {
 		this.maxLocals = 2;
 	}
@@ -5967,6 +6459,7 @@
 public void lstore_1() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	if (this.maxLocals < 3) {
 		this.maxLocals = 3;
 	}
@@ -5980,6 +6473,7 @@
 public void lstore_2() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	if (this.maxLocals < 4) {
 		this.maxLocals = 4;
 	}
@@ -5993,6 +6487,7 @@
 public void lstore_3() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	popTypeBinding();
 	if (this.maxLocals < 5) {
 		this.maxLocals = 5;
 	}
@@ -6006,6 +6501,7 @@
 public void lsub() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -6016,6 +6512,7 @@
 public void lushr() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -6026,6 +6523,7 @@
 public void lxor() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	pushTypeBinding(2, TypeBinding.LONG);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -6036,6 +6534,7 @@
 public void monitorenter() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -6046,6 +6545,7 @@
 public void monitorexit() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -6060,6 +6560,7 @@
 		ArrayAllocationExpression allocationExpression) {
 	this.countLabels = 0;
 	this.stackDepth += (1 - dimensions);
+	pushTypeBinding(dimensions, typeBinding);
 	if (this.classFileOffset + 3 >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -6069,15 +6570,16 @@
 	this.bCodeStream[this.classFileOffset++] = (byte) dimensions;
 }
 
-// We didn't call it new, because there is a conflit with the new keyword
+// We didn't call it new, because there is a conflict with the new keyword
 public void new_(TypeBinding typeBinding) {
 	this.new_(null, typeBinding);
 }
 
-// We didn't call it new, because there is a conflit with the new keyword
+// We didn't call it new, because there is a conflict with the new keyword
 public void new_(TypeReference typeReference, TypeBinding typeBinding) {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(typeBinding);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset + 3 >= this.bCodeStream.length) {
@@ -6096,6 +6598,7 @@
 	this.position += 2;
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_newarray;
 	this.bCodeStream[this.classFileOffset++] = (byte) array_Type;
+	pushTypeBinding(1, TypeBinding.wellKnownBaseType(array_Type));
 }
 
 public void newArray(ArrayBinding arrayBinding) {
@@ -6138,6 +6641,7 @@
 	// new: java.lang.AssertionError
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(ConstantPool.JavaLangAssertionErrorConstantPoolName);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset + 2 >= this.bCodeStream.length) {
@@ -6152,6 +6656,7 @@
 	// new: java.lang.Error
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(ConstantPool.JavaLangErrorConstantPoolName);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset + 2 >= this.bCodeStream.length) {
@@ -6165,6 +6670,7 @@
 	// new: java.lang.Error
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(ConstantPool.JavaLangIncompatibleClassChangeErrorConstantPoolName);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset + 2 >= this.bCodeStream.length) {
@@ -6178,6 +6684,7 @@
 	// new: java.lang.NoClassDefFoundError
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(ConstantPool.JavaLangNoClassDefFoundErrorConstantPoolName);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset + 2 >= this.bCodeStream.length) {
@@ -6193,6 +6700,7 @@
 	// new: java.lang.StringBuilder
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(ConstantPool.JavaLangStringBufferConstantPoolName);
 	if (this.stackDepth > this.stackMax) {
 		this.stackMax = this.stackDepth;
 	}
@@ -6221,30 +6729,39 @@
 	switch (typeID) {
 		case TypeIds.T_int : // new: java.lang.Integer
 			writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangIntegerConstantPoolName));
+			pushTypeBinding(ConstantPool.JavaLangIntegerConstantPoolName);
 			break;
 		case TypeIds.T_boolean : // new: java.lang.Boolean
 			writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangBooleanConstantPoolName));
+			pushTypeBinding(ConstantPool.JavaLangBooleanConstantPoolName);
 			break;
 		case TypeIds.T_byte : // new: java.lang.Byte
 			writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangByteConstantPoolName));
+			pushTypeBinding(ConstantPool.JavaLangByteConstantPoolName);
 			break;
 		case TypeIds.T_char : // new: java.lang.Character
 			writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangCharacterConstantPoolName));
+			pushTypeBinding(ConstantPool.JavaLangCharacterConstantPoolName);
 			break;
 		case TypeIds.T_float : // new: java.lang.Float
 			writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangFloatConstantPoolName));
+			pushTypeBinding(ConstantPool.JavaLangFloatConstantPoolName);
 			break;
 		case TypeIds.T_double : // new: java.lang.Double
 			writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangDoubleConstantPoolName));
+			pushTypeBinding(ConstantPool.JavaLangDoubleConstantPoolName);
 			break;
 		case TypeIds.T_short : // new: java.lang.Short
 			writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangShortConstantPoolName));
+			pushTypeBinding(ConstantPool.JavaLangShortConstantPoolName);
 			break;
 		case TypeIds.T_long : // new: java.lang.Long
 			writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangLongConstantPoolName));
+			pushTypeBinding(ConstantPool.JavaLangLongConstantPoolName);
 			break;
 		case TypeIds.T_void : // new: java.lang.Void
 			writeUnsignedShort(this.constantPool.literalIndexForType(ConstantPool.JavaLangVoidConstantPoolName));
+			pushTypeBinding(ConstantPool.JavaLangVoidConstantPoolName);
 	}
 }
 
@@ -6283,6 +6800,7 @@
 public void pop() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -6290,9 +6808,23 @@
 	this.bCodeStream[this.classFileOffset++] = Opcodes.OPC_pop;
 }
 
+private void adjustTypeBindingStackForPop2() {
+	if (!isSwitchStackTrackingActive())
+		return;
+	TypeBinding v1 = this.switchSaveTypeBindings.peek();
+	if (TypeIds.getCategory(v1.id) == 1) {
+		TypeBinding v2 = this.switchSaveTypeBindings.peek();
+		if (TypeIds.getCategory(v2.id) == 1) {
+			popTypeBinding(2);
+		}
+	} else {
+		popTypeBinding();
+	}
+}
 public void pop2() {
 	this.countLabels = 0;
 	this.stackDepth -= 2;
+	adjustTypeBindingStackForPop2();
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -6302,6 +6834,8 @@
 
 public void pushExceptionOnStack(TypeBinding binding) {
 	this.stackDepth = 1;
+	clearTypeBindingStack();
+	pushTypeBinding(binding);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 }
@@ -6309,6 +6843,7 @@
 public void pushOnStack(TypeBinding binding) {
 	if (++this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
+	pushTypeBinding(binding);
 }
 
 public void record(LocalVariableBinding local) {
@@ -6653,6 +7188,7 @@
 public void saload() {
 	this.countLabels = 0;
 	this.stackDepth--;
+	pushTypeBindingArray();
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -6663,6 +7199,7 @@
 public void sastore() {
 	this.countLabels = 0;
 	this.stackDepth -= 3;
+	popTypeBinding(3);
 	if (this.classFileOffset >= this.bCodeStream.length) {
 		resizeByteArray();
 	}
@@ -6795,6 +7332,7 @@
 public void sipush(int s) {
 	this.countLabels = 0;
 	this.stackDepth++;
+	pushTypeBinding(TypeBinding.SHORT);
 	if (this.stackDepth > this.stackMax)
 		this.stackMax = this.stackDepth;
 	if (this.classFileOffset >= this.bCodeStream.length) {
@@ -6931,6 +7469,7 @@
 public void tableswitch(CaseLabel defaultLabel, int low, int high, int[] keys, int[] sortedIndexes, int[] mapping, CaseLabel[] casesLabel) {
 	this.countLabels = 0;
 	this.stackDepth--;
+	popTypeBinding();
 	int length = casesLabel.length;
 	int pos = this.position;
 	defaultLabel.placeInstruction();
@@ -7083,4 +7622,87 @@
 		this.writeSignedWord(forward, offset);
 	}
 }
+private boolean isSwitchStackTrackingActive() {
+	return this.methodDeclaration != null && this.methodDeclaration.containsSwitchWithTry;
+}
+private TypeBinding retrieveLocalType(int currentPC, int resolvedPosition) {
+	for (int i = this.allLocalsCounter  - 1 ; i >= 0; i--) {
+		LocalVariableBinding localVariable = this.locals[i];
+		if (localVariable == null) continue;
+		if (resolvedPosition == localVariable.resolvedPosition) {
+			inits: for (int j = 0; j < localVariable.initializationCount; j++) {
+				int startPC = localVariable.initializationPCs[j << 1];
+				int endPC = localVariable.initializationPCs[(j << 1) + 1];
+				if (currentPC < startPC) {
+					continue inits;
+				} else if (endPC == -1) { // still live
+					// the current local is an active local
+					return localVariable.type;
+				} else if (currentPC < endPC) {
+					// the current local is an active local
+					return localVariable.type;
+				}
+			}
+		}
+	}
+	return null;
+}
+private void pushTypeBinding(int resolvedPosition) {
+	if (!isSwitchStackTrackingActive())
+		return;
+	assert resolvedPosition < this.maxLocals;
+	TypeBinding type = retrieveLocalType(this.position, resolvedPosition);
+	if (type == null && resolvedPosition == 0 && !this.methodDeclaration.isStatic()) {
+		type = this.methodDeclaration.binding.declaringClass; // thisReference.resolvedType
+	}
+	assert type != null;
+	pushTypeBinding(type);
+}
+private void pushTypeBindingArray() {
+	if (!isSwitchStackTrackingActive())
+		return;
+	assert this.switchSaveTypeBindings.size() >= 2; // atleast arrayref and index in the typebinding stack
+	TypeBinding[] arrayref_t = {popTypeBinding()/* index */, popTypeBinding()/* arrayref */};
+	TypeBinding type = arrayref_t[1]; // arrayref
+	assert type instanceof ArrayBinding;
+	pushTypeBinding(((ArrayBinding) type).leafComponentType);
+}
+private TypeBinding getPopularBinding(char[] typeName) {
+	Scope scope = this.classFile.referenceBinding.scope;
+	assert scope != null;
+	Supplier<ReferenceBinding> finder = scope.getCommonReferenceBinding(typeName);
+	return finder != null ? finder.get() : TypeBinding.NULL;
+}
+
+private void pushTypeBinding(char[] typeName) {
+	if (!isSwitchStackTrackingActive())
+		return;
+	pushTypeBinding(getPopularBinding(typeName));
+}
+private void pushTypeBinding(TypeBinding typeBinding) {
+	if (isSwitchStackTrackingActive()) {
+		assert typeBinding != null;
+		this.switchSaveTypeBindings.push(typeBinding);
+	}
+}
+private void pushTypeBinding(int nPop, TypeBinding typeBinding) {
+	if (!isSwitchStackTrackingActive())
+		return;
+	popTypeBinding(nPop);
+	pushTypeBinding(typeBinding);
+}
+private TypeBinding popTypeBinding() {
+	return isSwitchStackTrackingActive() ? this.switchSaveTypeBindings.pop() : null;
+}
+private void popTypeBinding(int nPop) {
+	if (!isSwitchStackTrackingActive())
+		return;
+	for (int i = 0; i< nPop; ++i)
+		popTypeBinding();
+}
+private void clearTypeBindingStack() {
+	if (!isSwitchStackTrackingActive())
+		return;
+	this.switchSaveTypeBindings.clear();
+}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java
index 700a70d..3141451 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/ConstantPool.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -11,7 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Jesper S Moller - Contributions for
- *							Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335        
+ *							Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335
  *							Bug 406982 - [1.8][compiler] Generation of MethodParameters Attribute in classfile
  *							Bug 416885 - [1.8][compiler]IncompatibleClassChange error (edit)
  *							Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable
@@ -275,7 +275,7 @@
 	public static final char[] METAFACTORY = "metafactory".toCharArray(); //$NON-NLS-1$
 	public static final char[] JAVA_LANG_INVOKE_LAMBDAMETAFACTORY_METAFACTORY_SIGNATURE = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;".toCharArray(); //$NON-NLS-1$
 	public static final char[] ALTMETAFACTORY = "altMetafactory".toCharArray(); //$NON-NLS-1$
-	public static final char[] JAVA_LANG_INVOKE_LAMBDAMETAFACTORY_ALTMETAFACTORY_SIGNATURE = 
+	public static final char[] JAVA_LANG_INVOKE_LAMBDAMETAFACTORY_ALTMETAFACTORY_SIGNATURE =
 			"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;".toCharArray(); //$NON-NLS-1$
 	public static final char[] JavaLangInvokeSerializedLambda = "Ljava/lang/invoke/SerializedLambda;".toCharArray(); //$NON-NLS-1$
 	public static final char[] JavaLangInvokeSerializedLambdaConstantPoolName = "java/lang/invoke/SerializedLambda".toCharArray(); //$NON-NLS-1$
@@ -299,14 +299,16 @@
 	public static final char[] JAVA_LANG_ANNOTATION_REPEATABLE = "Ljava/lang/annotation/Repeatable;".toCharArray(); //$NON-NLS-1$
 
 	public static final char[] HashCode = "hashCode".toCharArray(); //$NON-NLS-1$
-	public static final char[] HashCodeSignature = "()I".toCharArray(); //$NON-NLS-1$; 
+	public static final char[] HashCodeSignature = "()I".toCharArray(); //$NON-NLS-1$;
 	public static final char[] Equals = "equals".toCharArray(); //$NON-NLS-1$
-	public static final char[] EqualsSignature = "(Ljava/lang/Object;)Z".toCharArray(); //$NON-NLS-1$; 
+	public static final char[] EqualsSignature = "(Ljava/lang/Object;)Z".toCharArray(); //$NON-NLS-1$;
 	public static final char[] AddSuppressed = "addSuppressed".toCharArray(); //$NON-NLS-1$;
 	public static final char[] AddSuppressedSignature = "(Ljava/lang/Throwable;)V".toCharArray(); //$NON-NLS-1$
 	public static final char[] Clone = "clone".toCharArray(); //$NON-NLS-1$
 	public static final char[] CloneSignature = "()Ljava/lang/Object;".toCharArray(); //$NON-NLS-1$
-	
+	public static final char[] BOOTSTRAP = "bootstrap".toCharArray(); //$NON-NLS-1$
+	public static final char[] JAVA_LANG_RUNTIME_OBJECTMETHOD_BOOTSTRAP_SIGNATURE = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;".toCharArray(); //$NON-NLS-1$
+
 	/**
 	 * ConstantPool constructor comment.
 	 */
@@ -859,10 +861,10 @@
 			: binding.isStatic() ? MethodHandleRefKindInvokeStatic
 			: binding.isPrivate() ? MethodHandleRefKindInvokeSpecial
 			: MethodHandleRefKindInvokeVirtual;
-		
+
 		return literalIndexForMethodHandle(referenceKind, binding.declaringClass, binding.selector, binding.signature(), isInterface);
 	}
-	
+
 	public int literalIndexForMethodHandle(int referenceKind, TypeBinding declaringClass, char[] selector, char[] signature, boolean isInterface) {
 		int indexForMethod = literalIndexForMethod(declaringClass, selector, signature, isInterface);
 
@@ -872,7 +874,7 @@
 			// resize
 			System.arraycopy(this.offsets, 0, (this.offsets = new int[index * 2]), 0, length);
 		}
-		
+
 		this.offsets[index] = this.currentOffset;
 		writeU1(MethodHandleTag);
 		writeU1(referenceKind);
@@ -880,11 +882,29 @@
 
 		return index;
 	}
+	public int literalIndexForMethodHandleFieldRef(int referenceKind, char[] declaringClass, char[] name, char[] signature) {
+		assert referenceKind == MethodHandleRefKindGetField;
+		int indexForField = literalIndexForField(declaringClass, name, signature);
+
+		int index = this.currentIndex++;
+		int length = this.offsets.length;
+		if (length <= index) {
+			// resize
+			System.arraycopy(this.offsets, 0, (this.offsets = new int[index * 2]), 0, length);
+		}
+
+		this.offsets[index] = this.currentOffset;
+		writeU1(MethodHandleTag);
+		writeU1(referenceKind);
+		writeU2(indexForField);
+
+		return index;
+	}
 	public int literalIndexForMethodType(char[] descriptor) {
 		int signatureIndex = literalIndex(descriptor);
 
 		int index = this.currentIndex++;
-		
+
 		int length = this.offsets.length;
 		if (length <= index) {
 			// resize
@@ -1103,7 +1123,7 @@
 		}
 		return index;
 	}
-	
+
 	/**
 	 * @param bootstrapIndex the given bootstrap index
 	 * @param selector the given method selector
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MultiCatchExceptionLabel.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MultiCatchExceptionLabel.java
index c12f3e7..9ab7b3b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MultiCatchExceptionLabel.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/MultiCatchExceptionLabel.java
@@ -28,7 +28,7 @@
 	public MultiCatchExceptionLabel(CodeStream codeStream, TypeBinding exceptionType) {
 		super(codeStream, exceptionType);
 	}
-	
+
 	public void initialize(UnionTypeReference typeReference, Annotation [] annotations) {
 		TypeReference[] typeReferences = typeReference.typeReferences;
 		int length = typeReferences.length;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Opcodes.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Opcodes.java
index dfe0f08..e509d67 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Opcodes.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/Opcodes.java
@@ -10,9 +10,9 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *     Jesper S Moller - Contributions for
- *							Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335    
+ *							Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.codegen;
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java
index c2ef996..a0fc8e2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrame.java
@@ -129,7 +129,7 @@
 		return result;
 	}
 
-	private VerificationTypeInfo getCachedValue(Map<VerificationTypeInfo, VerificationTypeInfo> cache, VerificationTypeInfo value) {
+	private static VerificationTypeInfo getCachedValue(Map<VerificationTypeInfo, VerificationTypeInfo> cache, VerificationTypeInfo value) {
 		VerificationTypeInfo cachedValue = value;
 		if (value != null) {
 			if (value.tag == VerificationTypeInfo.ITEM_UNINITIALIZED || value.tag == VerificationTypeInfo.ITEM_UNINITIALIZED_THIS) {
@@ -393,7 +393,7 @@
 		return 0;
 	}
 
-	private boolean equals(VerificationTypeInfo info, VerificationTypeInfo info2) {
+	private static boolean equals(VerificationTypeInfo info, VerificationTypeInfo info2) {
 		if (info == null) {
 			return info2 == null;
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java
index 3e44c49..0a4337b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/StackMapFrameCodeStream.java
@@ -213,7 +213,7 @@
 			/*
 			 * Macro for building a class descriptor object... using or not a field cache to store it into... this
 			 * sequence is responsible for building the actual class descriptor.
-			 * 
+			 *
 			 * If the fieldCache is set, then it is supposed to be the body of a synthetic access method factoring the
 			 * actual descriptor creation out of the invocation site (saving space). If the fieldCache is nil, then we
 			 * are dumping the bytecode on the invocation site, since we have no way to get a hand on the field cache to
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/TypeAnnotationCodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/TypeAnnotationCodeStream.java
index 6d9e5a6..4476515 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/TypeAnnotationCodeStream.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/TypeAnnotationCodeStream.java
@@ -39,11 +39,11 @@
 		this.generateAttributes |= ClassFileConstants.ATTR_TYPE_ANNOTATION;
 		this.allTypeAnnotationContexts = new ArrayList();
 	}
-	
+
 	private void addAnnotationContext(TypeReference typeReference, int info, int targetType, ArrayAllocationExpression allocationExpression) {
 		allocationExpression.getAllAnnotationContexts(targetType, info, this.allTypeAnnotationContexts);
 	}
-	
+
 	private void addAnnotationContext(TypeReference typeReference, int info, int targetType) {
 		typeReference.getAllAnnotationContexts(targetType, info, this.allTypeAnnotationContexts);
 	}
@@ -51,7 +51,7 @@
 	private void addAnnotationContext(TypeReference typeReference, int info, int typeIndex, int targetType) {
 		typeReference.getAllAnnotationContexts(targetType, info, typeIndex, this.allTypeAnnotationContexts);
 	}
-	
+
 	@Override
 	public void instance_of(TypeReference typeReference, TypeBinding typeBinding) {
 		if (typeReference != null && (typeReference.bits & ASTNode.HasTypeAnnotations) != 0) {
@@ -59,7 +59,7 @@
 		}
 		super.instance_of(typeReference, typeBinding);
 	}
-	
+
 	@Override
 	public void multianewarray(
 			TypeReference typeReference,
@@ -79,7 +79,7 @@
 		}
 		super.new_(typeReference, typeBinding);
 	}
-	
+
 	@Override
 	public void newArray(TypeReference typeReference, ArrayAllocationExpression allocationExpression, ArrayBinding arrayBinding) {
 		if (typeReference != null && (typeReference.bits & ASTNode.HasTypeAnnotations) != 0) {
@@ -87,7 +87,7 @@
 		}
 		super.newArray(typeReference, allocationExpression, arrayBinding);
 	}
-	
+
 	@Override
 	public void checkcast(TypeReference typeReference, TypeBinding typeBinding, int currentPosition) {
 		/* We use a slightly sub-optimal generation for intersection casts by resorting to a runtime cast for every intersecting type, but in
@@ -116,7 +116,7 @@
 			super.checkcast(null, typeBinding, currentPosition);
 		}
 	}
-	
+
 	@Override
 	public void invoke(byte opcode, MethodBinding methodBinding, TypeBinding declaringClass, TypeReference[] typeArguments) {
 		if (typeArguments != null) {
@@ -132,10 +132,11 @@
 		}
 		super.invoke(opcode, methodBinding, declaringClass, typeArguments);
 	}
-	
+
 	@Override
-	public void invokeDynamic(int bootStrapIndex, int argsSize, int returnTypeSize, char[] selector, char[] signature, 
-			boolean isConstructorReference, TypeReference lhsTypeReference, TypeReference [] typeArguments) {
+	public void invokeDynamic(int bootStrapIndex, int argsSize, int returnTypeSize, char[] selector, char[] signature,
+			boolean isConstructorReference, TypeReference lhsTypeReference, TypeReference [] typeArguments,
+			int typeId, TypeBinding type) {
 		if (lhsTypeReference != null && (lhsTypeReference.bits & ASTNode.HasTypeAnnotations) != 0) {
 			if (isConstructorReference) {
 				addAnnotationContext(lhsTypeReference, this.position, 0, AnnotationTargetTypeConstants.CONSTRUCTOR_REFERENCE);
@@ -144,7 +145,7 @@
 			}
 		}
 		if (typeArguments != null) {
-			int targetType = 
+			int targetType =
 					isConstructorReference
 					? AnnotationTargetTypeConstants.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
 					: AnnotationTargetTypeConstants.METHOD_REFERENCE_TYPE_ARGUMENT;
@@ -155,7 +156,7 @@
 				}
 			}
 		}
-		super.invokeDynamic(bootStrapIndex, argsSize, returnTypeSize, selector, signature, isConstructorReference, lhsTypeReference, typeArguments);
+		super.invokeDynamic(bootStrapIndex, argsSize, returnTypeSize, selector, signature, isConstructorReference, lhsTypeReference, typeArguments, typeId, type);
 	}
 
 	@Override
@@ -163,7 +164,7 @@
 		super.reset(givenClassFile);
 		this.allTypeAnnotationContexts = new ArrayList();
 	}
-	
+
 	@Override
 	public void init(ClassFile targetClassFile) {
 		super.init(targetClassFile);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/VerificationTypeInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/VerificationTypeInfo.java
index d3afd5b..c2e2244 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/VerificationTypeInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/VerificationTypeInfo.java
@@ -25,55 +25,55 @@
 public class VerificationTypeInfo {
 	/**
 	 * The tag value representing top variable info
-	 * 
+	 *
 	 * @since 3.2
 	 */
 	public static final int ITEM_TOP = 0;
 	/**
 	 * The tag value representing integer variable info
-	 * 
+	 *
 	 * @since 3.2
 	 */
 	public static final int ITEM_INTEGER = 1;
 	/**
 	 * The tag value representing float variable info
-	 * 
+	 *
 	 * @since 3.2
 	 */
 	public static final int ITEM_FLOAT = 2;
 	/**
 	 * The tag value representing double variable info
-	 * 
+	 *
 	 * @since 3.2
 	 */
 	public static final int ITEM_DOUBLE = 3;
 	/**
 	 * The tag value representing long variable info
-	 * 
+	 *
 	 * @since 3.2
 	 */
 	public static final int ITEM_LONG = 4;
 	/**
 	 * The tag value representing null variable info
-	 * 
+	 *
 	 * @since 3.2
 	 */
 	public static final int ITEM_NULL = 5;
 	/**
 	 * The tag value representing uninitialized this variable info
-	 * 
+	 *
 	 * @since 3.2
 	 */
 	public static final int ITEM_UNINITIALIZED_THIS = 6;
 	/**
 	 * The tag value representing object variable info
-	 * 
+	 *
 	 * @since 3.2
 	 */
 	public static final int ITEM_OBJECT = 7;
 	/**
 	 * The tag value representing uninitialized variable info
-	 * 
+	 *
 	 * @since 3.2
 	 */
 	public static final int ITEM_UNINITIALIZED = 8;
@@ -195,14 +195,16 @@
 	public boolean equals(Object obj) {
 		if (obj instanceof VerificationTypeInfo) {
 			VerificationTypeInfo info1 = (VerificationTypeInfo) obj;
-			return info1.tag == this.tag && CharOperation.equals(info1.constantPoolName(), constantPoolName());
+			return info1.tag == this.tag
+					&& info1.offset == this.offset
+					&& CharOperation.equals(info1.constantPoolName(), constantPoolName());
 		}
 		return false;
 	}
 
 	@Override
 	public int hashCode() {
-		return this.tag + this.id + this.binding.constantPoolName().length;
+		return this.tag + this.offset + CharOperation.hashCode(constantPoolName());
 	}
 
 	public char[] constantPoolName() {
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 815bc96..3a624ed 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
@@ -84,7 +84,7 @@
 	 * Determine the automatic module name if no "Automatic-Module-Name" was found in the Manifest, as specified in
 	 * {@link <a href=
 	 * "http://download.java.net/java/jdk9/docs/api/java/lang/module/ModuleFinder.html#of-java.nio.file.Path...-">ModuleFinder.of</a>}
-	 * 
+	 *
 	 * @param name
 	 *            the filename (or directory name)
 	 * @param skipDirectory
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryTypeAnnotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryTypeAnnotation.java
index 2038cbc..1910b75 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryTypeAnnotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IBinaryTypeAnnotation.java
@@ -20,7 +20,7 @@
  * This represents class file information about an annotation instance.
  */
 public interface IBinaryTypeAnnotation {
-	
+
 	static int[] NO_TYPE_PATH = new int[0];
 
 /**
@@ -34,42 +34,42 @@
 int getTargetType();
 
 /**
- * 
+ *
  * @return the raw type path data, each pair of ints is a type path entry
  */
 int[] getTypePath();
 
 /**
  * Applicable for target type 0x10(CLASS_EXTENDS)
- * 
+ *
  * @return the supertype index. -1 (65535) for superclass, 0..n for superinterfaces
  */
 int getSupertypeIndex();
 
 /**
  * Applicable for target type 0x00(CLASS_TYPE_PARAMETER), 0x01(METHOD_TYPE_PARAMETER)
- * 
+ *
  * @return the type parameter index (0 based)
  */
 int getTypeParameterIndex();
 
 /**
  * Applicable for target type 0x11(CLASS_TYPE_PARAMETER_BOUND), 0x12(METHOD_TYPE_PARAMETER_BOUND)
- * 
+ *
  * @return the bound index
  */
 int getBoundIndex();
 
 /**
  * Applicable for target type 0x16(METHOD_FORMAL_PARAMETER)
- * 
+ *
  * @return the method formal parameter index
  */
 int getMethodFormalParameterIndex();
 
 /**
  * Applicable for target type 0x17(THROWS)
- * 
+ *
  * @return the throws type index
  */
 int getThrowsTypeIndex();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java
index a27574e..24bd52d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ICompilationUnit.java
@@ -18,7 +18,7 @@
 
 /**
  * This interface denotes a compilation unit, providing its name and content.
- * 
+ *
  * <p>
  * Note: This internal interface has been implemented illegally by the
  * org.apache.jasper.glassfish bundle from Orbit, see
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IComponent.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IComponent.java
new file mode 100644
index 0000000..c3f6f09
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IComponent.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2019 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.env;
+
+public interface IComponent {
+/**
+ * Answer the runtime visible and invisible annotations for this component or null if none.
+ */
+IBinaryAnnotation[] getAnnotations();
+
+/**
+ * Answer the runtime visible and invisible type annotations for this component or null if none.
+ */
+IBinaryTypeAnnotation[] getTypeAnnotations();
+
+/**
+ * Answer the receiver's componentSignature, which describes the component's type
+ * as specified in "4.7.9.1 Signatures" of the Java SE 8 VM spec.
+ */
+char[] getGenericSignature();
+
+/**
+ * Answer the name of the component.
+ */
+char[] getName();
+
+/**
+ * Answer the tagbits set according to the bits for annotations.
+ */
+long getTagBits();
+
+/**
+ * Answer the resolved name of the receiver's type in the
+ * class file format as specified in section 4.3.2 of the Java 2 VM spec.
+ *
+ * For example:
+ *   - java.lang.String is Ljava/lang/String;
+ *   - an int is I
+ *   - a 2 dimensional array of strings is [[Ljava/lang/String;
+ *   - an array of floats is [F
+ */
+char[] getTypeName();
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModule.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModule.java
index bd417f0..11998aa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModule.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModule.java
@@ -70,7 +70,7 @@
 		public char[] name();
 		char[][] with();
 	}
-	
+
 	public default boolean isAutomatic() {
 		return false;
 	}
@@ -92,32 +92,32 @@
 			public char[] name() {
 				return this.name;
 			}
-			
+
 			@Override
 			public IModuleReference[] requires() {
 				return IModule.NO_MODULE_REFS;
 			}
-			
+
 			@Override
 			public IPackageExport[] exports() {
 				return IModule.NO_EXPORTS;
 			}
-			
+
 			@Override
 			public char[][] uses() {
 				return IModule.NO_USES;
 			}
-			
+
 			@Override
 			public IService[] provides() {
 				return IModule.NO_PROVIDES;
 			}
-			
+
 			@Override
 			public IPackageExport[] opens() {
 				return NO_OPENS;
 			}
-			
+
 			@Override
 			public boolean isAutomatic() {
 				return true;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModuleAwareNameEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModuleAwareNameEnvironment.java
index 539caab..cbc554e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModuleAwareNameEnvironment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModuleAwareNameEnvironment.java
@@ -72,7 +72,7 @@
 		public <T> boolean matches(T elem, Predicate<T> isNamed) {
 			return matchesWithName(elem, isNamed, t -> true);
 		}
-		
+
 		/** Get the lookup strategy corresponding to the given module name. */
 		public static LookupStrategy get(char[] moduleName) {
 			if (moduleName == ModuleBinding.ANY)
@@ -91,7 +91,7 @@
 			}
 		}
 	}
-	
+
 	@Override
 	default NameEnvironmentAnswer findType(char[][] compoundTypeName) {
 		return findType(compoundTypeName, ModuleBinding.ANY);
@@ -121,7 +121,7 @@
 		return allNames;
 	}
 
-	
+
 	/**
 	 * Answer whether the given package (within the given module) contains any compilation unit.
 	 * @param qualifiedPackageName
@@ -129,7 +129,7 @@
 	 * @return true iff the package contains at least one compilation unit.
 	 */
 	boolean hasCompilationUnit(char[][] qualifiedPackageName, char[] moduleName, boolean checkCUs);
-	
+
 	/** Get the module with the given name, which must denote a named module. */
 	IModule getModule(char[] moduleName);
 	char[][] getAllAutomaticModules();
@@ -142,7 +142,7 @@
 	default void applyModuleUpdates(IUpdatableModule module, IUpdatableModule.UpdateKind kind) { /* default: do nothing */ }
 
 	/**
-	 * Lists all packages in the module identified by the given, real module name 
+	 * Lists all packages in the module identified by the given, real module name
 	 * (i.e., this method is implemented only for {@link LookupStrategy#Named}).
 	 * @param moduleName
 	 * @return array of flat, dot-separated package names
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModulePathEntry.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModulePathEntry.java
index 86f24f7..e5eb40c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModulePathEntry.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IModulePathEntry.java
@@ -25,18 +25,18 @@
 	/**
 	 * Get the module that this entry contributes. May be null, for instance when this entry does not
 	 * represent a single module
-	 * 
+	 *
 	 * @return The module that this entry contributes or null
 	 */
 	default IModule getModule() {
 		return null;
 	}
-	
+
 	/**
 	 * Get the module named name from this entry. May be null
-	 * 
+	 *
 	 * @param name - The name of the module to look up
-	 * 
+	 *
 	 * @return The module named name or null
 	 */
 	default IModule getModule(char[] name) {
@@ -48,9 +48,9 @@
 
 	/**
 	 * Indicates whether this entry knows the module named name and can answer queries regarding the module
-	 * 
+	 *
 	 * @param name The name of the module
-	 * 
+	 *
 	 * @return True if this entry knows the module, false otherwise
 	 */
 	default boolean servesModule(char[] name) {
@@ -84,7 +84,7 @@
 
 	/**
 	 * Specifies whether this entry represents an automatic module.
-	 * 
+	 *
 	 * @return true if this is an automatic module, false otherwise
 	 */
 	public default boolean isAutomaticModule() {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IMultiModuleEntry.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IMultiModuleEntry.java
index 1d48ff9..ca0b105 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IMultiModuleEntry.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/IMultiModuleEntry.java
@@ -23,7 +23,7 @@
 public interface IMultiModuleEntry extends IModulePathEntry {
 
 	/**
-	 * Get the module named name that this entry contributes to the module path 
+	 * Get the module named name that this entry contributes to the module path
 	 */
 
 	@Override
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/INameEnvironmentExtension.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/INameEnvironmentExtension.java
index 5fd1970..986fc82 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/INameEnvironmentExtension.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/INameEnvironmentExtension.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -18,10 +18,10 @@
  * can use to look up types, compilation units, and packages in the
  * current environment.  The name environment is passed to the compiler
  * on creation.
- * 
+ *
  * This name environment adds a method to switch on/off the search for secondary types.
  * Refer {@link #findType(char[], char[][], boolean)}.
- * 
+ *
  */
 public interface INameEnvironmentExtension extends INameEnvironment {
 	/**
@@ -48,7 +48,7 @@
 	 * @return {@link NameEnvironmentAnswer}
 	 */
 	NameEnvironmentAnswer findType(char[] typeName, char[][] packageName, boolean searchWithSecondaryTypes, char[] moduleName);
-	
+
 	default NameEnvironmentAnswer findType(char[] typeName, char[][] packageName, boolean searchWithSecondaryTypes) {
 		return findType(typeName, packageName, searchWithSecondaryTypes, null);
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ITypeAnnotationWalker.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ITypeAnnotationWalker.java
index cc846ad..7c3a783 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ITypeAnnotationWalker.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ITypeAnnotationWalker.java
@@ -18,7 +18,7 @@
  * A TypeAnnotationWalker is initialized with all type annotations found at a given element.
  * It can be used to walk into the types at the given element and finally answer the
  * actual annotations at any node of the walk.
- * 
+ *
  * The walker is implemented as immutable objects. During the walk either new instances
  * are created, or the current instance is shared if no difference is encountered.
  */
@@ -90,13 +90,13 @@
 
 	/**
 	 * Detail of {@link #toTypeParameterBounds(boolean, int)}: walk to the bounds
-	 * of the previously selected type parameter. 
+	 * of the previously selected type parameter.
 	 * @param boundIndex
 	 */
 	public abstract ITypeAnnotationWalker toTypeBound(short boundIndex);
 
 	/** Walk to the specified supertype either index based or name based:
-	 * @param index -1 is superclass, else index into the list of superinterfaces 
+	 * @param index -1 is superclass, else index into the list of superinterfaces
 	 * @param superTypeSignature name and type arguments of the super type to visit
 	 */
 	public abstract ITypeAnnotationWalker toSupertype(short index, char[] superTypeSignature);
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 0704eef..82e3bd1 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
@@ -45,15 +45,15 @@
 		public void accept(IUpdatableModule t) {
 			t.addExports(this.name, this.targets);
 		}
-		
+
 		public char[] getName() {
 			return this.name;
 		}
-		
+
 		public char[][] getTargetModules() {
 			return this.targets;
 		}
-		
+
 		public UpdateKind getKind() {
 			return UpdateKind.PACKAGE;
 		}
@@ -62,7 +62,7 @@
 			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))
@@ -80,11 +80,11 @@
 			return hash;
 		}
 	}
-	
+
 	class AddReads implements Consumer<IUpdatableModule> {
 
 		char[] targetModule;
-		
+
 		public AddReads(char[] target) {
 			this.targetModule = target;
 		}
@@ -93,11 +93,11 @@
 			// TODO Auto-generated method stub
 			t.addReads(this.targetModule);
 		}
-		
+
 		public char[] getTarget() {
 			return this.targetModule;
 		}
-		
+
 		public UpdateKind getKind() {
 			return UpdateKind.MODULE;
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ModuleReferenceImpl.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ModuleReferenceImpl.java
index 6af1a82..cdc6958 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ModuleReferenceImpl.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/ModuleReferenceImpl.java
@@ -24,7 +24,7 @@
 	}
 	@Override
 	public boolean equals(Object o) {
-		if (this == o) 
+		if (this == o)
 			return true;
 		if (!(o instanceof IModule.IModuleReference))
 			return false;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java
index b11078d..6f6496c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/env/NameEnvironmentAnswer.java
@@ -55,7 +55,7 @@
 		this.externalAnnotationPath = externalAnnotationPath;
 		this.moduleName = module;
 	}
-	
+
 	public NameEnvironmentAnswer(ReferenceBinding binding, ModuleBinding module) {
 		this.binding = binding;
 		this.moduleBinding = module;
@@ -86,7 +86,7 @@
 		}
 		return baseString;
 	}
-	
+
 	/**
 	 * Returns the associated access restriction, or null if none.
 	 */
@@ -167,10 +167,10 @@
 	public boolean ignoreIfBetter() {
 		return this.accessRestriction != null && this.accessRestriction.ignoreIfBetter();
 	}
-	
-	/** 
+
+	/**
 	 * Name of the module to which the CU in this answer is associated.
-	 * {@code null} when associated to the unnamed module. 
+	 * {@code null} when associated to the unnamed module.
 	 * @return module name or {@code null}
 	 */
 	public char[] moduleName() {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
index 256bb09..51fcfcb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
@@ -121,7 +121,7 @@
 
 @Override
 public boolean hasNullInfoFor(LocalVariableBinding local) {
-	return this.initsWhenTrue.hasNullInfoFor(local) 
+	return this.initsWhenTrue.hasNullInfoFor(local)
 			|| this.initsWhenFalse.hasNullInfoFor(local);
 }
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
index 735326b..76e0eab 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -19,6 +19,8 @@
 package org.eclipse.jdt.internal.compiler.flow;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
@@ -50,15 +52,15 @@
 	int[] isReached;
 	int[] isNeeded;
 	// WARNING: This is an array that maps to catch blocks, not caught exceptions (which could be more than catch blocks in a multi-catch block)
-	UnconditionalFlowInfo[] initsOnExceptions; 
+	UnconditionalFlowInfo[] initsOnExceptions;
 	ObjectCache indexes = new ObjectCache();
 	boolean isMethodContext;
 
 	public UnconditionalFlowInfo initsOnReturn;
 	public FlowContext initializationParent; // special parent relationship only for initialization purpose
-	
+
 	// for dealing with anonymous constructor thrown exceptions
-	public ArrayList extendedExceptions;
+	public List extendedExceptions;
 
 	private static final Argument[] NO_ARGUMENTS = new Argument[0];
 	public  Argument [] catchArguments;
@@ -82,11 +84,10 @@
 		FlowContext initializationParent,
 		BlockScope scope,
 		FlowInfo flowInfo) {
-	this(parent, tryStatement, handledExceptions, exceptionToCatchBlockMap, 
+	this(parent, tryStatement, handledExceptions, exceptionToCatchBlockMap,
 			tryStatement.catchArguments, initializationParent, scope, flowInfo.unconditionalInits());
 	UnconditionalFlowInfo unconditionalCopy = flowInfo.unconditionalCopy();
-	unconditionalCopy.iNBit = -1L;
-	unconditionalCopy.iNNBit = -1L;
+	unconditionalCopy.acceptAllIncomingNullness();
 	unconditionalCopy.tagBits |= FlowInfo.UNROOTED;
 	this.initsOnFinally = unconditionalCopy;
 }
@@ -189,7 +190,7 @@
 	}
 }
 
-private ASTNode getExceptionType(int index) {	
+private ASTNode getExceptionType(int index) {
 	if (this.exceptionToCatchBlockMap == null) {
 		return this.catchArguments[index].type;
 	}
@@ -200,8 +201,8 @@
 		for (int i = 0, len = typeRefs.length; i < len; i++) {
 			TypeReference typeRef = typeRefs[i];
 			if (TypeBinding.equalsEquals(typeRef.resolvedType, this.handledExceptions[index])) return typeRef;
-		}	
-	} 
+		}
+	}
 	return node;
 }
 
@@ -251,10 +252,7 @@
  */
 public void mergeUnhandledException(TypeBinding newException){
 	if (this.extendedExceptions == null){
-		this.extendedExceptions = new ArrayList(5);
-		for (int i = 0; i < this.handledExceptions.length; i++){
-			this.extendedExceptions.add(this.handledExceptions[i]);
-		}
+		this.extendedExceptions = new ArrayList<>(Arrays.asList(this.handledExceptions));
 	}
 	boolean isRedundant = false;
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java
index e763088..cd07575 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -27,6 +27,7 @@
 
 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
 import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
 import org.eclipse.jdt.internal.compiler.ast.Reference;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
@@ -52,6 +53,7 @@
 	ASTNode[] nullReferences;	// Expressions for null checking, Statements for resource analysis
 								// cast to Expression is safe if corresponding nullCheckType != EXIT_RESOURCE
 	int[] nullCheckTypes;
+	NullAnnotationMatching[] nullAnnotationStatuses;
 	int nullCount;
 	// see also the related field FlowContext#expectedTypes
 
@@ -210,11 +212,19 @@
 					int nullStatus = flowInfo.nullStatus(local);
 					if (nullStatus != FlowInfo.NON_NULL) {
 						char[][] annotationName = scope.environment().getNonNullAnnotationName();
-						scope.problemReporter().nullityMismatch((Expression) location, this.providedExpectedTypes[i][0], this.providedExpectedTypes[i][1], nullStatus, annotationName);
+						TypeBinding providedType = this.providedExpectedTypes[i][0];
+						TypeBinding expectedType = this.providedExpectedTypes[i][1];
+						Expression expression2 = (Expression) location;
+						if (this.nullAnnotationStatuses[i] != null) {
+							this.nullAnnotationStatuses[i] = this.nullAnnotationStatuses[i].withNullStatus(nullStatus);
+							scope.problemReporter().nullityMismatchingTypeAnnotation(expression2, providedType, expectedType, this.nullAnnotationStatuses[i]);
+						} else {
+							scope.problemReporter().nullityMismatch(expression2, providedType, expectedType, nullStatus, annotationName);
+						}
 					}
 					break;
 				case IN_UNBOXING:
-					checkUnboxing(scope, (Expression) location, flowInfo);	
+					checkUnboxing(scope, (Expression) location, flowInfo);
 					break;
 				default:
 					// should not happen
@@ -449,12 +459,13 @@
 	}
 
 @Override
-protected void recordNullReference(LocalVariableBinding local,
-	ASTNode expression, int checkType, FlowInfo nullInfo) {
+protected void recordNullReferenceWithAnnotationStatus(LocalVariableBinding local,
+	ASTNode expression, int checkType, FlowInfo nullInfo, NullAnnotationMatching nullAnnotationStatus) {
 	if (this.nullCount == 0) {
 		this.nullLocals = new LocalVariableBinding[5];
 		this.nullReferences = new ASTNode[5];
 		this.nullCheckTypes = new int[5];
+		this.nullAnnotationStatuses = new NullAnnotationMatching[5];
 	}
 	else if (this.nullCount == this.nullLocals.length) {
 		int newLength = this.nullCount * 2;
@@ -467,9 +478,13 @@
 		System.arraycopy(this.nullCheckTypes, 0,
 			this.nullCheckTypes = new int[newLength], 0,
 			this.nullCount);
+		System.arraycopy(this.nullAnnotationStatuses, 0,
+			this.nullAnnotationStatuses = new NullAnnotationMatching[this.nullCount * 2], 0,
+			this.nullCount);
 	}
 	this.nullLocals[this.nullCount] = local;
 	this.nullReferences[this.nullCount] = expression;
+	this.nullAnnotationStatuses[this.nullCount] = nullAnnotationStatus;
 	this.nullCheckTypes[this.nullCount++] = checkType;
 }
 @Override
@@ -480,12 +495,12 @@
 		recordNullReference(null, expression, IN_UNBOXING, flowInfo);
 }
 @Override
-protected boolean internalRecordNullityMismatch(Expression expression, TypeBinding providedType, FlowInfo flowInfo, int nullStatus, TypeBinding expectedType, int checkType) {
+protected boolean internalRecordNullityMismatch(Expression expression, TypeBinding providedType, FlowInfo flowInfo, int nullStatus, NullAnnotationMatching nullAnnotationStatus, TypeBinding expectedType, int checkType) {
 	// cf. decision structure inside FinallyFlowContext.recordUsingNullReference(..)
 	if (nullStatus == FlowInfo.UNKNOWN ||
 			((this.tagBits & FlowContext.DEFER_NULL_DIAGNOSTIC) != 0 && nullStatus != FlowInfo.NULL)) {
 		recordProvidedExpectedTypes(providedType, expectedType, this.nullCount);
-		recordNullReference(expression.localVariableBinding(), expression, checkType, flowInfo);
+		recordNullReferenceWithAnnotationStatus(expression.localVariableBinding(), expression, checkType, flowInfo, nullAnnotationStatus);
 		return true;
 	}
 	return false;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
index 8d031f2..9871808 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -834,8 +834,33 @@
  *      Alternatively, a {@link #IN_UNBOXING} check can e requested.
  * @param nullInfo the null flow info observed at this first visit of location.
  */
-protected void recordNullReference(LocalVariableBinding local,
+protected final void recordNullReference(LocalVariableBinding local,
 	ASTNode location, int checkType, FlowInfo nullInfo) {
+	recordNullReferenceWithAnnotationStatus(local, location, checkType, nullInfo, null);
+}
+
+/**
+ * Record a null reference for use by deferred checks. Only looping or
+ * finally contexts really record that information. Other contexts
+ * immediately check for unboxing.
+ * @param local the local variable involved in the check
+ * @param location the location triggering the analysis, for normal null dereference
+ *      this is an expression resolving to 'local', for resource leaks it is an
+ *      early exit statement.
+ * @param checkType the checkType against which the check must be performed; one of
+ * 		{@link #CAN_ONLY_NULL CAN_ONLY_NULL}, {@link #CAN_ONLY_NULL_NON_NULL
+ * 		CAN_ONLY_NULL_NON_NULL}, {@link #MAY_NULL MAY_NULL},
+ *      {@link #CAN_ONLY_NON_NULL CAN_ONLY_NON_NULL}, potentially
+ *      combined with a context indicator (one of {@link #IN_COMPARISON_NULL},
+ *      {@link #IN_COMPARISON_NON_NULL}, {@link #IN_ASSIGNMENT} or {@link #IN_INSTANCEOF}).
+ *      <br>
+ *      Alternatively, a {@link #IN_UNBOXING} check can e requested.
+ * @param nullInfo the null flow info observed at this first visit of location.
+ * @param nullAnnotationStatus if null annotations are analysed this may hold more information
+ * 		about the exact kind of problem, can be <code>null</code>
+ */
+protected void recordNullReferenceWithAnnotationStatus(LocalVariableBinding local,
+	ASTNode location, int checkType, FlowInfo nullInfo, NullAnnotationMatching nullAnnotationStatus) {
 	// default implementation: do nothing
 }
 
@@ -1068,7 +1093,7 @@
 			if ((this.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
 				isInsideAssert = FlowContext.HIDE_NULL_COMPARISON_WARNING;
 			}
-			if (currentContext.internalRecordNullityMismatch(expression, providedType, flowInfo, nullStatus, expectedType, ASSIGN_TO_NONNULL | isInsideAssert))
+			if (currentContext.internalRecordNullityMismatch(expression, providedType, flowInfo, nullStatus, annotationStatus, expectedType, ASSIGN_TO_NONNULL | isInsideAssert))
 				return;
 			currentContext = currentContext.parent;
 		}
@@ -1080,7 +1105,7 @@
 		currentScope.problemReporter().nullityMismatch(expression, providedType, expectedType, nullStatus,
 														currentScope.environment().getNonNullAnnotationName());
 }
-protected boolean internalRecordNullityMismatch(Expression expression, TypeBinding providedType, FlowInfo flowInfo, int nullStatus, TypeBinding expectedType, int checkType) {
+protected boolean internalRecordNullityMismatch(Expression expression, TypeBinding providedType, FlowInfo flowInfo, int nullStatus, NullAnnotationMatching nullAnnotationStatus, TypeBinding expectedType, int checkType) {
 	// nop, to be overridden in subclasses
 	return false; // not recorded
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
index e45954b..00ba8d8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
@@ -10,7 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for 
+ *     Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for
  *			     				bug 292478 - Report potentially null across variable assignment
  *     							bug 332637 - Dead Code detection removing code that isn't dead
  *								bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional
@@ -29,9 +29,9 @@
 
 	public int tagBits; // REACHABLE by default
 	public final static int REACHABLE = 0;
-	/* unreachable code 
+	/* unreachable code
 	 * eg. while (true);
-	 *     i++;  --> unreachable code 
+	 *     i++;  --> unreachable code
 	 */
 	public final static int UNREACHABLE_OR_DEAD = 1;
 	/* unreachable code as inferred by null analysis
@@ -46,7 +46,7 @@
 	 */
 	public final static int UNREACHABLE = UNREACHABLE_OR_DEAD | UNREACHABLE_BY_NULLANALYSIS;
 	public final static int NULL_FLAG_MASK = 4;
-	
+
 	public final static int UNKNOWN = 1;
 	public final static int NULL = 2;
 	public final static int NON_NULL = 4;
@@ -55,7 +55,7 @@
 	public final static int POTENTIALLY_NON_NULL = 32;
 
 	public final static int UNROOTED = 64; // marks a flowInfo that may be appended to another flowInfo (accepting incoming nulls/nonnulls, see UFI.iNBit/iNNBit).
-	
+
 	public static final int FREE_TYPEVARIABLE = FlowInfo.POTENTIALLY_NULL | FlowInfo.POTENTIALLY_NON_NULL;
 
 	public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization
@@ -542,7 +542,7 @@
 		// if a variable is only initialized in one branch and not initialized in the other,
 		// then we need to cast a doubt on its initialization in the merged info
 		mergedInfo.mergeDefiniteInitsWith(initsWhenFalse.unconditionalCopy());
-		
+
 		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=415997, classify unreachability precisely, IsElseStatementUnreachable could be due to null analysis
 		if ((mergedInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 && (initsWhenFalse.tagBits & FlowInfo.UNREACHABLE) == FlowInfo.UNREACHABLE_BY_NULLANALYSIS) {
 			mergedInfo.tagBits &= ~UNREACHABLE_OR_DEAD;
@@ -556,7 +556,7 @@
 		// true or false (i.e if(true), etc) for sure
 		// We don't do this if both if and else branches themselves are in an unreachable code
 		// or if any of them is a DEAD_END (e.g. contains 'return' or 'throws')
-		mergedInfo = 
+		mergedInfo =
 			initsWhenFalse.addPotentialInitializationsFrom(initsWhenTrue.
 				nullInfoLessUnconditionalCopy()).
 			unconditionalInits();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InitializationFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InitializationFlowContext.java
index 75202b0..5d2f440 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InitializationFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/InitializationFlowContext.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -29,7 +29,7 @@
 	public ASTNode[] exceptionThrowers = new ASTNode[5];
 	public FlowInfo[] exceptionThrowerFlowInfos = new FlowInfo[5];
 	public FlowInfo	initsBeforeContext;
-	
+
 	public InitializationFlowContext(FlowContext parent, ASTNode associatedNode, FlowInfo initsBeforeContext, FlowContext initializationParent, BlockScope scope) {
 		super(
 			parent,
@@ -58,7 +58,7 @@
 	public FlowContext getInitializationContext() {
 		return this;
 	}
-	
+
 	@Override
 	public String individualToString() {
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
index 82f40c8..f8af489 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - contributions for
@@ -37,6 +37,7 @@
 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
 import org.eclipse.jdt.internal.compiler.ast.Expression;
 import org.eclipse.jdt.internal.compiler.ast.FakedTrackingVariable;
+import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
 import org.eclipse.jdt.internal.compiler.ast.Reference;
 import org.eclipse.jdt.internal.compiler.codegen.BranchLabel;
 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
@@ -75,6 +76,7 @@
 								// cast to Expression is safe if corresponding nullCheckType != EXIT_RESOURCE
 	int[] nullCheckTypes;
 	UnconditionalFlowInfo[] nullInfos;	// detailed null info observed during the first visit of nullReferences[i], or null
+	NullAnnotationMatching[] nullAnnotationStatuses;
 	int nullCount;
 	// see also the related field FlowContext#expectedTypes
 
@@ -274,7 +276,7 @@
 								}
 								break;
 						}
-					}	
+					}
 					break;
 				case MAY_NULL:
 					if (flowInfo.isDefinitelyNull(local)) {
@@ -408,7 +410,15 @@
 					int nullStatus = flowInfo.nullStatus(local);
 					if (nullStatus != FlowInfo.NON_NULL) {
 						char[][] annotationName = scope.environment().getNonNullAnnotationName();
-						scope.problemReporter().nullityMismatch((Expression) location, this.providedExpectedTypes[i][0], this.providedExpectedTypes[i][1], nullStatus, annotationName);
+						TypeBinding providedType = this.providedExpectedTypes[i][0];
+						TypeBinding expectedType = this.providedExpectedTypes[i][1];
+						Expression expression2 = (Expression) location;
+						if (this.nullAnnotationStatuses[i] != null) {
+							this.nullAnnotationStatuses[i] = this.nullAnnotationStatuses[i].withNullStatus(nullStatus);
+							scope.problemReporter().nullityMismatchingTypeAnnotation(expression2, providedType, expectedType, this.nullAnnotationStatuses[i]);
+						} else {
+							scope.problemReporter().nullityMismatch(expression2, providedType, expectedType, nullStatus, annotationName);
+						}
 					}
 					break;
 				case EXIT_RESOURCE:
@@ -497,7 +507,7 @@
 		FlowContext inner = innerFlowContext;
 		while (inner != this && !(inner instanceof LoopingFlowContext)) {
 			inner = inner.parent;
-			// we know that inner is reachable from this without crossing a type boundary 
+			// we know that inner is reachable from this without crossing a type boundary
 		}
 		if (inner == this) {
 			this.upstreamNullFlowInfo.
@@ -563,13 +573,14 @@
 	}
 
 @Override
-protected void recordNullReference(LocalVariableBinding local,
-	ASTNode expression, int checkType, FlowInfo nullInfo) {
+protected void recordNullReferenceWithAnnotationStatus(LocalVariableBinding local,
+	ASTNode expression, int checkType, FlowInfo nullInfo, NullAnnotationMatching nullAnnotationStatus) {
 	if (this.nullCount == 0) {
 		this.nullLocals = new LocalVariableBinding[5];
 		this.nullReferences = new ASTNode[5];
 		this.nullCheckTypes = new int[5];
 		this.nullInfos = new UnconditionalFlowInfo[5];
+		this.nullAnnotationStatuses = new NullAnnotationMatching[5];
 	}
 	else if (this.nullCount == this.nullLocals.length) {
 		System.arraycopy(this.nullLocals, 0,
@@ -580,10 +591,13 @@
 			this.nullCheckTypes = new int[this.nullCount * 2], 0, this.nullCount);
 		System.arraycopy(this.nullInfos, 0,
 			this.nullInfos = new UnconditionalFlowInfo[this.nullCount * 2], 0, this.nullCount);
+		System.arraycopy(this.nullAnnotationStatuses, 0,
+			this.nullAnnotationStatuses = new NullAnnotationMatching[this.nullCount * 2], 0, this.nullCount);
 	}
 	this.nullLocals[this.nullCount] = local;
 	this.nullReferences[this.nullCount] = expression;
 	this.nullCheckTypes[this.nullCount] = checkType;
+	this.nullAnnotationStatuses[this.nullCount] = nullAnnotationStatus;
 	this.nullInfos[this.nullCount++] = nullInfo != null ? nullInfo.unconditionalCopy() : null;
 }
 @Override
@@ -781,9 +795,9 @@
 	}
 
 	@Override
-	protected boolean internalRecordNullityMismatch(Expression expression, TypeBinding providedType, FlowInfo flowInfo, int nullStatus, TypeBinding expectedType, int checkType) {
+	protected boolean internalRecordNullityMismatch(Expression expression, TypeBinding providedType, FlowInfo flowInfo, int nullStatus, NullAnnotationMatching nullAnnotationStatus, TypeBinding expectedType, int checkType) {
 		recordProvidedExpectedTypes(providedType, expectedType, this.nullCount);
-		recordNullReference(expression.localVariableBinding(), expression, checkType, flowInfo);
+		recordNullReferenceWithAnnotationStatus(expression.localVariableBinding(), expression, checkType, flowInfo, nullAnnotationStatus);
 		return true;
 	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java
index 32d9cee..4df6bbf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/TryFlowContext.java
@@ -30,7 +30,7 @@
 	public TryFlowContext(FlowContext parent, ASTNode associatedNode) {
 		super(parent, associatedNode, true);
 	}
-	
+
 	@Override
 	public void markFinallyNullStatus(LocalVariableBinding local, int nullStatus) {
 		if (this.outerTryContext != null) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
index be247db..2c2bc23 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -88,7 +88,7 @@
 		1110	prot. null
 		1111	prot. non null
  */
-	public long 
+	public long
 		iNBit,	// can an incoming null value reach the current point?
 		iNNBit;	// can an incoming nonnull value reach the current point?
 
@@ -110,12 +110,12 @@
 	public static final int IN = 6;
 	public static final int INN = 7;
 
-/* fakeInitializedFlowInfo: For Lambda expressions tentative analysis during overload resolution. 
-   We presume that any and all outer locals touched by the lambda are definitely assigned and 
+/* fakeInitializedFlowInfo: For Lambda expressions tentative analysis during overload resolution.
+   We presume that any and all outer locals touched by the lambda are definitely assigned and
    effectively final. Whether they are or not is immaterial for overload analysis (errors encountered
-   in the body are not supposed to influence the resolution. It is pertinent only for the eventual 
+   in the body are not supposed to influence the resolution. It is pertinent only for the eventual
    resolution/analysis post overload resolution. For lambda's the problem is that we start the control/data
-   flow analysis abruptly at the start of the lambda, so we need to present a cogent world view and hence 
+   flow analysis abruptly at the start of the lambda, so we need to present a cogent world view and hence
    all this charade.
 */
 public static UnconditionalFlowInfo fakeInitializedFlowInfo(int localsCount, int maxFieldCount) {
@@ -147,7 +147,7 @@
 		// union of potentially set ones
 		this.potentialInits |= otherInits.potentialInits;
 	}
-	
+
 	// combine null information
 	boolean thisHadNulls = (this.tagBits & NULL_FLAG_MASK) != 0,
 		otherHasNulls = (otherInits.tagBits & NULL_FLAG_MASK) != 0;
@@ -182,7 +182,7 @@
 			long protNN1111 = a1&a2&a3&a4;
 
 			// filter 'a' using iNBit,iNNBit from otherInits:
-			// this implements that otherInit does not accept certain bits which are known to be superseded by info in otherInits.			
+			// this implements that otherInit does not accept certain bits which are known to be superseded by info in otherInits.
 			long acceptNonNull = otherInits.iNNBit;
 			long acceptNull = otherInits.iNBit
 								| protNN1111; // for 1111 don't bother suppressing incoming null, logic operation would produce wrong result
@@ -193,7 +193,7 @@
 			a3 = dontResetToStart & acceptNonNull & a3;
 			a4 &= dontResetToStart;
 			a1 &= (a2 | a3 | a4);		// translate 1000 (undefined state) to 0000
-			
+
 			this.nullBit1 = (b1 = otherInits.nullBit1)
                 				| a1 & (a3
                 					& a4 & (nb2 = ~(b2 = otherInits.nullBit2))
@@ -244,10 +244,7 @@
 				if ((length = this.extra[0].length) <
 						(otherLength = otherInits.extra[0].length)) {
 					// current storage is shorter -> grow current
-					for (int j = 0; j < extraLength; j++) {
-						System.arraycopy(this.extra[j], 0,
-							(this.extra[j] = new long[otherLength]), 0, length);
-					}
+					growSpace(otherLength, 0, length);
 					mergeLimit = length;
 					copyLimit = otherLength;
 					if (COVERAGE_TEST_FLAG) {
@@ -270,16 +267,21 @@
 			// shortcut regular copy because array copy is better
 			int otherLength;
 			this.extra = new long[extraLength][];
-			System.arraycopy(otherInits.extra[0], 0,
-				(this.extra[0] = new long[otherLength =
-					otherInits.extra[0].length]), 0, otherLength);
-			System.arraycopy(otherInits.extra[1], 0,
-				(this.extra[1] = new long[otherLength]), 0, otherLength);
+			this.extra[0] = new long[otherLength = otherInits.extra[0].length];
+			this.extra[1] = new long[otherLength];
+			if (handleInits) {
+				System.arraycopy(otherInits.extra[0], 0, this.extra[0], 0, otherLength);
+				System.arraycopy(otherInits.extra[1], 0, this.extra[1], 0, otherLength);
+			}
 			if (otherHasNulls) {
 				for (int j = 2; j < extraLength; j++) {
 					System.arraycopy(otherInits.extra[j], 0,
 						(this.extra[j] = new long[otherLength]), 0, otherLength);
 				}
+				if ((this.tagBits & UNROOTED) != 0) {
+					Arrays.fill(this.extra[IN], 0, otherLength, -1);
+					Arrays.fill(this.extra[INN], 0, otherLength, -1);
+				}
 				if (COVERAGE_TEST_FLAG) {
 					if (CoverageTestId == 5) {
 						this.extra[5][otherLength - 1] = ~0;
@@ -309,7 +311,7 @@
 			for (; i < copyLimit; i++) {
 				this.extra[0][i] = otherInits.extra[0][i];
 				this.extra[1][i] = otherInits.extra[1][i];
-			
+
 			}
 		}
 		// tweak limits for nulls
@@ -332,7 +334,7 @@
 			long protNN1111 = a1&a2&a3&a4;
 
 			// filter 'a' using iNBit,iNNBit from otherInits:
-			// this implements that otherInit does not accept certain bits which are known to be superseded by info in otherInits.			
+			// this implements that otherInit does not accept certain bits which are known to be superseded by info in otherInits.
 			long acceptNonNull = otherInits.extra[INN][i];
 			long acceptNull = otherInits.extra[IN][i]
 								| protNN1111; // for 1111 don't bother suppressing incoming null, logic operation would produce wrong result
@@ -345,7 +347,7 @@
 			a1 &= (a2 | a3 | a4);		// translate 1000 (undefined state) to 0000
 
 			this.extra[1 + 1][i] = (b1 = otherInits.extra[1 + 1][i])
-                				| a1 & (a3 
+                				| a1 & (a3
                 					& a4 & (nb2 = ~(b2 = otherInits.extra[2 + 1][i]))
                 					& (nb4 = ~(b4 = otherInits.extra[4 + 1][i]))
                         		| ((na4 = ~a4) | (na3 = ~a3))
@@ -415,10 +417,7 @@
 			int i = 0, length, otherLength;
 			if ((length = this.extra[0].length) < (otherLength = otherInits.extra[0].length)) {
 				// current storage is shorter -> grow current
-				for (int j = 0; j < extraLength; j++) {
-					System.arraycopy(this.extra[j], 0,
-						(this.extra[j] = new long[otherLength]), 0, length);
-				}
+				growSpace(otherLength, 0, length);
 				for (; i < length; i++) {
 					this.extra[1][i] |= otherInits.extra[1][i];
 				}
@@ -532,11 +531,7 @@
 			mergeLimit = copyLimit;
 			if (mergeLimit > this.extra[0].length) {
 				mergeLimit = this.extra[0].length;
-				for (int j = 0; j < extraLength; j++) {
-					System.arraycopy(this.extra[j], 0,
-							this.extra[j] = new long[copyLimit], 0,
-							mergeLimit);
-				}
+				growSpace(copyLimit, 0, mergeLimit);
 				if (! thisHadNulls) {
     				mergeLimit = 0;
     				// will do with a copy -- caveat: only valid because definite assignment bits copied above
@@ -1200,12 +1195,7 @@
 			else {
 				int oldLength;
 				if (vectorIndex >= (oldLength = this.extra[0].length)) {
-					int newLength = vectorIndex + 1;
-					for (int j = 0; j < extraLength; j++) {
-						System.arraycopy(this.extra[j], 0,
-							(this.extra[j] = new long[newLength]), 0,
-							oldLength);
-					}
+					growSpace(vectorIndex + 1, 0, oldLength);
 					if (COVERAGE_TEST_FLAG) {
 						if (CoverageTestId == 17) {
 							throw new AssertionFailedException("COVERAGE 17"); //$NON-NLS-1$
@@ -1297,12 +1287,7 @@
 			else {
 				int oldLength;
 				if (vectorIndex >= (oldLength = this.extra[0].length)) {
-					int newLength = vectorIndex + 1;
-					for (int j = 0; j < extraLength; j++) {
-						System.arraycopy(this.extra[j], 0,
-							(this.extra[j] = new long[newLength]), 0,
-							oldLength);
-					}
+					growSpace(vectorIndex + 1, 0, oldLength);
 					if (COVERAGE_TEST_FLAG) {
 						if(CoverageTestId == 21) {
 							throw new AssertionFailedException("COVERAGE 21"); //$NON-NLS-1$
@@ -1357,11 +1342,7 @@
 			else {
 				int oldLength; // might need to grow the arrays
 				if (vectorIndex >= (oldLength = this.extra[0].length)) {
-					for (int j = 0; j < extraLength; j++) {
-						System.arraycopy(this.extra[j], 0,
-							(this.extra[j] = new long[vectorIndex + 1]), 0,
-							oldLength);
-					}
+					growSpace(vectorIndex + 1, 0, oldLength);
 				}
 			}
 			long mask;
@@ -1418,11 +1399,7 @@
     		else {
     			int oldLength; // might need to grow the arrays
     			if (vectorIndex >= (oldLength = this.extra[0].length)) {
-    				for (int j = 0; j < extraLength; j++) {
-    					System.arraycopy(this.extra[j], 0,
-    						(this.extra[j] = new long[vectorIndex + 1]), 0,
-    						oldLength);
-    				}
+    				growSpace(vectorIndex + 1, 0, oldLength);
     			}
     		}
     		this.extra[2][vectorIndex]
@@ -1476,11 +1453,7 @@
     		else {
     			int oldLength; // might need to grow the arrays
     			if (vectorIndex >= (oldLength = this.extra[0].length)) {
-    				for (int j = 0; j < extraLength; j++) {
-    					System.arraycopy(this.extra[j], 0,
-    						(this.extra[j] = new long[vectorIndex + 1]), 0,
-    						oldLength);
-    				}
+    				growSpace(vectorIndex + 1, 0, oldLength);
     			}
     		}
     		this.extra[2][vectorIndex]
@@ -1541,11 +1514,7 @@
 			else {
 				int oldLength; // might need to grow the arrays
 				if (vectorIndex >= (oldLength = this.extra[0].length)) {
-					for (int j = 0; j < extraLength; j++) {
-						System.arraycopy(this.extra[j], 0,
-							(this.extra[j] = new long[vectorIndex + 1]), 0,
-							oldLength);
-					}
+					growSpace(vectorIndex+1, 0, oldLength);
 				}
 			}
 			this.extra[2][vectorIndex]
@@ -1629,11 +1598,7 @@
 			else {
 				int oldLength; // might need to grow the arrays
 				if (vectorIndex >= (oldLength = this.extra[0].length)) {
-					for (int j = 0; j < extraLength; j++) {
-						System.arraycopy(this.extra[j], 0,
-							(this.extra[j] = new long[vectorIndex + 1]), 0,
-							oldLength);
-					}
+    				growSpace(vectorIndex + 1, 0, oldLength);
 				}
 			}
     		mask = 1L << (position % BitCacheSize);
@@ -1677,11 +1642,7 @@
 			else {
 				int oldLength; // might need to grow the arrays
 				if (vectorIndex >= (oldLength = this.extra[0].length)) {
-					for (int j = 0; j < extraLength; j++) {
-						System.arraycopy(this.extra[j], 0,
-							(this.extra[j] = new long[vectorIndex + 1]), 0,
-							oldLength);
-					}
+    				growSpace(vectorIndex + 1, 0, oldLength);
 				}
 			}
     		mask = 1L << (position % BitCacheSize);
@@ -1725,11 +1686,7 @@
 			else {
 				int oldLength; // might need to grow the arrays
 				if (vectorIndex >= (oldLength = this.extra[0].length)) {
-					for (int j = 0; j < extraLength; j++) {
-						System.arraycopy(this.extra[j], 0,
-							(this.extra[j] = new long[vectorIndex + 1]), 0,
-							oldLength);
-					}
+					growSpace(vectorIndex + 1, 0, oldLength);
 				}
 			}
     		mask = 1L << (position % BitCacheSize);
@@ -1775,14 +1732,15 @@
 	boolean
 		thisHasNulls = (this.tagBits & NULL_FLAG_MASK) != 0,
 		otherHasNulls = (otherInits.tagBits & NULL_FLAG_MASK) != 0,
-		thisHadNulls = thisHasNulls;
+		thisWasUnreachable = false,
+		otherIsUnreachable = false;
 	long
 		a1, a2, a3, a4,
 		na1, na2, na3, na4,
 		nb1, nb2, nb3, nb4,
 		b1, b2, b3, b4;
 	if ((otherInits.tagBits & FlowInfo.UNREACHABLE_BY_NULLANALYSIS) != 0) {
-		otherHasNulls = false; // skip merging, otherInits is unreachable by null analysis
+		otherIsUnreachable = true; // skip merging, otherInits is unreachable by null analysis
 	} else if ((this.tagBits & FlowInfo.UNREACHABLE_BY_NULLANALYSIS) != 0) { // directly copy if this is unreachable by null analysis
 		this.nullBit1 = otherInits.nullBit1;
 		this.nullBit2 = otherInits.nullBit2;
@@ -1790,13 +1748,13 @@
 		this.nullBit4 = otherInits.nullBit4;
 		this.iNBit = otherInits.iNBit;
 		this.iNNBit = otherInits.iNNBit;
-		thisHadNulls = false;
+		thisWasUnreachable = true;
 		thisHasNulls = otherHasNulls;
 		this.tagBits = otherInits.tagBits;
-	} else if (thisHadNulls) {
+	} else if (thisHasNulls) {
     	if (otherHasNulls) {
     		this.nullBit1 = (a1 = this.nullBit1) & (b1 = otherInits.nullBit1) & (
-    				((a2 = this.nullBit2) & (((b2 = otherInits.nullBit2) & 
+    				((a2 = this.nullBit2) & (((b2 = otherInits.nullBit2) &
     											~(((a3=this.nullBit3) & (a4=this.nullBit4)) ^ ((b3=otherInits.nullBit3) & (b4=otherInits.nullBit4))))
     										|(a3 & a4 & (nb2 = ~b2))))
     				|((na2 = ~a2) & ((b2 & b3 & b4)
@@ -1857,7 +1815,11 @@
 
 	// treating extra storage
 	if (this.extra != null || otherInits.extra != null) {
-		int mergeLimit = 0, copyLimit = 0, resetLimit = 0;
+		// four areas, but not all combinations are possible: only one of copyLimit/resetLimit will be > 0, takeLimit is exclusive to all others
+		int takeLimit = 0;  // [..takeLimit]			: this is unreachable, take null info from other as-is
+		int mergeLimit = 0; // [0..mergeLimit]			: both flows have extra bits. Merge'em
+		int copyLimit = 0;  // (mergeLimit..copyLimit] 	: only other has extra bits. Copy'em, sheding some doubt
+		int resetLimit = 0; // (copyLimit..resetLimit]  : only this has extra bits. Shed doubt on them.
 		int i;
 		if (this.extra != null) {
 			if (otherInits.extra != null) {
@@ -1866,10 +1828,7 @@
 				if ((length = this.extra[0].length) <
 						(otherLength = otherInits.extra[0].length)) {
 					// current storage is shorter -> grow current
-					for (int j = 0; j < extraLength; j++) {
-						System.arraycopy(this.extra[j], 0,
-							(this.extra[j] = new long[otherLength]), 0, length);
-					}
+					growSpace(otherLength, 0, length);
 					mergeLimit = length;
 					copyLimit = otherLength;
 					if (COVERAGE_TEST_FLAG) {
@@ -1929,20 +1888,33 @@
 		  	this.extra[0][i] = 0;
 		}
 		// refine null bits requirements
-		if (!otherHasNulls) {
-		  if (resetLimit < mergeLimit) {
-			resetLimit = mergeLimit;
-		  }
-		  copyLimit = 0; // no need to carry inexisting nulls
-		  mergeLimit = 0;
+		if (!otherHasNulls || otherIsUnreachable) {
+			if (otherIsUnreachable) {
+				// other is unreachable, completely ignore it
+				resetLimit = 0;
+			} else {
+				// if there was anything to do, do it per resetLimit loop:
+				resetLimit = Math.max(resetLimit, mergeLimit);
+			}
+			copyLimit = 0; // no need to carry inexisting nulls
+			mergeLimit = 0;
 		}
-		if (!thisHadNulls) {
-		  resetLimit = 0; // no need to reset anything
+		if (thisWasUnreachable) {
+			// completely ignore unreachable info (don't shed any doubts on other)
+			takeLimit = Math.max(resetLimit, mergeLimit);
+			mergeLimit = 0;
+			resetLimit = 0;
 		}
 		// compose nulls
-		for (i = 0; i < mergeLimit; i++) {
+		for (i = 0; i < takeLimit; i++) {
+    		this.extra[1 + 1][i] = otherInits.extra[1+1][i];
+    		this.extra[2 + 1][i] = otherInits.extra[2+1][i];
+    		this.extra[3 + 1][i] = otherInits.extra[3+1][i];
+    		this.extra[4 + 1][i] = otherInits.extra[4+1][i];
+		}
+		for (; i < mergeLimit; i++) {
     		this.extra[1 + 1][i] = (a1=this.extra[1+1][i]) & (b1=otherInits.extra[1+1][i]) & (
-    				((a2=this.extra[2+1][i]) & (((b2=otherInits.extra[2+1][i]) & 
+    				((a2=this.extra[2+1][i]) & (((b2=otherInits.extra[2+1][i]) &
     												~(((a3=this.extra[3+1][i]) & (a4=this.extra[4+1][i])) ^ ((b3=otherInits.extra[3+1][i]) & (b4=otherInits.extra[4+1][i]))))
     											|(a3 & a4 & (nb2=~b2))))
     				|((na2=~a2) & ((b2 & b3 & b4)
@@ -1997,6 +1969,10 @@
       		this.extra[2 + 1][i] = (a2 = this.extra[2 + 1][i]) & (na3 = ~(a3 = this.extra[3 + 1][i]) | (na1 = ~a1));
       		this.extra[3 + 1][i] = a3 & ((na2 = ~a2) & (a4 = this.extra[4 + 1][i]) | na1) | a1 & na2 & ~a4;
       		this.extra[4 + 1][i] = (na3 | na2) & na1 & a4	| a1 & na3 & na2;
+      		if (otherInits.extra != null && otherInits.extra[0].length > i) {
+	    		this.extra[IN][i] |= otherInits.extra[IN][i];
+	    		this.extra[INN][i] |= otherInits.extra[INN][i];
+      		}
 			thisHasNulls = thisHasNulls ||
 				this.extra[3][i] != 0 ||
 				this.extra[4][i] != 0 ||
@@ -2071,7 +2047,7 @@
 public FlowInfo setReachMode(int reachMode) {
 	if (this == DEAD_END) {// cannot modify DEAD_END
 		return this;
-	}	
+	}
 	if (reachMode == REACHABLE ) {
 		this.tagBits &= ~UNREACHABLE;
 	} else if (reachMode == UNREACHABLE_BY_NULLANALYSIS ) {
@@ -2101,29 +2077,30 @@
 	}
 	if ((this.tagBits & NULL_FLAG_MASK) != 0) {
 		if (this.extra == null) {
-			return "FlowInfo<def: " + this.definiteInits //$NON-NLS-1$
-				+", pot: " + this.potentialInits  //$NON-NLS-1$
+			return "FlowInfo<def: " + Long.toHexString(this.definiteInits) //$NON-NLS-1$
+				+", pot: " + Long.toHexString(this.potentialInits)  //$NON-NLS-1$
 				+ ", reachable:" + ((this.tagBits & UNREACHABLE) == 0) //$NON-NLS-1$
-				+", null: " + this.nullBit1 //$NON-NLS-1$
-					+ this.nullBit2 + this.nullBit3 + this.nullBit4
-				+", incoming: " + this.iNBit + this.iNNBit //$NON-NLS-1$
+				+", null: " + Long.toHexString(this.nullBit1) //$NON-NLS-1$
+					+'.'+ Long.toHexString(this.nullBit2) +'.'+ Long.toHexString(this.nullBit3) +'.'+ Long.toHexString(this.nullBit4)
+				+", incoming: " + Long.toHexString(this.iNBit) +'.'+ Long.toHexString(this.iNNBit) //$NON-NLS-1$
 				+">"; //$NON-NLS-1$
 		}
 		else {
-			String def = "FlowInfo<def:[" + this.definiteInits, //$NON-NLS-1$
-				pot = "], pot:[" + this.potentialInits, //$NON-NLS-1$
-				nullS = ", null:[" + this.nullBit1 //$NON-NLS-1$
-					+ this.nullBit2 + this.nullBit3 + this.nullBit4;
+			String def = "FlowInfo<def:[" + Long.toHexString(this.definiteInits), //$NON-NLS-1$
+				pot = "], pot:[" + Long.toHexString(this.potentialInits), //$NON-NLS-1$
+				nullS = ", null:[" + Long.toHexString(this.nullBit1) //$NON-NLS-1$
+					+'.'+ Long.toHexString(this.nullBit2) +'.'+ Long.toHexString(this.nullBit3) +'.'+ Long.toHexString(this.nullBit4)
+					+", incoming: " + Long.toHexString(this.iNBit) +'.'+ Long.toHexString(this.iNNBit); //$NON-NLS-1$
 			int i, ceil;
 			for (i = 0, ceil = this.extra[0].length > 3 ?
 								3 :
 								this.extra[0].length;
 				i < ceil; i++) {
-				def += "," + this.extra[0][i]; //$NON-NLS-1$
-				pot += "," + this.extra[1][i]; //$NON-NLS-1$
-				nullS += "," + this.extra[2][i] //$NON-NLS-1$
-				    + this.extra[3][i] + this.extra[4][i] + this.extra[5][i]
-					+", incoming: " + this.extra[IN][i] + this.extra[INN]; //$NON-NLS-1$
+				def += "," + Long.toHexString(this.extra[0][i]); //$NON-NLS-1$
+				pot += "," + Long.toHexString(this.extra[1][i]); //$NON-NLS-1$
+				nullS += "\n\t" + Long.toHexString(this.extra[2][i]) //$NON-NLS-1$
+					+'.'+ Long.toHexString(this.extra[3][i]) +'.'+ Long.toHexString(this.extra[4][i]) +'.'+ Long.toHexString(this.extra[5][i])
+					+", incoming: " + Long.toHexString(this.extra[IN][i]) +'.'+ Long.toHexString(this.extra[INN][i]); //$NON-NLS-1$
 			}
 			if (ceil < this.extra[0].length) {
 				def += ",..."; //$NON-NLS-1$
@@ -2247,10 +2224,7 @@
 			int i = 0, length, otherLength;
 			if ((length = this.extra[0].length) < (otherLength = otherInits.extra[0].length)) {
 				// current storage is shorter -> grow current
-				for (int j = 0; j < extraLength; j++) {
-					System.arraycopy(this.extra[j], 0,
-						(this.extra[j] = new long[otherLength]), 0, length);
-				}
+				growSpace(otherLength, 0, length);
 				for (; i < length; i++) {
 					this.extra[0][i] &= otherInits.extra[0][i];
 				}
@@ -2263,6 +2237,9 @@
 				for (; i < otherLength; i++) {
 					this.extra[0][i] &= otherInits.extra[0][i];
 				}
+				for (; i < length; i++) {
+					this.extra[0][i] = 0; // absent otherInit.extra means: all are 0
+				}
 			}
 		} else {
 			for (int i = 0; i < this.extra[0].length; i++) {
@@ -2314,5 +2291,26 @@
 		Arrays.fill(this.extra[INN], -1L);
 	}
 }
+
+public void growSpace(int newLength, int copyStart, int copyLength) {
+	for (int j = 0; j < extraLength; j++) {
+		System.arraycopy(this.extra[j], copyStart,
+			(this.extra[j] = new long[newLength]), copyStart,
+			copyLength);
+	}
+	if ((this.tagBits & UNROOTED) != 0) {
+		Arrays.fill(this.extra[IN], copyStart+copyLength, newLength, -1);
+		Arrays.fill(this.extra[INN], copyStart+copyLength, newLength, -1);
+	}
+}
+
+public void acceptAllIncomingNullness() {
+	this.iNBit = -1L;
+	this.iNNBit = -1L;
+	if (this.extra != null) {
+		Arrays.fill(this.extra[IN], -1L);
+		Arrays.fill(this.extra[INN], -1L);
+	}
+}
 }
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
index b58f871..7cb9ab1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
@@ -195,6 +195,7 @@
 	public static final String OPTION_ReportNonnullParameterAnnotationDropped = "org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped";  //$NON-NLS-1$
 	public static final String OPTION_PessimisticNullAnalysisForFreeTypeVariables = "org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables";  //$NON-NLS-1$
 	public static final String OPTION_ReportNonNullTypeVariableFromLegacyInvocation = "org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation"; //$NON-NLS-1$
+	public static final String OPTION_ReportAnnotatedTypeArgumentToUnannotated = "org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated"; //$NON-NLS-1$
 	
 	public static final String OPTION_ReportUnlikelyCollectionMethodArgumentType = "org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType"; //$NON-NLS-1$
 	public static final String OPTION_ReportUnlikelyCollectionMethodArgumentTypeStrict = "org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict"; //$NON-NLS-1$
@@ -233,6 +234,7 @@
 	public static final String VERSION_11 = "11"; //$NON-NLS-1$
 	public static final String VERSION_12 = "12"; //$NON-NLS-1$
 	public static final String VERSION_13 = "13"; //$NON-NLS-1$
+	public static final String VERSION_14 = "14"; //$NON-NLS-1$
 	/*
 	 * Note: Whenever a new version is added, make sure getLatestVersion()
 	 * is updated with it.
@@ -348,6 +350,7 @@
 	public static final int UnstableAutoModuleName = IrritantSet.GROUP2 | ASTNode.Bit26;
 	public static final int PreviewFeatureUsed = IrritantSet.GROUP2 | ASTNode.Bit27;
 	public static final int SuppressWarningsNotAnalysed = IrritantSet.GROUP2 | ASTNode.Bit28;
+	public static final int AnnotatedTypeArgumentToUnannotated = IrritantSet.GROUP2 | ASTNode.Bit29;
 
 	// AspectJ Extension
 	// Not sure we need this anymore...
@@ -610,7 +613,7 @@
 	 * Return the latest Java language version supported by the Eclipse compiler
 	 */
 	public static String getLatestVersion() {
-		return VERSION_13;
+		return VERSION_14;
 	}
 	/**
 	 * Return the most specific option key controlling this irritant. Note that in some case, some irritant is controlled by
@@ -780,6 +783,8 @@
 				return OPTION_PessimisticNullAnalysisForFreeTypeVariables;
 			case NonNullTypeVariableFromLegacyInvocation:
 				return OPTION_ReportNonNullTypeVariableFromLegacyInvocation;
+			case AnnotatedTypeArgumentToUnannotated:
+				return OPTION_ReportAnnotatedTypeArgumentToUnannotated;
 			case UnlikelyCollectionMethodArgumentType:
 				return OPTION_ReportUnlikelyCollectionMethodArgumentType;
 			case UnlikelyEqualsArgumentType:
@@ -1029,6 +1034,7 @@
 			OPTION_ReportUnusedTypeParameter,
 			OPTION_InheritNullAnnotations,
 			OPTION_ReportNonnullParameterAnnotationDropped,
+			OPTION_ReportAnnotatedTypeArgumentToUnannotated,
 			OPTION_ReportUnlikelyCollectionMethodArgumentType,
 			OPTION_ReportUnlikelyEqualsArgumentType,
 			OPTION_ReportAPILeak,
@@ -1110,6 +1116,7 @@
 			case NonnullParameterAnnotationDropped:
 			case PessimisticNullAnalysisForFreeTypeVariables:
 			case NonNullTypeVariableFromLegacyInvocation:
+			case AnnotatedTypeArgumentToUnannotated:
 				return "null"; //$NON-NLS-1$
 			case FallthroughCase :
 				return "fallthrough"; //$NON-NLS-1$
@@ -1381,6 +1388,7 @@
 		optionsMap.put(OPTION_ReportUninternedIdentityComparison, this.complainOnUninternedIdentityComparison ? ENABLED : DISABLED);
 		optionsMap.put(OPTION_PessimisticNullAnalysisForFreeTypeVariables, getSeverityString(PessimisticNullAnalysisForFreeTypeVariables));
 		optionsMap.put(OPTION_ReportNonNullTypeVariableFromLegacyInvocation, getSeverityString(NonNullTypeVariableFromLegacyInvocation));
+		optionsMap.put(OPTION_ReportAnnotatedTypeArgumentToUnannotated, getSeverityString(AnnotatedTypeArgumentToUnannotated));
 		optionsMap.put(OPTION_ReportUnlikelyCollectionMethodArgumentType, getSeverityString(UnlikelyCollectionMethodArgumentType));
 		optionsMap.put(OPTION_ReportUnlikelyCollectionMethodArgumentTypeStrict, this.reportUnlikelyCollectionMethodArgumentTypeStrict ? ENABLED : DISABLED);
 		optionsMap.put(OPTION_ReportUnlikelyEqualsArgumentType, getSeverityString(UnlikelyEqualsArgumentType));
@@ -1959,6 +1967,7 @@
 				this.inheritNullAnnotations = ENABLED.equals(optionValue);
 			}
 			if ((optionValue = optionsMap.get(OPTION_ReportNonnullParameterAnnotationDropped)) != null) updateSeverity(NonnullParameterAnnotationDropped, optionValue);
+			if ((optionValue = optionsMap.get(OPTION_ReportAnnotatedTypeArgumentToUnannotated)) != null) updateSeverity(AnnotatedTypeArgumentToUnannotated, optionValue);
 			if ((optionValue = optionsMap.get(OPTION_PessimisticNullAnalysisForFreeTypeVariables)) != null) updateSeverity(PessimisticNullAnalysisForFreeTypeVariables, optionValue);
 			if (getSeverity(PessimisticNullAnalysisForFreeTypeVariables) == ProblemSeverities.Ignore) {
 				this.pessimisticNullAnalysisForFreeTypeVariablesEnabled = false;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java
index 29a45a3..889ff94 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/Constant.java
@@ -22,7 +22,7 @@
 
 	public static final Constant NotAConstant = DoubleConstant.fromValue(Double.NaN);
 	public static final Constant[] NotAConstantList = new Constant[] {DoubleConstant.fromValue(Double.NaN)};
-	
+
 	public boolean booleanValue() {
 		throw new ShouldNotImplement(Messages.bind(Messages.constant_cannotCastedInto, new String[] { typeName(), "boolean" })); //$NON-NLS-1$
 	}
@@ -1469,7 +1469,7 @@
 	public float floatValue() {
 		throw new ShouldNotImplement(Messages.bind(Messages.constant_cannotCastedInto, new String[] { typeName(), "float" })); //$NON-NLS-1$
 	}
-	
+
 	/**
 	 * Returns true if both constants have the same type and the same actual value
 	 * @param otherConstant
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java
index 95c3d3b..51d14d5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java
@@ -88,7 +88,8 @@
 		// group-2 infos enabled by default
 		.set(
 			CompilerOptions.UnlikelyEqualsArgumentType
-			| CompilerOptions.SuppressWarningsNotAnalysed);
+			| CompilerOptions.SuppressWarningsNotAnalysed
+			| CompilerOptions.AnnotatedTypeArgumentToUnannotated);
 		
 		COMPILER_DEFAULT_WARNINGS
 			// group-0 warnings enabled by default
@@ -160,7 +161,8 @@
 			.set(CompilerOptions.NonnullParameterAnnotationDropped)
 			.set(CompilerOptions.MissingNonNullByDefaultAnnotation)
 			.set(CompilerOptions.PessimisticNullAnalysisForFreeTypeVariables)
-			.set(CompilerOptions.NonNullTypeVariableFromLegacyInvocation);
+			.set(CompilerOptions.NonNullTypeVariableFromLegacyInvocation)
+			.set(CompilerOptions.AnnotatedTypeArgumentToUnannotated);
 
 		RESTRICTION.set(CompilerOptions.DiscouragedReference);
 		STATIC_ACCESS.set(CompilerOptions.NonStaticAccessToStatic);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/LongConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/LongConstant.java
index d21ee7b..fc56bea 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/LongConstant.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/LongConstant.java
@@ -17,7 +17,7 @@
 
 		private static final LongConstant ZERO = new LongConstant(0L);
 		private static final LongConstant MIN_VALUE = new LongConstant(Long.MIN_VALUE);
-		
+
 		private long value;
 
 public static Constant fromValue(long value) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java
index 2f9eab1..6db2e27 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ReferenceContext.java
@@ -34,7 +34,7 @@
 	boolean hasErrors();
 
 	void tagAsHavingErrors();
-	
+
 	void tagAsHavingIgnoredMandatoryErrors(int problemId);
 
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ShortConstant.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ShortConstant.java
index 91c4623..11dbb8c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ShortConstant.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/ShortConstant.java
@@ -14,7 +14,7 @@
 package org.eclipse.jdt.internal.compiler.impl;
 
 public class ShortConstant extends Constant {
-	
+
 	private short value;
 
 	public static Constant fromValue(short value) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java
index 228f129..d2989bc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotatableTypeSystem.java
@@ -11,7 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
- *								Bug 432977 - [1.8][null] Incorrect 'type is not visible' compiler error 
+ *								Bug 432977 - [1.8][null] Incorrect 'type is not visible' compiler error
  *								Bug 446434 - [1.8][null] Enable interned captures also when analysing null type annotations
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
@@ -20,29 +20,29 @@
 import org.eclipse.jdt.internal.compiler.util.Util;
 
 /* AnnotatableTypeSystem: Keep track of annotated types so as to provide unique bindings for identically annotated versions identical underlying "naked" types.
-   As of now, we ensure uniqueness only for marker annotated types and for others that default to all default attribute values, i.e two instances of @NonNull String 
-   would have the same binding, while @T(1) X and @T(2) X will not. Binding uniqueness is only a memory optimization and is not essential for correctness of compilation. 
+   As of now, we ensure uniqueness only for marker annotated types and for others that default to all default attribute values, i.e two instances of @NonNull String
+   would have the same binding, while @T(1) X and @T(2) X will not. Binding uniqueness is only a memory optimization and is not essential for correctness of compilation.
    Various subsystems should expect to determine binding identity/equality by calling TypeBinding.equalsEquals and not by using == operator.
- 	
-   ATS is AnnotatableTypeSystem and not AnnotatedTypeSystem, various methods may actually return unannotated types if the input arguments do not specify any annotations 
-   and component types of the composite type being constructed are themselves also unannotated. We rely on the master type table maintained by TypeSystem and use 
+
+   ATS is AnnotatableTypeSystem and not AnnotatedTypeSystem, various methods may actually return unannotated types if the input arguments do not specify any annotations
+   and component types of the composite type being constructed are themselves also unannotated. We rely on the master type table maintained by TypeSystem and use
    getDerivedTypes() and cacheDerivedType() to get/put.
 */
 
 public class AnnotatableTypeSystem extends TypeSystem {
 
 	private boolean isAnnotationBasedNullAnalysisEnabled;
-	
+
 	public AnnotatableTypeSystem(LookupEnvironment environment) {
 		super(environment);
 		this.environment = environment;
 		this.isAnnotationBasedNullAnalysisEnabled = environment.globalOptions.isAnnotationBasedNullAnalysisEnabled;
 	}
-	
+
 	// Given a type, return all its annotated variants: parameter may be annotated.
 	@Override
 	public TypeBinding[] getAnnotatedTypes(TypeBinding type) {
-		
+
 		TypeBinding[] derivedTypes = getDerivedTypes(type);
 		final int length = derivedTypes.length;
 		TypeBinding [] annotatedVersions = new TypeBinding[length];
@@ -56,16 +56,16 @@
 			if (derivedType.id == type.id)
 				annotatedVersions[versions++] = derivedType;
 		}
-		
+
 		if (versions != length)
 			System.arraycopy(annotatedVersions, 0, annotatedVersions = new TypeBinding[versions], 0, versions);
 		return annotatedVersions;
 	}
-	
-	/* This method replaces the version that used to sit in LE. The parameter `annotations' is a flattened sequence of annotations, 
+
+	/* This method replaces the version that used to sit in LE. The parameter `annotations' is a flattened sequence of annotations,
 	   where each dimension's annotations end with a sentinel null. Leaf type can be an already annotated type.
-	   
-	   See ArrayBinding.swapUnresolved for further special case handling if incoming leafType is a URB that would resolve to a raw 
+
+	   See ArrayBinding.swapUnresolved for further special case handling if incoming leafType is a URB that would resolve to a raw
 	   type later.
 	*/
 	@Override
@@ -86,14 +86,14 @@
 			if (derivedType == null) break;
 			if (!derivedType.isArrayType() || derivedType.dimensions() != dimensions || derivedType.leafComponentType() != leafType) //$IDENTITY-COMPARISON$
 				continue;
-			if (Util.effectivelyEqual(derivedType.getTypeAnnotations(), annotations)) 
+			if (Util.effectivelyEqual(derivedType.getTypeAnnotations(), annotations))
 				return (ArrayBinding) derivedType;
 			if (!derivedType.hasTypeAnnotations())
 				nakedType = (ArrayBinding) derivedType;
 		}
 		if (nakedType == null)
 			nakedType = super.getArrayType(leafType, dimensions);
-		
+
 		if (!haveTypeAnnotations(leafType, annotations))
 			return nakedType;
 
@@ -114,29 +114,29 @@
 			return super.getMemberType(memberType, enclosingType);
 		return (ReferenceBinding) getAnnotatedType(memberType, enclosingType, memberType.getTypeAnnotations());
 	}
-	
+
 	@Override
 	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, AnnotationBinding [] annotations) {
-		
+
 		if (genericType.hasTypeAnnotations())   // @NonNull (List<String>) and not (@NonNull List)<String>
 			throw new IllegalStateException();
-		
+
 		ParameterizedTypeBinding parameterizedType = this.parameterizedTypes.get(genericType, typeArguments, enclosingType, annotations);
 		if (parameterizedType != null)
 			return parameterizedType;
-		
+
 		ParameterizedTypeBinding nakedType = super.getParameterizedType(genericType, typeArguments, enclosingType);
-		
+
 		if (!haveTypeAnnotations(genericType, enclosingType, typeArguments, annotations))
 			return nakedType;
-		
+
 		parameterizedType = new ParameterizedTypeBinding(genericType, typeArguments, enclosingType, this.environment);
 		parameterizedType.id = nakedType.id;
 		parameterizedType.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled);
 		this.parameterizedTypes.put(genericType, typeArguments, enclosingType, parameterizedType);
 		return (ParameterizedTypeBinding) cacheDerivedType(genericType, nakedType, parameterizedType);
 	}
-	
+
 	@Override
 	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType) {
 		return getParameterizedType(genericType, typeArguments, enclosingType, Binding.NO_ANNOTATIONS);
@@ -149,7 +149,7 @@
 		if (!genericType.hasEnclosingInstanceContext() && enclosingType != null) {
 			enclosingType = (ReferenceBinding) enclosingType.original();
 		}
-		
+
 		RawTypeBinding nakedType = null;
 		TypeBinding[] derivedTypes = getDerivedTypes(genericType);
 		for (int i = 0, length = derivedTypes.length; i < length; i++) {
@@ -165,36 +165,36 @@
 		}
 		if (nakedType == null)
 			nakedType = super.getRawType(genericType, enclosingType);
-		
+
 		if (!haveTypeAnnotations(genericType, enclosingType, null, annotations))
 			return nakedType;
-	
+
 		RawTypeBinding rawType = new RawTypeBinding(genericType, enclosingType, this.environment);
 		rawType.id = nakedType.id;
 		rawType.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled);
 		return (RawTypeBinding) cacheDerivedType(genericType, nakedType, rawType);
 	}
-	
+
 	@Override
 	public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType) {
 		return getRawType(genericType, enclosingType, Binding.NO_ANNOTATIONS);
 	}
-	
+
 	@Override
 	public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind, AnnotationBinding [] annotations) {
-		
+
 		if (genericType == null) // pseudo wildcard denoting composite bounds for lub computation
 			genericType = ReferenceBinding.LUB_GENERIC;
 
 		if (genericType.hasTypeAnnotations())
 			throw new IllegalStateException();
-		
+
 		WildcardBinding nakedType = null;
 		boolean useDerivedTypesOfBound = bound instanceof TypeVariableBinding || (bound instanceof ParameterizedTypeBinding && !(bound instanceof RawTypeBinding)) ;
 		TypeBinding[] derivedTypes = getDerivedTypes(useDerivedTypesOfBound ? bound : genericType);
 		for (int i = 0, length = derivedTypes.length; i < length; i++) {
 			TypeBinding derivedType = derivedTypes[i];
-			if (derivedType == null) 
+			if (derivedType == null)
 				break;
 			if (!derivedType.isWildcard() || derivedType.actualType() != genericType || derivedType.rank() != rank) //$IDENTITY-COMPARISON$
 				continue;
@@ -205,13 +205,13 @@
 			if (!derivedType.hasTypeAnnotations())
 				nakedType = (WildcardBinding) derivedType;
 		}
-		
+
 		if (nakedType == null)
 			nakedType = super.getWildcard(genericType, rank, bound, otherBounds, boundKind);
-		
+
 		if (!haveTypeAnnotations(genericType, bound, otherBounds, annotations))
 			return nakedType;
-		
+
 		WildcardBinding wildcard = new WildcardBinding(genericType, rank, bound, otherBounds, boundKind, this.environment);
 		wildcard.id = nakedType.id;
 		wildcard.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled);
@@ -228,10 +228,10 @@
 	*/
 	@Override
 	public TypeBinding getAnnotatedType(TypeBinding type, AnnotationBinding[][] annotations) {
-		
+
 		if (type == null || !type.isValidBinding() || annotations == null || annotations.length == 0)
 			return type;
-		
+
 		TypeBinding annotatedType = null;
 		switch (type.kind()) {
 			case Binding.ARRAY_TYPE:
@@ -247,17 +247,17 @@
 			case Binding.WILDCARD_TYPE:
 			case Binding.INTERSECTION_TYPE:
 			case Binding.INTERSECTION_TYPE18:
-				/* Taking the binding of QTR as an example, there could be different annotatable components, but we come in a with a single binding, e.g: 
+				/* Taking the binding of QTR as an example, there could be different annotatable components, but we come in a with a single binding, e.g:
 				   @T Z;                                      type => Z  annotations => [[@T]]
 				   @T Y.@T Z                                  type => Z  annotations => [[@T][@T]]
-				   @T X.@T Y.@T Z                             type => Z  annotations => [[@T][@T][@T]] 
+				   @T X.@T Y.@T Z                             type => Z  annotations => [[@T][@T][@T]]
 				   java.lang.@T X.@T Y.@T Z                   type => Z  annotations => [[][][@T][@T][@T]]
 				   in all these cases the incoming type binding is for Z, but annotations are for different levels. We need to align their layout for proper attribution.
 				 */
-				
+
 				if (type.isUnresolvedType() && CharOperation.indexOf('$', type.sourceName()) > 0)
 				    type = BinaryTypeBinding.resolveType(type, this.environment, true); // must resolve member types before asking for enclosingType
-				
+
 				int levels = type.depth() + 1;
 				TypeBinding [] types = new TypeBinding[levels];
 				types[--levels] = type;
@@ -273,7 +273,7 @@
 					if (annotations[i] != null && annotations[i].length > 0)
 						break;
 				}
-				if (i == levels) // empty annotations array ? 
+				if (i == levels) // empty annotations array ?
 					return type;
 				if (j < 0) // Not kosher, broken type that is not flagged as invalid while reporting compilation error ? don't touch.
 					return type;
@@ -292,10 +292,10 @@
 		return annotatedType;
 	}
 
-	/* Private subroutine for public APIs. Create an annotated version of the type. To materialize the annotated version, we can't use new since 
-	   this is a general purpose method designed to deal type bindings of all types. "Clone" the incoming type, specializing for any enclosing type 
-	   that may itself be possibly be annotated. This is so the binding for @Outer Outer.Inner != Outer.@Inner Inner != @Outer Outer.@Inner Inner. 
-	   Likewise so the bindings for @Readonly List<@NonNull String> != @Readonly List<@Nullable String> != @Readonly List<@Interned String> 
+	/* Private subroutine for public APIs. Create an annotated version of the type. To materialize the annotated version, we can't use new since
+	   this is a general purpose method designed to deal type bindings of all types. "Clone" the incoming type, specializing for any enclosing type
+	   that may itself be possibly be annotated. This is so the binding for @Outer Outer.Inner != Outer.@Inner Inner != @Outer Outer.@Inner Inner.
+	   Likewise so the bindings for @Readonly List<@NonNull String> != @Readonly List<@Nullable String> != @Readonly List<@Interned String>
 	*/
 	private TypeBinding getAnnotatedType(TypeBinding type, TypeBinding enclosingType, AnnotationBinding[] annotations) {
 		if (type.kind() == Binding.PARAMETERIZED_TYPE) {
@@ -306,10 +306,10 @@
 		for (int i = 0, length = derivedTypes.length; i < length; i++) {
 			TypeBinding derivedType = derivedTypes[i];
 			if (derivedType == null) break;
-			
+
 			if (derivedType.enclosingType() != enclosingType || !Util.effectivelyEqual(derivedType.typeArguments(), type.typeArguments())) //$IDENTITY-COMPARISON$
 				continue;
-			
+
 			switch(type.kind()) {
 				case Binding.ARRAY_TYPE:
 					if (!derivedType.isArrayType() || derivedType.dimensions() != type.dimensions() || derivedType.leafComponentType() != type.leafComponentType()) //$IDENTITY-COMPARISON$
@@ -345,10 +345,10 @@
 		}
 		if (nakedType == null)
 			nakedType = getUnannotatedType(type);
-		
+
 		if (!haveTypeAnnotations(type, enclosingType, null, annotations))
 			return nakedType;
-		
+
 		TypeBinding annotatedType = type.clone(enclosingType);
 		annotatedType.id = nakedType.id;
 		annotatedType.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled);
@@ -389,12 +389,12 @@
 	private boolean haveTypeAnnotations(TypeBinding leafType, AnnotationBinding[] annotations) {
 		return haveTypeAnnotations(leafType, null, null, annotations);
 	}
-	
+
 	private boolean haveTypeAnnotations(TypeBinding memberType, TypeBinding enclosingType) {
 		return haveTypeAnnotations(memberType, enclosingType, null, null);
 	}
 
-	/* Utility method to "flatten" annotations. For multidimensional arrays, we encode the annotations into a flat array 
+	/* Utility method to "flatten" annotations. For multidimensional arrays, we encode the annotations into a flat array
 	   where a null separates the annotations of dimension n from dimension n - 1 as well as dimenion n + 1. There is a
 	   final null always.
 	*/
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java
index 1f2618b..3aa1b60 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/AnnotationBinding.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -97,7 +97,7 @@
 }
 
 private static AnnotationBinding buildMarkerAnnotationForMemberType(char[][] compoundName, ModuleBinding module, LookupEnvironment env) {
-	ReferenceBinding type = env.getResolvedType(compoundName, module, null);
+	ReferenceBinding type = env.getResolvedType(compoundName, module, null, false);
 	// since this is a member type name using '$' the return binding is a
 	// problem reference binding with reason ProblemReasons.InternalNameProvided
 	if (!type.isValidBinding()) {
@@ -107,7 +107,7 @@
 }
 
 private static AnnotationBinding buildMarkerAnnotation(char[][] compoundName, ModuleBinding module, LookupEnvironment env) {
-	ReferenceBinding type = env.getResolvedType(compoundName, module, null);
+	ReferenceBinding type = env.getResolvedType(compoundName, module, null, false);
 	return env.createAnnotation(type, Binding.NO_ELEMENT_VALUE_PAIRS);
 }
 
@@ -158,7 +158,9 @@
 		arraysize++;
 	if ((bits & TagBits.AnnotationForModule) != 0)
 		arraysize++;
-	
+	if ((bits & TagBits.AnnotationForRecordComponent) != 0)
+		arraysize++;
+
 	Object[] value = new Object[arraysize];
 	if (arraysize > 0) {
 		ReferenceBinding elementType = env.getResolvedType(TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE, null);
@@ -171,6 +173,8 @@
 			value[index++] = elementType.getField(TypeConstants.UPPER_CONSTRUCTOR, true);
 		if ((bits & TagBits.AnnotationForField) != 0)
 			value[index++] = elementType.getField(TypeConstants.UPPER_FIELD, true);
+		if ((bits & TagBits.AnnotationForRecordComponent) != 0)
+			value[index++] = elementType.getField(TypeConstants.UPPER_RECORD_COMPONENT, true);
 		if ((bits & TagBits.AnnotationForMethod) != 0)
 			value[index++] = elementType.getField(TypeConstants.UPPER_METHOD, true);
 		if ((bits & TagBits.AnnotationForPackage) != 0)
@@ -245,7 +249,7 @@
 	if (this.pairs != null && this.pairs.length > 0) {
 		buffer.append('(');
 		if (this.pairs.length == 1 && CharOperation.equals(this.pairs[0].getName(), TypeConstants.VALUE)) {
-			buffer.append(this.pairs[0].value); 
+			buffer.append(this.pairs[0].value);
 		} else {
 			for (int i = 0, max = this.pairs.length; i < max; i++) {
 				if (i > 0) buffer.append(", "); //$NON-NLS-1$
@@ -280,7 +284,7 @@
 	final ElementValuePair[] thisElementValuePairs = this.getElementValuePairs();
 	final ElementValuePair[] thatElementValuePairs = that.getElementValuePairs();
 	final int length = thisElementValuePairs.length;
-	if (length != thatElementValuePairs.length) 
+	if (length != thatElementValuePairs.length)
 		return false;
 	loop: for (int i = 0; i < length; i++) {
 		ElementValuePair thisPair = thisElementValuePairs[i];
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
index 8c298b9..9edfbc1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
@@ -55,7 +55,7 @@
 	// possible bits are TagBits.AnnotationNonNull and TagBits.AnnotationNullable
 	// (only ever set when CompilerOptions.isAnnotationBasedNullAnalysisEnabled == true):
 	public long[] nullTagBitsPerDimension;
-	
+
 	private MethodBinding clone;
 
 public ArrayBinding(TypeBinding type, int dimensions, LookupEnvironment environment) {
@@ -200,13 +200,13 @@
 */
 
 public TypeBinding elementsType() {
-	
-	if (this.dimensions == 1) 
+
+	if (this.dimensions == 1)
 		return this.leafComponentType;
-	
+
 	AnnotationBinding [] oldies = getTypeAnnotations();
 	AnnotationBinding [] newbies = Binding.NO_ANNOTATIONS;
-	
+
 	for (int i = 0, length = oldies == null ? 0 : oldies.length; i < length; i++) {
 		if (oldies[i] == null) {
 			System.arraycopy(oldies, i+1, newbies = new AnnotationBinding[length - i - 1], 0, length - i - 1);
@@ -388,8 +388,8 @@
 				fqAnnotationName = options.nonNullAnnotationName;
 			else
 				fqAnnotationName = options.nullableAnnotationName;
-			char[] annotationName = shortNames 
-										? fqAnnotationName[fqAnnotationName.length-1] 
+			char[] annotationName = shortNames
+										? fqAnnotationName[fqAnnotationName.length-1]
 										: CharOperation.concatWith(fqAnnotationName, '.');
 			brackets[i] = new char[annotationName.length+3];
 			brackets[i][0] = '@';
@@ -397,10 +397,10 @@
 			brackets[i][annotationName.length+1] = '[';
 			brackets[i][annotationName.length+2] = ']';
 		} else {
-			brackets[i] = new char[]{'[', ']'}; 
+			brackets[i] = new char[]{'[', ']'};
 		}
 	}
-	return CharOperation.concat(this.leafComponentType.nullAnnotatedReadableName(options, shortNames), 
+	return CharOperation.concat(this.leafComponentType.nullAnnotatedReadableName(options, shortNames),
 								 CharOperation.concatWith(brackets, ' '),
 								 ' ');
 }
@@ -439,12 +439,12 @@
 	if (annotations == null || annotations.length == 0)
 		return;
 	this.typeAnnotations = annotations;
-	
+
 	if (evalNullAnnotations) {
 		long nullTagBits = 0;
 		if (this.nullTagBitsPerDimension == null)
 			this.nullTagBitsPerDimension = new long[this.dimensions + 1];
-		
+
 		int dimension = 0;
 		for (int i = 0, length = annotations.length; i < length; i++) {
 			AnnotationBinding annotation = annotations[i];
@@ -493,15 +493,15 @@
 		/* Leaf component type is the key in the type system. If it undergoes change, the array has to be rehashed.
 		   We achieve by creating a fresh array with the new component type and equating this array's id with that.
 		   This means this array can still be found under the old key, but that is harmless (since the component type
-		   is always consulted (see TypeSystem.getArrayType()). 
-		   
-		   This also means that this array type is not a fully interned singleton: There is `this' object and there is 
-		   the array that is being created down below that gets cached by the type system and doled out for all further 
-		   array creations against the same (raw) component type, dimensions and annotations. This again is harmless, 
-		   since TypeBinding.id is consulted for (in)equality checks. 
-		   
+		   is always consulted (see TypeSystem.getArrayType()).
+
+		   This also means that this array type is not a fully interned singleton: There is `this' object and there is
+		   the array that is being created down below that gets cached by the type system and doled out for all further
+		   array creations against the same (raw) component type, dimensions and annotations. This again is harmless,
+		   since TypeBinding.id is consulted for (in)equality checks.
+
 		   See https://bugs.eclipse.org/bugs/show_bug.cgi?id=430425 for details and a test case.
-		*/ 
+		*/
 		if (this.leafComponentType != resolvedType) //$IDENTITY-COMPARISON$
 			this.id = env.createArrayType(this.leafComponentType, this.dimensions, this.typeAnnotations).id;
 		this.tagBits |= this.leafComponentType.tagBits & (TagBits.HasTypeVariable | TagBits.HasDirectWildcard | TagBits.HasMissingType | TagBits.HasCapturedWildcard);
@@ -536,7 +536,7 @@
 @Override
 public long updateTagBits() {
 	if (this.leafComponentType != null)
-		this.tagBits |= this.leafComponentType.updateTagBits(); 
+		this.tagBits |= this.leafComponentType.updateTagBits();
 	return super.updateTagBits();
 }
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java
index ea66be2..ba5ac37 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BaseTypeBinding.java
@@ -17,8 +17,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
-import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
-
 public class BaseTypeBinding extends TypeBinding {
 
 	public static final int[] CONVERSIONS;
@@ -26,17 +24,17 @@
 	public static final int WIDENING = 2;
 	public static final int NARROWING = 4;
 	public static final int MAX_CONVERSIONS = 16*16; // well-known x well-known
-	
+
 	static {
 		CONVERSIONS	 = initializeConversions();
 	}
-	
+
 	public static final int[] initializeConversions(){
 		// fromType   destType --> conversion
 		//  0000   0000       				0000
 
 		int[] table  = new int[MAX_CONVERSIONS];
-		
+
 		table[TypeIds.Boolean2Boolean] = IDENTITY;
 
 		table[TypeIds.Byte2Byte] 		= IDENTITY;
@@ -94,7 +92,7 @@
 		table[TypeIds.Double2Long] 	= NARROWING;
 		table[TypeIds.Double2Float] 	= NARROWING;
 		table[TypeIds.Double2Double]= IDENTITY;
-		
+
 		return table;
 	}
 	/**
@@ -106,8 +104,8 @@
 	 */
 	public static final boolean isNarrowing(int left, int right) {
 		int right2left = right + (left<<4);
-		return right2left >= 0 
-						&& right2left < MAX_CONVERSIONS 
+		return right2left >= 0
+						&& right2left < MAX_CONVERSIONS
 						&& (CONVERSIONS[right2left] & (IDENTITY|NARROWING)) != 0;
 	}
 
@@ -120,11 +118,11 @@
 	 */
 	public static final boolean isWidening(int left, int right) {
 		int right2left = right + (left<<4);
-		return right2left >= 0 
-						&& right2left < MAX_CONVERSIONS 
+		return right2left >= 0
+						&& right2left < MAX_CONVERSIONS
 						&& (CONVERSIONS[right2left] & (IDENTITY|WIDENING)) != 0;
 	}
-	
+
 	public char[] simpleName;
 
 	private char[] constantPoolName;
@@ -156,13 +154,13 @@
 	public TypeBinding clone(TypeBinding enclosingType) {
 		return new BaseTypeBinding(this.id, this.simpleName, this.constantPoolName);
 	}
-	
+
 	@Override
 	public PackageBinding getPackage() {
 
 		return null;
 	}
-	
+
 	/* Answer true if the receiver type can be assigned to the argument type (right)
 	*/
 	@Override
@@ -170,13 +168,13 @@
 		if (equalsEquals(this, right))
 			return true;
 		int right2left = this.id + (right.id<<4);
-		if (right2left >= 0 
-				&& right2left < MAX_CONVERSIONS 
+		if (right2left >= 0
+				&& right2left < MAX_CONVERSIONS
 				&& (CONVERSIONS[right2left] & (IDENTITY|WIDENING)) != 0)
 			return true;
 		return this == TypeBinding.NULL && !right.isBaseType();
 	}
-	
+
 	@Override
 	public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) {
 		super.setTypeAnnotations(annotations, false); // never set nullTagBits on base types
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryModuleBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryModuleBinding.java
index 5102e9c..4f35dc2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryModuleBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryModuleBinding.java
@@ -28,7 +28,7 @@
 import org.eclipse.jdt.internal.compiler.env.IModuleAwareNameEnvironment;
 
 public class BinaryModuleBinding extends ModuleBinding {
-	
+
 	private static class AutomaticModuleBinding extends ModuleBinding {
 
 		boolean autoNameFromManifest;
@@ -80,12 +80,12 @@
 			return this.moduleName;
 		}
 	}
-	
+
 	private IPackageExport[] unresolvedExports;
 	private IPackageExport[] unresolvedOpens;
 	private char[][] unresolvedUses;
 	private IService[] unresolvedProvides;
-	
+
 	/**
 	 * Construct a named module from binary, could be an auto module - or from an info from Java Model.
 	 * <p>
@@ -106,7 +106,7 @@
 		existingEnvironment.root.knownModules.put(this.moduleName, this);
 		cachePartsFrom(module);
 	}
-	
+
 	void cachePartsFrom(IBinaryModule module) {
 		if (module.isOpen())
 			this.modifiers |= ClassFileConstants.ACC_OPEN;
@@ -173,7 +173,7 @@
 			resolvePackages();
 		return super.getExports();
 	}
-	
+
 	@Override
 	public PlainPackageBinding[] getOpens() {
 		if (this.openedPackages == null && this.unresolvedOpens != null)
@@ -195,7 +195,7 @@
 		}
 		if (count < this.exportedPackages.length)
 			System.arraycopy(this.exportedPackages, 0, this.exportedPackages = new PlainPackageBinding[count], 0, count);
-		
+
 		this.openedPackages = new PlainPackageBinding[this.unresolvedOpens.length];
 		count = 0;
 		for (int i = 0; i < this.unresolvedOpens.length; i++) {
@@ -224,7 +224,7 @@
 		}
 		return super.getUses();
 	}
-	
+
 	@Override
 	public TypeBinding[] getServices() {
 		if (this.services == null)
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 aab7c3c..f082efb 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
@@ -506,6 +506,9 @@
 				// attempt to find the superclass if it exists in the cache (otherwise - resolve it when requested)
 				this.superclass = this.environment.getTypeFromConstantPoolName(superclassName, 0, -1, false, missingTypeNames, toplevelWalker.toSupertype((short) -1, superclassName));
 				this.tagBits |= TagBits.HasUnresolvedSuperclass;
+				if (CharOperation.equals(superclassName, TypeConstants.CharArray_JAVA_LANG_RECORD_SLASH)){
+					this.modifiers |= ExtraCompilerModifiers.AccRecord;
+				}
 			}
 
 			this.superInterfaces = Binding.NO_SUPERINTERFACES;
@@ -1685,6 +1688,10 @@
 public boolean isPrototype() {
 	return this == this.prototype; //$IDENTITY-COMPARISON$
 }
+@Override
+public boolean isRecord() {
+	return (this.modifiers & ExtraCompilerModifiers.AccRecord) != 0;
+}
 
 @Override
 public ReferenceBinding containerAnnotationType() {
@@ -2171,7 +2178,7 @@
 	}
 	this.typeBits |= (this.superclass.typeBits & TypeIds.InheritableBits);
 	if ((this.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0) // avoid the side-effects of hasTypeBit()! 
-		this.typeBits |= applyCloseableClassWhitelists();
+		this.typeBits |= applyCloseableClassWhitelists(this.environment.globalOptions);
 	detectCircularHierarchy();
 	return this.superclass;
 }
@@ -2295,7 +2302,8 @@
 	if (isStatic() && isNestedType()) buffer.append("static "); //$NON-NLS-1$
 	if (isFinal()) buffer.append("final "); //$NON-NLS-1$
 
-	if (isEnum()) buffer.append("enum "); //$NON-NLS-1$
+	if (isRecord()) buffer.append("record "); //$NON-NLS-1$
+	else if (isEnum()) buffer.append("enum "); //$NON-NLS-1$
 	else if (isAnnotationType()) buffer.append("@interface "); //$NON-NLS-1$
 	else if (isClass()) buffer.append("class "); //$NON-NLS-1$
 	else buffer.append("interface "); //$NON-NLS-1$
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 72394d2..660122b 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
@@ -44,8 +44,8 @@
 	public static final int TYPE_USE = TYPE | ASTNode.Bit15;
 	public static final int INTERSECTION_TYPE18 = TYPE | ASTNode.Bit16;
 	public static final int POLY_TYPE = TYPE | ASTNode.Bit17;
-	
-	// In the unlikely event you add a new type binding, remember to update TypeBindingVisitor and Scope.substitute methods. 
+
+	// In the unlikely event you add a new type binding, remember to update TypeBindingVisitor and Scope.substitute methods.
 
 	// Shared binding collections
 	public static final ModuleBinding[] NO_MODULES = new ModuleBinding[0];
@@ -64,7 +64,7 @@
 	public static final AnnotationBinding[] NO_ANNOTATIONS = new AnnotationBinding[0];
 	public static final ElementValuePair[] NO_ELEMENT_VALUE_PAIRS = new ElementValuePair[0];
 	public static final char[][] NO_PARAMETER_NAMES = new char[0][];
-	
+
 	public static final FieldBinding[] UNINITIALIZED_FIELDS = new FieldBinding[0];
 	public static final MethodBinding[] UNINITIALIZED_METHODS = new MethodBinding[0];
 	public static final ReferenceBinding[] UNINITIALIZED_REFERENCE_TYPES = new ReferenceBinding[0];
@@ -112,7 +112,7 @@
 
 	public static final int DefaultLocationsForTrueValue = DefaultLocationParameter | DefaultLocationReturnType | DefaultLocationField;
 
-	public static final int NullnessDefaultMASK = 
+	public static final int NullnessDefaultMASK =
 			NULL_UNSPECIFIED_BY_DEFAULT | // included to terminate search up the parent chain
 			DefaultLocationParameter | DefaultLocationReturnType | DefaultLocationField |
 			DefaultLocationTypeArgument | DefaultLocationTypeParameter | DefaultLocationTypeBound | DefaultLocationArrayContents;
@@ -141,7 +141,7 @@
 	/**
 	 * Compute the tagbits for standard annotations. For source types, these could require
 	 * lazily resolving corresponding annotation nodes, in case of forward references.
-	 * For type use bindings, this method still returns the tagbits corresponding to the type 
+	 * For type use bindings, this method still returns the tagbits corresponding to the type
 	 * declaration binding.
 	 * @see org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding#getAnnotationTagBits()
 	 */
@@ -161,7 +161,7 @@
 	public boolean isAnnotationType() {
 		return false;
 	}
-	
+
 	/* API
 	* Answer true if the receiver is not a problem binding
 	*/
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
index e498378..22d4d2b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java
@@ -1,6 +1,6 @@
 //AspectJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -213,6 +213,42 @@
 	varBinding.modifiers = modifiers;
 }
 
+public void adjustLocalVariablePositions(int delta, boolean offsetAlreadyUpdated) {
+	this.offset += offsetAlreadyUpdated ? 0 : delta;
+	if (this.offset > this.maxOffset)
+		this.maxOffset = this.offset;
+
+	for (Scope subScope : this.subscopes) {
+		if (subScope instanceof BlockScope) {
+			((BlockScope) subScope).adjustCurrentAndSubScopeLocalVariablePositions(delta);
+		}
+	}
+
+	Scope scope = this.parent;
+	while (scope instanceof BlockScope) {
+		BlockScope pBlock = (BlockScope) scope;
+		int diff = this.maxOffset - pBlock.maxOffset;
+		pBlock.maxOffset += diff > 0 ? diff : 0;
+		if (scope instanceof MethodScope)
+			break;
+		scope = scope.parent;
+	}
+}
+public void adjustCurrentAndSubScopeLocalVariablePositions(int delta) {
+	this.offset += delta;
+	if (this.offset > this.maxOffset)
+		this.maxOffset = this.offset;
+
+	for (LocalVariableBinding lvb : this.locals) {
+		if (lvb != null && lvb.resolvedPosition != -1)
+			lvb.resolvedPosition += delta;
+	}
+	for (Scope subScope : this.subscopes) {
+		if (subScope instanceof BlockScope) {
+			((BlockScope) subScope).adjustCurrentAndSubScopeLocalVariablePositions(delta);
+		}
+	}
+}
 /* Compute variable positions in scopes given an initial position offset
  * ignoring unused local variables.
  *
@@ -420,7 +456,7 @@
 		} else {
 			// consider variable first
 			LocalVariableBinding local = this.locals[ilocal]; // if no local at all, will be locals[ilocal]==null
-			if (local != null) {
+			if (local != null && (local.modifiers & ExtraCompilerModifiers.AccPatternVariable) == 0) {
 				LocalDeclaration localDecl = local.declaration;
 				if (localDecl != null) {
 					if (localDecl.declarationSourceStart <= position) {
@@ -448,9 +484,20 @@
 public LocalVariableBinding findVariable(char[] variableName) {
 	int varLength = variableName.length;
 	for (int i = this.localIndex-1; i >= 0; i--) { // lookup backward to reach latest additions first
-		LocalVariableBinding local;
+		LocalVariableBinding local = this.locals[i];
+		if ((local.modifiers & ExtraCompilerModifiers.AccPatternVariable) != 0)
+			continue;
 		char[] localName;
-		if ((localName = (local = this.locals[i]).name).length == varLength && CharOperation.equals(localName, variableName))
+		if ((localName = local.name).length == varLength && CharOperation.equals(localName, variableName))
+			return local;
+	}
+	// Look at the pattern variables now
+	for (int i = this.localIndex-1; i >= 0; i--) { // lookup backward to reach latest additions first
+		LocalVariableBinding local = this.locals[i];
+		if ((local.modifiers & ExtraCompilerModifiers.AccPatternVariable) == 0)
+			continue;
+		char[] localName;
+		if ((localName = local.name).length == varLength && CharOperation.equals(localName, variableName))
 			return local;
 	}
 	return null;
@@ -1076,6 +1123,11 @@
 public void pruneWrapperTrackingVar(FakedTrackingVariable trackingVariable) {
 	this.trackingVariables.remove(trackingVariable);
 }
+
+public boolean hasResourceTrackers() {
+	return this.trackingVariables != null && !this.trackingVariables.isEmpty();
+}
+
 /**
  * At the end of a block check the closing-status of all tracked closeables that are declared in this block.
  * Also invoked when entering unreachable code.
@@ -1172,8 +1224,19 @@
 		int trackVarCount = this.trackingVariables.size();
 		for (int i=0; i<trackVarCount; i++) {
 			FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i);
-			if (trackingVar.originalBinding == null)
+			if (trackingVar.originalBinding == null) {
+				// avoid problem weakened to 'potential' if unassigned resource exists only in one branch:
+				boolean hasNullInfoInThen = thenFlowInfo.hasNullInfoFor(trackingVar.binding);
+				boolean hasNullInfoInElse = elseFlowInfo.hasNullInfoFor(trackingVar.binding);
+				if (hasNullInfoInThen && !hasNullInfoInElse) {
+					int nullStatus = thenFlowInfo.nullStatus(trackingVar.binding);
+					elseFlowInfo.markNullStatus(trackingVar.binding, nullStatus);
+				} else if (!hasNullInfoInThen && hasNullInfoInElse) {
+					int nullStatus = elseFlowInfo.nullStatus(trackingVar.binding);
+					thenFlowInfo.markNullStatus(trackingVar.binding, nullStatus);
+				}
 				continue;
+			}
 			if (   thenFlowInfo.isDefinitelyNonNull(trackingVar.binding)			// closed in then branch
 				&& elseFlowInfo.isDefinitelyNull(trackingVar.originalBinding))		// null in else branch
 			{
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
index d004bd7..643964f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
@@ -51,10 +51,10 @@
 			enableOptimizationForBug543480 = enableOptimizationForBug543480Property.equalsIgnoreCase("true"); //$NON-NLS-1$
 		}
 	}
-	
+
 	static final BoundSet TRUE = new BoundSet();	// empty set of bounds
 	static final BoundSet FALSE = new BoundSet();	// pseudo bounds
-	
+
 	/**
 	 * For a given inference variable this structure holds all type bounds
 	 * with a relation in { SUPERTYPE, SAME, SUBTYPE }.
@@ -131,7 +131,7 @@
 				if (!onlyProper || right.isProperType(true)) {
 					if (right instanceof ReferenceBinding) {
 						rights[i++] = right;
-						nullHints |= right.tagBits & TagBits.AnnotationNullMASK; 
+						nullHints |= right.tagBits & TagBits.AnnotationNullMASK;
 					} else {
 						if (simpleUpper != null)
 							return Binding.NO_TYPES; // shouldn't
@@ -237,7 +237,7 @@
 								return boundType;
 						}
 					}
-				}		
+				}
 			}
 			if (this.superBounds != null) {
 				Iterator<TypeBound> it = this.superBounds.iterator();
@@ -256,7 +256,7 @@
 								return boundType;
 						}
 					}
-				}		
+				}
 			}
 			return null;
 		}
@@ -330,10 +330,10 @@
 	}
 	// main storage of type bounds:
 	HashMap<InferenceVariable, ThreeSets> boundsPerVariable = new HashMap<>();
-	
+
 	/**
 	 * 18.1.3 bullet 4: G<α1, ..., αn> = capture(G<A1, ..., An>)
-	 * On both sides we only enter types with nonnull arguments. 
+	 * On both sides we only enter types with nonnull arguments.
 	 */
 	HashMap<ParameterizedTypeBinding,ParameterizedTypeBinding> captures = new HashMap<>();
 	/** 18.1.3 bullet 5: throws α */
@@ -343,9 +343,9 @@
 	private TypeBound [] unincorporatedBounds = new TypeBound [1024];
 	private int unincorporatedBoundsCount = 0;
 	private TypeBound [] mostRecentBounds = new TypeBound[4]; // for quick & dirty duplicate elimination.
-	
+
 	public BoundSet() {}
-	
+
 	// pre: typeParameters != null, variables[i].typeParameter == typeParameters[i]
 	public void addBoundsFromTypeParameters(InferenceContext18 context, TypeVariableBinding[] typeParameters, InferenceVariable[] variables) {
 		int length = typeParameters.length;
@@ -396,7 +396,7 @@
 	}
 
 	public void addBound(TypeBound bound, LookupEnvironment environment) {
-		
+
 		if (bound.relation == ReductionResult.SUBTYPE && bound.right.id == TypeIds.T_JavaLangObject)
 			return;
 		if (bound.left == bound.right) //$IDENTITY-COMPARISON$
@@ -417,12 +417,12 @@
 				return;
 			}
 		}
-		
+
 		this.mostRecentBounds[3] = this.mostRecentBounds[2];
 		this.mostRecentBounds[2] = this.mostRecentBounds[1];
 		this.mostRecentBounds[1] = this.mostRecentBounds[0];
 		this.mostRecentBounds[0] = bound;
-				
+
 		InferenceVariable variable = bound.left.prototype();
 		ThreeSets three = this.boundsPerVariable.get(variable);
 		if (three == null)
@@ -459,13 +459,13 @@
 		}
 		return hasProperBound;
 	}
-	
+
 	public void addBounds(BoundSet that, LookupEnvironment environment) {
 		if (that == null || environment == null)
 			return;
 		addBounds(that.flatten(), environment);
 	}
-	
+
 	public boolean isInstantiated(InferenceVariable inferenceVariable) {
 		ThreeSets three = this.boundsPerVariable.get(inferenceVariable.prototype());
 		if (three != null)
@@ -477,7 +477,7 @@
 		ThreeSets three = this.boundsPerVariable.get(inferenceVariable.prototype());
 		if (three != null) {
 			TypeBinding instantiation = three.instantiation;
-			if (environment != null && environment.globalOptions.isAnnotationBasedNullAnalysisEnabled 
+			if (environment != null && environment.globalOptions.isAnnotationBasedNullAnalysisEnabled
 					&& instantiation != null && (instantiation.tagBits & TagBits.AnnotationNullMASK) == 0)
 				return three.combineAndUseNullHints(instantiation, inferenceVariable.nullHints, environment);
 			return instantiation;
@@ -493,22 +493,22 @@
 		}
 		return num;
 	}
-	
-	// Driver for the real workhorse - Implements generational incorporation a la generational garbage collector. 
+
+	// Driver for the real workhorse - Implements generational incorporation a la generational garbage collector.
 	boolean incorporate(InferenceContext18 context) throws InferenceFailureException {
-		
+
 		if (this.unincorporatedBoundsCount == 0 && this.captures.size() == 0)
 			return true;
-		
+
 		do {
 			TypeBound [] freshBounds;
 			System.arraycopy(this.unincorporatedBounds, 0, freshBounds = new TypeBound[this.unincorporatedBoundsCount], 0, this.unincorporatedBoundsCount);
 			this.unincorporatedBoundsCount = 0;
-			
+
 			// Pairwise bidirectional compare all bounds from previous generation with the fresh set.
 			if (!incorporate(context, this.incorporatedBounds, freshBounds))
 				return false;
-			// Pairwise bidirectional compare all fresh bounds. 
+			// Pairwise bidirectional compare all fresh bounds.
 			if (!incorporate(context, freshBounds, freshBounds))
 				return false;
 
@@ -519,17 +519,17 @@
 			System.arraycopy(this.incorporatedBounds, 0, aggregate, 0, incorporatedLength);
 			System.arraycopy(freshBounds, 0, aggregate, incorporatedLength, unincorporatedLength);
 			this.incorporatedBounds = aggregate;
-			
+
 		} while (this.unincorporatedBoundsCount > 0);
-		
+
 		return true;
 	}
 	/**
 	 * <b>JLS 18.3:</b> Try to infer new constraints from pairs of existing type bounds.
 	 * Each new constraint is first reduced and checked for TRUE or FALSE, which will
-	 * abort the processing. 
+	 * abort the processing.
 	 * @param context the context that manages our inference variables
-	 * @return false if any constraint resolved to false, true otherwise  
+	 * @return false if any constraint resolved to false, true otherwise
 	 * @throws InferenceFailureException a compile error has been detected during inference
 	 */
 	boolean incorporate(InferenceContext18 context, TypeBound [] first, TypeBound [] next) throws InferenceFailureException {
@@ -604,10 +604,10 @@
 						mostRecentFormulas[2] = mostRecentFormulas[1];
 						mostRecentFormulas[1] = mostRecentFormulas[0];
 						mostRecentFormulas[0] = newConstraint;
-					
+
 						if (!reduceOneConstraint(context, newConstraint))
 							return false;
-						
+
 						if (analyzeNull) {
 							// not per JLS: if the new constraint relates types where at least one has a null annotations,
 							// record all null tagBits as hints for the final inference solution.
@@ -638,7 +638,7 @@
 			}
 		}
 		/* TODO: are we sure this will always terminate? Cf. e.g. (Discussion in 18.3):
-		 *  
+		 *
 		 *    "The assertion that incorporation reaches a fixed point oversimplifies the matter slightly. ..."
 		 */
 		Iterator<Entry<ParameterizedTypeBinding, ParameterizedTypeBinding>> captIter = this.captures.entrySet().iterator();
@@ -685,7 +685,7 @@
 								bi1 = context.object; // implicit bound
 							}
 							// If Bi is Object, α <: R implies ⟨T <: R⟩	(extends wildcard)
-							// α <: R implies ⟨θ Bi <: R⟩				(else) 
+							// α <: R implies ⟨θ Bi <: R⟩				(else)
 							it = three.subBounds.iterator();
 							while (it.hasNext()) {
 								TypeBound bound = it.next();
@@ -708,7 +708,7 @@
 						}
 						if (three.superBounds != null) {
 							//  R <: α implies ⟨R <: T⟩  (super wildcard)
-							//  R <: α implies false	 (else) 
+							//  R <: α implies false	 (else)
 							it = three.superBounds.iterator();
 							while (it.hasNext()) {
 								TypeBound bound = it.next();
@@ -746,7 +746,7 @@
 	}
 
 	private ConstraintTypeFormula combineSameSame(TypeBound boundS, TypeBound boundT, TypeBound[] firstBounds, TypeBound[] nextBounds) {
-		
+
 		// α = S and α = T imply ⟨S = T⟩
 		if (TypeBinding.equalsEquals(boundS.left, boundT.left))
 			return ConstraintTypeFormula.create(boundS.right, boundT.right, ReductionResult.SAME, boundS.isSoft||boundT.isSoft);
@@ -763,7 +763,7 @@
 	}
 
 	// pre: boundLeft.left != boundRight.left
-	private ConstraintTypeFormula combineSameSameWithProperType(TypeBound boundLeft, TypeBound boundRight, 
+	private ConstraintTypeFormula combineSameSameWithProperType(TypeBound boundLeft, TypeBound boundRight,
 			TypeBound[] firstBounds, TypeBound[] nextBounds) {
 		//  α = U and S = T imply ⟨S[α:=U] = T[α:=U]⟩
 		TypeBinding u = boundLeft.right;
@@ -781,9 +781,9 @@
 		}
 		return null;
 	}
-	
+
 	private ConstraintTypeFormula combineSameSubSuper(TypeBound boundS, TypeBound boundT, TypeBound[] firstBounds, TypeBound[] nextBounds) {
-		//  α = S and α <: T imply ⟨S <: T⟩ 
+		//  α = S and α <: T imply ⟨S <: T⟩
 		//  α = S and T <: α imply ⟨T <: S⟩
 		InferenceVariable alpha = boundS.left;
 		TypeBinding s = boundS.right;
@@ -807,7 +807,7 @@
 			if (TypeBinding.equalsEquals(alpha, boundT.right)) {
 				TypeBinding t = boundT.left;
 				return ConstraintTypeFormula.create(t, s, boundT.relation, boundT.isSoft||boundS.isSoft);
-			}			
+			}
 		}
 		return combineSameSubSuperWithProperType(boundS, boundT, alpha, firstBounds, nextBounds);
 	}
@@ -818,7 +818,7 @@
 			InferenceVariable alpha, TypeBound[] firstBounds, TypeBound[] nextBounds) {
 		//  α = U and S <: T imply ⟨S[α:=U] <: T[α:=U]⟩
 		TypeBinding u = boundLeft.right;
-		
+
 		if (enableOptimizationForBug543480 && isParameterizedDependency(boundRight)) {
 			// Performance optimization: do not incorporate arguments one by one, which yielt 2^n new bounds (n=number of type arguments) in the past.
 			// Instead, all arguments of a parameterized dependency are incorporated at once - but only when they are available.
@@ -835,7 +835,7 @@
 		}
 		return null;
 	}
-	
+
 	private ConstraintTypeFormula combineSuperAndSub(TypeBound boundS, TypeBound boundT) {
 		//  permutations of: S <: α and α <: T imply ⟨S <: T⟩
 		InferenceVariable alpha = boundS.left;
@@ -851,14 +851,14 @@
 		}
 		return null;
 	}
-	
+
 	private ConstraintTypeFormula combineEqualSupers(TypeBound boundS, TypeBound boundT) {
 		//  more permutations of: S <: α and α <: T imply ⟨S <: T⟩
 		if (TypeBinding.equalsEquals(boundS.left, boundT.right))
-			// came in as: α REL S and T REL α imply ⟨T REL S⟩ 
+			// came in as: α REL S and T REL α imply ⟨T REL S⟩
 			return ConstraintTypeFormula.create(boundT.left, boundS.right, boundS.relation, boundT.isSoft||boundS.isSoft);
 		if (TypeBinding.equalsEquals(boundS.right, boundT.left))
-			// came in as: S REL α and α REL T imply ⟨S REL T⟩ 
+			// came in as: S REL α and α REL T imply ⟨S REL T⟩
 			return ConstraintTypeFormula.create(boundS.left, boundT.right, boundS.relation, boundT.isSoft||boundS.isSoft);
 		return null;
 	}
@@ -868,7 +868,7 @@
 				&& !typeBound.right.isProperType(true) /* is a dependency, not a type bound */
 				&& typeBound.right.isParameterizedTypeWithActualArguments();
 	}
-	
+
 	private ConstraintTypeFormula incorporateIntoParameterizedDependencyIfAllArgumentsAreProperTypes(TypeBound typeBound,
 			TypeBound[] firstBounds, TypeBound[] nextBounds) {
 		Collection<TypeBound> properTypesForAllInferenceVariables = getProperTypesForAllInferenceVariablesOrNull((ParameterizedTypeBinding)typeBound.right, firstBounds, nextBounds);
@@ -877,8 +877,8 @@
 		}
 		return null;
 	}
-	
-	private Collection<TypeBound> getProperTypesForAllInferenceVariablesOrNull(ParameterizedTypeBinding parameterizedType, 
+
+	private Collection<TypeBound> getProperTypesForAllInferenceVariablesOrNull(ParameterizedTypeBinding parameterizedType,
 			TypeBound[] firstBounds, TypeBound[] nextBounds) {
 		final Map<InferenceVariable,TypeBound> properTypesByInferenceVariable = properTypesByInferenceVariable(firstBounds, nextBounds);
 		if(properTypesByInferenceVariable.size() == 0) {
@@ -896,7 +896,7 @@
 				.filter(bound -> bound.relation == ReductionResult.SAME)
 				.filter(bound -> bound.right.isProperType(true))
 				.collect(toMap(bound -> bound.left, identity(),
-						// If nextBounds and firstBounds have a bound for the IV, prefer the newer one from nextBounds. 
+						// If nextBounds and firstBounds have a bound for the IV, prefer the newer one from nextBounds.
 						(boundFromNextBounds, boundFromFirstBounds) -> boundFromNextBounds));
 	}
 
@@ -918,7 +918,7 @@
 		}
 		return inferenceVariables;
 	}
-	
+
 	private ConstraintTypeFormula combineWithProperTypes(Collection<TypeBound> properTypesForAllInferenceVariables, TypeBound boundRight) {
 		// either: α = U, β = V, ... and S =  T imply ⟨S[α:=U, β:=V, ...] =  T[α:=U, β:=V, ...]⟩
 		// or:     α = U, β = V, ... and S <: T imply ⟨S[α:=U, β:=V, ...] <: T[α:=U, β:=V, ...]⟩
@@ -928,7 +928,7 @@
 		boolean isAnyLeftSoft = false;
 		InferenceVariable left = boundRight.left;
 		TypeBinding right = boundRight.right;
-		for(final TypeBound properTypeForInferenceVariable: properTypesForAllInferenceVariables) {			
+		for(final TypeBound properTypeForInferenceVariable: properTypesForAllInferenceVariables) {
 			final TypeBound boundLeft = properTypeForInferenceVariable;
 			final InferenceVariable alpha = boundLeft.left;
 			final TypeBinding u = boundLeft.right;
@@ -942,7 +942,7 @@
 		/* From 18.4:
 		 *  If two bounds have the form α <: S and α <: T, and if for some generic class or interface, G,
 		 *  there exists a supertype (4.10) of S of the form G<S1, ..., Sn> and a supertype of T of the form G<T1, ..., Tn>,
-		 *  then for all i, 1 ≤ i ≤ n, if Si and Ti are types (not wildcards), the constraint ⟨Si = Ti⟩ is implied. 
+		 *  then for all i, 1 ≤ i ≤ n, if Si and Ti are types (not wildcards), the constraint ⟨Si = Ti⟩ is implied.
 		 */
 		// callers must ensure both relations are <: and both lefts are equal
 		TypeBinding[] supers = superTypesWithCommonGenericType(boundS.right, boundT.right);
@@ -960,7 +960,7 @@
 		TypeBinding[] tis = t.typeArguments();
 		if (sis == null || tis == null || sis.length != tis.length)
 			return null;
-		List<ConstraintTypeFormula> result = new ArrayList<>(); 
+		List<ConstraintTypeFormula> result = new ArrayList<>();
 		for (int i = 0; i < sis.length; i++) {
 			TypeBinding si = sis[i];
 			TypeBinding ti = tis[i];
@@ -1006,7 +1006,7 @@
 
 	/**
 	 * Helper for resolution (18.4):
-	 * Does this bound set define a direct dependency between the two given inference variables? 
+	 * Does this bound set define a direct dependency between the two given inference variables?
 	 */
 	public boolean dependsOnResolutionOf(InferenceVariable alpha, InferenceVariable beta) {
 		alpha = alpha.prototype();
@@ -1025,7 +1025,7 @@
 					ParameterizedTypeBinding captured = entry.getValue();
 					if (captured.mentionsAny(new TypeBinding[]{beta}, -1/*don't care about index*/))
 						return true;
-					if (g.mentionsAny(new TypeBinding[]{beta}, i)) // exclude itself 
+					if (g.mentionsAny(new TypeBinding[]{beta}, i)) // exclude itself
 						return true;
 				} else if (TypeBinding.equalsEquals(g.arguments[i], beta)) {
 					betaIsInCaptureLhs = true;
@@ -1112,7 +1112,7 @@
 
 	/**
 	 * JLS 18.1.3:
-	 * Answer all upper bounds for the given inference variable as defined by any bounds in this set. 
+	 * Answer all upper bounds for the given inference variable as defined by any bounds in this set.
 	 */
 	public TypeBinding[] upperBounds(InferenceVariable variable, boolean onlyProper) {
 		ThreeSets three = this.boundsPerVariable.get(variable.prototype());
@@ -1122,10 +1122,10 @@
 		// TODO: if !onlyProper: should we also consider ThreeSets.inverseBounds,
 		//        or is it safe to rely on incorporation to produce the required bounds?
 	}
-	
+
 	/**
 	 * JLS 18.1.3:
-	 * Answer all lower bounds for the given inference variable as defined by any bounds in this set. 
+	 * Answer all lower bounds for the given inference variable as defined by any bounds in this set.
 	 */
 	TypeBinding[] lowerBounds(InferenceVariable variable, boolean onlyProper) {
 		ThreeSets three = this.boundsPerVariable.get(variable.prototype());
@@ -1163,7 +1163,7 @@
 	}
 	// this condition is just way too complex to check it in-line:
 	public boolean condition18_5_2_bullet_3_3_1(InferenceVariable alpha, TypeBinding targetType) {
-		// T is a reference type, but is not a wildcard-parameterized type, and either 
+		// T is a reference type, but is not a wildcard-parameterized type, and either
 		// i) B2 contains a bound of one of the forms α = S or S <: α, where S is a wildcard-parameterized type, or ...
 		if (targetType.isBaseType()) return false;
 		if (InferenceContext18.parameterizedWithWildcard(targetType) != null) return false;
@@ -1197,7 +1197,7 @@
 					TypeBinding s2 = superBounds.get(j).right;
 					TypeBinding[] supers = superTypesWithCommonGenericType(s1, s2);
 					if (supers != null) {
-						/* HashMap<K#8,V#9> and HashMap<K#8,ArrayList<T>> with an instantiation for V9 = ArrayList<T> already in the 
+						/* HashMap<K#8,V#9> and HashMap<K#8,ArrayList<T>> with an instantiation for V9 = ArrayList<T> already in the
 						   bound set should not be seen as two different parameterizations of the same generic class or interface.
 						   See https://bugs.eclipse.org/bugs/show_bug.cgi?id=432626 for a test that triggers this condition.
 						   See https://bugs.openjdk.java.net/browse/JDK-8056092: recommendation is to check for proper types.
@@ -1247,7 +1247,7 @@
 			return s.isCompatibleWith(env.convertToRawType(g, false));
 		return false;
 	}
-	
+
 	protected TypeBinding[] superTypesWithCommonGenericType(TypeBinding s, TypeBinding t) {
 		if (s == null || s.id == TypeIds.T_JavaLangObject || t == null || t.id == TypeIds.T_JavaLangObject)
 			return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
index cd6da93..a3e888f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java
@@ -72,7 +72,7 @@
 			}
 		}
 	}
-	
+
 	// for subclass CaptureBinding18
 	protected CaptureBinding(ReferenceBinding sourceType, char[] sourceName, int start, int end, int captureID, LookupEnvironment environment) {
 		super(sourceName, null, 0, environment);
@@ -94,7 +94,7 @@
 		this.tagBits |= (prototype.tagBits & TagBits.HasCapturedWildcard);
 		this.cud = prototype.cud;
 	}
-	
+
 	// Captures may get cloned and annotated during type inference.
 	@Override
 	public TypeBinding clone(TypeBinding enclosingType) {
@@ -397,7 +397,7 @@
 		}
 		return super.readableName();
 	}
-	
+
 	@Override
 	public char[] signableName() {
 		if (this.wildcard != null) {
@@ -429,7 +429,7 @@
 		}
 		return super.shortReadableName();
 	}
-	
+
 	@Override
 	public char[] nullAnnotatedReadableName(CompilerOptions options, boolean shortNames) {
 	    StringBuffer nameBuffer = new StringBuffer(10);
@@ -467,13 +467,13 @@
 			return this;
 		if (this.wildcard != null && this.wildcard.hasNullTypeAnnotations()) {
 			WildcardBinding newWildcard = (WildcardBinding) this.wildcard.withoutToplevelNullAnnotation();
-			if (newWildcard != this.wildcard) { //$IDENTITY-COMPARISON$	
-				
+			if (newWildcard != this.wildcard) { //$IDENTITY-COMPARISON$
+
 				CaptureBinding newCapture = (CaptureBinding) this.environment.getUnannotatedType(this).clone(null);
 				if (newWildcard.hasTypeAnnotations())
 					newCapture.tagBits |= TagBits.HasTypeAnnotations;
 				newCapture.wildcard = newWildcard;
-				
+
 				// manually transfer the following two, because we are not in a context where we can call initializeBounds():
 				newCapture.superclass = this.superclass;
 				newCapture.superInterfaces = this.superInterfaces;
@@ -514,7 +514,7 @@
 			this.pendingSubstitute = null;
 		}
 	}
-	
+
 	@Override
 	public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) {
 		super.setTypeAnnotations(annotations, evalNullAnnotations);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
index d00704b..ad96463 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding18.java
@@ -20,7 +20,7 @@
  * Capture-like type variable introduced during 1.8 type inference.
  */
 public class CaptureBinding18 extends CaptureBinding {
-	
+
 	TypeBinding[] upperBounds;
 	private char[] originalName;
 	private CaptureBinding18 prototype;
@@ -30,13 +30,13 @@
 		this.originalName = originalName;
 		this.prototype = this;
 	}
-	
+
 	private CaptureBinding18(CaptureBinding18 prototype) {
 		super(prototype);
 		this.sourceName = CharOperation.append(prototype.sourceName, '\'');
 		this.originalName = prototype.originalName;
 		this.upperBounds = prototype.upperBounds;
-		this.prototype = prototype.prototype;		
+		this.prototype = prototype.prototype;
 	}
 
 	public boolean setUpperBounds(TypeBinding[] upperBounds, ReferenceBinding javaLangObject) {
@@ -141,7 +141,7 @@
 			return true;
 		if (this.inRecursiveFunction)
 			return true;
-		this.inRecursiveFunction = true; 
+		this.inRecursiveFunction = true;
 		try {
 			if (this.upperBounds != null) {
 				int length = this.upperBounds.length;
@@ -187,7 +187,7 @@
 				if (candidate != null)
 					return candidate;
 				// TODO: maybe we should double check about multiple candidates here,
-				// but upper bounds should be consistent so hopefully the first non-null candidate is good enough. 
+				// but upper bounds should be consistent so hopefully the first non-null candidate is good enough.
 			}
 		}
 		return super.findSuperTypeOriginatingFrom(otherType);
@@ -277,7 +277,7 @@
 
 	@Override
 	public boolean isProperType(boolean admitCapture18) {
-		if (!admitCapture18) 
+		if (!admitCapture18)
 			return false;
 		if (this.inRecursiveFunction)
 			return true;
@@ -352,7 +352,7 @@
 		}
 		return super.shortReadableName();
 	}
-	
+
 	@Override
 	public TypeBinding uncapture(Scope scope) {
 		return this;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CatchParameterBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CatchParameterBinding.java
index 5df69c7..25da77e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CatchParameterBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CatchParameterBinding.java
@@ -16,13 +16,13 @@
 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
 
 public class CatchParameterBinding extends LocalVariableBinding {
-	
+
 	TypeBinding [] preciseTypes = Binding.NO_EXCEPTIONS;  // the catch block can be entered with the parameters set to these types.
-	
+
 	public CatchParameterBinding(LocalDeclaration declaration, TypeBinding type, int modifiers, boolean isArgument) {
 		super(declaration, type, modifiers, isArgument);
 	}
-	
+
 	public TypeBinding [] getPreciseTypes() {
 		return this.preciseTypes;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
index d8db622..59bf9d0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -43,7 +43,7 @@
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;
+import org.eclipse.jdt.internal.compiler.ast.QualifiedAllocationExpression;import org.eclipse.jdt.internal.compiler.ast.RecordDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
@@ -105,6 +105,12 @@
 					problemReporter().cannotExtendEnum(anonymousType, typeReference, supertype);
 					anonymousType.tagBits |= TagBits.HierarchyHasProblems;
 					anonymousType.setSuperClass(getJavaLangObject());
+				} else if (supertype.erasure().id == TypeIds.T_JavaLangRecord) {
+					if (!(this.referenceContext instanceof RecordDeclaration)) {
+						problemReporter().recordCannotExtendRecord(anonymousType, typeReference, supertype);
+						anonymousType.tagBits |= TagBits.HierarchyHasProblems;
+						anonymousType.setSuperClass(getJavaLangObject());
+					}
 				} else if (supertype.isFinal()) {
 					problemReporter().anonymousClassCannotExtendFinalClass(typeReference, supertype);
 					anonymousType.tagBits |= TagBits.HierarchyHasProblems;
@@ -346,7 +352,7 @@
 		if (sourceType.areMethodsInitialized()) return;
 
 		boolean isEnum = TypeDeclaration.kind(this.referenceContext.modifiers) == TypeDeclaration.ENUM_DECL;
-		if (this.referenceContext.methods == null && !isEnum) {
+		if (this.referenceContext.methods == null && !(isEnum || sourceType.isRecord())) {
 			this.referenceContext.binding.setMethods(Binding.NO_METHODS);
 			return;
 		}
@@ -399,6 +405,11 @@
 			if (hasAbstractMethods)
 				problemReporter().abstractMethodInConcreteClass(sourceType);
 		}
+		if (sourceType.isRecord()) {
+			assert this.referenceContext instanceof RecordDeclaration;
+			methodBindings = sourceType.checkAndAddSyntheticRecordMethods(methodBindings, count);
+			count = methodBindings.length;
+		}
 		if (count != methodBindings.length)
 			System.arraycopy(methodBindings, 0, methodBindings = new MethodBinding[count], 0, count);
 		sourceType.tagBits &= ~(TagBits.AreMethodsSorted|TagBits.AreMethodsComplete); // in case some static imports reached already into this type
@@ -512,6 +523,10 @@
 	private void checkAndSetModifiers() {
 		SourceTypeBinding sourceType = this.referenceContext.binding;
 		int modifiers = sourceType.modifiers;
+		if (sourceType.isRecord()) {
+			/* JLS 14 Records Sec 8.10 - A record declaration is implicitly final. */
+			modifiers |= ClassFileConstants.AccFinal;
+		}
 		if ((modifiers & ExtraCompilerModifiers.AccAlternateModifierProblem) != 0)
 			problemReporter().duplicateModifierForType(sourceType);
 		ReferenceBinding enclosingType = sourceType.enclosingType();
@@ -530,6 +545,9 @@
 					modifiers |= ClassFileConstants.AccStatic;
 			} else if (sourceType.isInterface()) {
 				modifiers |= ClassFileConstants.AccStatic; // 8.5.1
+			} else if (sourceType.isRecord()) {
+				/* JLS 14 Records Sec 8.10 A nested record type is implicitly static */
+				modifiers |= ClassFileConstants.AccStatic;
 			}
 		} else if (sourceType.isLocalType()) {
 			if (sourceType.isEnum()) {
@@ -697,6 +715,37 @@
 					modifiers |= ClassFileConstants.AccFinal;
 				}
 			}
+		} else if (sourceType.isRecord()) {
+			if (isMemberType) {
+				final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic | ClassFileConstants.AccPrivate | ClassFileConstants.AccProtected | ClassFileConstants.AccStatic | ClassFileConstants.AccFinal | ClassFileConstants.AccStrictfp);
+				if ((realModifiers & UNEXPECTED_MODIFIERS) != 0)
+					problemReporter().illegalModifierForInnerRecord(sourceType);
+			} else if (sourceType.isLocalType()) {
+				final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccAbstract | ClassFileConstants.AccFinal | ClassFileConstants.AccStrictfp | ClassFileConstants.AccStatic);
+				if ((realModifiers & UNEXPECTED_MODIFIERS) != 0)
+					problemReporter().illegalModifierForLocalClass(sourceType);
+			} else {
+				final int UNEXPECTED_MODIFIERS = ~(ClassFileConstants.AccPublic |  ClassFileConstants.AccFinal | ClassFileConstants.AccStrictfp);
+				if ((realModifiers & UNEXPECTED_MODIFIERS) != 0)
+					problemReporter().illegalModifierForRecord(sourceType);
+			}
+			// JLS 14 8.10 : It is a compile-time error if a record declaration has the modifier abstract.
+
+			/* Section 8.10 http://cr.openjdk.java.net/~gbierman/8222777/8222777-20190823/specs/records-jls.html#jls-8.10
+			 * It is a compile-time error if a record declaration has the modifier abstract.
+			 *
+			 * A record declaration is implicitly final. It is permitted for the declaration of a record type
+			 * to redundantly specify the final modifier.
+			 *
+			 * A nested record type is implicitly static. It is permitted for the declaration of a nested record
+			 * type to redundantly specify the static modifier.
+			 *
+			 * This implies that it is impossible to declare a record type in the body of an inner class (8.1.3),
+			 * because an inner class cannot have static members except for constant variables.
+			 *
+			 * It is a compile-time error if the same keyword appears more than once as a modifier for a record declaration,
+			 * or if a record declaration has more than one of the access modifiers public, protected, and private (6.6).
+			 */
 		} else {
 			// detect abnormal cases for classes
 			if (isMemberType) { // includes member types defined inside local types
@@ -752,6 +801,9 @@
 				if (enclosingType.isInterface())
 					modifiers |= ClassFileConstants.AccStatic;
 			} else if (!enclosingType.isStatic()) {
+				if (sourceType.isRecord())
+					problemReporter().recordNestedRecordInherentlyStatic(sourceType);
+				else
 				// error the enclosing type of a static field must be static or a top-level type
 				problemReporter().illegalStaticModifierForMemberType(sourceType);
 			}
@@ -1017,6 +1069,12 @@
 				problemReporter().superTypeCannotUseWildcard(sourceType, superclassRef, superclass);
 			} else if (superclass.erasure().id == TypeIds.T_JavaLangEnum) {
 				problemReporter().cannotExtendEnum(sourceType, superclassRef, superclass);
+			} else if (superclass.erasure().id == TypeIds.T_JavaLangRecord) {
+				if (!(this.referenceContext instanceof RecordDeclaration)) {
+					problemReporter().recordCannotExtendRecord(sourceType, superclassRef, superclass);
+				} else {
+					return connectRecordSuperclass();
+				}
 			} else if ((superclass.tagBits & TagBits.HierarchyHasProblems) != 0
 					|| !superclassRef.resolvedType.isValidBinding()) {
 				sourceType.setSuperClass(superclass);
@@ -1028,12 +1086,12 @@
 				sourceType.typeBits |= (superclass.typeBits & TypeIds.InheritableBits);
 				// further analysis against white lists for the unlikely case we are compiling java.io.*:
 				if ((sourceType.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0)
-					sourceType.typeBits |= sourceType.applyCloseableClassWhitelists();
+					sourceType.typeBits |= sourceType.applyCloseableClassWhitelists(this.compilerOptions());
 				return true;
 			}
 		}
 		sourceType.tagBits |= TagBits.HierarchyHasProblems;
-		sourceType.setSuperClass(getJavaLangObject());
+		sourceType.setSuperClass(sourceType.isRecord() ? getJavaLangRecord() : getJavaLangObject());
 		if ((sourceType.superclass.tagBits & TagBits.BeginHierarchyCheck) == 0)
 			detectHierarchyCycle(sourceType, sourceType.superclass, null);
 		return false; // reported some error against the source type
@@ -1076,6 +1134,16 @@
 		return !foundCycle;
 	}
 
+	private boolean connectRecordSuperclass() {
+		SourceTypeBinding sourceType = this.referenceContext.binding;
+		ReferenceBinding rootRecordType = getJavaLangRecord();
+		sourceType.setSuperClass(rootRecordType);
+		if ((rootRecordType.tagBits & TagBits.HasMissingType) != 0) {
+			sourceType.tagBits |= TagBits.HierarchyHasProblems; // mark missing supertpye
+			return false;
+		}
+		return !detectHierarchyCycle(sourceType, rootRecordType, null);
+	}
 	/*
 		Our current belief based on available JCK 1.3 tests is:
 			inherited member types are visible as a potential superclass.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
index 1445509..ab667b1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -711,7 +711,7 @@
 		problemReporter().isClassPathCorrect(
 				TypeConstants.JAVA_LANG_OBJECT,
 			this.referenceContext,
-			this.environment.missingClassFileLocation);
+			this.environment.missingClassFileLocation, false);
 		BinaryTypeBinding missingObject = this.environment.createMissingType(null, TypeConstants.JAVA_LANG_OBJECT);
 		importBinding = missingObject.fPackage;
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java
index 84394cd..bd4d223 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java
@@ -35,13 +35,13 @@
 public class ConstraintExceptionFormula extends ConstraintFormula {
 
 	FunctionalExpression left;
-	
+
 	public ConstraintExceptionFormula(FunctionalExpression left, TypeBinding type) {
 		this.left = left;
 		this.right = type;
 		this.relation = EXCEPTIONS_CONTAINED;
 	}
-	
+
 	@Override
 	public Object reduce(InferenceContext18 inferenceContext) {
 		// JLS 18.2.5
@@ -61,7 +61,7 @@
 			if (sam.returnType != TypeBinding.VOID && !sam.returnType.isProperType(true))
 				return FALSE;
 		} else { // reference expression
-			if (!((ReferenceExpression)this.left).isExactMethodReference()) {					
+			if (!((ReferenceExpression)this.left).isExactMethodReference()) {
 				int nParam = sam.parameters.length;
 				for (int i = 0; i < nParam; i++)
 					if (!sam.parameters[i].isProperType(true))
@@ -76,13 +76,13 @@
 		for (int i = 0; i < thrown.length; i++)
 			if (!thrown[i].isProperType(true))
 				e[n++] = (InferenceVariable) thrown[i]; // thrown[i] is not a proper type, since it's an exception it must be an inferenceVariable, right?
-		
+
 		/* If throw specification does not encode any type parameters, there are no constraints to be gleaned/gathered from the throw sites.
 		   See also that thrown exceptions are not allowed to influence compatibility and overload resolution.
 		*/
 		if (n == 0)
 			return TRUE;
-		
+
 		TypeBinding[] ePrime = null;
 		if (this.left instanceof LambdaExpression) {
 			LambdaExpression lambda = ((LambdaExpression) this.left).resolveExpressionExpecting(this.right, inferenceContext.scope, inferenceContext);
@@ -108,7 +108,7 @@
 					continue actual;
 			for (int j = 0; j < n; j++)
 				result.add(ConstraintTypeFormula.create(ePrime[i], e[j], SUBTYPE));
-		}				
+		}
 		for (int j = 0; j < n; j++)
 			inferenceContext.currentBounds.inThrows.add(e[j].prototype());
 		return result.toArray(new ConstraintFormula[result.size()]);
@@ -131,7 +131,7 @@
 					for (int i = 0; i < len; i++) {
 						sam.parameters[i].collectInferenceVariables(variables);
 					}
-				} 
+				}
 				if (sam.returnType != TypeBinding.VOID) {
 					// ii)
 					sam.returnType.collectInferenceVariables(variables);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
index ccf6562..c8d11c7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java
@@ -51,7 +51,7 @@
 		this.right = type;
 		this.relation = relation;
 	}
-	
+
 	ConstraintExpressionFormula(Expression expression, TypeBinding type, int relation, boolean isSoft) {
 		this(expression, type, relation);
 		this.isSoft = isSoft;
@@ -59,17 +59,17 @@
 
 	@Override
 	public Object reduce(InferenceContext18 inferenceContext) throws InferenceFailureException {
-		
+
 		if (this.relation == POTENTIALLY_COMPATIBLE) {
-			/* 15.12.2.1: ... The definition of potential applicability goes beyond a basic arity check to also take into account the presence and "shape" of functional interface 
-			   target types. In some cases involving type argument inference, a lambda expression appearing as a method invocation argument cannot be properly typed until after 
-			   overload resolution. These rules allow the form of the lambda expression to still be taken into account, discarding obviously incorrect target types that might 
+			/* 15.12.2.1: ... The definition of potential applicability goes beyond a basic arity check to also take into account the presence and "shape" of functional interface
+			   target types. In some cases involving type argument inference, a lambda expression appearing as a method invocation argument cannot be properly typed until after
+			   overload resolution. These rules allow the form of the lambda expression to still be taken into account, discarding obviously incorrect target types that might
 			   otherwise cause ambiguity errors.
 			*/
-			
+
 			return  this.left.isPotentiallyCompatibleWith(this.right, inferenceContext.scope) ? TRUE: FALSE;
 		}
-	
+
 		// JLS 18.2.1
 		if (this.right.isProperType(true)) {
 			if (this.left.isCompatibleWith(this.right, inferenceContext.scope) || this.left.isBoxingCompatibleWith(this.right, inferenceContext.scope)) {
@@ -98,7 +98,7 @@
 					return null; 				// -> proceed with no new constraints
 				MethodBinding method = previousMethod;
 				// ignore previous (inner) inference result and do a fresh start:
-				// avoid original(), since we only want to discard one level of instantiation 
+				// avoid original(), since we only want to discard one level of instantiation
 				// (method type variables - not class type variables)!
 				method = previousMethod.shallowOriginal();
 				SuspendedInferenceRecord prevInvocation = inferenceContext.enterPolyInvocation(invocation, invocation.arguments());
@@ -113,7 +113,7 @@
 					if (previousMethod instanceof ParameterizedGenericMethodBinding) {
 						// find the previous inner inference context to see what inference kind this invocation needs:
 						innerCtx = invocation.getInferenceContext((ParameterizedGenericMethodBinding) previousMethod);
-						if (innerCtx == null) { 
+						if (innerCtx == null) {
 							/* No inference context -> the method was likely manufactured by Scope.findExactMethod -> assume it wasn't really poly after all.
 							   -> proceed as for non-poly expressions.
 							*/
@@ -161,7 +161,7 @@
 					return TRUE; // assume inner inference will handle the fine print
 				if (!this.right.isFunctionalInterface(scope))
 					return FALSE;
-				
+
 				ReferenceBinding t = (ReferenceBinding) this.right;
 				ParameterizedTypeBinding withWildCards = InferenceContext18.parameterizedWithWildcard(t);
 				if (withWildCards != null) {
@@ -240,7 +240,7 @@
 	}
 
 	private boolean canBePolyExpression(Expression expr) {
-		// when inferring compatibility against a right type, the check isPolyExpression 
+		// when inferring compatibility against a right type, the check isPolyExpression
 		// must assume that expr occurs in s.t. like an assignment context:
 		ExpressionContext previousExpressionContext = expr.getExpressionContext();
 		if (previousExpressionContext == ExpressionContext.VANILLA_CONTEXT)
@@ -352,7 +352,7 @@
 		} else {
 			compileTimeReturn =  original.returnType;
 		}
-		return (original.typeVariables() != Binding.NO_TYPE_VARIABLES 
+		return (original.typeVariables() != Binding.NO_TYPE_VARIABLES
 				&& compileTimeReturn.mentionsAny(original.typeVariables(), -1));
 	}
 
@@ -397,8 +397,8 @@
 	}
 
 	/** Perform steps from JLS 18.5.2. needed for computing the bound set B3. */
-	static boolean inferPolyInvocationType(InferenceContext18 inferenceContext, InvocationSite invocationSite, TypeBinding targetType, MethodBinding method) 
-				throws InferenceFailureException 
+	static boolean inferPolyInvocationType(InferenceContext18 inferenceContext, InvocationSite invocationSite, TypeBinding targetType, MethodBinding method)
+				throws InferenceFailureException
 	{
 		TypeBinding[] typeArguments = invocationSite.genericTypeArguments();
 		if (typeArguments == null) {
@@ -530,7 +530,7 @@
 					sam.parameters[i].collectInferenceVariables(variables);
 				}
 				return variables;
-			}			
+			}
 		} else if (this.left instanceof ConditionalExpression && this.left.isPolyExpression()) {
 			ConditionalExpression expr = (ConditionalExpression) this.left;
 			Set<InferenceVariable> variables = new HashSet<>();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java
index 898c3ec..36bf8c3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintFormula.java
@@ -38,7 +38,7 @@
 	Collection<InferenceVariable> inputVariables(InferenceContext18 context) {
 		return EMPTY_VARIABLE_LIST;
 	}
-	
+
 	Collection<InferenceVariable> outputVariables(InferenceContext18 context) {
 		Set<InferenceVariable> variables = new HashSet<>();
 		this.right.collectInferenceVariables(variables);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java
index 830ca76..33fa2bb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintTypeFormula.java
@@ -33,18 +33,18 @@
 class ConstraintTypeFormula extends ConstraintFormula {
 
 	TypeBinding left;
-	
+
 	// this flag contributes to the workaround controlled by InferenceContext18.ARGUMENT_CONSTRAINTS_ARE_SOFT:
 	boolean isSoft;
 
 	public static ConstraintTypeFormula create(TypeBinding exprType, TypeBinding right, int relation) {
-		if (exprType == null || right == null) 
+		if (exprType == null || right == null)
 			return FALSE;
 		return new ConstraintTypeFormula(exprType, right, relation, false);
 	}
 
 	public static ConstraintTypeFormula create(TypeBinding exprType, TypeBinding right, int relation, boolean isSoft) {
-		if (exprType == null || right == null) 
+		if (exprType == null || right == null)
 			return FALSE;
 		return new ConstraintTypeFormula(exprType, right, relation, isSoft);
 	}
@@ -83,7 +83,7 @@
 					break;
 				//$FALL-THROUGH$ array of parameterized is handled below:
 			case Binding.PARAMETERIZED_TYPE:
-				{																
+				{
 					//															  this.right = G<T1,T2,...> or G<T1,T2,...>[]k
 					TypeBinding gs = this.left.findSuperTypeOriginatingFrom(this.right);	// G<S1,S2,...> or G<S1,S2,...>[]k
 					if (gs != null && gs.leafComponentType().isRawType()) {
@@ -110,7 +110,7 @@
 			// 18.2.3:
 			if (this.right.kind() != Binding.WILDCARD_TYPE) { // "If T is a type" ... all alternatives require "wildcard"
 				if (this.left.kind() != Binding.WILDCARD_TYPE) {
-					return ConstraintTypeFormula.create(this.left, this.right, SAME, this.isSoft);						
+					return ConstraintTypeFormula.create(this.left, this.right, SAME, this.isSoft);
 				} else {
 					// TODO: speculative addition:
 					if (this.right instanceof InferenceVariable)
@@ -129,15 +129,15 @@
 						switch (s.boundKind) {
 							case Wildcard.UNBOUND:
 								return ConstraintTypeFormula.create(inferenceContext.object, t.bound, SUBTYPE, this.isSoft);
-							case Wildcard.EXTENDS: 
+							case Wildcard.EXTENDS:
 								return ConstraintTypeFormula.create(s.bound, t.bound, SUBTYPE, this.isSoft);
-							case Wildcard.SUPER: 
+							case Wildcard.SUPER:
 								return ConstraintTypeFormula.create(inferenceContext.object, t.bound, SAME, this.isSoft);
 							default:
 								throw new IllegalArgumentException("Unexpected boundKind "+s.boundKind);  //$NON-NLS-1$
 						}
 					}
-				} else { // SUPER 
+				} else { // SUPER
 					if (this.left.kind() != Binding.WILDCARD_TYPE) {
 						return ConstraintTypeFormula.create(t.bound, this.left, SUBTYPE, this.isSoft);
 					} else {
@@ -181,7 +181,7 @@
 					||(leftWC.boundKind == Wildcard.SUPER && rightWC.boundKind == Wildcard.SUPER))
 				{
 					return ConstraintTypeFormula.create(leftWC.bound, rightWC.bound, SAME, this.isSoft);
-				}						
+				}
 			}
 		} else {
 			if (this.right.kind() != Binding.WILDCARD_TYPE) {
@@ -200,9 +200,9 @@
 				if (this.right instanceof InferenceVariable && !this.left.isPrimitiveType()) {
 					return new TypeBound((InferenceVariable) this.right, this.left, SAME, this.isSoft);
 				}
-				if ((this.left.isClass() || this.left.isInterface()) 
+				if ((this.left.isClass() || this.left.isInterface())
 						&& (this.right.isClass() || this.right.isInterface())
-						&& TypeBinding.equalsEquals(this.left.erasure(), this.right.erasure())) 
+						&& TypeBinding.equalsEquals(this.left.erasure(), this.right.erasure()))
 				{
 					TypeBinding[] leftParams = this.left.typeArguments();
 					TypeBinding[] rightParams = this.right.typeArguments();
@@ -268,7 +268,7 @@
 					boolean isFirst = true;
 					while (superCandidate != null && superCandidate.kind() == Binding.PARAMETERIZED_TYPE && subCandidate != null)  {
 						if (!addConstraintsFromTypeParameters(subCandidate, (ParameterizedTypeBinding) superCandidate, constraints))
-							if (isFirst) return FALSE;				
+							if (isFirst) return FALSE;
 						isFirst = false;
 						// travel to enclosing types to check if they have type parameters, too:
 						superCandidate = superCandidate.enclosingType();
@@ -300,7 +300,7 @@
 						sPrimeArray = findMostSpecificSuperArray(subTVB.firstBound, subTVB.otherUpperBounds(), subTVB);
 						break;
 					}
-				default:					
+				default:
 					return FALSE;
 				}
 				if (sPrimeArray == null)
@@ -360,7 +360,7 @@
 		}
 		throw new IllegalStateException("Unexpected RHS "+superCandidate); //$NON-NLS-1$
 	}
-	
+
 	private ArrayBinding findMostSpecificSuperArray(TypeBinding firstBound, TypeBinding[] otherUpperBounds, TypeBinding theType) {
 		int numArrayBounds = 0;
 		ArrayBinding result = null;
@@ -385,7 +385,7 @@
 	boolean addConstraintsFromTypeParameters(TypeBinding subCandidate, ParameterizedTypeBinding ca, List<ConstraintFormula> constraints) {
 		TypeBinding cb = subCandidate.findSuperTypeOriginatingFrom(ca);	// C<B1,B2,...>
 		if (cb == null)
-			return false; // nothing here means we failed 
+			return false; // nothing here means we failed
 		if (TypeBinding.equalsEquals(ca, cb)) // incl C#RAW vs C#RAW
 			return true;
 		if (!(cb instanceof ParameterizedTypeBinding)) {
@@ -397,17 +397,17 @@
 		if (ai == null)
 			return true; // no arguments here means nothing to check
 		if (cb.isRawType() || bi == null || bi.length == 0)
-			return (this.isSoft && InferenceContext18.SIMULATE_BUG_JDK_8026527) ? true : false; // FALSE would conform to the spec 
+			return (this.isSoft && InferenceContext18.SIMULATE_BUG_JDK_8026527) ? true : false; // FALSE would conform to the spec
 		for (int i = 0; i < ai.length; i++)
 			constraints.add(ConstraintTypeFormula.create(bi[i], ai[i], TYPE_ARGUMENT_CONTAINED, this.isSoft));
 		return true;
 	}
 
 	public boolean equalsEquals (ConstraintTypeFormula that) {
-		return (that != null && this.relation == that.relation && this.isSoft == that.isSoft && 
+		return (that != null && this.relation == that.relation && this.isSoft == that.isSoft &&
 					TypeBinding.equalsEquals(this.left, that.left) && TypeBinding.equalsEquals(this.right, that.right));
 	}
-	
+
 	@Override
 	public boolean applySubstitution(BoundSet solutionSet, InferenceVariable[] variables) {
 		super.applySubstitution(solutionSet, variables);
@@ -426,7 +426,7 @@
 	public String toString() {
 		StringBuffer buf = new StringBuffer("Type Constraint:\n"); //$NON-NLS-1$
 		buf.append('\t').append(LEFT_ANGLE_BRACKET);
-		appendTypeName(buf, this.left); 
+		appendTypeName(buf, this.left);
 		buf.append(relationToString(this.relation));
 		appendTypeName(buf, this.right);
 		buf.append(RIGHT_ANGLE_BRACKET);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ElementValuePair.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ElementValuePair.java
index dea720c..ff19f33 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ElementValuePair.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ElementValuePair.java
@@ -23,7 +23,7 @@
 	char[] name;
 	public Object value;
 	public MethodBinding binding;
-	
+
 	/**
 	 * We want to avoid eagerly resolving of all enums that are used in annotations.
 	 * This class encapsulates an unresolved enum constant as referenced in an ElementValuePair.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExternalAnnotationSuperimposer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExternalAnnotationSuperimposer.java
index b1785aa..f4dfe20 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExternalAnnotationSuperimposer.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExternalAnnotationSuperimposer.java
@@ -55,7 +55,7 @@
 		} catch (FileNotFoundException e) {
 			// file not found is expected
 		} catch (IOException e) {
-			typeBinding.scope.problemReporter().abortDueToInternalError(Messages.bind(Messages.abort_externaAnnotationFile, 
+			typeBinding.scope.problemReporter().abortDueToInternalError(Messages.bind(Messages.abort_externaAnnotationFile,
 						new String[] {String.valueOf(typeBinding.readableName()), externalAnnotationPath, e.getMessage()}));
 		} finally {
 			if (zipFile != null)
@@ -118,7 +118,7 @@
 	private TypeBinding typeReplacement;
 	private LookupEnvironment environment;
 	private boolean isReplacing;
-	
+
 	ExternalAnnotationSuperimposer(LookupEnvironment environment) {
 		this.environment = environment;
 	}
@@ -157,13 +157,13 @@
 			return cl.cast(this.typeReplacement);
 		return type;
 	}
-	
+
 	private TypeBinding goAndSuperimpose(ITypeAnnotationWalker walker, TypeBinding type) {
 		// no reset here
 		if (walker == ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER)
 			return type;
 		this.currentWalker = walker;
-		
+
 		TypeBindingVisitor.visit(this, type);
 
 		if (this.typeReplacement == null)
@@ -173,7 +173,7 @@
 		this.typeReplacement = null;
 		return answer;
 	}
-	
+
 	@Override
 	public boolean visit(ArrayBinding arrayBinding) {
 		ExternalAnnotationSuperimposer memento = snapshot();
@@ -229,7 +229,7 @@
 			return false;
 		} finally {
 			restore(memento);
-		}		
+		}
 	}
 	@Override
 	public boolean visit(RawTypeBinding rawTypeBinding) {
@@ -254,7 +254,7 @@
 			if (bound != null) {
 				bound = goAndSuperimpose(memento.currentWalker.toWildcardBound(), bound);
 			}
-			IBinaryAnnotation[] binaryAnnotations = memento.currentWalker.getAnnotationsAtCursor(-1, false); 
+			IBinaryAnnotation[] binaryAnnotations = memento.currentWalker.getAnnotationsAtCursor(-1, false);
 			if (this.isReplacing || binaryAnnotations != ITypeAnnotationWalker.NO_ANNOTATIONS) {
 				TypeBinding[] otherBounds = wildcardBinding.otherBounds;
 				if (binaryAnnotations != ITypeAnnotationWalker.NO_ANNOTATIONS) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java
index ab10b8a..97329cc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ExtraCompilerModifiers.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -40,11 +40,12 @@
 	final int AccAlternateModifierProblem = ASTNode.Bit23;
 	final int AccModifierProblem = ASTNode.Bit24;
 	final int AccSemicolonBody = ASTNode.Bit25;
+	final int AccRecord = ASTNode.Bit25;
 	final int AccUnresolved = ASTNode.Bit26;
 	final int AccBlankFinal = ASTNode.Bit27; // for blank final variables
 	final int AccIsDefaultConstructor = ASTNode.Bit27; // for default constructor
 	final int AccLocallyUsed = ASTNode.Bit28; // used to diagnose unused (a) private/local members or (b) members of private classes
-											  // generally set when actual usage has been detected 
+											  // generally set when actual usage has been detected
 											  // or, (b) when member of a private class is exposed via a non-private subclass
 											  //     see https://bugs.eclipse.org/bugs/show_bug.cgi?id=328281
 	final int AccVisibilityMASK = ClassFileConstants.AccPublic | ClassFileConstants.AccProtected | ClassFileConstants.AccPrivate;
@@ -52,4 +53,5 @@
 	final int AccOverriding = ASTNode.Bit29; // record fact a method overrides another one
 	final int AccImplementing = ASTNode.Bit30; // record fact a method implements another one (it is concrete and overrides an abstract one)
 	final int AccGenericSignature = ASTNode.Bit31; // record fact a type/method/field involves generics in its signature (and need special signature attr)
+	final int AccPatternVariable = ASTNode.Bit29;
 }
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 86e05be..1d71ef9 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
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -414,6 +414,9 @@
 public final int kind() {
 	return FIELD;
 }
+public boolean isRecordComponent() {
+	return this.declaringClass != null && this.declaringClass.isRecord() && !this.isStatic();
+}
 /* Answer true if the receiver is visible to the invocationPackage.
 */
 /**
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
index 95594bd..c91697b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2018 GK Software AG, IBM Corporation and others.
+ * Copyright (c) 2012, 2020 GK Software SE, IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -25,6 +25,7 @@
 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
 import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching.CheckMode;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 
 /**
@@ -96,15 +97,15 @@
 			// compatibility & inheritance do not consider constructors / static methods:
 			boolean isInstanceMethod = !currentMethod.isConstructor() && !currentMethod.isStatic();
 			complain &= isInstanceMethod;
-			if (!needToApplyNonNullDefault 
-					&& !complain 
+			if (!needToApplyNonNullDefault
+					&& !complain
 					&& !(this.inheritNullAnnotations && isInstanceMethod)) {
 				return; // short cut, no work to be done
 			}
 
 			if (isInstanceMethod) {
 				List superMethodList = new ArrayList();
-				
+
 				// need super types connected:
 				if (currentType instanceof SourceTypeBinding && !currentType.isHierarchyConnected() && !currentType.isAnonymousType()) {
 					((SourceTypeBinding) currentType).scope.connectTypeHierarchy();
@@ -113,8 +114,8 @@
 				int paramLen = currentMethod.parameters.length;
 				findAllOverriddenMethods(currentMethod.original(), currentMethod.selector, paramLen,
 								currentType, new HashSet(), superMethodList);
-				
-				// prepare interim storage for nullness info so we don't pollute currentMethod before we know its conflict-free: 
+
+				// prepare interim storage for nullness info so we don't pollute currentMethod before we know its conflict-free:
 				InheritedNonNullnessInfo[] inheritedNonNullnessInfos = new InheritedNonNullnessInfo[paramLen+1]; // index 0 is for the return type
 				for (int i=0; i<paramLen+1; i++) inheritedNonNullnessInfos[i] = new InheritedNonNullnessInfo();
 
@@ -128,7 +129,7 @@
 					checkNullSpecInheritance(currentMethod, srcMethod, needToApplyReturnNonNullDefault, needToApplyParameterNonNullDefault, complain, currentSuper, null, scope, inheritedNonNullnessInfos);
 					needToApplyNonNullDefault = false;
 				}
-				
+
 				// transfer collected information into currentMethod:
 				InheritedNonNullnessInfo info = inheritedNonNullnessInfos[0];
 				if (!info.complained) {
@@ -167,17 +168,17 @@
 				else
 					currentMethod.fillInDefaultNonNullness18(srcMethod, scope.environment());
 			}
-		} finally {			
+		} finally {
 			currentMethod.tagBits |= TagBits.IsNullnessKnown;
 		}
 	}
 
-	/* 
+	/*
 	 * Recursively traverse the tree of ancestors but whenever we find a matching method prune the super tree.
 	 * Collect all matching methods in 'result'.
 	 */
-	private void findAllOverriddenMethods(MethodBinding original, char[] selector, int suggestedParameterLength, 
-			ReferenceBinding currentType, Set ifcsSeen, List result) 
+	private void findAllOverriddenMethods(MethodBinding original, char[] selector, int suggestedParameterLength,
+			ReferenceBinding currentType, Set ifcsSeen, List result)
 	{
 		if (currentType.id == TypeIds.T_JavaLangObject)
 			return;
@@ -201,7 +202,7 @@
 
 	/* collect matching methods from one supertype. */
 	private void collectOverriddenMethods(MethodBinding original, char[] selector, int suggestedParameterLength,
-			ReferenceBinding superType, Set ifcsSeen, List result) 
+			ReferenceBinding superType, Set ifcsSeen, List result)
 	{
 		MethodBinding [] ifcMethods = superType.unResolvedMethods();
 		int length = ifcMethods.length;
@@ -229,7 +230,7 @@
 	 * @param srcMethod AST of 'currentMethod' if present
 	 * @param hasReturnNonNullDefault is a @NonNull default applicable for the return type of currentMethod?
 	 * @param hasParameterNonNullDefault is a @NonNull default applicable for parameters of currentMethod?
-	 * @param shouldComplain should we report any errors found? 
+	 * @param shouldComplain should we report any errors found?
 	 *   (see also comment about flows into this method, below).
 	 * @param inheritedMethod one overridden method from a super type
 	 * @param allInheritedMethods look here to see if nonnull-unannotated conflict already exists in one super type
@@ -238,9 +239,9 @@
 	 * 	 interim recording of nullness information from inheritedMethod rather than prematurely updating currentMethod.
 	 *   Index position 0 is used for the return type, positions i+1 for argument i.
 	 */
-	void checkNullSpecInheritance(MethodBinding currentMethod, AbstractMethodDeclaration srcMethod, 
+	void checkNullSpecInheritance(MethodBinding currentMethod, AbstractMethodDeclaration srcMethod,
 			boolean hasReturnNonNullDefault, ParameterNonNullDefaultProvider hasParameterNonNullDefault, boolean shouldComplain,
-			MethodBinding inheritedMethod, MethodBinding[] allInheritedMethods, Scope scope, InheritedNonNullnessInfo[] inheritedNonNullnessInfos) 
+			MethodBinding inheritedMethod, MethodBinding[] allInheritedMethods, Scope scope, InheritedNonNullnessInfo[] inheritedNonNullnessInfos)
 	{
 		if(currentMethod.declaringClass.id == TypeIds.T_JavaLangObject) {
 			// all method implementations in java.lang.Object return non-null results and accept nullable as parameter.
@@ -263,7 +264,7 @@
 		boolean useTypeAnnotations = this.environment.usesNullTypeAnnotations();
 		long inheritedNullnessBits = getReturnTypeNullnessTagBits(inheritedMethod, useTypeAnnotations);
 		long currentNullnessBits = getReturnTypeNullnessTagBits(currentMethod, useTypeAnnotations);
-		
+
 		boolean shouldInherit = this.inheritNullAnnotations;
 
 		// return type:
@@ -281,12 +282,12 @@
 							// 	still use the inherited bits to avoid incompatibility
 						}
 						if (inheritedNonNullnessInfos != null && srcMethod != null) {
-							recordDeferredInheritedNullness(scope, ((MethodDeclaration) srcMethod).returnType, 
+							recordDeferredInheritedNullness(scope, ((MethodDeclaration) srcMethod).returnType,
 									inheritedMethod, Boolean.valueOf(inheritedNullnessBits == TagBits.AnnotationNonNull), inheritedNonNullnessInfos[0]);
 						} else {
 							// no need to defer, record this info now:
 							applyReturnNullBits(currentMethod, inheritedNullnessBits);
-						}	
+						}
 						break returnType; // compatible by construction, skip complain phase below
 					}
 				}
@@ -353,7 +354,7 @@
 		for (int i = 0; i < length; i++) {
 			if (currentMethod.parameters[i].isBaseType()) continue;
 
-			Argument currentArgument = currentArguments == null 
+			Argument currentArgument = currentArguments == null
 										? null : currentArguments[i];
 			Boolean inheritedNonNullNess = getParameterNonNullness(inheritedMethod, i, useTypeAnnotations);
 			Boolean currentNonNullNess = getParameterNonNullness(currentMethod, i, useTypeAnnotations);
@@ -403,7 +404,7 @@
 					annotationName = this.environment.getNullableAnnotationName();
 				}
 				if (inheritedNonNullNess != Boolean.TRUE		// super parameter is not restricted to @NonNull
-						&& currentNonNullNess == Boolean.TRUE)	// current parameter is restricted to @NonNull 
+						&& currentNonNullNess == Boolean.TRUE)	// current parameter is restricted to @NonNull
 				{
 					// incompatible
 					if (currentArgument != null) {
@@ -415,10 +416,10 @@
 						scope.problemReporter().cannotImplementIncompatibleNullness(scope.referenceContext(), currentMethod, inheritedMethod, false);
 					}
 					continue;
-				} else if (currentNonNullNess == null) 
+				} else if (currentNonNullNess == null)
 				{
 					// unannotated strictly conflicts only with inherited @Nullable
-					if (inheritedNonNullNess == Boolean.FALSE) { 
+					if (inheritedNonNullNess == Boolean.FALSE) {
 						if (currentArgument != null) {
 							scope.problemReporter().parameterLackingNullableAnnotation(
 									currentArgument,
@@ -436,13 +437,16 @@
 								if (TypeBinding.equalsEquals(inheritedMethod.declaringClass, one.declaringClass) && getParameterNonNullness(one, i, useTypeAnnotations) != Boolean.TRUE)
 									continue parameterLoop;
 						}
-						scope.problemReporter().parameterLackingNonnullAnnotation(
-								currentArgument,
-								inheritedMethod.declaringClass,
-								annotationName);
+						if (currentArgument != null) {
+							scope.problemReporter().parameterLackingNonnullAnnotation(currentArgument, inheritedMethod.declaringClass, annotationName);
+						} else {
+							TypeDeclaration type = scope.classScope().referenceContext;
+							ASTNode location = type.superclass != null ? type.superclass : type;
+							scope.problemReporter().inheritedParameterLackingNonnullAnnotation(currentMethod, i+1, inheritedMethod.declaringClass, location, annotationName);
+						}
 						continue;
 					}
-				} 
+				}
 				if (useTypeAnnotations) {
 					TypeBinding inheritedParameter = inheritedMethod.parameters[i];
 					TypeBinding substituteParameter = substituteParameters != null ? substituteParameters[i] : null;
@@ -504,12 +508,12 @@
 
 	/* check for conflicting annotations and record here the info 'inheritedNonNullness' found in 'inheritedMethod'. */
 	protected void recordDeferredInheritedNullness(Scope scope, ASTNode location,
-			MethodBinding inheritedMethod, Boolean inheritedNonNullness, 
-			InheritedNonNullnessInfo nullnessInfo) 
+			MethodBinding inheritedMethod, Boolean inheritedNonNullness,
+			InheritedNonNullnessInfo nullnessInfo)
 	{
 		if (nullnessInfo.inheritedNonNullness != null && nullnessInfo.inheritedNonNullness != inheritedNonNullness) {
-			scope.problemReporter().conflictingInheritedNullAnnotations(location, 
-					nullnessInfo.inheritedNonNullness.booleanValue(), nullnessInfo.annotationOrigin, 
+			scope.problemReporter().conflictingInheritedNullAnnotations(location,
+					nullnessInfo.inheritedNonNullness.booleanValue(), nullnessInfo.annotationOrigin,
 					inheritedNonNullness.booleanValue(), inheritedMethod);
 			nullnessInfo.complained = true;
 			// leave previous info intact, so subsequent errors are reported against the same first method
@@ -538,7 +542,7 @@
 	}
 
 	// ==== minimal set of utility methods previously from MethodVerifier15: ====
-	
+
 	static boolean areParametersEqual(MethodBinding one, MethodBinding two) {
 		TypeBinding[] oneArgs = one.parameters;
 		TypeBinding[] twoArgs = two.parameters;
@@ -547,7 +551,7 @@
 		int length = oneArgs.length;
 		if (length != twoArgs.length) return false;
 
-		
+
 		// methods with raw parameters are considered equal to inherited methods
 		// with parameterized parameters for backwards compatibility, need a more complex check
 		int i;
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 d8da7dc..97c5a55 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
@@ -41,7 +41,7 @@
 /**
  * Main class for new type inference as per JLS8 sect 18.
  * Keeps contextual state and drives the algorithm.
- * 
+ *
  * <h2>Inference Basics</h2>
  * <ul>
  * <li>18.1.1 Inference variables: {@link InferenceVariable}</li>
@@ -111,14 +111,14 @@
 
 	/** to conform with javac regarding https://bugs.openjdk.java.net/browse/JDK-8026527 */
 	static final boolean SIMULATE_BUG_JDK_8026527 = true;
-	
-	/** Temporary workaround until we know fully what to do with https://bugs.openjdk.java.net/browse/JDK-8054721 
+
+	/** Temporary workaround until we know fully what to do with https://bugs.openjdk.java.net/browse/JDK-8054721
 	 *  It looks likely that we have a bug independent of this JLS bug in that we clear the capture bounds eagerly.
 	*/
 	static final boolean SHOULD_WORKAROUND_BUG_JDK_8054721 = true; // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=437444#c24 onwards
-	
+
 	static final boolean SHOULD_WORKAROUND_BUG_JDK_8153748 = true; // emulating javac behaviour after private email communication
-	
+
 	/**
 	 * Detail flag to control the extent of {@link #SIMULATE_BUG_JDK_8026527}.
 	 * A setting of 'false' implements the advice from http://mail.openjdk.java.net/pipermail/lambda-spec-experts/2013-December/000447.html
@@ -133,7 +133,7 @@
 	InvocationSite currentInvocation;
 	/** arguments of #currentInvocation, if any */
 	Expression[] invocationArguments;
-	
+
 	/** The inference variables for which as solution is sought. */
 	InferenceVariable[] inferenceVariables;
 
@@ -155,7 +155,7 @@
 	/** Invocation Type Inference (18.5.2) has been completed (for some target type). */
 	public static final int TYPE_INFERRED = 2;
 	public static final int TYPE_INFERRED_FINAL = 3; // as above plus asserting that target type was a proper type
-	
+
 	/** Signals whether any type compatibility makes use of unchecked conversion. */
 	public List<ConstraintFormula> constraintsWithUncheckedConversion;
 	public boolean usesUncheckedConversion;
@@ -167,12 +167,12 @@
 	public BoundSet b2;
 	private BoundSet b3;
 	/** Not per JLS: inbox for emulation of how javac passes type bounds from inner to outer */
-	private BoundSet innerInbox; 
+	private BoundSet innerInbox;
 	/** Not per JLS: signal when current is ready to directly merge all bounds from inner. */
 	private boolean directlyAcceptingInnerBounds = false;
 	/** Not per JLS: pushing bounds from inner to outer may have to be deferred till after overload resolution, store here a runnable to perform the push. */
 	private Runnable pushToOuterJob = null;
-	
+
 	public static boolean isSameSite(InvocationSite site1, InvocationSite site2) {
 		if (site1 == site2)
 			return true;
@@ -187,7 +187,7 @@
 	public static final int CHECK_STRICT = 1;
 	public static final int CHECK_LOOSE = 2;
 	public static final int CHECK_VARARG = 3;
-	
+
 	static class SuspendedInferenceRecord {
 		InvocationSite site;
 		Expression[] invocationArguments;
@@ -202,7 +202,7 @@
 			this.usesUncheckedConversion = usesUncheckedConversion;
 		}
 	}
-	
+
 	/** Construct an inference context for an invocation (method/constructor). */
 	public InferenceContext18(Scope scope, Expression[] arguments, InvocationSite site, InferenceContext18 outerContext) {
 		this.scope = scope;
@@ -226,7 +226,7 @@
 	 * @return the set of inference variables created for the given typeParameters
 	 */
 	public InferenceVariable[] createInitialBoundSet(TypeVariableBinding[] typeParameters) {
-		// 
+		//
 		if (this.currentBounds == null) {
 			this.currentBounds = new BoundSet();
 		}
@@ -239,7 +239,7 @@
 	}
 
 	/**
-	 * Substitute any type variables mentioned in 'type' by the corresponding inference variable, if one exists. 
+	 * Substitute any type variables mentioned in 'type' by the corresponding inference variable, if one exists.
 	 */
 	public TypeBinding substitute(TypeBinding type) {
 		InferenceSubstitution inferenceSubstitution = new InferenceSubstitution(this);
@@ -368,7 +368,7 @@
 					break;
 				}
 			}
-		}		
+		}
 	}
 
 	/** JLS 18.5.1 Invocation Applicability Inference. */
@@ -377,8 +377,8 @@
 	}
 
 	/** Perform steps from JLS 18.5.2. needed for computing the bound set B3. */
-	boolean computeB3(InvocationSite invocationSite, TypeBinding targetType, MethodBinding method) 
-				throws InferenceFailureException 
+	boolean computeB3(InvocationSite invocationSite, TypeBinding targetType, MethodBinding method)
+				throws InferenceFailureException
 	{
 		boolean result = ConstraintExpressionFormula.inferPolyInvocationType(this, invocationSite, targetType, method);
 		if (result) {
@@ -389,16 +389,16 @@
 		return result;
 	}
 
-	/** JLS 18.5.2 Invocation Type Inference 
+	/** JLS 18.5.2 Invocation Type Inference
 	 */
-	public BoundSet inferInvocationType(TypeBinding expectedType, InvocationSite invocationSite, MethodBinding method) throws InferenceFailureException 
+	public BoundSet inferInvocationType(TypeBinding expectedType, InvocationSite invocationSite, MethodBinding method) throws InferenceFailureException
 	{
 		// not JLS: simply ensure that null hints from the return type have been seen even in standalone contexts:
 		if (expectedType == null && method.returnType != null)
 			substitute(method.returnType); // result is ignore, the only effect is on InferenceVariable.nullHints
-		
+
 		this.currentBounds = this.b2.copy();
-		
+
 		int step = (expectedType == null || expectedType.isProperType(true)) ? TYPE_INFERRED_FINAL : TYPE_INFERRED;
 
 		try {
@@ -406,7 +406,7 @@
 			if (expectedType != null
 					&& expectedType != TypeBinding.VOID
 					&& invocationSite instanceof Expression && ((Expression) invocationSite).isTrulyExpression()
-					&& ((Expression)invocationSite).isPolyExpression(method)) 
+					&& ((Expression)invocationSite).isPolyExpression(method))
 			{
 				// 3. bullet: special treatment for poly expressions
 				if (!computeB3(invocationSite, expectedType, method)) {
@@ -457,7 +457,7 @@
 				// don't bother with finding the necessary superset, just resolve all:
 				if (solution == null)
 					solution = resolve(this.inferenceVariables);
-				// * ~ apply substitutions to all constraints: 
+				// * ~ apply substitutions to all constraints:
 				bottomIt = bottomSet.iterator();
 				while (bottomIt.hasNext()) {
 					ConstraintFormula constraint = bottomIt.next();
@@ -550,7 +550,9 @@
 			for (int i = 0; i < arguments.length; i++) {
 				Expression argument = arguments[i];
 				TypeBinding parameter = getParameter(method.parameters, i, method.isVarargs());
-				parameter = substitution.substitute(substitution, parameter); 
+				if (parameter == null)
+					return ReductionResult.FALSE;
+				parameter = substitution.substitute(substitution, parameter);
 				ReductionResult result = addJDK_8153748ConstraintsFromExpression(argument, parameter, method, substitution);
 				if (result == ReductionResult.FALSE)
 					return ReductionResult.FALSE;
@@ -607,7 +609,7 @@
 		}
 		return null;
 	}
-	
+
 	InferenceSubstitution enrichSubstitution(InferenceSubstitution substitution, Invocation innerInvocation, MethodBinding innerMethod) {
 		if (innerMethod instanceof ParameterizedGenericMethodBinding) {
 			InferenceContext18 innerContext = innerInvocation.getInferenceContext((ParameterizedMethodBinding) innerMethod);
@@ -696,7 +698,7 @@
 			MethodBinding innerMethod = invocation.binding();
 			if (innerMethod == null)
 				return true; 		  // -> proceed with no new C set elements.
-			
+
 			Expression[] arguments = invocation.arguments();
 			TypeBinding[] argumentTypes = arguments == null ? Binding.NO_PARAMETERS : new TypeBinding[arguments.length];
 			for (int i = 0; i < argumentTypes.length; i++)
@@ -704,7 +706,7 @@
 			InferenceContext18 innerContext = null;
 			if (innerMethod instanceof ParameterizedGenericMethodBinding)
 				 innerContext = invocation.getInferenceContext((ParameterizedGenericMethodBinding) innerMethod);
-			
+
 			if (innerContext != null) {
 				MethodBinding shallowMethod = innerMethod.shallowOriginal();
 				innerContext.outerContext = this;
@@ -736,7 +738,7 @@
 		return true;
 	}
 
-	
+
 	protected int getInferenceKind(MethodBinding nonGenericMethod, TypeBinding[] argumentTypes) {
 		switch (this.scope.parameterCompatibilityLevel(nonGenericMethod, argumentTypes)) {
 			case Scope.AUTOBOX_COMPATIBLE:
@@ -751,8 +753,8 @@
 	/**
 	 * 18.5.3 Functional Interface Parameterization Inference
 	 */
-	public ReferenceBinding inferFunctionalInterfaceParameterization(LambdaExpression lambda, BlockScope blockScope, 
-			ParameterizedTypeBinding targetTypeWithWildCards) 
+	public ReferenceBinding inferFunctionalInterfaceParameterization(LambdaExpression lambda, BlockScope blockScope,
+			ParameterizedTypeBinding targetTypeWithWildCards)
 	{
 		TypeBinding[] q = createBoundsForFunctionalInterfaceParameterizationInference(targetTypeWithWildCards);
 		if (q == null || q.length != lambda.arguments().length) {
@@ -779,7 +781,7 @@
 	/**
 	 * Create initial bound set for 18.5.3 Functional Interface Parameterization Inference
 	 * @param functionalInterface the functional interface F<A1,..Am>
-	 * @return the parameter types Q1..Qk of the function type of the type F<α1, ..., αm>, or null 
+	 * @return the parameter types Q1..Qk of the function type of the type F<α1, ..., αm>, or null
 	 */
 	TypeBinding[] createBoundsForFunctionalInterfaceParameterizationInference(ParameterizedTypeBinding functionalInterface) {
 		if (this.currentBounds == null)
@@ -868,7 +870,7 @@
 			return false;
 		}
 	}
-	
+
 	// FALSE: inference fails
 	// TRUE:  constraints have been incorporated
 	// null:  need to create the si <: ti constraint
@@ -892,13 +894,13 @@
 					for (int i = 0; i < elements.length; i++)
 						if (!siSuperI(elements[i], funcI))
 							break checkSuper;
-					return null;							// bullet 4 
+					return null;							// bullet 4
 					// each element of the intersection is a superinterface of I, or a parameterization of a superinterface of I.
 				}
 				for (int i = 0; i < elements.length; i++)
 					if (siSubI(elements[i], funcI))
 						return null;						// bullet 5
-						// some element of the intersection is a subinterface of I, or a parameterization of a subinterface of I.	
+						// some element of the intersection is a subinterface of I, or a parameterization of a subinterface of I.
 			}
 			// all passed, time to do some work:
 			TypeBinding siCapture = si.capture(this.scope, expri.sourceStart, expri.sourceEnd);
@@ -913,7 +915,7 @@
 		return null;
 	}
 
-	private boolean checkExpression(Expression expri, TypeBinding[] u, TypeBinding r1, TypeBinding[] v, TypeBinding r2) 
+	private boolean checkExpression(Expression expri, TypeBinding[] u, TypeBinding r1, TypeBinding[] v, TypeBinding r2)
 			throws InferenceFailureException {
 		if (expri instanceof LambdaExpression && !((LambdaExpression)expri).argumentsTypeElided()) {
 			for (int i = 0; i < u.length; i++) {
@@ -952,7 +954,7 @@
 							break checkPrimitive2;
 					}
 					return true;
-				}	
+				}
 			}
 			return reduceAndIncorporate(ConstraintTypeFormula.create(r1, r2, ReductionResult.SUBTYPE));
 		} else if (expri instanceof ReferenceExpression && ((ReferenceExpression)expri).isExactMethodReference()) {
@@ -965,7 +967,7 @@
 				return true;
 			MethodBinding method = reference.getExactMethod();
 			TypeBinding returnType = method.isConstructor() ? method.declaringClass : method.returnType;
-			if (r1.isPrimitiveType() && !r2.isPrimitiveType() && returnType.isPrimitiveType()) 
+			if (r1.isPrimitiveType() && !r2.isPrimitiveType() && returnType.isPrimitiveType())
 				return true;
 			if (r2.isPrimitiveType() && !r1.isPrimitiveType() && !returnType.isPrimitiveType())
 				return true;
@@ -1026,14 +1028,14 @@
 			this.b2 = this.currentBounds.copy(); // Preserve the result after reduction, without effects of resolve() for later use in invocation type inference.
 
 		BoundSet solution = resolve(this.inferenceVariables);
-		
+
 		/* If inferring applicability make a final pass over the initial constraints preserved as final constraints to make sure they hold true at a macroscopic level.
 		   See https://bugs.eclipse.org/bugs/show_bug.cgi?id=426537#c55 onwards.
 		*/
 		if (inferringApplicability && solution != null && this.finalConstraints != null) {
 			for (ConstraintExpressionFormula constraint: this.finalConstraints) {
 				if (constraint.left.isPolyExpression())
-					continue; // avoid redundant re-inference, inner poly's own constraints get validated in its own context & poly invocation type inference proved compatibility against target. 
+					continue; // avoid redundant re-inference, inner poly's own constraints get validated in its own context & poly invocation type inference proved compatibility against target.
 				constraint.applySubstitution(solution, this.inferenceVariables);
 				if (!this.currentBounds.reduceOneConstraint(this, constraint)) {
 					return null;
@@ -1042,11 +1044,11 @@
 		}
 		return solution;
 	}
-	
+
 	public /*@Nullable*/ BoundSet solve() throws InferenceFailureException {
 		return solve(false);
 	}
-	
+
 	public /*@Nullable*/ BoundSet solve(InferenceVariable[] toResolve) throws InferenceFailureException {
 		if (!reduce())
 			return null;
@@ -1057,8 +1059,8 @@
 	}
 
 	/**
-	 * JLS 18.2. reduce all initial constraints 
-	 * @throws InferenceFailureException 
+	 * JLS 18.2. reduce all initial constraints
+	 * @throws InferenceFailureException
 	 */
 	private boolean reduce() throws InferenceFailureException {
 		// Caution: This can be reentered recursively even as an earlier call is munching through the constraints !
@@ -1125,11 +1127,11 @@
 	/**
 	 * <b>JLS 18.4</b> Resolution
 	 * @return answer null if some constraint resolved to FALSE, otherwise the boundset representing the solution
-	 * @throws InferenceFailureException 
+	 * @throws InferenceFailureException
 	 */
 	private /*@Nullable*/ BoundSet resolve(InferenceVariable[] toResolve) throws InferenceFailureException {
 		this.captureId = 0;
-		// NOTE: 18.5.2 ... 
+		// NOTE: 18.5.2 ...
 		// "(While it was necessary to demonstrate that the inference variables in B1 could be resolved
 		//   in order to establish applicability, the resulting instantiations are not considered part of B1.)
 		// For this reason, resolve works on a temporary bound set, copied before any modification.
@@ -1178,7 +1180,7 @@
 												if (glb == null) {
 													// inconsistent intersection
 													tmpBoundSet = prevBoundSet; // clean up
-													break variables; // and start over													
+													break variables; // and start over
 												}
 											}
 										}
@@ -1199,7 +1201,7 @@
 					final BoundSet kurrentBoundSet = tmpBoundSet;
 					Substitution theta = new Substitution() {
 						@Override
-						public LookupEnvironment environment() { 
+						public LookupEnvironment environment() {
 							return InferenceContext18.this.environment;
 						}
 						@Override
@@ -1272,7 +1274,7 @@
 		}
 		return tmpBoundSet;
 	}
-	
+
 	private TypeBinding intersectionFromGlb(TypeBinding[] glbs) {
 		ReferenceBinding[] refGlbs = new ReferenceBinding[glbs.length];
 		for (int i = 0; i < glbs.length; i++) {
@@ -1288,9 +1290,9 @@
 			return intersection;
 		return null;
 	}
-	
+
 	int captureId = 0;
-	
+
 	/** For 18.4: "Let Z1, ..., Zn be fresh type variables" use capture bindings. */
 	private CaptureBinding18 freshCapture(InferenceVariable variable) {
 		int id = this.captureId++;
@@ -1301,7 +1303,7 @@
 						start, end, id, this.environment);
 	}
 	// === ===
-	
+
 	private boolean setUpperBounds(CaptureBinding18 typeVariable, TypeBinding[] substitutedUpperBounds) {
 		// 18.4: ... define the upper bound of Zi as glb(L1θ, ..., Lkθ)
 		if (substitutedUpperBounds.length == 1) {
@@ -1328,7 +1330,7 @@
 		Arrays.sort(types, new Comparator<TypeBinding>() {
 			@Override
 			public int compare(TypeBinding o1, TypeBinding o2) {
-				int i1 = o1.id, i2 = o2.id; 
+				int i1 = o1.id, i2 = o2.id;
 				return (i1<i2 ? -1 : (i1==i2 ? 0 : 1));
 			}
 		});
@@ -1340,7 +1342,7 @@
 	 */
 	private Set<InferenceVariable> getSmallestVariableSet(BoundSet bounds, InferenceVariable[] subSet) {
 		// "Given a set of inference variables to resolve, let V be the union of this set and
-		//  all variables upon which the resolution of at least one variable in this set depends." 
+		//  all variables upon which the resolution of at least one variable in this set depends."
 		Set<InferenceVariable> v = new HashSet<InferenceVariable>();
 		Map<InferenceVariable,Set<InferenceVariable>> dependencies = new HashMap<>(); // compute only once, store for the final loop over 'v'.
 		for (InferenceVariable iv : subSet) {
@@ -1399,7 +1401,7 @@
 		// causing non-termination of the algorithm.
 		// Since that is not acceptable, I'm *interpreting* the spec to request a search for a constraint
 		// that "best matches" the given conditions.
-		
+
 		// collect all constraints participating in a cycle
 		HashMap<ConstraintFormula,Set<ConstraintFormula>> dependencies = new HashMap<ConstraintFormula, Set<ConstraintFormula>>();
 		Set<ConstraintFormula> cycles = new HashSet<ConstraintFormula>();
@@ -1438,7 +1440,7 @@
 		}
 		if (candidatesII.isEmpty())
 			candidatesII = c; // not spec'ed but needed to avoid returning null below, witness: java.util.stream.Collectors
-		
+
 		// tentatively: (iii)  has the form ⟨Expression → T⟩
 		Set<ConstraintFormula> candidatesIII = new HashSet<ConstraintFormula>();
 		for (ConstraintFormula candidate : candidatesII) {
@@ -1450,7 +1452,7 @@
 		} else { // candidatesIII contains all relevant constraints ⟨Expression → T⟩
 			// (iv) contains an expression that appears to the left of the expression
 			// 		of every other constraint satisfying the previous three requirements
-			
+
 			// collect containment info regarding all expressions in candidate constraints:
 			// (a) find minimal enclosing expressions:
 			Map<ConstraintExpressionFormula,ConstraintExpressionFormula> expressionContainedBy = new HashMap<ConstraintExpressionFormula, ConstraintExpressionFormula>();
@@ -1477,7 +1479,7 @@
 					containmentForest.put(parent, children = new HashSet<ConstraintExpressionFormula>());
 				children.add(parentRelation.getKey());
 			}
-			
+
 			// approximate the spec by searching the largest containment tree:
 			int bestRank = -1;
 			ConstraintExpressionFormula candidate = null;
@@ -1491,7 +1493,7 @@
 			if (candidate != null)
 				return candidate;
 		}
-		
+
 		if (candidatesIII.isEmpty())
 			throw new IllegalStateException("cannot pick constraint from cyclic set"); //$NON-NLS-1$
 		return candidatesIII.iterator().next();
@@ -1543,7 +1545,7 @@
 	}
 
 	/** non-roots answer -1, roots answer the size of the spanned tree */
-	private int rankNode(ConstraintExpressionFormula parent, 
+	private int rankNode(ConstraintExpressionFormula parent,
 			Map<ConstraintExpressionFormula,ConstraintExpressionFormula> expressionContainedBy,
 			Map<ConstraintExpressionFormula, Set<ConstraintExpressionFormula>> containmentForest)
 	{
@@ -1561,7 +1563,7 @@
 		return sum;
 	}
 
-	private Set<ConstraintFormula> findBottomSet(Set<ConstraintFormula> constraints, 
+	private Set<ConstraintFormula> findBottomSet(Set<ConstraintFormula> constraints,
 			Set<InferenceVariable> allOutputVariables, List<Set<InferenceVariable>> components)
 	{
 		// 18.5.2 bullet 5.(1)
@@ -1612,7 +1614,7 @@
 			types[i] = last;
 		return types;
 	}
-	
+
 	public SuspendedInferenceRecord enterPolyInvocation(InvocationSite invocation, Expression[] innerArguments) {
 		SuspendedInferenceRecord record = new SuspendedInferenceRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind, this.usesUncheckedConversion);
 		this.inferenceVariables = null;
@@ -1621,7 +1623,7 @@
 		this.usesUncheckedConversion = false;
 		return record;
 	}
-	
+
 	public SuspendedInferenceRecord enterLambda(LambdaExpression lambda) {
 		SuspendedInferenceRecord record = new SuspendedInferenceRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind, this.usesUncheckedConversion);
 		this.inferenceVariables = null;
@@ -1656,7 +1658,7 @@
 			System.arraycopy(this.inferenceVariables, 0, this.inferenceVariables=new InferenceVariable[l1+l2], l2, l1);
 			System.arraycopy(record.inferenceVariables, 0, this.inferenceVariables, 0, l2);
 		}
-		
+
 		// replace invocation site & arguments:
 		this.currentInvocation = record.site;
 		this.invocationArguments = record.invocationArguments;
@@ -1673,11 +1675,11 @@
 		}
 		return this.seenInnerContexts.add(innerContext);
 	}
-	
+
 	private Substitution getResultSubstitution(final BoundSet result) {
 		return new Substitution() {
 			@Override
-			public LookupEnvironment environment() { 
+			public LookupEnvironment environment() {
 				return InferenceContext18.this.environment;
 			}
 			@Override
@@ -1708,7 +1710,7 @@
 	public static TypeBinding getParameter(TypeBinding[] parameters, int rank, boolean isVarArgs) {
 		if (isVarArgs) {
 			if (rank >= parameters.length-1)
-				return ((ArrayBinding)parameters[parameters.length-1]).elementsType();			
+				return ((ArrayBinding)parameters[parameters.length-1]).elementsType();
 		} else if (rank >= parameters.length) {
 			return null;
 		}
@@ -1730,7 +1732,7 @@
 		}
 		/* 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.
 		   if we get here with expected type set to null at all, the target context does not define a target type (vanilla context), so inference has done its
-		   best and nothing more to do than to signal error. 
+		   best and nothing more to do than to signal error.
 		 */
 		ProblemMethodBinding problemMethod = new ProblemMethodBinding(method, method.selector, method.parameters, ProblemReasons.InvocationTypeInferenceFailure);
 		problemMethod.returnType = expectedType != null ? expectedType : method.returnType;
@@ -1816,7 +1818,7 @@
 		this.constraintsWithUncheckedConversion.add(constraint);
 		this.usesUncheckedConversion = true;
 	}
-	
+
 	void reportUncheckedConversions(BoundSet solution) {
 		if (this.constraintsWithUncheckedConversion != null) {
 			int len = this.constraintsWithUncheckedConversion.size();
@@ -1840,7 +1842,7 @@
 			}
 		}
 	}
-	
+
 	/** For use by 15.12.2.6 Method Invocation Type */
 	public boolean usesUncheckedConversion() {
 		return this.constraintsWithUncheckedConversion != null;
@@ -1869,7 +1871,7 @@
 				if (binding instanceof ParameterizedGenericMethodBinding) {
 					MethodBinding shallowOriginal = binding.shallowOriginal();
 					TypeBinding[] solutions = getSolutions(shallowOriginal.typeVariables(), polyInvocation, result);
-					if (solutions == null)  // in CEF.reduce, we lift inner poly expressions into outer context only if their target type has inference variables. 
+					if (solutions == null)  // in CEF.reduce, we lift inner poly expressions into outer context only if their target type has inference variables.
 						continue;
 					methodSubstitute = this.environment.createParameterizedGenericMethod(shallowOriginal, solutions);
 				} else {
@@ -1878,7 +1880,7 @@
 					MethodBinding shallowOriginal = binding.shallowOriginal();
 					ReferenceBinding genericType = shallowOriginal.declaringClass;
 					TypeBinding[] solutions = getSolutions(genericType.typeVariables(), polyInvocation, result);
-					if (solutions == null)  // in CEF.reduce, we lift inner poly expressions into outer context only if their target type has inference variables. 
+					if (solutions == null)  // in CEF.reduce, we lift inner poly expressions into outer context only if their target type has inference variables.
 						continue;
 					ParameterizedTypeBinding parameterizedType = this.environment.createParameterizedType(genericType, solutions, binding.declaringClass.enclosingType());
 					for (MethodBinding parameterizedMethod : parameterizedType.methods()) {
@@ -1899,7 +1901,7 @@
 					}
 				}
 				TypeBinding parameterType = InferenceContext18.getParameter(parameters, i, variableArity);
-				forwardResults(result, polyInvocation, methodSubstitute, parameterType);		
+				forwardResults(result, polyInvocation, methodSubstitute, parameterType);
 			}
 		}
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceFailureException.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceFailureException.java
index a017f1a..1882702 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceFailureException.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceFailureException.java
@@ -21,9 +21,9 @@
 	private static final long serialVersionUID = 1L;
 
 	// TODO(stephan); add more details so that ProblemReported can eventually manufacture an appropriate message
-	
+
 	public InferenceFailureException(String message) {
 		super(message);
 	}
-	
+
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java
index 938bfec..7c49396 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java
@@ -55,7 +55,7 @@
 				return false;
 			}
 		};
-		
+
 		int l1 = this.sites.length;
 		subst.sites = new InvocationSite[l1+1];
 		System.arraycopy(this.sites, 0, subst.sites, 0, l1);
@@ -74,7 +74,7 @@
 	}
 
 	/**
-	 * Override method {@link Scope.Substitutor#substitute(Substitution, TypeBinding)}, 
+	 * Override method {@link Scope.Substitutor#substitute(Substitution, TypeBinding)},
 	 * to add substitution of types other than type variables.
 	 */
 	@Override
@@ -127,7 +127,7 @@
 				continue;
 			}
 			if (superInterfaces != null) {
-				int ifcLen = superInterfaces.length; 
+				int ifcLen = superInterfaces.length;
 				for (int j = 0; j < ifcLen; j++) {
 					if (TypeBinding.equalsEquals(pi, superInterfaces[j])) {
 						if (superInterfaces == typeVariable.superInterfaces)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
index e19f81d..e3f54db 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
@@ -22,7 +22,7 @@
  * Implementation of 18.1.1 in JLS8
  */
 public class InferenceVariable extends TypeVariableBinding {
-	
+
 	/** Structured key for interning. */
 	static class InferenceVarKey {
 		/*@NonNull*/ TypeBinding typeParameter;
@@ -58,7 +58,7 @@
 			if (TypeBinding.notEquals(this.typeParameter, other.typeParameter))
 				return false;
 			return true;
-		}	
+		}
 	}
 
 	/**
@@ -88,9 +88,9 @@
 	long nullHints; // one of TagBits.{AnnotationNonNull,AnnotationNullable} may steer inference into inferring nullness as well; set both bits to request avoidance.
 	private InferenceVariable prototype;
 	int varId; // this is used for constructing a source name like T#0.
-	public boolean isFromInitialSubstitution; 	// further ivars created during 18.5.2 (for capture bounds) set this to false 
+	public boolean isFromInitialSubstitution; 	// further ivars created during 18.5.2 (for capture bounds) set this to false
 												// to mark that they don't participate in any theta substitution
-	
+
 	private InferenceVariable(TypeBinding typeParameter, int parameterRank, int iVarId, InvocationSite site, LookupEnvironment environment, ReferenceBinding object, boolean initial) {
 		this(typeParameter, parameterRank, site, makeName(typeParameter, iVarId), environment, object);
 		this.varId = iVarId;
@@ -198,17 +198,17 @@
 	public boolean hasTypeBit(int bit) {
 		throw new UnsupportedOperationException();
 	}
-	
+
 	@Override
 	public String debugName() {
 		return String.valueOf(this.sourceName);
 	}
-	
+
 	@Override
 	public String toString() {
 		return debugName();
 	}
-	
+
 	@Override
 	public int hashCode() {
 		int code = this.typeParameter.hashCode() + 17 * this.rank;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java
index e30bbb5..8095019 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -42,7 +42,7 @@
 	public ReferenceBinding [] intersectingTypes;
 	private ReferenceBinding javaLangObject;
 	int length;
-	
+
 	public IntersectionTypeBinding18(ReferenceBinding[] intersectingTypes, LookupEnvironment environment) {
 		this.intersectingTypes = intersectingTypes;
 		this.length = intersectingTypes.length;
@@ -51,7 +51,7 @@
 			this.modifiers |= ClassFileConstants.AccInterface;
 		}
 	}
-	
+
 	private IntersectionTypeBinding18(IntersectionTypeBinding18 prototype) {
 		this.intersectingTypes = prototype.intersectingTypes;
 		this.length = prototype.length;
@@ -60,7 +60,7 @@
 			this.modifiers |= ClassFileConstants.AccInterface;
 		}
 	}
-	
+
 	@Override
 	public TypeBinding clone(TypeBinding enclosingType) {
 		return new IntersectionTypeBinding18(this);
@@ -87,7 +87,7 @@
 
 	@Override
 	public boolean hasTypeBit(int bit) { // Stephan ??
-		for (int i = 0; i < this.length; i++) {		
+		for (int i = 0; i < this.length; i++) {
 			if (this.intersectingTypes[i].hasTypeBit(bit))
 				return true;
 		}
@@ -98,7 +98,7 @@
 	public boolean canBeInstantiated() {
 		return false;
 	}
-	
+
 	@Override
 	public boolean canBeSeenBy(PackageBinding invocationPackage) {
 		for (int i = 0; i < this.length; i++) {
@@ -107,7 +107,7 @@
 		}
 		return true;
 	}
-	
+
 	@Override
 	public boolean canBeSeenBy(Scope scope) {
 		for (int i = 0; i < this.length; i++) {
@@ -116,7 +116,7 @@
 		}
 		return true;
 	}
-	
+
 	@Override
 	public boolean canBeSeenBy(ReferenceBinding receiverType, ReferenceBinding invocationType) {
 		for (int i = 0; i < this.length; i++) {
@@ -125,8 +125,8 @@
 		}
 		return true;
 	}
-	
-	
+
+
 	@Override
 	public char[] constantPoolName() {
 		TypeBinding erasure = erasure();
@@ -141,7 +141,7 @@
 	public PackageBinding getPackage() {
 		throw new UnsupportedOperationException(); // cannot be referred to
 	}
-	
+
 	@Override
 	public ReferenceBinding[] getIntersectingTypes() {
 		return this.intersectingTypes;
@@ -149,9 +149,9 @@
 
 	@Override
 	public ReferenceBinding superclass() {
-		return this.intersectingTypes[0].isClass() ? this.intersectingTypes[0] : this.javaLangObject; 
+		return this.intersectingTypes[0].isClass() ? this.intersectingTypes[0] : this.javaLangObject;
 	}
-	
+
 	@Override
 	public ReferenceBinding [] superInterfaces() {
 		if (this.intersectingTypes[0].isClass()) {
@@ -161,12 +161,12 @@
 		}
 		return this.intersectingTypes;
 	}
-	
+
 	@Override
 	public boolean isBoxedPrimitiveType() {
 		return this.intersectingTypes[0].isBoxedPrimitiveType();
 	}
-	
+
 	/* Answer true if the receiver type can be assigned to the argument type (right)
 	 */
 	@Override
@@ -199,13 +199,13 @@
 		}
 
 		// normal case:
-		for (int i = 0; i < this.length; i++) {		
+		for (int i = 0; i < this.length; i++) {
 			if (this.intersectingTypes[i].isCompatibleWith(right, scope))
 				return true;
 		}
 		return false;
 	}
-	
+
 	@Override
 	public boolean isSubtypeOf(TypeBinding other, boolean simulatingBugJDK8026527) {
 		if (TypeBinding.equalsEquals(this, other))
@@ -259,7 +259,7 @@
 	@Override
 	public char[] qualifiedSourceName() {
 		StringBuffer qualifiedSourceName = new StringBuffer(16);
-		for (int i = 0; i < this.length; i++) {		
+		for (int i = 0; i < this.length; i++) {
 				qualifiedSourceName.append(this.intersectingTypes[i].qualifiedSourceName());
 				if (i != this.length - 1)
 					qualifiedSourceName.append(" & "); //$NON-NLS-1$
@@ -270,7 +270,7 @@
 	@Override
 	public char[] sourceName() {
 		StringBuffer srcName = new StringBuffer(16);
-		for (int i = 0; i < this.length; i++) {		
+		for (int i = 0; i < this.length; i++) {
 				srcName.append(this.intersectingTypes[i].sourceName());
 				if (i != this.length - 1)
 					srcName.append(" & "); //$NON-NLS-1$
@@ -281,7 +281,7 @@
 	@Override
 	public char[] readableName() {
 		StringBuffer readableName = new StringBuffer(16);
-		for (int i = 0; i < this.length; i++) {		
+		for (int i = 0; i < this.length; i++) {
 				readableName.append(this.intersectingTypes[i].readableName());
 				if (i != this.length - 1)
 					readableName.append(" & "); //$NON-NLS-1$
@@ -291,7 +291,7 @@
 	@Override
 	public char[] shortReadableName() {
 		StringBuffer shortReadableName = new StringBuffer(16);
-		for (int i = 0; i < this.length; i++) {		
+		for (int i = 0; i < this.length; i++) {
 				shortReadableName.append(this.intersectingTypes[i].shortReadableName());
 				if (i != this.length - 1)
 					shortReadableName.append(" & "); //$NON-NLS-1$
@@ -309,7 +309,7 @@
 	@Override
 	public String debugName() {
 		StringBuffer debugName = new StringBuffer(16);
-		for (int i = 0; i < this.length; i++) {		
+		for (int i = 0; i < this.length; i++) {
 				debugName.append(this.intersectingTypes[i].debugName());
 				if (i != this.length - 1)
 					debugName.append(" & "); //$NON-NLS-1$
@@ -339,7 +339,7 @@
 		for (int i = 0; i < this.intersectingTypes.length; i++)
 			this.intersectingTypes[i].collectInferenceVariables(variables);
 	}
-	
+
 	@Override
 	public ReferenceBinding upwardsProjection(Scope scope, TypeBinding[] mentionedTypeVariables) {
 		ReferenceBinding[] projectedTypes = new ReferenceBinding[this.intersectingTypes.length];
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java
index aa57e12..afb5f22 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InvocationSite.java
@@ -40,11 +40,11 @@
 	boolean receiverIsImplicitThis();
 	boolean checkingPotentialCompatibility();
 	void acceptPotentiallyCompatibleMethods(MethodBinding [] methods);
-	
+
 	/** When inference for this invocationSite starts, get a fresh inference context, initialized from this site. */
 	InferenceContext18 freshInferenceContext(Scope scope);
 	ExpressionContext getExpressionContext();
-	
+
 	static class EmptyWithAstNode implements InvocationSite {
 		ASTNode node;
 		public EmptyWithAstNode(ASTNode node) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java
index fb47d87..c1495e1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalTypeBinding.java
@@ -14,7 +14,7 @@
  *								bug 365662 - [compiler][null] warn on contradictory and redundant null annotations
  *								bug 401030 - [1.8][null] Null analysis support for lambda methods.
  *								Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
- *								Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations 
+ *								Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
@@ -99,7 +99,7 @@
 		return ((LocalTypeBinding) this.prototype).anonymousOriginalSuperType();
 	if (this.superclass == null && this.scope != null)
 		return this.scope.getJavaLangObject();
-	
+
 	if (this.superInterfaces != Binding.NO_SUPERINTERFACES) {
 		return this.superInterfaces[0];
 	}
@@ -119,7 +119,7 @@
 public char[] computeUniqueKey(boolean isLeaf) {
 	if (!isPrototype())
 		return this.prototype.computeUniqueKey(isLeaf);
-	
+
 	char[] outerKey = outermostEnclosingType().computeUniqueKey(isLeaf);
 	int semicolon = CharOperation.lastIndexOf(';', outerKey);
 
@@ -156,7 +156,7 @@
 		// cases where the left hand does not know what the right is doing.
 		this.constantPoolName = this.scope.compilationUnitScope().computeConstantPoolName(this);
 	}
-	return this.constantPoolName;	
+	return this.constantPoolName;
 }
 
 @Override
@@ -177,10 +177,10 @@
  */
 @Override
 public char[] genericTypeSignature() {
-	
+
 	if (!isPrototype())
 		return this.prototype.genericTypeSignature();
-	
+
 	if (this.genericReferenceTypeSignature == null && this.constantPoolName == null) {
 		if (isAnonymousType())
 			setConstantPoolName(superclass().sourceName());
@@ -278,10 +278,10 @@
  */
 @Override
 public char[] signature() {
-	
+
 	if (!isPrototype())
 		return this.prototype.signature();
-	
+
 	if (this.signature == null && this.constantPoolName == null) {
 		if (isAnonymousType())
 			setConstantPoolName(superclass().sourceName());
@@ -303,7 +303,7 @@
 public String toString() {
 	if (this.hasTypeAnnotations())
 		return annotatedDebugName() + " (local)"; //$NON-NLS-1$
-    
+
 	if (isAnonymousType())
 		return "Anonymous type : " + super.toString(); //$NON-NLS-1$
 	if (isMemberType())
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 a0bce83..a41f4c2 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
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for
@@ -72,7 +72,7 @@
 		this(declaration.name, type, modifiers, isArgument);
 		this.declaration = declaration;
 	}
-	
+
 	// argument
 	public LocalVariableBinding(LocalDeclaration declaration, TypeBinding type, int modifiers, MethodScope declaringScope) {
 
@@ -307,7 +307,7 @@
 	public boolean isParameter() {
 		return ((this.tagBits & TagBits.IsArgument) != 0);
 	}
-	
+
 	public boolean isCatchParameter() {
 		return false;
 	}
@@ -325,7 +325,7 @@
 		}
 		return null;
 	}
-	
+
 	public void markInitialized() {
 		// Signals that the type is correctly set now - This is for extension in subclasses
 	}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
index 289b352..ca7fa8b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -1527,7 +1527,7 @@
 	if (this.root != this) {
 		return this.nonNullAnnotation = this.root.getNonNullAnnotation();
 	}
-	ReferenceBinding nonNull = getResolvedType(this.globalOptions.nonNullAnnotationName, null);
+	ReferenceBinding nonNull = getResolvedType(this.globalOptions.nonNullAnnotationName, this.UnNamedModule, null, true);
 	return this.nonNullAnnotation = this.typeSystem.getAnnotationType(nonNull, true);
 }
 
@@ -1635,11 +1635,11 @@
 * Fail with a classpath error if the type cannot be found.
 */
 public ReferenceBinding getResolvedType(char[][] compoundName, Scope scope) {
-	return getResolvedType(compoundName, scope == null ? this.UnNamedModule : scope.module(), scope);
+	return getResolvedType(compoundName, scope == null ? this.UnNamedModule : scope.module(), scope, false);
 }
-public ReferenceBinding getResolvedType(char[][] compoundName, ModuleBinding moduleBinding, Scope scope) {
+public ReferenceBinding getResolvedType(char[][] compoundName, ModuleBinding moduleBinding, Scope scope, boolean implicitAnnotationUse) {
 	if (this.module != moduleBinding)
-		return moduleBinding.environment.getResolvedType(compoundName, moduleBinding, scope);
+		return moduleBinding.environment.getResolvedType(compoundName, moduleBinding, scope, implicitAnnotationUse);
 	ReferenceBinding type = getType(compoundName, moduleBinding);
 	if (type != null) return type;
 
@@ -1648,11 +1648,11 @@
 	this.problemReporter.isClassPathCorrect(
 		compoundName,
 		scope == null ? this.root.unitBeingCompleted : scope.referenceCompilationUnit(),
-		this.missingClassFileLocation);
+		this.missingClassFileLocation, implicitAnnotationUse);
 	return createMissingType(null, compoundName);
 }
 public ReferenceBinding getResolvedJavaBaseType(char[][] compoundName, Scope scope) {
-	return getResolvedType(compoundName, javaBaseModule(), scope);
+	return getResolvedType(compoundName, javaBaseModule(), scope, false);
 }
 
 /* Answer the top level package named name.
@@ -1772,7 +1772,7 @@
 			 * misconfiguration now that did not also exist in some equivalent form while producing the class files which encode 
 			 * these missing types. So no need to bark again. Note that wasMissingType == true signals a type referenced in a .class 
 			 * file which could not be found when the binary was produced. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=364450 */
-			this.problemReporter.isClassPathCorrect(compoundName, this.root.unitBeingCompleted, this.missingClassFileLocation);
+			this.problemReporter.isClassPathCorrect(compoundName, this.root.unitBeingCompleted, this.missingClassFileLocation, false);
 		}
 		// create a proxy for the missing BinaryType
 		binding = createMissingType(null, compoundName);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
index 667d8e0..cb44056 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- *  * Copyright (c) 2000, 2017 IBM Corporation and others.
+ *  * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -51,7 +51,9 @@
 	// note that #initializedField can be null AND lastVisibleFieldID >= 0, when processing instance field initializers.
 
 	// flow analysis
-	public int analysisIndex; // for setting flow-analysis id
+	/* By specifying {@code -Djdt.flow.test.extra=true} tests can push all flow analysis into the extra bits of UnconditionalFlowInfo. */
+	private static int baseAnalysisIndex = 0;
+	public int analysisIndex = baseAnalysisIndex; // for setting flow-analysis id
 	public boolean isPropagatingInnerClassEmulation;
 
 	// for local variables table attributes
@@ -65,6 +67,13 @@
 	// remember suppressed warning re missing 'default:' to give hints on possibly related flow problems
 	public boolean hasMissingSwitchDefault; // TODO(stephan): combine flags to a bitset?
 
+	static {
+		if (Boolean.getBoolean("jdt.flow.test.extra")) { //$NON-NLS-1$
+			baseAnalysisIndex = 64;
+			System.out.println("JDT/Core testing with -Djdt.flow.test.extra=true"); //$NON-NLS-1$
+		}
+	}
+
 public MethodScope(Scope parent, ReferenceContext context, boolean isStatic) {
 	super(METHOD_SCOPE, parent);
 	this.locals = new LocalVariableBinding[5];
@@ -143,6 +152,10 @@
 	} else if ((((AbstractMethodDeclaration) this.referenceContext).modifiers & ClassFileConstants.AccStrictfp) != 0) {
 		// must check the parse node explicitly
 		problemReporter().illegalModifierForMethod((AbstractMethodDeclaration) this.referenceContext);
+	} else if (this.referenceContext instanceof CompactConstructorDeclaration) {
+		if ((((AbstractMethodDeclaration) this.referenceContext).modifiers & ClassFileConstants.AccPublic) == 0) {
+			problemReporter().recordCanonicalConstructorNotPublic((AbstractMethodDeclaration) this.referenceContext);
+		}
 	}
 
 	// check for incompatible modifiers in the visibility bits, isolate the visibility bits
@@ -200,7 +213,7 @@
 			}
 			if (reportIllegalModifierCombination) {
 				problemReporter().illegalModifierCombinationForInterfaceMethod((AbstractMethodDeclaration) this.referenceContext);
-			} 
+			}
 			if (sourceLevel >= ClassFileConstants.JDK9 && (methodBinding.modifiers & ClassFileConstants.AccPrivate) != 0) {
 				int remaining = realModifiers & ~expectedModifiers;
 				if (remaining == 0) { // check for the combination of allowed modifiers with private
@@ -229,7 +242,7 @@
 		LocalTypeBinding local = (LocalTypeBinding) declaringClass;
 		TypeReference ref = local.scope.referenceContext.allocation.type;
 		if (ref != null && (ref.bits & ASTNode.IsDiamond) != 0) {
-			// 
+			//
 			if ((realModifiers & (ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic )) == 0) {
 				methodBinding.tagBits |= TagBits.AnnotationOverride;
 			}
@@ -427,8 +440,15 @@
 		method.binding.typeVariables = createTypeVariables(typeParameters, method.binding);
 		method.binding.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
 	}
+    checkAndSetRecordCanonicalConsAndMethods(method);
 	return method.binding;
 }
+private void checkAndSetRecordCanonicalConsAndMethods(AbstractMethodDeclaration am) {
+	if (am.binding != null && (am.bits & ASTNode.IsImplicit) != 0) {
+		am.binding.tagBits |= TagBits.isImplicit;
+		am.binding.tagBits |= (am.bits & ASTNode.IsCanonicalConstructor) != 0 ? TagBits.IsCanonicalConstructor : 0;
+	}
+}
 
 /**
  * Overridden to detect the error case inside an explicit constructor call:
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ModuleBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ModuleBinding.java
index 741b9ef..a145a47 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ModuleBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ModuleBinding.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
@@ -197,7 +197,7 @@
 		this.environment = new LookupEnvironment(existingEnvironment.root, this);
 		this.declaredPackages = new HashtableOfPackage<PlainPackageBinding>(5);
 	}
-	
+
 	public PlainPackageBinding[] getExports() {
 		completeIfNeeded(UpdateKind.PACKAGE);
 		return this.exportedPackages;
@@ -207,7 +207,7 @@
 		if (this.exportRestrictions != null) {
 			SimpleSetOfCharArray set = this.exportRestrictions.get(pack);
 			if (set != null) {
-				char[][] names = new char[set.elementSize][]; 
+				char[][] names = new char[set.elementSize][];
 				set.asArray(names);
 				return CharOperation.charArrayToStringArray(names);
 			}
@@ -223,7 +223,7 @@
 		if (this.openRestrictions != null) {
 			SimpleSetOfCharArray set = this.openRestrictions.get(pack);
 			if (set != null) {
-				char[][] names = new char[set.elementSize][]; 
+				char[][] names = new char[set.elementSize][];
 				set.asArray(names);
 				return CharOperation.charArrayToStringArray(names);
 			}
@@ -244,11 +244,11 @@
 		completeIfNeeded(UpdateKind.MODULE);
 		return this.requiresTransitive;
 	}
-	
+
 	public TypeBinding[] getUses() {
 		return this.uses;
 	}
-	
+
 	public TypeBinding[] getServices() {
 		return this.services;
 	}
@@ -456,7 +456,7 @@
 	 * All required modules include modules explicitly specified as required in the module declaration
 	 * as well as implicit dependencies - those specified as ' requires transitive ' by one of the
 	 * dependencies
-	 * 
+	 *
 	 * @return
 	 *   An array of all required modules
 	 */
@@ -470,9 +470,9 @@
 		}
 		ModuleBinding javaBase = this.environment.javaBaseModule();
 																			// add java.base?
-		if (!CharOperation.equals(this.moduleName, TypeConstants.JAVA_BASE)	// ... not if this *is* java.base 
+		if (!CharOperation.equals(this.moduleName, TypeConstants.JAVA_BASE)	// ... not if this *is* java.base
 				&& javaBase != null 										// ... nor when java.base is absent
-				&& javaBase != this.environment.UnNamedModule)				// ..... or faked by the unnamed module 
+				&& javaBase != this.environment.UnNamedModule)				// ..... or faked by the unnamed module
 		{
 			allRequires.add(javaBase);
 		}
@@ -538,14 +538,14 @@
 
 	/**
 	 * Return a package binding if there exists a package named name in this module's context and it can be seen by this module.
-	 * A package can be seen by this module if it is declared in this module or any other module read by this module 
+	 * A package can be seen by this module if it is declared in this module or any other module read by this module
 	 * (JLS 7.4.3 for packages based on JLS 7.3 for compilation units).
 	 * Package exports are not considered for visibility check (only when checking "uniquely visible" (JLS 7.4.3)).
 	 * <p>
 	 * The returned package may be a {@link SplitPackageBinding}, if more than one package of the given name is visible.
 	 * </p>
 	 * <p>
-	 * When asked via the unnamed module or an automatic module all other named modules are considered visible. 
+	 * When asked via the unnamed module or an automatic module all other named modules are considered visible.
 	 * </p>
 	 */
 	public PackageBinding getTopLevelPackage(char[] name) {
@@ -611,11 +611,11 @@
 			if (this.environment.nameEnvironment.isPackage(parentName, name))
 				binding = this.createDeclaredPackage(subPkgCompoundName, parent);
 		}
-		
+
 		binding = combineWithPackagesFromOtherRelevantModules(binding, subPkgCompoundName, declaringModuleNames);
 
 		assert binding == null || binding instanceof PlainPackageBinding || binding.enclosingModule == this;
-		
+
 		if (binding == null || !binding.isValidBinding()) {
 			if (parent != null) {
 				if (binding == null) {
@@ -656,7 +656,7 @@
 
 		// check each sub package
 		for (int i = 1; i < qualifiedPackageName.length; i++) {
-			PackageBinding binding = getVisiblePackage(parent, qualifiedPackageName[i]); 
+			PackageBinding binding = getVisiblePackage(parent, qualifiedPackageName[i]);
 			if (binding == null) {
 				return null;
 			}
@@ -691,9 +691,9 @@
 	 * Check if the given package is accessible by this module. True when the package is declared in
 	 * this module or exported by some required module to this module.
 	 * See {@link #isPackageExportedTo(PackageBinding, ModuleBinding)}
-	 * 
+	 *
 	 * @param pkg
-	 * 
+	 *
 	 * @return True, if the package is accessible by this module, false otherwise
 	 */
 	public boolean canAccess(PackageBinding pkg) {
@@ -857,7 +857,7 @@
 		return this.defaultNullness;
 	}
 	SimpleLookupTable storedAnnotations(boolean forceInitialize, boolean forceStore) {
-		
+
 		if (forceInitialize && this.storedAnnotations == null) {
 			if (!this.environment.globalOptions.storeAnnotations && !forceStore)
 				return null; // not supported during this compile
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ModuleScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ModuleScope.java
new file mode 100644
index 0000000..65fd87c
--- /dev/null
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ModuleScope.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2019, 2020 SAP SE and others
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.lookup;
+
+import org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration;
+import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
+
+public class ModuleScope extends BlockScope {
+	public ModuleDeclaration referenceContext;
+
+	public ModuleScope(Scope parent, ModuleDeclaration referenceContext) {
+		super(Scope.MODULE_SCOPE, parent);
+		this.referenceContext = referenceContext;
+	}
+
+	/**
+	 * Answer the problem reporter to use for raising new problems.
+	 *
+	 * Note that as a side-effect, this updates the current reference context
+	 * (here: module declaration) in case the problem handler decides it is necessary
+	 * to abort.
+	 */
+	@Override
+	public ProblemReporter problemReporter() {
+		ProblemReporter problemReporter = referenceCompilationUnit().problemReporter;
+		problemReporter.referenceContext = this.referenceContext;
+		return problemReporter;
+	}
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MostSpecificExceptionMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MostSpecificExceptionMethodBinding.java
index bc89a8f..9816471 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MostSpecificExceptionMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MostSpecificExceptionMethodBinding.java
@@ -23,20 +23,20 @@
 public class MostSpecificExceptionMethodBinding  extends MethodBinding {
 
 	private MethodBinding originalMethod;
-	
+
 	public MostSpecificExceptionMethodBinding (MethodBinding originalMethod, ReferenceBinding[] mostSpecificExceptions) {
 		super(
-				originalMethod.modifiers, 
-				originalMethod.selector, 
-				originalMethod.returnType, 
-				originalMethod.parameters, 
-				mostSpecificExceptions, 
+				originalMethod.modifiers,
+				originalMethod.selector,
+				originalMethod.returnType,
+				originalMethod.parameters,
+				mostSpecificExceptions,
 				originalMethod.declaringClass);
 		this.originalMethod = originalMethod;
 		this.parameterNonNullness = originalMethod.parameterNonNullness;
 		this.defaultNullness = originalMethod.defaultNullness;
 	}
-	
+
 	@Override
 	public MethodBinding original() {
 		return this.originalMethod.original();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java
index 52124c4..529574f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NestedTypeBinding.java
@@ -13,7 +13,7 @@
  *     Stephan Herrmann - Contributions for
  *								Bug 365662 - [compiler][null] warn on contradictory and redundant null annotations
  *								Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault
- *								Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations 
+ *								Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations
  *     Keigo Imai - Contribution for  bug 388903 - Cannot extend inner class as an anonymous class when it extends the outer class
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
@@ -46,9 +46,9 @@
 * Answer the new argument or the existing argument if one already existed.
 */
 public SyntheticArgumentBinding addSyntheticArgument(LocalVariableBinding actualOuterLocalVariable) {
-	
+
 	if (!isPrototype()) throw new IllegalStateException();
-	
+
 	SyntheticArgumentBinding synthLocal = null;
 
 	if (this.outerLocalVariables == null) {
@@ -161,7 +161,7 @@
 				default :
 					this.outerLocalVariablesSlotSize  ++;
 					break;
-			}		
+			}
 		}
 	}
 	return this.outerLocalVariablesSlotSize;
@@ -181,28 +181,28 @@
 /* Answer the synthetic argument for <targetEnclosingType> or null if one does not exist.
 */
 public SyntheticArgumentBinding getSyntheticArgument(ReferenceBinding targetEnclosingType, boolean onlyExactMatch, boolean scopeIsConstructorCall) {
-	
+
 	if (!isPrototype()) throw new IllegalStateException();
-	
+
 	if (this.enclosingInstances == null) return null;		// is null if no enclosing instances are known
-	
+
 	// exact match
-	
-	// firstly, during allocation, check and use the leftmost one (if possible) 
+
+	// firstly, during allocation, check and use the leftmost one (if possible)
 	// to handle cases involving two instances of same type, such as
 	// class X {
 	//   class Inner extends X {}
 	//   void f(){
-	//     new X().new Inner(){} 
+	//     new X().new Inner(){}
 	//     // here the result of (new X()) is passed as the first (synthetic) arg for ctor of new Inner(){}
-	//     // (and (this) as the second, of course) 
+	//     // (and (this) as the second, of course)
 	//   }
 	// }
 	if (scopeIsConstructorCall && this.enclosingInstances.length > 0)
-		if (TypeBinding.equalsEquals(this.enclosingInstances[0].type, targetEnclosingType)) 
+		if (TypeBinding.equalsEquals(this.enclosingInstances[0].type, targetEnclosingType))
 			if (this.enclosingInstances[0].actualOuterLocalVariable == null)
 				return this.enclosingInstances[0];
-	
+
 	// then check other possibility
 	for (int i = this.enclosingInstances.length; --i >= 0;)
 		if (TypeBinding.equalsEquals(this.enclosingInstances[i].type, targetEnclosingType))
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NullTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NullTypeBinding.java
index dca633b..bee6817 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NullTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/NullTypeBinding.java
@@ -21,17 +21,17 @@
 	NullTypeBinding() {
 		super(TypeIds.T_null, TypeConstants.NULL, new char[] { 'N' }); // N stands for null even if it is never internally used);
 	}
-	
+
 	@Override
 	public TypeBinding clone(TypeBinding enclosingType) {
 		return this;  // enforce solitude.
 	}
-	
+
 	@Override
 	public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) {
 		return; // reject misguided attempt.
 	}
-	
+
 	@Override
 	public TypeBinding unannotated() {
 		return this;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java
index a43381f..92d1673 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java
@@ -60,15 +60,15 @@
 	this.environment = environment;
 	this.knownTypes = null; // initialized if used... class counts can be very large 300-600
 	this.knownPackages = new HashtableOfPackage<PackageBinding>(3); // sub-package counts are typically 0-3
-	
+
 	if (compoundName != CharOperation.NO_CHAR_CHAR)
 		checkIfNullAnnotationPackage();
-	
+
 	if (enclosingModule != null)
 		this.enclosingModule = enclosingModule;
 	else if (parent != null)
 		this.enclosingModule = parent.enclosingModule; // stop-gap for any remaining calls that don't provide an enclosingModule (they should)
-	
+
 	if (this.enclosingModule == null)
 		throw new IllegalStateException("Package should have an enclosing module"); //$NON-NLS-1$
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
index ffcdd26..03e40e0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2005, 2018 IBM Corporation and others.
+ * Copyright (c) 2005, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -867,6 +867,11 @@
 		return false;
 	}
 
+	@Override
+	protected boolean hasMethodWithNumArgs(char[] selector, int numArgs) {
+		return this.type.hasMethodWithNumArgs(selector, numArgs);
+	}
+
 	/**
 	 * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#implementsMethod(MethodBinding)
 	 */
@@ -1429,7 +1434,7 @@
 		    this.superclass = (ReferenceBinding) Scope.substitute(this, genericSuperclass);
 			this.typeBits |= (this.superclass.typeBits & TypeIds.InheritableBits);
 			if ((this.typeBits & (TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) != 0) // avoid the side-effects of hasTypeBit()! 
-				this.typeBits |= applyCloseableClassWhitelists();
+				this.typeBits |= applyCloseableClassWhitelists(this.environment.globalOptions);
 	    }
 		return this.superclass;
 	}
@@ -1513,7 +1518,8 @@
 			if (isStatic() && isNestedType()) buffer.append("static "); //$NON-NLS-1$
 			if (isFinal()) buffer.append("final "); //$NON-NLS-1$
 
-			if (isEnum()) buffer.append("enum "); //$NON-NLS-1$
+			if (isRecord()) buffer.append("record "); //$NON-NLS-1$
+			else if (isEnum()) buffer.append("enum "); //$NON-NLS-1$
 			else if (isAnnotationType()) buffer.append("@interface "); //$NON-NLS-1$
 			else if (isClass()) buffer.append("class "); //$NON-NLS-1$
 			else buffer.append("interface "); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolyParameterizedGenericMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolyParameterizedGenericMethodBinding.java
index ed8bbf4..a1ddaa8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolyParameterizedGenericMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolyParameterizedGenericMethodBinding.java
@@ -1,37 +1,37 @@
-/*******************************************************************************

- * Copyright (c) 2014, 2015 IBM Corporation and others.

+/*******************************************************************************
+ * Copyright (c) 2014, 2015 IBM Corporation and others.
  *
- * This program and the accompanying materials

- * are made available under the terms of the Eclipse Public License 2.0

- * which accompanies this distribution, and is available at

+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
  * https://www.eclipse.org/legal/epl-2.0/
  *
- * SPDX-License-Identifier: EPL-2.0

- *

- * Contributors:

- *     IBM Corporation - initial API and implementation

- *******************************************************************************/

-package org.eclipse.jdt.internal.compiler.lookup;

-

-public class PolyParameterizedGenericMethodBinding extends ParameterizedGenericMethodBinding { // confused citizen.

-

-	private ParameterizedGenericMethodBinding wrappedBinding; 

-	public PolyParameterizedGenericMethodBinding(ParameterizedGenericMethodBinding applicableMethod) {

-		super(applicableMethod.originalMethod, applicableMethod.typeArguments, applicableMethod.environment, applicableMethod.inferredWithUncheckedConversion, false,  applicableMethod.targetType);

-		this.wrappedBinding = applicableMethod;

-	}

-	

-	@Override

-	public boolean equals(Object other) {

-		if (other instanceof PolyParameterizedGenericMethodBinding) {

-			PolyParameterizedGenericMethodBinding ppgmb = (PolyParameterizedGenericMethodBinding)other;

-			return this.wrappedBinding.equals(ppgmb.wrappedBinding);

-		}

-		return false;

-	}

-

-	@Override

-	public int hashCode() {

-		return this.wrappedBinding.hashCode();

-	}

-}

+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.lookup;
+
+public class PolyParameterizedGenericMethodBinding extends ParameterizedGenericMethodBinding { // confused citizen.
+
+	private ParameterizedGenericMethodBinding wrappedBinding;
+	public PolyParameterizedGenericMethodBinding(ParameterizedGenericMethodBinding applicableMethod) {
+		super(applicableMethod.originalMethod, applicableMethod.typeArguments, applicableMethod.environment, applicableMethod.inferredWithUncheckedConversion, false,  applicableMethod.targetType);
+		this.wrappedBinding = applicableMethod;
+	}
+
+	@Override
+	public boolean equals(Object other) {
+		if (other instanceof PolyParameterizedGenericMethodBinding) {
+			PolyParameterizedGenericMethodBinding ppgmb = (PolyParameterizedGenericMethodBinding)other;
+			return this.wrappedBinding.equals(ppgmb.wrappedBinding);
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		return this.wrappedBinding.hashCode();
+	}
+}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolyTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolyTypeBinding.java
index 5736e99..dfe3ace 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolyTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolyTypeBinding.java
@@ -23,11 +23,11 @@
 
 	Expression expression;
 	boolean vanillaCompatibilty = true;
-	
+
 	public PolyTypeBinding(Expression expression) {
 		this.expression = expression;
 	}
-	
+
 	@Override
 	public char[] constantPoolName() {
 		throw new UnsupportedOperationException();  // should never reach code generation
@@ -42,7 +42,7 @@
 	public boolean isCompatibleWith(TypeBinding left, Scope scope) {
 		return this.vanillaCompatibilty ? this.expression.isCompatibleWith(left, scope) : this.expression.isBoxingCompatibleWith(left, scope);
 	}
-	
+
 	@Override
 	public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope) {
 		return this.expression.isPotentiallyCompatibleWith(targetType, scope);
@@ -52,7 +52,7 @@
 	public boolean isPolyType() {
 		return true;
 	}
-	
+
 	@Override
 	public boolean isFunctionalType() {
 		return this.expression.isFunctionalType();
@@ -83,13 +83,13 @@
 	public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope scope) {
 		return this.expression.sIsMoreSpecific(s, t, scope);
 	}
-	
+
 	@Override
 	public String toString() {
 		StringBuffer buffer = new StringBuffer("PolyTypeBinding for: "); //$NON-NLS-1$
 		return this.expression.printExpression(0,  buffer).toString();
 	}
-	
+
 	@Override
 	public int kind() {
 		return Binding.POLY_TYPE;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolymorphicMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolymorphicMethodBinding.java
index 578e138..d8c7e10 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolymorphicMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PolymorphicMethodBinding.java
@@ -31,7 +31,7 @@
 		this.polymorphicMethod = polymorphicMethod;
 		this.tagBits = polymorphicMethod.tagBits;
 	}
-	
+
 	public PolymorphicMethodBinding(MethodBinding polymorphicMethod, TypeBinding returnType, TypeBinding[] parameterTypes) {
 		super(
 				polymorphicMethod.modifiers,
@@ -48,7 +48,7 @@
 	public MethodBinding original() {
 		return this.polymorphicMethod;
 	}
-	
+
 	@Override
 	public boolean isPolymorphic() {
 		return true;
@@ -78,7 +78,7 @@
 		// all arguments match
 		return true;
 	}
-	
+
 	/*
 	 * Even if polymorphic methods are varargs method, we don't want them to be treated as varargs method
 	 */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
index 5888abf..b5ac431 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/RawTypeBinding.java
@@ -92,7 +92,7 @@
 		sig.getChars(0, sigLength, uniqueKey, 0);
 		return uniqueKey;
    	}
-	
+
 	@Override
 	public TypeBinding clone(TypeBinding outerType) {
 		return new RawTypeBinding(this.actualType(), (ReferenceBinding) outerType, this.environment);
@@ -239,17 +239,17 @@
 		}
 		this.arguments = typeArguments;
 	}
-		
+
 	@Override
 	public ParameterizedTypeBinding capture(Scope scope, int start, int end) {
 		return this;
 	}
-	
-	@Override 
+
+	@Override
 	public TypeBinding uncapture(Scope scope) {
 		return this;
 	}
-	
+
 	@Override
 	TypeBinding substituteInferenceVariable(InferenceVariable var, TypeBinding substituteType) {
 		// NEVER substitute the type arguments of a raw type
@@ -269,7 +269,7 @@
 		MethodBinding theAbstractMethod = genericType.getSingleAbstractMethod(scope, replaceWildcards);
 		if (theAbstractMethod == null || !theAbstractMethod.isValidBinding())
 			return this.singleAbstractMethod[index] = theAbstractMethod;
-		
+
 		ReferenceBinding declaringType = (ReferenceBinding) scope.environment().convertToRawType(genericType, true);
 		declaringType = (ReferenceBinding) declaringType.findSuperTypeOriginatingFrom(theAbstractMethod.declaringClass);
 		MethodBinding [] choices = declaringType.getMethods(theAbstractMethod.selector);
@@ -312,7 +312,7 @@
 		}
 		return shortReadableName;
 	}
-	
+
 	@Override
 	void collectInferenceVariables(Set<InferenceVariable> variables) {
 		// nothing to collect for a raw type.
@@ -327,11 +327,11 @@
 	public ReferenceBinding downwardsProjection(Scope scope, TypeBinding[] mentionedTypeVariables) {
 		return this;
 	}
-	
+
 	@Override
 	public ReferenceBinding enclosingType() {
 		// ParameterizedTypeBinding earlier always had a resolved enclosed type, but now it does on-demand resolving.
-		// Behaviour for RawTypeBinding should be unchanged. 
+		// Behaviour for RawTypeBinding should be unchanged.
 	    return this.enclosingType;
 	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReductionResult.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReductionResult.java
index 1c157db..c99f2f8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReductionResult.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReductionResult.java
@@ -26,14 +26,14 @@
 		@Override
 		public String toString() { return "TRUE"; } //$NON-NLS-1$
 	};
-	protected static final ConstraintTypeFormula FALSE = new ConstraintTypeFormula() { 
-		/* empty body just to make abstract class instantiable */ 
+	protected static final ConstraintTypeFormula FALSE = new ConstraintTypeFormula() {
+		/* empty body just to make abstract class instantiable */
 		@Override
 		public Object reduce(InferenceContext18 context) { return this; }
 		@Override
 		public String toString() { return "FALSE"; } //$NON-NLS-1$
 	};
-	
+
 	// Relation kinds, mimic an enum:
 	protected static final int COMPATIBLE = 1;
 	protected static final int SUBTYPE = 2;
@@ -43,7 +43,7 @@
 	protected static final int CAPTURE = 6;
 	static final int EXCEPTIONS_CONTAINED = 7;
 	protected static final int POTENTIALLY_COMPATIBLE = 8;
-	
+
 	protected TypeBinding right; // note that the LHS differs between sub-classes.
 	protected int relation;
 
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 ef12f64..d42bae5 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,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -741,6 +741,8 @@
 				case 'R' :
 					if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION[2]))
 						this.id = 	TypeIds.T_JavaLangRuntimeException;
+					if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_RECORD[2]))
+						this.id = TypeIds.T_JavaLangRecord;
 					break;
 				case 'S' :
 					switch (typeName.length) {
@@ -2128,7 +2130,7 @@
  * If a type - known to be a Closeable - is mentioned in one of our white lists
  * answer the typeBit for the white list (BitWrapperCloseable or BitResourceFreeCloseable).
  */
-protected int applyCloseableClassWhitelists() {
+protected int applyCloseableClassWhitelists(CompilerOptions options) {
 	switch (this.compoundName.length) {
 		case 3:
 			if (CharOperation.equals(TypeConstants.JAVA, this.compoundName[0])) {
@@ -2167,9 +2169,26 @@
 		if (CharOperation.equals(this.compoundName, TypeConstants.OTHER_WRAPPER_CLOSEABLES[i]))
 			return TypeIds.BitWrapperCloseable;
 	}	
+	if (options.analyseResourceLeaks) {
+		ReferenceBinding mySuper = this.superclass();
+		if (mySuper != null && mySuper.id != TypeIds.T_JavaLangObject) {
+			if (hasMethodWithNumArgs(TypeConstants.CLOSE, 0))
+				return 0; // close methods indicates: class may need more closing than super
+			return mySuper.applyCloseableClassWhitelists(options);
+		}
+	}
 	return 0;
 }
 
+protected boolean hasMethodWithNumArgs(char[] selector, int numArgs) {
+	for (MethodBinding methodBinding : unResolvedMethods()) {
+		if (CharOperation.equals(methodBinding.selector, selector)
+				&& methodBinding.parameters.length == numArgs) {
+			return true;
+		}
+	}
+	return false;
+}
 
 /*
  * If a type - known to be a Closeable - is mentioned in one of our white lists
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index afd5cf8..282e349 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -59,15 +59,19 @@
  *  							Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335
  *     Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for
  *                          	Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas
+ *     Pierre-Yves B. <pyvesdev@gmail.com> - Contributions for
+ *                              Bug 559618 - No compiler warning for import from same package
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
 import java.util.*;
 import java.util.function.Function;
+import java.util.function.Supplier;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
+import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
 import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
@@ -97,6 +101,7 @@
 	public final static int CLASS_SCOPE = 3;
 	public final static int COMPILATION_UNIT_SCOPE = 4;
 	public final static int METHOD_SCOPE = 2;
+	public final static int MODULE_SCOPE = 5;
 
 	/* Argument Compatibilities */
 	public final static int NOT_COMPATIBLE = -1;
@@ -111,6 +116,7 @@
 
 	public int kind;
 	public Scope parent;
+	private Map<String, Supplier<ReferenceBinding>> commonTypeBindings = null;
 	
 	private static class NullDefaultRange {
 		final int start, end;
@@ -148,6 +154,7 @@
 	protected Scope(int kind, Scope parent) {
 		this.kind = kind;
 		this.parent = parent;
+		this.commonTypeBindings = null;
 	}
 
 	/* Answer an int describing the relationship between the given types.
@@ -773,10 +780,6 @@
 		return false;
 	}
 
-	public boolean isModuleScope() {
-		return false;
-	}
-
 	/**
 	 * Finds the most specific compiler options
 	 */
@@ -1192,6 +1195,8 @@
 					return ((MethodScope) current).referenceContext;
 				case CLASS_SCOPE :
 					return ((ClassScope) current).referenceContext;
+				case MODULE_SCOPE :
+					return ((ModuleScope) current).referenceContext;
 				case COMPILATION_UNIT_SCOPE :
 					return ((CompilationUnitScope) current).referenceContext;
 			}
@@ -2271,6 +2276,7 @@
 							insideConstructorCall = enclosingMethodScope == null ? false : enclosingMethodScope.isConstructorCall;
 							break;
 						case COMPILATION_UNIT_SCOPE :
+						case MODULE_SCOPE :
 							break done;
 					}
 					if (scope.isLambdaScope()) // Not in Kansas anymore ...
@@ -2632,6 +2638,8 @@
 						return type.modifiers;
 				}
 				break;
+			case Scope.MODULE_SCOPE :
+				return ((ModuleScope)this).referenceContext.modifiers;
 			case Scope.CLASS_SCOPE :
 				ReferenceBinding context = ((ClassScope)this).referenceType().binding;
 				if (context != null)
@@ -2917,6 +2925,21 @@
 		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_ASSERTIONERROR, this);
 	}
 
+	public final ReferenceBinding getJavaLangBoolean() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_BOOLEAN);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_BOOLEAN, this);
+	}
+	public final ReferenceBinding getJavaLangByte() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_BYTE);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_BYTE, this);
+	}
+	public final ReferenceBinding getJavaLangCharacter() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_CHARACTER);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_CHARACTER, this);
+	}
 	public final ReferenceBinding getJavaLangClass() {
 		CompilationUnitScope unitScope = compilationUnitScope();
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_CLASS);
@@ -2933,6 +2956,26 @@
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_CLASSNOTFOUNDEXCEPTION);
 		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_CLASSNOTFOUNDEXCEPTION, this);
 	}
+	public final ReferenceBinding getJavaLangDouble() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_DOUBLE);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_DOUBLE, this);
+	}
+	public final ReferenceBinding getJavaLangFloat() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_FLOAT);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_FLOAT, this);
+	}
+	public final ReferenceBinding getJavaLangIncompatibleClassChangeError() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_INCOMPATIBLECLASSCHANGEERROR);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_INCOMPATIBLECLASSCHANGEERROR, this);
+	}
+	public final ReferenceBinding getJavaLangNoClassDefFoundError() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_NOCLASSDEFERROR);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_NOCLASSDEFERROR, this);
+	}
 	public final ReferenceBinding getJavaLangNoSuchFieldError() {
 		CompilationUnitScope unitScope = compilationUnitScope();
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_NOSUCHFIELDERROR);
@@ -2943,7 +2986,29 @@
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_ENUM);
 		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_ENUM, this);
 	}
+	public final ReferenceBinding getJavaLangError() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_ERROR);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_ERROR, this);
+	}
 
+	public final ReferenceBinding getJavaLangReflectField() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_REFLECT_FIELD);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_REFLECT_FIELD, this);
+	}
+
+	public final ReferenceBinding getJavaLangReflectMethod() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_REFLECT_METHOD);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_REFLECT_METHOD, this);
+	}
+
+	public final ReferenceBinding getJavaLangRuntimeObjectMethods() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_RUNTIME_OBJECTMETHODS);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_RUNTIME_OBJECTMETHODS, this);
+	}
 	public final ReferenceBinding getJavaLangInvokeLambdaMetafactory() {
 		CompilationUnitScope unitScope = compilationUnitScope();
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_INVOKE_LAMBDAMETAFACTORY);
@@ -2963,29 +3028,65 @@
 		return findDirectMemberType("Lookup".toCharArray(), outerType); //$NON-NLS-1$
 	}
 
+	public final ReferenceBinding getJavaLangInteger() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_INTEGER);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_INTEGER, this);
+	}
 	public final ReferenceBinding getJavaLangIterable() {
 		CompilationUnitScope unitScope = compilationUnitScope();
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_ITERABLE);
 		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_ITERABLE, this);
 	}
+	public final ReferenceBinding getJavaLangLong() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_LONG);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_LONG, this);
+	}
 	public final ReferenceBinding getJavaLangObject() {
 		CompilationUnitScope unitScope = compilationUnitScope();
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_OBJECT);
 		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_OBJECT, this);
 	}
 
+	public final ReferenceBinding getJavaLangRecord() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_RECORD);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_RECORD, this);
+	}
+
+	public final ReferenceBinding getJavaLangShort() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_SHORT);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_SHORT, this);
+	}
 	public final ReferenceBinding getJavaLangString() {
 		CompilationUnitScope unitScope = compilationUnitScope();
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_STRING);
 		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_STRING, this);
 	}
+	public final ReferenceBinding getJavaLangStringBuffer() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_STRINGBUFFER);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_STRINGBUFFER, this);
+	}
 
+	public final ReferenceBinding getJavaLangStringBuilder() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_STRINGBUILDER);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_STRINGBUILDER, this);
+	}
 	public final ReferenceBinding getJavaLangThrowable() {
 		CompilationUnitScope unitScope = compilationUnitScope();
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_THROWABLE);
 		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_THROWABLE, this);
 	}
 	
+	public final ReferenceBinding getJavaLangVoid() {
+		CompilationUnitScope unitScope = compilationUnitScope();
+		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_VOID);
+		return unitScope.environment.getResolvedJavaBaseType(TypeConstants.JAVA_LANG_VOID, this);
+	}
 	public final ReferenceBinding getJavaLangIllegalArgumentException() {
 		CompilationUnitScope unitScope = compilationUnitScope();
 		unitScope.recordQualifiedReference(TypeConstants.JAVA_LANG_ILLEGALARGUMENTEXCEPTION);
@@ -3425,14 +3526,15 @@
 			Binding cachedBinding = (Binding) typeOrPackageCache.get(name);
 			if (cachedBinding != null) { // can also include NotFound ProblemReferenceBindings if we already know this name is not found
 				if (cachedBinding instanceof ImportBinding) { // single type import cached in faultInImports(), replace it in the cache with the type
-					ImportReference importReference = ((ImportBinding) cachedBinding).reference;
-					if (importReference != null) {
+					ImportBinding importBinding = (ImportBinding) cachedBinding;
+					ImportReference importReference = importBinding.reference;
+					if (importReference != null && !isUnnecessarySamePackageImport(importBinding.resolvedImport, unitScope)) {
 						importReference.bits |= ASTNode.Used;
 					}
 					if (cachedBinding instanceof ImportConflictBinding)
 						typeOrPackageCache.put(name, cachedBinding = ((ImportConflictBinding) cachedBinding).conflictingTypeBinding); // already know its visible
 					else
-						typeOrPackageCache.put(name, cachedBinding = ((ImportBinding) cachedBinding).resolvedImport); // already know its visible
+						typeOrPackageCache.put(name, cachedBinding = importBinding.resolvedImport); // already know its visible
 				}
 				if ((mask & Binding.TYPE) != 0) {
 					if (foundType != null && foundType.problemId() != ProblemReasons.NotVisible && cachedBinding.problemId() != ProblemReasons.Ambiguous)
@@ -3570,6 +3672,17 @@
 		return foundType;
 	}
 
+	private boolean isUnnecessarySamePackageImport(Binding resolvedImport, Scope unitScope) {
+		if (resolvedImport instanceof ReferenceBinding) {
+			if (unitScope.getCurrentPackage() == ((ReferenceBinding) resolvedImport).getPackage()) {
+				if ((resolvedImport.getAnnotationTagBits() & TagBits.IsNestedType) != 0)
+					return false; // importing nested types is still necessary
+				return true;
+			}
+		}
+		return false;
+	}
+
 	// Added for code assist... NOT Public API
 	// DO NOT USE to resolve import references since this method assumes 'A.B' is relative to a single type import of 'p1.A'
 	// when it may actually mean the type B in the package A
@@ -5116,6 +5229,8 @@
 					return ((ClassScope) current).referenceContext;
 				case COMPILATION_UNIT_SCOPE :
 					return ((CompilationUnitScope) current).referenceContext;
+				case MODULE_SCOPE :
+					return ((ModuleScope) current).referenceContext;
 			}
 		} while ((current = current.parent) != null);
 		return null;
@@ -5481,6 +5596,41 @@
 		}
 	}
 	
+	public Supplier<ReferenceBinding> getCommonReferenceBinding(char[] typeName) {
+		assert typeName != null && typeName.length > 0;
+		initializeCommonTypeBindings();
+		Supplier<ReferenceBinding> typeSupplier = this.commonTypeBindings.get(new String(typeName));
+		return typeSupplier;
+	}
+
+	private Map<String, Supplier<ReferenceBinding>> initializeCommonTypeBindings() {
+		if (this.commonTypeBindings != null)
+			return this.commonTypeBindings;
+		Map<String, Supplier<ReferenceBinding>> t = new HashMap<>();
+		t.put(new String(ConstantPool.JavaLangAssertionErrorConstantPoolName), this :: getJavaLangAssertionError);
+		t.put(new String(ConstantPool.JavaLangErrorConstantPoolName), this :: getJavaLangError);
+		t.put(new String(ConstantPool.JavaLangIncompatibleClassChangeErrorConstantPoolName), this :: getJavaLangIncompatibleClassChangeError);
+		t.put(new String(ConstantPool.JavaLangNoClassDefFoundErrorConstantPoolName), this :: getJavaLangNoClassDefFoundError);
+		t.put(new String(ConstantPool.JavaLangStringBufferConstantPoolName), this :: getJavaLangStringBuffer);
+		t.put(new String(ConstantPool.JavaLangIntegerConstantPoolName), this :: getJavaLangInteger);
+		t.put(new String(ConstantPool.JavaLangBooleanConstantPoolName), this :: getJavaLangBoolean);
+		t.put(new String(ConstantPool.JavaLangByteConstantPoolName), this :: getJavaLangByte);
+		t.put(new String(ConstantPool.JavaLangCharacterConstantPoolName), this :: getJavaLangCharacter);
+		t.put(new String(ConstantPool.JavaLangFloatConstantPoolName), this :: getJavaLangFloat);
+		t.put(new String(ConstantPool.JavaLangDoubleConstantPoolName), this :: getJavaLangDouble);
+		t.put(new String(ConstantPool.JavaLangShortConstantPoolName), this :: getJavaLangShort);
+		t.put(new String(ConstantPool.JavaLangLongConstantPoolName), this :: getJavaLangLong);
+		t.put(new String(ConstantPool.JavaLangVoidConstantPoolName), this :: getJavaLangVoid);
+		t.put(new String(ConstantPool.JavaLangStringConstantPoolName), this :: getJavaLangString);
+		t.put(new String(ConstantPool.JavaLangStringBuilderConstantPoolName), this :: getJavaLangStringBuilder);
+		t.put(new String(ConstantPool.JavaLangClassConstantPoolName), this :: getJavaLangClass);
+		t.put(new String(ConstantPool.JAVALANGREFLECTFIELD_CONSTANTPOOLNAME), this :: getJavaLangReflectField);
+		t.put(new String(ConstantPool.JAVALANGREFLECTMETHOD_CONSTANTPOOLNAME), this :: getJavaLangReflectMethod);
+		t.put(new String(ConstantPool.JavaUtilIteratorConstantPoolName), this :: getJavaUtilIterator);
+		t.put(new String(ConstantPool.JavaLangEnumConstantPoolName), this :: getJavaLangEnum);
+		t.put(new String(ConstantPool.JavaLangObjectConstantPoolName), this :: getJavaLangObject);
+		return this.commonTypeBindings = t;
+	}
 	// AspectJ Extension
 	/**
      * Other scopes can override this method
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 0bd5732..d266118 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,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -64,16 +64,22 @@
 import java.util.stream.Collectors;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ASTVisitor;
 import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.Annotation;
 import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.CompactConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.RecordDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression;
+import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
 import org.eclipse.jdt.internal.compiler.ast.SwitchStatement;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
@@ -149,6 +155,9 @@
 	protected SourceTypeBinding nestHost;
 	public HashSet<SourceTypeBinding> nestMembers;
 	
+	private boolean isRecordDeclaration = false;
+	private FieldBinding[] recordComponents; // cache
+	private MethodBinding[] recordComponentAccessors = null; // hash maybe an overkill
 public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) {
 	this.compoundName = compoundName;
 	this.fPackage = fPackage;
@@ -162,6 +171,7 @@
 	this.fields = Binding.UNINITIALIZED_FIELDS;
 	this.methods = Binding.UNINITIALIZED_METHODS;
 	this.prototype = this;
+	this.isRecordDeclaration = scope.referenceContext instanceof RecordDeclaration;
 	computeId();
 }
 
@@ -189,6 +199,7 @@
 	this.nullnessDefaultInitialized= prototype.nullnessDefaultInitialized;
 	this.containerAnnotationType = prototype.containerAnnotationType;
 	this.tagBits |= TagBits.HasUnresolvedMemberTypes; // see memberTypes()
+	this.isRecordDeclaration = this.prototype.isRecordDeclaration;
 }
 
 private void addDefaultAbstractMethods() {
@@ -880,6 +891,115 @@
 	}
 	return accessMethod;
 }
+/* JLS 14 Record - Preview - begin */
+public MethodBinding[] checkAndAddSyntheticRecordMethods(MethodBinding[] methodBindings, int count) {
+	if (!this.isRecordDeclaration)
+		return methodBindings;
+	List<MethodBinding> implicitMethods = checkAndAddSyntheticRecordComponentAccessors(methodBindings);
+	implicitMethods = checkAndAddSyntheticRecordOverrideMethods(methodBindings, implicitMethods);
+	for (int i = 0; i < count; ++i)
+		implicitMethods.add(methodBindings[i]);
+	return implicitMethods.toArray(new MethodBinding[0]);
+}
+public List<MethodBinding> checkAndAddSyntheticRecordOverrideMethods(MethodBinding[] methodBindings, List<MethodBinding> implicitMethods) {
+	if (!hasMethodWithNumArgs(TypeConstants.TOSTRING, 0)) {
+		MethodBinding m = addSyntheticRecordOverrideMethod(TypeConstants.TOSTRING, implicitMethods.size());
+		implicitMethods.add(m);
+	}
+	if (!hasMethodWithNumArgs(TypeConstants.HASHCODE, 0)) {
+		MethodBinding m = addSyntheticRecordOverrideMethod(TypeConstants.HASHCODE, implicitMethods.size());
+		implicitMethods.add(m);
+	}
+	boolean isEqualsPresent = Arrays.stream(methodBindings)
+			.filter(m -> CharOperation.equals(TypeConstants.EQUALS, m.selector))
+			.anyMatch(m -> m.parameters != null || m.parameters.length == 1 &&
+				m.parameters[0].equals(this.scope.getJavaLangObject()));
+	if (!isEqualsPresent) {
+		MethodBinding m = addSyntheticRecordOverrideMethod(TypeConstants.EQUALS, implicitMethods.size());
+		implicitMethods.add(m);
+	}
+	return implicitMethods;
+}
+public List<MethodBinding> checkAndAddSyntheticRecordComponentAccessors(MethodBinding[] methodBindings) {
+	List<MethodBinding> implicitMethods = new ArrayList<>(0);
+	if (this.fields == null)
+		return implicitMethods;
+	// JLS 14 8.10.3 Item 2 create the accessors for the fields if required
+	/*
+	 * An implicitly declared public accessor method with the same name as the record component,
+	 * whose return type is the declared type of the record component,
+	 * unless a public method with the same signature is explicitly declared in the body of the declaration of R.
+	 */
+
+	List<String> componentNames = Arrays.stream(this.fields) // initialize with all the record components
+			.filter(f -> f.isRecordComponent())
+			.map(f -> new String(f.name))
+			.collect(Collectors.toList());
+
+	List<MethodBinding> accessors = new ArrayList<>();
+	if (this.methods != null) {
+		accessors = Arrays.stream(methodBindings)
+				.filter(m -> m.selector != null && m.selector.length > 0)
+				.filter(m -> componentNames.contains(new String(m.selector)))
+				.filter(m -> m.parameters == null || m.parameters.length == 0)
+				.collect(Collectors.toList());
+
+		List<String> candidates = accessors.stream()
+			.map(m -> new String(m.selector))
+			.collect(Collectors.toList());
+		componentNames.removeAll(candidates);
+	}
+	int missingCount = componentNames.size();
+	for (int i = 0; i < missingCount; ++i) {
+		implicitMethods.add(addSyntheticRecordComponentAccessor(componentNames.get(i).toCharArray(), i));
+	}
+	accessors.addAll(implicitMethods);
+	this.recordComponentAccessors = accessors.toArray(new MethodBinding[0]);
+	return implicitMethods;
+}
+/* Add a new synthetic component accessor for the recordtype. Selector should be identical to component name.
+ * char[] component name of the record
+*/
+public SyntheticMethodBinding addSyntheticRecordComponentAccessor(char[] selector, int index) {
+	if (!isPrototype()) throw new IllegalStateException();
+	if (this.synthetics == null)
+		this.synthetics = new HashMap[MAX_SYNTHETICS];
+	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
+		this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap(5);
+
+	SyntheticMethodBinding accessMethod = null;
+	SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(selector);
+	accessMethod = new SyntheticMethodBinding(this, getField(selector, true), index);
+	if (accessors == null) {
+		this.synthetics[SourceTypeBinding.METHOD_EMUL].put(selector, accessors = new SyntheticMethodBinding[2]);
+		accessors[0] = accessMethod;
+	} else {
+		if ((accessMethod = accessors[0]) == null) {
+			accessors[0] = accessMethod;
+		}
+	}
+	return accessMethod;
+}
+public SyntheticMethodBinding addSyntheticRecordOverrideMethod(char[] selector, int index) {
+	if (this.synthetics == null)
+		this.synthetics = new HashMap[MAX_SYNTHETICS];
+	if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
+		this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap(5);
+
+	SyntheticMethodBinding accessMethod = null;
+	SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(selector);
+	accessMethod = new SyntheticMethodBinding(this, selector, index);
+	if (accessors == null) {
+		this.synthetics[SourceTypeBinding.METHOD_EMUL].put(selector, accessors = new SyntheticMethodBinding[2]);
+		accessors[0] = accessMethod;
+	} else {
+		if ((accessMethod = accessors[0]) == null) {
+			accessors[0] = accessMethod;
+		}
+	}
+	return accessMethod;
+}
+/* JLS 14 Record - Preview - end */
 boolean areFieldsInitialized() {
 	if (!isPrototype())
 		return this.prototype.areFieldsInitialized();
@@ -1023,6 +1143,7 @@
 		}
 	}
 	this.tagBits |= TagBits.AreFieldsComplete;
+	computeRecordComponents();
 	return this.fields;
 }
 /**
@@ -1097,20 +1218,23 @@
 	if (!isPrototype())
 		return this.prototype.getAnnotationTagBits();
 	
-	if ((this.tagBits & TagBits.EndHierarchyCheck) == 0 && this.scope != null) { // AspectJ added final this.scope check because BinaryTypeBinding subclass won't have scope
-		CompilationUnitScope pkgCUS = this.scope.compilationUnitScope();
-		boolean current = pkgCUS.connectingHierarchy;
-		pkgCUS.connectingHierarchy = true;
-		try {
-			return internalGetAnnotationTagBits();
-		} finally {
-			pkgCUS.connectingHierarchy = current;
+	if ((this.tagBits & TagBits.AnnotationResolved) == 0 && this.scope != null) {
+		if ((this.tagBits & TagBits.EndHierarchyCheck) == 0 && this.scope != null) { // AspectJ added final this.scope check because BinaryTypeBinding subclass won't have scope
+			CompilationUnitScope pkgCUS = this.scope.compilationUnitScope();
+			boolean current = pkgCUS.connectingHierarchy;
+			pkgCUS.connectingHierarchy = true;
+			try {
+				initAnnotationTagBits();
+			} finally {
+				pkgCUS.connectingHierarchy = current;
+			}
+		} else {
+			initAnnotationTagBits();
 		}
 	}
-	return internalGetAnnotationTagBits();
+	return this.tagBits;
 }
-private long internalGetAnnotationTagBits() {
-	if ((this.tagBits & TagBits.AnnotationResolved) == 0 && this.scope != null) {
+private void initAnnotationTagBits() {
 		TypeDeclaration typeDecl = this.scope.referenceContext;
 		boolean old = typeDecl.staticInitializerScope.insideTypeAnnotation;
 		try {
@@ -1121,8 +1245,6 @@
 		}
 		if ((this.tagBits & TagBits.AnnotationDeprecated) != 0)
 			this.modifiers |= ClassFileConstants.AccDeprecated;
-	}
-	return this.tagBits;
 }
 public MethodBinding[] getDefaultAbstractMethods() {
 	if (!isPrototype())
@@ -1661,6 +1783,55 @@
     return this.memberTypes.length > 0;
 }
 
+private int getImplicitCanonicalConstructor() {
+	if (this.methods != null && this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) {
+		for (int i = 0, l = this.methods.length; i < l; ++i) {
+			MethodBinding method = this.methods[i];
+			if ((method.tagBits & TagBits.IsCanonicalConstructor ) != 0 && (method.tagBits & TagBits.isImplicit) != 0)
+				return i;
+		}
+	}
+	return -1;
+}
+private MethodBinding[] checkAndGetExplicitCanonicalConstructors() {
+	List<MethodBinding> ec = new ArrayList<>();
+	if (!this.isRecordDeclaration)
+		return ec.toArray(new MethodBinding[0]);
+
+	FieldBinding[] recComps = this.getRecordComponents();
+	int nRecordComponents = recComps.length;
+	if (this.methods != null && this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) {
+		for (MethodBinding method : this.methods) {
+			if (!method.isConstructor() || (method.tagBits & TagBits.isImplicit) != 0
+					|| method.parameters.length != nRecordComponents)
+				continue;
+			boolean isEC = true;
+			for (int j = 0; j < nRecordComponents; ++j) {
+				if (TypeBinding.notEquals(method.parameters[j], recComps[j].type)) {
+					isEC = false;
+					break;
+				}
+			}
+			if (isEC) {
+				ec.add(method);
+				checkRecordCanonicalConstructor(method);
+			}
+		}
+	}
+	return ec.toArray(new MethodBinding[0]);
+}
+private int getImplicitMethod(char[] name) {
+	if (this.methods != null && this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) {
+		for (int i = 0, l = this.methods.length; i < l; ++i) {
+			MethodBinding method = this.methods[i];
+			if (!CharOperation.equals(method.selector, name))
+				continue;
+			if ((method.tagBits & TagBits.isImplicit) != 0)
+				return i;
+		}
+	}
+	return -1;
+}
 // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
 public MethodBinding[] methodsBase() {  // AspectJ Extension - added Base suffix, see methods()
 	
@@ -1691,7 +1862,7 @@
 	try {
 		for (int i = 0, length = this.methods.length; i < length; i++) {
 			if ((this.tagBits & TagBits.AreMethodsComplete) != 0) {
-				// recursive call to methods() from resolveTypesFor(..) resolved the methods
+				// recursive c-all to methods() from resolveTypesFor(..) resolved the methods
 				return this.methods;
 			}
 
@@ -1708,6 +1879,10 @@
 		// find & report collision cases
 		boolean complyTo15OrAbove = this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
 		boolean compliance16 = this.scope.compilerOptions().complianceLevel == ClassFileConstants.JDK1_6;
+		int recordCanonIndex = getImplicitCanonicalConstructor();
+		computeRecordComponents();
+		checkAndGetExplicitCanonicalConstructors();
+		int recordEqualsIndex = getImplicitMethod(TypeConstants.EQUALS);
 		
 		for (int i = 0, length = this.methods.length; i < length; i++) {
 			int severity = ProblemSeverities.Error;
@@ -1807,6 +1982,31 @@
 					// prior to 1.5, parameters identical meant a collision case
 					continue nextSibling;
 				}
+				if (recordCanonIndex == i || recordCanonIndex == j) {
+					methodDecl = this.methods[recordCanonIndex].sourceMethod();
+					assert methodDecl != null;
+					methodDecl.binding = null;
+					// do not alter original method array until resolution is over, due to reentrance (143259)
+					if (resolvedMethods == this.methods)
+						System.arraycopy(this.methods, 0, resolvedMethods = new MethodBinding[length], 0, length);
+					resolvedMethods[recordCanonIndex] = null;
+					failed++;
+					MethodBinding explicitCanonicalConstructor = recordCanonIndex == i ? this.methods[j] : this.methods[i];
+					methodDecl = explicitCanonicalConstructor.sourceMethod();
+					recordCanonIndex = -1; // reset;
+					continue;
+				}
+				if (recordEqualsIndex == i || recordEqualsIndex == j) {
+					methodDecl = this.methods[recordEqualsIndex].sourceMethod();
+					assert methodDecl != null;
+					methodDecl.binding = null;
+					// do not alter original method array until resolution is over, due to reentrance (143259)
+					if (resolvedMethods == this.methods)
+						System.arraycopy(this.methods, 0, resolvedMethods = new MethodBinding[length], 0, length);
+					resolvedMethods[recordEqualsIndex] = null;
+					failed++;
+					continue;
+				}
 				// otherwise duplicates / name clash
 				boolean isEnumSpecialMethod = isEnum() && (CharOperation.equals(selector,TypeConstants.VALUEOF) || CharOperation.equals(selector,TypeConstants.VALUES));
 				// report duplicate
@@ -1887,6 +2087,49 @@
 	return this.methods;
 }
 
+private void checkRecordCanonicalConstructor(MethodBinding explicitCanonicalConstructor) {
+
+	AbstractMethodDeclaration methodDecl = explicitCanonicalConstructor.sourceMethod();
+	if (!explicitCanonicalConstructor.isPublic())
+		this.scope.problemReporter().recordCanonicalConstructorNotPublic(methodDecl);
+	TypeParameter[] typeParameters = methodDecl.typeParameters();
+	if (typeParameters != null && typeParameters.length > 0)
+		this.scope.problemReporter().recordCanonicalConstructorShouldNotBeGeneric(methodDecl);
+	if (explicitCanonicalConstructor.thrownExceptions != null && explicitCanonicalConstructor.thrownExceptions.length > 0)
+		this.scope.problemReporter().recordCanonicalConstructorHasThrowsClause(methodDecl);
+	explicitCanonicalConstructor.tagBits |= TagBits.IsCanonicalConstructor;
+	ASTVisitor visitor = new ASTVisitor() {
+		boolean isInsideCCD = methodDecl instanceof CompactConstructorDeclaration;
+		@Override
+		public boolean visit(ExplicitConstructorCall explicitConstructorCall, BlockScope skope) {
+			if (explicitConstructorCall.accessMode != ExplicitConstructorCall.ImplicitSuper) {
+				if (this.isInsideCCD)
+					skope.problemReporter().recordCompactConstructorHasExplicitConstructorCall(explicitConstructorCall);
+				else
+					skope.problemReporter().recordCanonicalConstructorHasExplicitConstructorCall(explicitConstructorCall);
+			}
+			return false;
+		}
+		@Override
+		public boolean visit(MethodDeclaration methodDeclaration, ClassScope skope) {
+			return false;
+		}
+		@Override
+		public boolean visit(LambdaExpression lambda, BlockScope skope) {
+			return false;
+		}
+		@Override
+		public boolean visit(ReturnStatement returnStatement, BlockScope skope) {
+			if (this.isInsideCCD) {
+				skope.problemReporter().recordCompactConstructorHasReturnStatement(returnStatement);
+				return false;
+			}
+			return true;
+		}
+	};
+	methodDecl.traverse(visitor, this.scope);
+}
+
 @Override
 public TypeBinding prototype() {
 	return this.prototype;
@@ -1897,6 +2140,11 @@
 }
 
 @Override
+public boolean isRecord() {
+	return this.isRecordDeclaration;
+}
+
+@Override
 public ReferenceBinding containerAnnotationType() {
 	
 	if (!isPrototype()) throw new IllegalStateException();
@@ -2119,6 +2367,11 @@
 			if (parameterType == null) {
 				foundArgProblem = true;
 			} else if (parameterType == TypeBinding.VOID) {
+				if (this.isRecordDeclaration &&
+						methodDecl instanceof ConstructorDeclaration &&
+						((methodDecl.bits & ASTNode.IsImplicit) != 0)) {
+					// do nothing - already raised for record component.
+				} else
 				methodDecl.scope.problemReporter().argumentTypeCannotBeVoid(methodDecl, arg);
 				foundArgProblem = true;
 			} else {
@@ -2369,6 +2622,27 @@
 }
 
 @Override
+protected boolean hasMethodWithNumArgs(char[] selector, int numArgs) {
+	if ((this.tagBits & TagBits.AreMethodsComplete) != 0)
+		return super.hasMethodWithNumArgs(selector, numArgs);
+	// otherwise don't trigger unResolvedMethods() which would actually resolve!
+	if (this.scope != null && this.scope.referenceContext.methods != null) {
+		for (AbstractMethodDeclaration method : this.scope.referenceContext.methods) {
+			if (CharOperation.equals(method.selector, selector)) {
+				if (numArgs == 0) {
+					if (method.arguments == null)
+						return true;
+				} else {
+					if (method.arguments != null && method.arguments.length == numArgs)
+						return true;
+				}
+			}
+		}
+	}
+	return false;
+}
+
+@Override
 public AnnotationHolder retrieveAnnotationHolder(Binding binding, boolean forceInitialization) {
 	if (!isPrototype())
 		return this.prototype.retrieveAnnotationHolder(binding, forceInitialization);
@@ -2616,7 +2890,8 @@
 	if (isStatic() && isNestedType()) buffer.append("static "); //$NON-NLS-1$
 	if (isFinal()) buffer.append("final "); //$NON-NLS-1$
 
-	if (isEnum()) buffer.append("enum "); //$NON-NLS-1$
+	if (isRecord()) buffer.append("record "); //$NON-NLS-1$
+	else if (isEnum()) buffer.append("enum "); //$NON-NLS-1$
 	else if (isAnnotationType()) buffer.append("@interface "); //$NON-NLS-1$
 	else if (isClass()) buffer.append("class "); //$NON-NLS-1$
 	else buffer.append("interface "); //$NON-NLS-1$
@@ -2790,7 +3065,48 @@
 							.collect(Collectors.toList());
 	return list;
 }
-
+/* Get the field bindings in the order of record component declaration
+ * should be called only after a called to fields() */
+public FieldBinding[] getRecordComponents() {
+	return this.recordComponents;
+}
+/**
+ * Get the accessor method given the record component name
+ * @param name name of the record component
+ * @return the method binding of the accessor if found, else null
+ */
+public MethodBinding getRecordComponentAccessor(char[] name) {
+	MethodBinding accessor = null;
+	if (this.recordComponentAccessors != null) {
+		for (MethodBinding m : this.recordComponentAccessors) {
+			if (CharOperation.equals(m.selector, name)) {
+				accessor = m;
+				break;
+			}
+		}
+	}
+	return accessor;
+}
+public void computeRecordComponents() {
+	if (!this.isRecordDeclaration || this.recordComponents != null)
+		return;
+	Argument[] recComps = ((RecordDeclaration) this.scope.referenceContext).getArgs();
+	List<FieldBinding> list = new ArrayList<>();
+	if (recComps != null && recComps.length > 0 && this.fields != null) {
+		List<String> recordComponentNames = new ArrayList<>(0);
+		recordComponentNames = Arrays.stream(recComps)
+				.map(arg -> new String(arg.name))
+				.collect(Collectors.toList());
+		for (String rc : recordComponentNames) {
+			for (FieldBinding f : this.fields) {
+				if (rc.equals(new String(f.name))) {
+					list.add(f);
+				}
+			}
+		}
+	}
+	this.recordComponents = list.toArray(new FieldBinding[0]);
+}
 public void cleanUp() {
 	if (this.environment != null) {
 		// delegate so as to clean all variants of this prototype:
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SplitPackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SplitPackageBinding.java
index ee04403..24b8546 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SplitPackageBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SplitPackageBinding.java
@@ -22,7 +22,7 @@
 public class SplitPackageBinding extends PackageBinding {
 	Set<ModuleBinding> declaringModules;
 	public Set<PlainPackageBinding> incarnations;
-	
+
 	/**
 	 * Combine two potential package bindings, answering either the better of those if the other has a problem,
 	 * or combine both into a split package.
@@ -119,7 +119,7 @@
 		}
 		return childPackage;
 	}
-	
+
 	@Override
 	ModuleBinding[] getDeclaringModules() {
 		return this.declaringModules.toArray(new ModuleBinding[this.declaringModules.size()]);
@@ -135,12 +135,12 @@
 		for (PackageBinding incarnation : this.incarnations) {
 			PackageBinding package0 = incarnation.getPackage0(name);
 			if (package0 == null)
-				return null; // if any incarnation lacks cached info, a full findPackage will be necessary 
+				return null; // if any incarnation lacks cached info, a full findPackage will be necessary
 			candidate = combine(package0, candidate, this.enclosingModule);
 		}
 		if (candidate != null)
 			this.knownPackages.put(name, candidate);
-		
+
 		return candidate;
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java
index b17afb0..de075b8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticFactoryMethodBinding.java
@@ -23,7 +23,7 @@
 	private MethodBinding staticFactoryFor;
 	private LookupEnvironment environment;
 	private ReferenceBinding enclosingType;
-	
+
 	public SyntheticFactoryMethodBinding(MethodBinding method, LookupEnvironment environment, ReferenceBinding enclosingType) {
 		super(method.modifiers | ClassFileConstants.AccStatic, TypeConstants.SYNTHETIC_STATIC_FACTORY,
 				null, null, null, method.declaringClass);
@@ -31,14 +31,14 @@
 		this.staticFactoryFor = method;
 		this.enclosingType = enclosingType;
 	}
-	
+
 	public MethodBinding getConstructor() {
 		return this.staticFactoryFor;
 	}
-	
+
 	/** Apply the given type arguments on the (declaring class of the) actual constructor being represented by this factory method and
-	    if method type arguments is not empty materialize the parameterized generic constructor 
-	 * @param targetType 
+	    if method type arguments is not empty materialize the parameterized generic constructor
+	 * @param targetType
 	*/
 	public ParameterizedMethodBinding applyTypeArgumentsOnConstructor(TypeBinding[] typeArguments, TypeBinding[] constructorTypeArguments, boolean inferredWithUncheckedConversion, TypeBinding targetType) {
 		ReferenceBinding parameterizedType = typeArguments == null
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
index 9088959..b849381 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java
@@ -1,6 +1,6 @@
 // ASPECTJ
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -73,6 +73,9 @@
      * Is never directly materialized in bytecode
      */
     public static final int SerializableMethodReference = 18;
+    public static final int RecordOverrideToString = 19;
+    public static final int RecordOverrideHashCode = 20;
+    public static final int RecordOverrideEquals = 21;
     
 	public int sourceStart = 0; // start position of the matching declaration
 	public int index; // used for sorting access methods in the class file
@@ -441,6 +444,66 @@
 		this.index = methodId;
 	}
 
+	public SyntheticMethodBinding(ReferenceBinding declaringClass, FieldBinding targetField, int index) {
+		SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
+		assert declaringSourceType.isRecord();
+		this.declaringClass = declaringSourceType;
+		this.modifiers = ClassFileConstants.AccPublic;
+		if (targetField.type instanceof TypeVariableBinding ||
+				targetField.type instanceof ParameterizedTypeBinding)
+			this.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
+		if (this.declaringClass.isStrictfp())
+			this.modifiers |= ClassFileConstants.AccStrictfp;
+		this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
+		this.parameters = Binding.NO_PARAMETERS;
+		this.returnType = targetField.type;
+		this.selector = targetField.name;
+		this.targetReadField = targetField;
+		this.purpose = SyntheticMethodBinding.FieldReadAccess;
+		this.thrownExceptions = Binding.NO_EXCEPTIONS;
+		this.declaringClass = declaringSourceType;
+		this.setTypeAnnotations(targetField.getAnnotations());
+		this.index = index;
+
+		// retrieve sourceStart position for the target field for line number attributes
+		FieldDeclaration[] fieldDecls = declaringSourceType.scope.referenceContext.fields;
+		if (fieldDecls != null) {
+			for (int i = 0, max = fieldDecls.length; i < max; i++) {
+				if (fieldDecls[i].binding == targetField) {
+					this.sourceStart = fieldDecls[i].sourceStart;
+					return;
+				}
+			}
+		}
+		this.sourceStart = declaringSourceType.scope.referenceContext.sourceStart;
+	}
+	public SyntheticMethodBinding(ReferenceBinding declaringClass, char[] selector, int index) {
+		SourceTypeBinding declaringSourceType = (SourceTypeBinding) declaringClass;
+		assert declaringSourceType.isRecord();
+		this.declaringClass = declaringSourceType;
+		this.modifiers = ClassFileConstants.AccPublic;
+		if (this.declaringClass.isStrictfp())
+				this.modifiers |= ClassFileConstants.AccStrictfp;
+		this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved);
+	    this.selector = selector;
+	    this.thrownExceptions = Binding.NO_EXCEPTIONS;
+		if (selector == TypeConstants.TOSTRING) {
+			this.returnType = declaringSourceType.scope.getJavaLangString();
+		    this.parameters = Binding.NO_PARAMETERS;
+		    this.purpose = SyntheticMethodBinding.RecordOverrideToString;
+		} else if (selector == TypeConstants.HASHCODE) {
+			this.modifiers |= ClassFileConstants.AccFinal;
+			this.returnType = TypeBinding.INT;
+		    this.parameters = Binding.NO_PARAMETERS;
+		    this.purpose = SyntheticMethodBinding.RecordOverrideHashCode;
+		} else if (selector == TypeConstants.EQUALS) {
+			this.modifiers |= ClassFileConstants.AccFinal;
+			this.returnType = TypeBinding.BOOLEAN;
+		    this.parameters = new TypeBinding[] {declaringSourceType.scope.getJavaLangObject()};
+		    this.purpose = SyntheticMethodBinding.RecordOverrideEquals;
+		}
+		this.index = index;
+	}
 	/**
 	 * An constructor accessor is a constructor with an extra argument (declaringClass), in case of
 	 * collision with an existing constructor, then add again an extra argument (declaringClass again).
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
index 8ccdc0a..1429127 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TagBits.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -40,13 +40,13 @@
 
 	// for method
 	long HasUncheckedTypeArgumentForBoundCheck = ASTNode.Bit9;
-	
+
 	// local variable
 	long ForcedToBeRawType = ASTNode.Bit10;
 
 	// set when method has argument(s) that couldn't be resolved
 	long HasUnresolvedArguments = ASTNode.Bit10;
-	
+
 	// for the type cycle hierarchy check used by ClassScope
 	long BeginHierarchyCheck = ASTNode.Bit9;  // type
 	long EndHierarchyCheck = ASTNode.Bit10; // type
@@ -59,12 +59,16 @@
 
 	long IsArgument = ASTNode.Bit11; // local
 	long ClearPrivateModifier = ASTNode.Bit10; // constructor binding
-	
+
 	// for java 7 - this bit is also set if the variable is explicitly or implicitly final
 	long IsEffectivelyFinal = ASTNode.Bit12; // local
 	long MultiCatchParameter = ASTNode.Bit13; // local
 	long IsResource = ASTNode.Bit14; // local
 
+	// for java 14 Records Canonical constructor (preview)
+	long IsCanonicalConstructor = ASTNode.Bit12; // constructor
+	long isImplicit  = ASTNode.Bit13; // constructor and method
+
 	// have implicit null annotations been collected (inherited(?) & default)?
 	long IsNullnessKnown = ASTNode.Bit13; // method
 
@@ -88,7 +92,7 @@
 
 	// set for parameterized type NOT of the form X<?,?>
 	long IsBoundParameterizedType = ASTNode.Bit24; // PTB only.
-	
+
 	long HasAnnotatedVariants = ASTNode.Bit24; // TVB, STB
 
 	// used by BinaryTypeBinding
@@ -158,6 +162,8 @@
 
 	/** From Java 9 */
 	long AnnotationTerminallyDeprecated = ASTNode.Bit63L;
+	/** From Java 14 */
+	long AnnotationForRecordComponent = ASTNode.Bit31;
 
 	long AllStandardAnnotationsMask =
 				  AnnotationTargetMASK
@@ -175,18 +181,18 @@
 				| AnnotationNonNullByDefault
 				| AnnotationNullUnspecifiedByDefault
 				| AnnotationRepeatable;
-	
+
 	long AnnotationNullMASK = AnnotationNullable | AnnotationNonNull;
 	/** @since 3.10 marks a type that has a nullness annotation directly or on a detail (array dimension/type argument). */
 	long HasNullTypeAnnotation = ASTNode.Bit21;
 
 	long HasTypeAnnotations = ASTNode.Bit22;
-	
+
 	long DefaultValueResolved = ASTNode.Bit60L;
 
 	// set when type contains non-private constructor(s)
 	long HasNonPrivateConstructor = ASTNode.Bit61L;
-	
+
 	// set when type binding has a captured wildcard somewhere
 	long HasCapturedWildcard = ASTNode.Bit62L;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
index 645fd17..09f7755 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *      Stephen Herrmann <stephan@cs.tu-berlin.de> -  Contributions for
@@ -61,7 +61,7 @@
 	public long tagBits = 0; // See values in the interface TagBits below
 
 	protected AnnotationBinding [] typeAnnotations = Binding.NO_ANNOTATIONS;
-	
+
 	// jsr 308
 	public static final ReferenceBinding TYPE_USE_BINDING = new ReferenceBinding() { /* used for type annotation resolution. */
 		{ this.id = TypeIds.T_undefined; }
@@ -70,7 +70,7 @@
 		@Override
 		public boolean hasTypeBit(int bit) { return false; }
 	};
-	
+
 	/** Base type definitions */
 	public final static BaseTypeBinding INT = new BaseTypeBinding(
 			TypeIds.T_int, TypeConstants.INT, new char[] { 'I' });
@@ -104,7 +104,7 @@
 public TypeBinding() {
 	super();
 }
-	
+
 public TypeBinding(TypeBinding prototype) {  // faithfully copy most instance state - clone operation should specialize/override suitably.
 	this.id = prototype.id;
 	this.tagBits = prototype.tagBits & ~TagBits.AnnotationNullMASK;
@@ -139,6 +139,28 @@
 		return null;
 	}
 }
+public static final TypeBinding wellKnownBaseType(int id) {
+	switch (id) {
+	case TypeIds.T_boolean:
+		return TypeBinding.BOOLEAN;
+	case TypeIds.T_byte:
+		return TypeBinding.BYTE;
+	case TypeIds.T_char:
+		return TypeBinding.CHAR;
+	case TypeIds.T_short:
+		return TypeBinding.SHORT;
+	case TypeIds.T_double:
+		return TypeBinding.DOUBLE;
+	case TypeIds.T_float:
+		return TypeBinding.FLOAT;
+	case TypeIds.T_int:
+		return TypeBinding.INT;
+	case TypeIds.T_long:
+		return TypeBinding.LONG;
+	default:
+		return null;
+	}
+}
 
 public ReferenceBinding actualType() {
 	return null; // overridden in ParameterizedTypeBinding & WildcardBinding
@@ -232,7 +254,7 @@
 /** Virtual copy constructor: a copy is made of the receiver's entire instance state and then suitably
     parameterized by the arguments to the clone operation as seen fit by each type. Parameters may not
     make sense for every type in the hierarchy, in which case they are silently ignored. A type may
-    choose to retain a copy of the prototype for reference. 
+    choose to retain a copy of the prototype for reference.
 */
 public TypeBinding clone(TypeBinding enclosingType) {
 	throw new IllegalStateException("TypeBinding#clone() should have been overridden"); //$NON-NLS-1$
@@ -281,7 +303,7 @@
  * Perform an upwards type projection as per JLS 4.10.5
  * @param scope Relevant scope for evaluating type projection
  * @param mentionedTypeVariables Filter for mentioned type variabled
- * @returns Upwards type projection of 'this', or null if downwards projection is undefined 
+ * @returns Upwards type projection of 'this', or null if downwards projection is undefined
 */
 public TypeBinding upwardsProjection(Scope scope, TypeBinding[] mentionedTypeVariables) {
 	return this;
@@ -291,7 +313,7 @@
  * Perform a downwards type projection as per JLS 4.10.5
  * @param scope Relevant scope for evaluating type projection
  * @param mentionedTypeVariables Filter for mentioned type variabled
- * @returns Downwards type projection of 'this', or null if downwards projection is undefined 
+ * @returns Downwards type projection of 'this', or null if downwards projection is undefined
 */
 public TypeBinding downwardsProjection(Scope scope, TypeBinding[] mentionedTypeVariables) {
 	return this;
@@ -485,11 +507,11 @@
  * Returns the type to use for generic cast, or null if none required
  */
 public TypeBinding genericCast(TypeBinding targetType) {
-	if (TypeBinding.equalsEquals(this, targetType)) 
+	if (TypeBinding.equalsEquals(this, targetType))
 		return null;
 	TypeBinding targetErasure = targetType.erasure();
 	// type var get replaced by upper bound
-	if (erasure().findSuperTypeOriginatingFrom(targetErasure) != null) 
+	if (erasure().findSuperTypeOriginatingFrom(targetErasure) != null)
 		return null;
 	return targetErasure;
 }
@@ -605,7 +627,7 @@
 		case TypeIds.T_JavaLangInteger :
 		case TypeIds.T_JavaLangLong :
 			return true;
-		default: 
+		default:
 			return false;
 	}
 }
@@ -623,7 +645,7 @@
 		case TypeIds.T_JavaLangInteger :
 		case TypeIds.T_JavaLangLong :
 			return true;
-		default: 
+		default:
 			return false;
 	}
 }
@@ -646,6 +668,10 @@
 	return false;
 }
 
+public boolean isRecord() {
+	return false;
+}
+
 /* Answer true if the receiver type can be assigned to the argument type (right)
  */
 public boolean isCompatibleWith(TypeBinding right) {
@@ -661,16 +687,16 @@
 /* Answer true if the receiver type can be assigned to the argument type (right) with boxing/unboxing applied.
  */
 public boolean isBoxingCompatibleWith(TypeBinding right, /*@NonNull */ Scope scope) {
-	
+
 	if (right == null)
 		return false;
 
 	if (TypeBinding.equalsEquals(this, right))
 		return true;
-	
+
 	if (this.isCompatibleWith(right, scope))
 		return true;
-	
+
 	if (this.isBaseType() != right.isBaseType()) {
 		TypeBinding convertedType = scope.environment().computeBoxingType(this);
 		if (TypeBinding.equalsEquals(convertedType, right) || convertedType.isCompatibleWith(right, scope))
@@ -754,7 +780,7 @@
 
 /**
  * Returns true if the type is parameterized, e.g. List<String>.
- * Note that some instances of ParameterizedTypeBinding have no arguments, like for non-generic members 
+ * Note that some instances of ParameterizedTypeBinding have no arguments, like for non-generic members
  * of a parameterized type. Use {@link #isParameterizedTypeWithActualArguments()} instead to find out.
  */
 public boolean isParameterizedType() {
@@ -787,7 +813,7 @@
  * i.e. {@link #isParameterizedType()} is not equivalent to testing <code>type.kind() == Binding.PARAMETERIZED_TYPE</code>
  */
 public final boolean isParameterizedTypeWithActualArguments() {
-	return (kind() == Binding.PARAMETERIZED_TYPE) 
+	return (kind() == Binding.PARAMETERIZED_TYPE)
 					&& ((ParameterizedTypeBinding) this).arguments != null;
 }
 
@@ -870,15 +896,15 @@
 public boolean isProvablyDistinct(TypeBinding otherType) {
 
 	/* With the hybrid 1.4/1.5+ projects modes, while establishing type equivalence, we need to
-	   be prepared for a type such as Map appearing in one of three forms: As (a) a ParameterizedTypeBinding 
-	   e.g Map<String, String>, (b) as RawTypeBinding Map#RAW and finally (c) as a BinaryTypeBinding 
+	   be prepared for a type such as Map appearing in one of three forms: As (a) a ParameterizedTypeBinding
+	   e.g Map<String, String>, (b) as RawTypeBinding Map#RAW and finally (c) as a BinaryTypeBinding
 	   When the usage of a type lacks type parameters, whether we land up with the raw form or not depends
 	   on whether the underlying type was "seen to be" a generic type in the particular build environment or
 	   not. See:
 	    https://bugs.eclipse.org/bugs/show_bug.cgi?id=186565
-        https://bugs.eclipse.org/bugs/show_bug.cgi?id=328827 
+        https://bugs.eclipse.org/bugs/show_bug.cgi?id=328827
         https://bugs.eclipse.org/bugs/show_bug.cgi?id=329588
-	 */ 
+	 */
 
 	if (equalsEquals(this, otherType))
 	    return false;
@@ -1224,7 +1250,7 @@
 				if (cb18.firstBound != null) {
 					if (cb18.lowerBound != null)
 						return false; // type containment is not defined for variables with both upper and lower bound
-					TypeBinding[] otherBounds = null; 
+					TypeBinding[] otherBounds = null;
 					int len = cb18.upperBounds.length; // by construction non-null if firstBound is set
 					if (len > 1)
 						System.arraycopy(cb18.upperBounds, 1, otherBounds = new TypeBinding[len-1], 0, len-1);
@@ -1510,7 +1536,7 @@
 	}
 }
 
-/** 
+/**
  * Return this type minus its type annotations
  */
 public TypeBinding unannotated() {
@@ -1519,7 +1545,7 @@
 
 /**
  * Return this type minus its toplevel null annotations. Any annotations on type arguments or
- * bounds are retained. 
+ * bounds are retained.
  */
 public TypeBinding withoutToplevelNullAnnotation() {
 	return this;
@@ -1611,8 +1637,8 @@
  * In particular {@code null} is answered if the receiver is not a reference type, or is a problem type.
  * @param scope scope
  * @param replaceWildcards Should wildcards be replaced following JLS 9.8? Say false for lambdas with explicit argument types which should apply 18.5.3
- *  
- * @return The single abstract method of a functional interface, or one of {@code null} or {@link ReferenceBinding#samProblemBinding}, if the receiver is not a functional interface. 
+ *
+ * @return The single abstract method of a functional interface, or one of {@code null} or {@link ReferenceBinding#samProblemBinding}, if the receiver is not a functional interface.
  */
 public MethodBinding getSingleAbstractMethod(Scope scope, boolean replaceWildcards) {
 	return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBindingVisitor.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBindingVisitor.java
index c29a7fb..f0ff19e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBindingVisitor.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBindingVisitor.java
@@ -32,31 +32,31 @@
 	public boolean visit(ArrayBinding arrayBinding) {
 		return true;  // continue traversal.
 	}
-	
+
 	public boolean visit(TypeVariableBinding typeVariable) {
 		return true;  // continue traversal.
 	}
-	
+
 	public boolean visit(ReferenceBinding referenceBinding) {
 		return true;  // continue traversal.
 	}
-	
+
 	public boolean visit(WildcardBinding wildcardBinding) {
 		return true;  // continue traversal.
 	}
-	
+
 	public boolean visit(ParameterizedTypeBinding parameterizedTypeBinding) {
 		return true;  // continue traversal.
 	}
-	
+
 	public boolean visit(IntersectionTypeBinding18 intersectionTypeBinding18) {
 		return true;  // continue traversal.
 	}
-	
+
 	public boolean visit(RawTypeBinding rawTypeBinding) {
 		return true;  // continue traversal.
 	}
-	
+
 	public boolean visit(PolyTypeBinding polyTypeBinding) {
 		return true;  // continue traversal.
 	}
@@ -69,9 +69,9 @@
 
 	public static void visit(TypeBindingVisitor visitor, TypeBinding type) {
 
-		if (type == null) 
+		if (type == null)
 			return;
-		
+
 		SimpleLookupTable visitedCache = visitor.visitedCache;
 		if (visitedCache == null) {
 			visitor.visitedCache = new SimpleLookupTable(3);
@@ -83,7 +83,7 @@
 			return;
 		visitedCache.put(type, Boolean.TRUE);
 		switch (type.kind()) {
-			
+
 			case Binding.TYPE_PARAMETER:
 				TypeVariableBinding typeVariableBinding = (TypeVariableBinding) type;
 				if (visitor.visit(typeVariableBinding)) {
@@ -92,7 +92,7 @@
 					visit(visitor, typeVariableBinding.superInterfaces);
 				}
 	            break;
-	            
+
 			case Binding.PARAMETERIZED_TYPE:
 				ParameterizedTypeBinding parameterizedTypeBinding = (ParameterizedTypeBinding) type;
 				if (visitor.visit(parameterizedTypeBinding)) {
@@ -117,15 +117,15 @@
 		        	}
 		        }
 				break;
-			
+
 			case Binding.BASE_TYPE:
 				visitor.visit((BaseTypeBinding) type);
 				break;
-			
+
 			case Binding.RAW_TYPE:
 				visitor.visit((RawTypeBinding) type);
 				break;
-				
+
 			case Binding.TYPE:
 			case Binding.GENERIC_TYPE:
 				ReferenceBinding referenceBinding = (ReferenceBinding) type;
@@ -134,17 +134,17 @@
 					visit(visitor, referenceBinding.typeVariables());
 				}
 				break;
-			
+
 			case Binding.INTERSECTION_TYPE18:
 				IntersectionTypeBinding18 intersectionTypeBinding18 = (IntersectionTypeBinding18) type;
 				if (visitor.visit(intersectionTypeBinding18))
 					visit(visitor, intersectionTypeBinding18.intersectingTypes);
 				break;
-				
+
 			case Binding.POLY_TYPE:
 				visitor.visit((PolyTypeBinding) type);
 				break;
-				
+
 			default:
 				throw new InternalError("Unexpected binding type"); //$NON-NLS-1$
 		}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBound.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBound.java
index 770e02c..b91daac 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBound.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBound.java
@@ -19,15 +19,15 @@
  * Implementation of 18.1.3 in JLS8
  */
 public class TypeBound extends ReductionResult {
-	
+
 	InferenceVariable left;
-	
+
 	// this flag contributes to the workaround controlled by InferenceContext18.ARGUMENT_CONSTRAINTS_ARE_SOFT:
 	boolean isSoft;
 
 	// here we accumulate null tagBits from any types that have been related to this type bound during incorporation:
 	long nullHints;
-	
+
 	static TypeBound createBoundOrDependency(InferenceSubstitution theta, TypeBinding type, InferenceVariable variable) {
         // Part of JLS8 sect 18.1.3:
 		return new TypeBound(variable, theta.substitute(theta, type), SUBTYPE, true);
@@ -37,7 +37,7 @@
 	TypeBound(InferenceVariable inferenceVariable, TypeBinding typeBinding, int relation) {
 		this(inferenceVariable, typeBinding, relation, false);
 	}
-	
+
 	TypeBound(InferenceVariable inferenceVariable, TypeBinding typeBinding, int relation, boolean isSoft) {
 		this.left = inferenceVariable;
 		this.right = typeBinding;
@@ -65,12 +65,12 @@
 	boolean isBound() {
 		return this.right.isProperType(true);
 	}
-	
+
 	@Override
 	public int hashCode() {
 		return this.left.hashCode() + this.right.hashCode() + this.relation;
 	}
-	
+
 	@Override
 	public boolean equals(Object obj) {
 		if (obj instanceof TypeBound) {
@@ -79,7 +79,7 @@
 		}
 		return false;
 	}
-	
+
 	// debugging:
 	@Override
 	public String toString() {
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 8ad5e71..9053c23 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -43,6 +43,7 @@
 	char[] JAVAX = "javax".toCharArray(); //$NON-NLS-1$
 	char[] LANG = "lang".toCharArray(); //$NON-NLS-1$
 	char[] IO = "io".toCharArray(); //$NON-NLS-1$
+	char[] NIO = "nio".toCharArray(); //$NON-NLS-1$
 	char[] UTIL = "util".toCharArray(); //$NON-NLS-1$
 	char[] ZIP = "zip".toCharArray(); //$NON-NLS-1$
 	char[] ANNOTATION = "annotation".toCharArray(); //$NON-NLS-1$
@@ -52,6 +53,7 @@
 	char[] EQUALS = "equals".toCharArray(); //$NON-NLS-1$
 	char[] GETCLASS = "getClass".toCharArray(); //$NON-NLS-1$
 	char[] HASHCODE = "hashCode".toCharArray(); //$NON-NLS-1$
+	char[] TOSTRING = "toString".toCharArray(); //$NON-NLS-1$
 	char[] OBJECT = "Object".toCharArray(); //$NON-NLS-1$
 	char[] MAIN = "main".toCharArray(); //$NON-NLS-1$
 	char[] SERIALVERSIONUID = "serialVersionUID".toCharArray(); //$NON-NLS-1$
@@ -62,6 +64,8 @@
 	char[] WRITEOBJECT = "writeObject".toCharArray(); //$NON-NLS-1$
 	char[] CharArray_JAVA_LANG_OBJECT = "java.lang.Object".toCharArray(); //$NON-NLS-1$
 	char[] CharArray_JAVA_LANG_ENUM = "java.lang.Enum".toCharArray(); //$NON-NLS-1$
+	char[] CharArray_JAVA_LANG_RECORD = "java.lang.Record".toCharArray(); //$NON-NLS-1$
+	char[] CharArray_JAVA_LANG_RECORD_SLASH = "java/lang/Record".toCharArray(); //$NON-NLS-1$
 	char[] CharArray_JAVA_LANG_ANNOTATION_ANNOTATION = "java.lang.annotation.Annotation".toCharArray(); //$NON-NLS-1$
 	char[] CharArray_JAVA_IO_OBJECTINPUTSTREAM = "java.io.ObjectInputStream".toCharArray(); //$NON-NLS-1$
 	char[] CharArray_JAVA_IO_OBJECTOUTPUTSTREAM = "java.io.ObjectOutputStream".toCharArray(); //$NON-NLS-1$
@@ -109,14 +113,18 @@
     char[] DESERIALIZE_LAMBDA = "$deserializeLambda$".toCharArray(); //$NON-NLS-1$
     char[] LAMBDA_TYPE = "<lambda>".toCharArray(); //$NON-NLS-1$
     char[] UPPER_MODULE = "MODULE".toCharArray(); //$NON-NLS-1$
+    char[] UPPER_RECORD_COMPONENT = "RECORD_COMPONENT".toCharArray(); //$NON-NLS-1$
 
     // JEP 286
 	char[] VAR = "var".toCharArray(); //$NON-NLS-1$
+    // JEP 359 Records
+	char[] RECORD_RESTRICTED_IDENTIFIER = "record".toCharArray(); //$NON-NLS-1$
+	char[] RECORD_CLASS = "Record".toCharArray(); //$NON-NLS-1$
 
     // jsr308
 	char[] TYPE_USE_TARGET  = "TYPE_USE".toCharArray(); //$NON-NLS-1$
 	char[] TYPE_PARAMETER_TARGET = "TYPE_PARAMETER".toCharArray(); //$NON-NLS-1$
-    
+
     // common 3rd party package components:
     char[] ORG = "org".toCharArray(); //$NON-NLS-1$
     char[] ECLIPSE = "eclipse".toCharArray(); //$NON-NLS-1$
@@ -135,7 +143,7 @@
     char[] DOM = "dom".toCharArray(); //$NON-NLS-1$
     char[] ITYPEBINDING = "ITypeBinding".toCharArray(); //$NON-NLS-1$
     char[] SPRING = "springframework".toCharArray(); //$NON-NLS-1$
-    
+
 	// Constant compound names
 	char[][] JAVA_LANG = {JAVA, LANG};
 	char[][] JAVA_IO = {JAVA, IO};
@@ -150,9 +158,11 @@
 	char[][] JAVA_LANG_EXCEPTION = {JAVA, LANG, "Exception".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_ERROR = {JAVA, LANG, "Error".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_ILLEGALARGUMENTEXCEPTION = {JAVA, LANG, "IllegalArgumentException".toCharArray()}; //$NON-NLS-1$
+	char[][] JAVA_LANG_INCOMPATIBLECLASSCHANGEERROR = {JAVA, LANG, "IncompatibleClassChangeError".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_ITERABLE = {JAVA, LANG, "Iterable".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_NOCLASSDEFERROR = {JAVA, LANG, "NoClassDefError".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_OBJECT = {JAVA, LANG, OBJECT};
+	char[][] JAVA_LANG_RECORD = {JAVA, LANG, RECORD_CLASS};
 	char[][] JAVA_LANG_STRING = {JAVA, LANG, "String".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_STRINGBUFFER = {JAVA, LANG, "StringBuffer".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_STRINGBUILDER = {JAVA, LANG, "StringBuilder".toCharArray()}; //$NON-NLS-1$
@@ -175,6 +185,7 @@
 	char[][] JAVA_UTIL_ITERATOR = {JAVA, UTIL, "Iterator".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_UTIL_OBJECTS = {JAVA, UTIL, "Objects".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_UTIL_LIST = {JAVA, UTIL, "List".toCharArray()}; //$NON-NLS-1$
+	char[][] JAVA_UTIL_ARRAYS = {JAVA, UTIL, "Arrays".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$
@@ -224,6 +235,7 @@
 	char[][] JAVA_LANG_INVOKE_METHODHANDLES = {JAVA, LANG, INVOKE, "MethodHandles".toCharArray()}; //$NON-NLS-1$
 	char[][] JAVA_LANG_AUTOCLOSEABLE =  {JAVA, LANG, "AutoCloseable".toCharArray()}; //$NON-NLS-1$
 	char[] CLOSE = "close".toCharArray(); //$NON-NLS-1$
+	char[][] JAVA_LANG_RUNTIME_OBJECTMETHODS = {JAVA, LANG, RUNTIME, "ObjectMethods".toCharArray()}; //$NON-NLS-1$
 	// known helper functions for closing a Closeable (all receive a Closeable as their first argument):
 	public static class CloseMethodRecord {
 		public char[][] typeName;
@@ -244,7 +256,7 @@
 		new CloseMethodRecord(GUAVA_CLOSEABLES, CLOSE, 1),
 		new CloseMethodRecord(APACHE_IOUTILS, CLOSE_QUIETLY, 1),
 		new CloseMethodRecord(APACHE_DBUTILS, CLOSE, 1),
-		new CloseMethodRecord(APACHE_DBUTILS, CLOSE_QUIETLY, 3), // closeQuietly(Connection,Statement,ResultSet) 
+		new CloseMethodRecord(APACHE_DBUTILS, CLOSE_QUIETLY, 3), // closeQuietly(Connection,Statement,ResultSet)
 		new CloseMethodRecord(APACHE_DBUTILS, "commitAndClose".toCharArray(), 1), //$NON-NLS-1$
 		new CloseMethodRecord(APACHE_DBUTILS, "commitAndCloseQuietly".toCharArray(), 1), //$NON-NLS-1$
 		new CloseMethodRecord(APACHE_DBUTILS, "rollbackAndClose".toCharArray(), 1), //$NON-NLS-1$
@@ -294,7 +306,7 @@
 		{JAVA, "beans".toCharArray(), "XMLDecoder".toCharArray()}, //$NON-NLS-1$ //$NON-NLS-2$
 		{JAVAX, "sound".toCharArray(), "sampled".toCharArray(), "AudioInputStream".toCharArray()}, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 	};
-	char[][] JAVA_IO_RESOURCE_FREE_CLOSEABLES = new char[][] {			
+	char[][] JAVA_IO_RESOURCE_FREE_CLOSEABLES = new char[][] {
 		"StringReader".toCharArray(), //$NON-NLS-1$
 		"StringWriter".toCharArray(), //$NON-NLS-1$
 		"ByteArrayInputStream".toCharArray(), //$NON-NLS-1$
@@ -310,13 +322,34 @@
 		"LongStream".toCharArray(), //$NON-NLS-1$
 		"IntStream".toCharArray() //$NON-NLS-1$
 	};
-	
+
+	// closeable classes containing one or more 'fluent' methods (returning 'this'):
+	char[] CHANNELS = "channels".toCharArray(); //$NON-NLS-1$
+	char[][][] FLUENT_RESOURCE_CLASSES = {
+		new char[][] {JAVA, IO, "CharArrayWriter".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, IO, "Console".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, IO, "PrintStream".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, IO, "PrintWriter".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, IO, "StringWriter".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, IO, "Writer".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, NIO, CHANNELS, "AsynchronousFileChannel".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, NIO, CHANNELS, "AsynchronousServerSocketChannel".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, NIO, CHANNELS, "FileChannel".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, NIO, CHANNELS, "NetworkChannel".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, NIO, CHANNELS, "SeekableByteChannel".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, NIO, CHANNELS, "SelectableChannel".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, NIO, CHANNELS, "Selector".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, NIO, CHANNELS, "ServerSocketChannel".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, UTIL, "Formatter".toCharArray() }, //$NON-NLS-1$
+		new char[][] {JAVA, UTIL, "Scanner".toCharArray() }, //$NON-NLS-1$
+	};
+
 	// different assertion utilities:
 	char[] ASSERT_CLASS = "Assert".toCharArray(); //$NON-NLS-1$
 	char[][] ORG_ECLIPSE_CORE_RUNTIME_ASSERT = new char[][] { ORG, ECLIPSE, CORE, RUNTIME, ASSERT_CLASS };
 	// ... methods:
 	char[] IS_NOTNULL = "isNotNull".toCharArray(); //$NON-NLS-1$
-	
+
 	char[] JUNIT = "junit".toCharArray(); //$NON-NLS-1$
 	char[] FRAMEWORK = "framework".toCharArray(); //$NON-NLS-1$
 	char[] JUPITER = "jupiter".toCharArray(); //$NON-NLS-1$
@@ -332,7 +365,7 @@
 	// ... annotations:
 	char[] METHOD_SOURCE = "MethodSource".toCharArray(); //$NON-NLS-1$
 	char[][] ORG_JUNIT_METHOD_SOURCE = new char[][] { ORG, JUNIT, JUPITER, PARAMS, PROVIDER, METHOD_SOURCE };
-	
+
 	char[] VALIDATE_CLASS = "Validate".toCharArray(); //$NON-NLS-1$
 	char[][] ORG_APACHE_COMMONS_LANG_VALIDATE = new char[][] { ORG, APACHE, COMMONS, LANG, VALIDATE_CLASS };
 	char[][] ORG_APACHE_COMMONS_LANG3_VALIDATE = new char[][] { ORG, APACHE, COMMONS, LANG3, VALIDATE_CLASS };
@@ -343,7 +376,7 @@
 	char[] IS_TRUE = "isTrue".toCharArray(); //$NON-NLS-1$
 	char[] NOT_NULL = "notNull".toCharArray(); //$NON-NLS-1$
 
-	char[][] COM_GOOGLE_COMMON_BASE_PRECONDITIONS = new char[][] { 
+	char[][] COM_GOOGLE_COMMON_BASE_PRECONDITIONS = new char[][] {
 			COM, GOOGLE, "common".toCharArray(), "base".toCharArray(), "Preconditions".toCharArray() }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 	// ... methods:
 	char[] CHECK_NOT_NULL = "checkNotNull".toCharArray(); //$NON-NLS-1$
@@ -352,7 +385,7 @@
 
 	// ... methods in java.util.Objects:
 	char[] REQUIRE_NON_NULL = "requireNonNull".toCharArray(); //$NON-NLS-1$
-	
+
 	// different @Inject annotations are relevant for @NonNull fields
 	char[] INJECT_PACKAGE = "inject".toCharArray(); //$NON-NLS-1$
 	char[] INJECT_TYPE = "Inject".toCharArray(); //$NON-NLS-1$
@@ -360,7 +393,14 @@
 	char[][] COM_GOOGLE_INJECT_INJECT = new char[][] {COM, GOOGLE, INJECT_PACKAGE, INJECT_TYPE };
 	//    detail for the above:
 	char[] OPTIONAL = "optional".toCharArray(); //$NON-NLS-1$
-	
+
+	// utils that ensure argument is nonnull if result is true
+	// java.lang.Class:
+	char[] IS_INSTANCE = "isInstance".toCharArray(); //$NON-NLS-1$
+	// java.lang.Objects:
+	char[] NON_NULL = "nonNull".toCharArray();   //$NON-NLS-1$
+	char[] IS_NULL = "isNull".toCharArray();   //$NON-NLS-1$
+
 	// well-known methods with "dangerous" signatures:
 	char[][] JAVA_UTIL_MAP = new char[][] { JAVA, UTIL, "Map".toCharArray() }; //$NON-NLS-1$
 	char[] GET = "get".toCharArray(); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
index 52c1428..ff8f335 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contributions for
@@ -103,19 +103,19 @@
 	final int T_JavaIoExternalizable = 56;
 	final int T_JavaIoObjectStreamException = 57;
 	final int T_JavaIoException = 58;
-	
+
 	final int T_JavaUtilCollection = 59;
-	
+
 	// java 7
 	final int T_JavaLangSafeVarargs = 60;
-	
+
 	final int T_JavaLangInvokeMethodHandlePolymorphicSignature = 61;
 
 	// java 7 java.lang.AutoCloseable
 	final int T_JavaLangAutoCloseable = 62;
-	
+
 	// new in 3.8 for null annotations, removed in 4.6 (ids 65-67)
-	
+
 	// new in 3.8 to identify org.eclipse.core.runtime.Assert
 	final int T_OrgEclipseCoreRuntimeAssert = 68;
 	// new in 3.9 to identify more assertion utilities:
@@ -138,7 +138,7 @@
 
 	// Java 8 - JEP 120
 	final int T_JavaLangAnnotationRepeatable = 90;
-	
+
 	// classes with methods with "dangerous" signatures:
 	final int T_JavaUtilMap = 91;
 	final int T_JavaUtilList = 92;
@@ -146,9 +146,12 @@
 	// @MethodSource
 	final int T_OrgJunitJupiterParamsProviderMethodSource = 93;
 
+	// Java 14 preview
+	final int T_JavaLangRecord = 93;
+
 	// If you add new type id, make sure to bump up T_LastWellKnownTypeId if there is a cross over.
 	final int T_LastWellKnownTypeId = 128;
-	
+
 
 	final int NoId = Integer.MAX_VALUE;
 
@@ -236,19 +239,19 @@
 	 * @see ReferenceBinding#hasTypeBit(int)
 	 */
 	final int BitUninitialized = 0x8000000;
-	/** 
+	/**
 	 * Marks all sub-types of java.lang.AutoCloseable.
 	 * @see ReferenceBinding#hasTypeBit(int)
 	 */
 	final int BitAutoCloseable = 1;
-	/** 
+	/**
 	 * Marks all sub-types of java.io.Closeable.
 	 * @see ReferenceBinding#hasTypeBit(int)
 	 */
 	final int BitCloseable = 2;
 	/**
 	 * Bit for members of a white list:
-	 * Subtypes of Closeable that wrap another resource without directly holding any OS resources. 
+	 * Subtypes of Closeable that wrap another resource without directly holding any OS resources.
 	 */
 	final int BitWrapperCloseable = 4;
 	/**
@@ -256,7 +259,7 @@
 	 * Subtypes of Closeable that do not hold an OS resource that needs to be released.
 	 */
 	final int BitResourceFreeCloseable = 8;
-	
+
 	final int BitUninternedType = 16;
 
 	/** Bit for a type configured as a @NonNull annotation. */
@@ -280,4 +283,8 @@
 	 * Set of type bits that should be inherited by any sub types.
 	 */
 	final int InheritableBits = BitAutoCloseable | BitCloseable | BitUninternedType | BitMap | BitCollection | BitList ;
+	
+	public static int getCategory(int typeId) {
+		return typeId == TypeIds.T_double || typeId == TypeIds.T_long ? 2 : 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 23839be..0127309 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
@@ -27,47 +27,47 @@
 
 /* TypeSystem: An abstraction responsible for keeping track of types that undergo "derivation" of some sort and the derived types produced thus.
    Here we use the term derivation in the Pascal sense and not per object oriented parlance.
-   
+
    As of Java SE8, a type can undergo derivation in a bunch of ways:
-   
+
        - By being created arrays out of,
        - By being parameterized,
        - By being created raw forms of,
        - By being the generic type which a wildcard type or an intersection type parameterizes,
        - By being annotated.
-       
+
    It is the responsibility of the TypeSystem to serve as the factory and ensure that unique types are created and maintained. Most of the
    compiler depends on object identity given the derivation parameters are the same. E.g: If we dole out non-unique ParameterizedTypeBinding's
    for two attempts to create List<String>, then one cannot be assigned to the other.
-   
+
    Till Java SE7, we could manage to create a single binding for a type - not so with annotations coming into the picture. In order for
    two uses of the same type to be annotated differently, the bindings for them need to be distinct and cannot be shared. If we start
    doling out different bindings, then validating type identity and equivalence becomes an issue.
-   
+
    What we do to solve the problem is produce different bindings when they need to be annotated differently, but stamp them with the
    same id (TypeBinding#id). Thus types that fail == or != could quickly be ascertained to be mere annotation variants by comparing
    the id field.
-       
-   This class is responsible for id stamping unique types. Only those types that are "derived from" in some form or participate in the 
-   derivation in some form (by being type arguments say) get tracked and id'd here. A type which is not thus derived from in one form or 
+
+   This class is responsible for id stamping unique types. Only those types that are "derived from" in some form or participate in the
+   derivation in some form (by being type arguments say) get tracked and id'd here. A type which is not thus derived from in one form or
    the other or participate in the derivation thus - we are completely oblivious to.
-   
-   TypeBinding.id computation: For primitive types and certain "well known" types, id assignment happens elsewhere. Here we start with an 
-   id value that is suitably high and proceed monotonically upwards so we will not accidentally collide with the id space in use already. 
-   id assignments happens in such a way that a naked type and its annotated variants - variously annotated - would all share the same id. 
-   Example: @T1 Map<@T2 String, @T3 Object> and Map<@T4 String, @T5 Object> and @T6 Map<String, Object> and @T7 Map<String, @T8 Object> and 
-   Map<String, @T9 Object> would all share the same id since the unadorned naked type in each case is the same: Map<String, Object>. None 
-   of this would share the id with Map<String, String>. Briefly put, if you take a certain annotated type and strip it of all annotations 
-   to come up with the naked type, that naked type and the annotated type would have the same id. Alternately, if you take a certain naked 
-   type and arrive at the universe of all differently annotated types, they would all share the same id while their bindings could be different - 
+
+   TypeBinding.id computation: For primitive types and certain "well known" types, id assignment happens elsewhere. Here we start with an
+   id value that is suitably high and proceed monotonically upwards so we will not accidentally collide with the id space in use already.
+   id assignments happens in such a way that a naked type and its annotated variants - variously annotated - would all share the same id.
+   Example: @T1 Map<@T2 String, @T3 Object> and Map<@T4 String, @T5 Object> and @T6 Map<String, Object> and @T7 Map<String, @T8 Object> and
+   Map<String, @T9 Object> would all share the same id since the unadorned naked type in each case is the same: Map<String, Object>. None
+   of this would share the id with Map<String, String>. Briefly put, if you take a certain annotated type and strip it of all annotations
+   to come up with the naked type, that naked type and the annotated type would have the same id. Alternately, if you take a certain naked
+   type and arrive at the universe of all differently annotated types, they would all share the same id while their bindings could be different -
    would be different unless they are identically annotated.
-   
+
    Thus subsystems that are annotation agnostic could quickly ascertain binding equality by comparing the id field.
 */
 public class TypeSystem {
-	
+
 	public final class HashedParameterizedTypes {
-		
+
 		private final class PTBKey extends ReferenceBinding { // extends ReferenceBinding so it can be used as wrapper
 			protected ReferenceBinding type; // must ensure the type is resolved
 			public TypeBinding[] arguments;
@@ -110,7 +110,7 @@
 			}
 			@Override
 			public boolean equals(Object other) {
-				PTBKey that = (PTBKey) other;  // homogeneous container. 
+				PTBKey that = (PTBKey) other;  // homogeneous container.
 				return this.type == that.type && this.enclosingType == that.enclosingType && Util.effectivelyEqual(this.arguments, that.arguments); //$IDENTITY-COMPARISON$
 			}
 			final int hash(TypeBinding b) {
@@ -129,11 +129,11 @@
 				return hashCode;
 			}
 		}
-		
+
 		HashMap<PTBKey, ParameterizedTypeBinding []> hashedParameterizedTypes = new HashMap<>(256);
 
 		ParameterizedTypeBinding get(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType, AnnotationBinding[] annotations) {
-			
+
 			ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType);
 			int typeArgumentsLength = typeArguments == null ? 0: typeArguments.length;
 			TypeBinding [] unannotatedTypeArguments = typeArguments == null ? null : new TypeBinding[typeArgumentsLength];
@@ -141,7 +141,7 @@
 				unannotatedTypeArguments[i] = getUnannotatedType(typeArguments[i]);
 			}
 			ReferenceBinding unannotatedEnclosingType = enclosingType == null ? null : (ReferenceBinding) getUnannotatedType(enclosingType);
-			
+
 			PTBKey key = new PTBKey(unannotatedGenericType, unannotatedTypeArguments, unannotatedEnclosingType, null);
 			ReferenceBinding genericTypeToMatch = unannotatedGenericType, enclosingTypeToMatch = unannotatedEnclosingType;
 			TypeBinding [] typeArgumentsToMatch = unannotatedTypeArguments;
@@ -157,7 +157,7 @@
 					continue;
 				}
 				if (parameterizedType.enclosingType != enclosingTypeToMatch //$IDENTITY-COMPARISON$
-						|| !Util.effectivelyEqual(parameterizedType.typeArguments(), typeArgumentsToMatch)) 
+						|| !Util.effectivelyEqual(parameterizedType.typeArguments(), typeArgumentsToMatch))
 					continue;
 				if (Util.effectivelyEqual(annotations, parameterizedType.getTypeAnnotations()))
 					return parameterizedType;
@@ -174,34 +174,34 @@
 				unannotatedTypeArguments[i] = getUnannotatedType(typeArguments[i]);
 			}
 			ReferenceBinding unannotatedEnclosingType = enclosingType == null ? null : (ReferenceBinding) getUnannotatedType(enclosingType);
-			
+
 			PTBKey key = new PTBKey(unannotatedGenericType, unannotatedTypeArguments, unannotatedEnclosingType, TypeSystem.this.environment);
-			
+
 			ParameterizedTypeBinding [] parameterizedTypeBindings = this.hashedParameterizedTypes.get(key);
 			int slot;
 			if (parameterizedTypeBindings == null) {
 				slot = 0;
 				parameterizedTypeBindings = new ParameterizedTypeBinding[1];
-			} else { 
+			} else {
 				slot = parameterizedTypeBindings.length;
 				System.arraycopy(parameterizedTypeBindings, 0, parameterizedTypeBindings = new ParameterizedTypeBinding[slot + 1], 0, slot);
 			}
 			parameterizedTypeBindings[slot] = parameterizedType;
 			this.hashedParameterizedTypes.put(key, parameterizedTypeBindings);
 		}
-	}	
-	
+	}
+
 	private int typeid = TypeIds.T_LastWellKnownTypeId;
-	private TypeBinding [][] types; 
+	private TypeBinding [][] types;
 	protected HashedParameterizedTypes parameterizedTypes;  // auxiliary fast lookup table for parameterized types.
 	private SimpleLookupTable annotationTypes; // cannot store in types, since AnnotationBinding is not a TypeBinding and we don't want types to operate at Binding level.
 	LookupEnvironment environment;
-	
+
 	public TypeSystem(LookupEnvironment environment) {
 		this.environment = environment;
 		this.annotationTypes = new SimpleLookupTable(16);
 		this.typeid = TypeIds.T_LastWellKnownTypeId;
-		this.types = new TypeBinding[TypeIds.T_LastWellKnownTypeId * 2][]; 
+		this.types = new TypeBinding[TypeIds.T_LastWellKnownTypeId * 2][];
 		this.parameterizedTypes = new HashedParameterizedTypes();
 	}
 
@@ -235,7 +235,7 @@
 			if (urb != null && urb.id == TypeIds.NoId)
 				urb.id = type.id;
 		}
-	
+
 		return this.types[type.id][0] = type;
 	}
 
@@ -266,9 +266,9 @@
 
 	/* Note: parameters will not have type type annotations if lookup environment directly uses TypeSystem as its typeSystem. When ATS is used however
 	   they may be annotated and we need to materialize the unannotated versions and work on them.
-	   
+
 	   See ArrayBinding.swapUnresolved for further special case handling if incoming leafType is a URB that would resolve to a raw type later.
-	*/ 
+	*/
 	public ArrayBinding getArrayType(TypeBinding leafType, int dimensions) {
 		if  (leafType instanceof ArrayBinding) {
 			dimensions += leafType.dimensions();
@@ -279,7 +279,7 @@
 		int i, length = derivedTypes.length;
 		for (i = 0; i < length; i++) {
 			TypeBinding derivedType = derivedTypes[i];
-			if (derivedType == null) 
+			if (derivedType == null)
 				break;
 			if (!derivedType.isArrayType() || derivedType.hasTypeAnnotations())
 				continue;
@@ -297,7 +297,7 @@
 		this.types[this.typeid] = new TypeBinding[1];
 		return (ArrayBinding) (this.types[arrayType.id = this.typeid++][0] = arrayType);
 	}
-	
+
 	public ArrayBinding getArrayType(TypeBinding leafComponentType, int dimensions, AnnotationBinding[] annotations) {
 		return getArrayType(leafComponentType, dimensions);
 	}
@@ -308,7 +308,7 @@
 
 	/* Note: parameters will not have type type annotations if lookup environment directly uses TypeSystem. When AnnotatableTypeSystem is in use
 	   they may and we need to materialize the unannotated versions and work on them.
-	*/ 
+	*/
 	public ParameterizedTypeBinding getParameterizedType(ReferenceBinding genericType, TypeBinding[] typeArguments, ReferenceBinding enclosingType) {
 		ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType);
 		// getUnannotatedType may have replaced URB by resolvedType
@@ -324,7 +324,7 @@
 		ReferenceBinding unannotatedEnclosingType = enclosingType == null ? null : (ReferenceBinding) getUnannotatedType(enclosingType);
 
 		ParameterizedTypeBinding parameterizedType = this.parameterizedTypes.get(unannotatedGenericType, unannotatedTypeArguments, unannotatedEnclosingType, Binding.NO_ANNOTATIONS);
-		if (parameterizedType != null) 
+		if (parameterizedType != null)
 			return parameterizedType;
 
 		parameterizedType = new ParameterizedTypeBinding(unannotatedGenericType, unannotatedTypeArguments, unannotatedEnclosingType, this.environment);
@@ -343,19 +343,19 @@
 
 	/* Note: Parameters will not have type type annotations if lookup environment directly uses TypeSystem. However when AnnotatableTypeSystem is in use,
 	   they may and we need to materialize the unannotated versions and work on them.
-	*/ 
+	*/
 	public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType) {
 		if (!genericType.hasEnclosingInstanceContext() && enclosingType != null) {
 			enclosingType = (ReferenceBinding) enclosingType.original();
 		}
 		ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType);
 		ReferenceBinding unannotatedEnclosingType = enclosingType == null ? null : (ReferenceBinding) getUnannotatedType(enclosingType);
-	
+
 		TypeBinding[] derivedTypes = this.types[unannotatedGenericType.id];
 		int i, length = derivedTypes.length;
 		for (i = 0; i < length; i++) {
 			TypeBinding derivedType = derivedTypes[i];
-			if (derivedType == null) 
+			if (derivedType == null)
 				break;
 			if (!derivedType.isRawType() || derivedType.actualType() != unannotatedGenericType || derivedType.hasTypeAnnotations()) //$IDENTITY-COMPARISON$
 				continue;
@@ -367,7 +367,7 @@
 			System.arraycopy(derivedTypes, 0, derivedTypes = new TypeBinding[length * 2], 0, length);
 			this.types[unannotatedGenericType.id] = derivedTypes;
 		}
-		
+
 		TypeBinding rawTytpe = derivedTypes[i] = new RawTypeBinding(unannotatedGenericType, unannotatedEnclosingType, this.environment);
 		int typesLength = this.types.length;
 		if (this.typeid == typesLength)
@@ -375,18 +375,18 @@
 		this.types[this.typeid] = new TypeBinding[1];
 		return (RawTypeBinding) (this.types[rawTytpe.id = this.typeid++][0] = rawTytpe);
 	}
-	
+
 	public RawTypeBinding getRawType(ReferenceBinding genericType, ReferenceBinding enclosingType, AnnotationBinding[] annotations) {
 		return getRawType(genericType, enclosingType);
 	}
 
 	/* Parameters will not have type type annotations if lookup environment directly uses TypeSystem. When AnnotatableTypeSystem is in use,
 	   they may and we need to materialize the unannotated versions and work on them.
-	*/ 
+	*/
 	public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind) {
 		if (genericType == null) // pseudo wildcard denoting composite bounds for lub computation
 			genericType = ReferenceBinding.LUB_GENERIC;
-		
+
 		ReferenceBinding unannotatedGenericType = (ReferenceBinding) getUnannotatedType(genericType);
 		int otherBoundsLength = otherBounds == null ? 0: otherBounds.length;
 		TypeBinding [] unannotatedOtherBounds = otherBounds == null ? null : new TypeBinding[otherBoundsLength];
@@ -401,7 +401,7 @@
 		int i, length = derivedTypes.length;
 		for (i = 0; i < length; i++) {
 			TypeBinding derivedType = derivedTypes[i];
-			if (derivedType == null) 
+			if (derivedType == null)
 				break;
 			if (!derivedType.isWildcard() || derivedType.actualType() != unannotatedGenericType || derivedType.hasTypeAnnotations()) //$IDENTITY-COMPARISON$
 				continue;
@@ -410,29 +410,29 @@
 			if (Util.effectivelyEqual(derivedType.additionalBounds(), unannotatedOtherBounds))
 				return (WildcardBinding) derivedType;
 		}
-		
+
 		if (i == length) {
 			System.arraycopy(derivedTypes, 0, derivedTypes = new TypeBinding[length * 2], 0, length);
 			this.types[useDerivedTypesOfBound ? unannotatedBound.id :unannotatedGenericType.id] = derivedTypes;
 		}
 		TypeBinding wildcard = derivedTypes[i] = new WildcardBinding(unannotatedGenericType, rank, unannotatedBound, unannotatedOtherBounds, boundKind, this.environment);
-	
+
 		int typesLength = this.types.length;
 		if (this.typeid == typesLength)
 			System.arraycopy(this.types, 0, this.types = new TypeBinding[typesLength * 2][], 0, typesLength);
 		this.types[this.typeid] = new TypeBinding[1];
 		return (WildcardBinding) (this.types[wildcard.id = this.typeid++][0] = wildcard);
 	}
-	
+
 	// No need for an override in ATS, since interning is position specific and either the wildcard there is annotated or not.
 	public final CaptureBinding getCapturedWildcard(WildcardBinding wildcard, ReferenceBinding contextType, int start, int end, ASTNode cud, int id) {
-		
+
 		WildcardBinding unannotatedWildcard = (WildcardBinding) getUnannotatedType(wildcard);
 		TypeBinding[] derivedTypes = this.types[unannotatedWildcard.id];  // by construction, cachedInfo != null now.
 		int i, length = derivedTypes.length;
-		
+
 		/* Search backwards looking at recent captures, if we encounter a capture from a different compilation unit, this is a fresh uninterned capture.
-		   While compiling one file, we may reach into another file to build structure, we should not compile method bodies there, so we expect to see 
+		   While compiling one file, we may reach into another file to build structure, we should not compile method bodies there, so we expect to see
 		   all captures from the same file together without being interleaved by captures from other files.
 		*/
 		int nullSlot = length;
@@ -442,7 +442,7 @@
 				break;
 			}
 			TypeBinding derivedType = derivedTypes[i];
-			if (derivedType == null) { 
+			if (derivedType == null) {
 				nullSlot = i;
 				continue;
 			}
@@ -457,7 +457,7 @@
 				continue;
 			return prior;
 		}
-		
+
 		if (i == length) {
 			System.arraycopy(derivedTypes, 0, derivedTypes = new TypeBinding[length * 2], 0, length);
 			this.types[unannotatedWildcard.id] = derivedTypes;
@@ -465,7 +465,7 @@
 		return (CaptureBinding) (derivedTypes[i] = new CaptureBinding(wildcard, contextType, start, end, cud, id));
 		// the above constructor already registers the capture, don't repeat that here
 	}
-	
+
 	public WildcardBinding getWildcard(ReferenceBinding genericType, int rank, TypeBinding bound, TypeBinding[] otherBounds, int boundKind, AnnotationBinding[] annotations) {
 		return getWildcard(genericType, rank, bound, otherBounds, boundKind);
 	}
@@ -473,16 +473,16 @@
 	public TypeBinding getAnnotatedType(TypeBinding type, AnnotationBinding[][] annotations) {
 		return type; // Nothing to do for plain vanilla type system.
 	}
-	
+
 	protected final TypeBinding /* @NonNull */ [] getDerivedTypes(TypeBinding keyType) {
 		keyType = getUnannotatedType(keyType);
 		return this.types[keyType.id];
 	}
-	
+
 	private TypeBinding cacheDerivedType(TypeBinding keyType, TypeBinding derivedType) {
 		if (keyType == null || derivedType == null || keyType.id == TypeIds.NoId)
 			throw new IllegalStateException();
-		
+
 		TypeBinding[] derivedTypes = this.types[keyType.id];
 		// binary search for the *earliest* slot with a null reference. By design and construction, a null value will never be followed by a valid derived type.
 		int first, last,length = derivedTypes.length;
@@ -493,7 +493,7 @@
 				  if (i == first || i > 0 && derivedTypes[i - 1] != null)
 					  break;
 				  last = i - 1;
-			  } else { 
+			  } else {
 				  first = i + 1;
 			  }
 			  i = (first + last) / 2;
@@ -504,19 +504,19 @@
 		}
 		return derivedTypes[i] = derivedType;
 	}
-	
+
 	protected final TypeBinding cacheDerivedType(TypeBinding keyType, TypeBinding nakedType, TypeBinding derivedType) {
-		
+
 		/* Cache the derived type, tagging it as a derivative of both the key type and the naked type.
 		   E.g: int @NonNull [] would be tagged as a derived type of both int and int []. This is not
 		   needed for correctness, but for annotated object reuse. We provide two alternate ways to
-		   annotate a type: 
-		   
+		   annotate a type:
+
 		   Taking parameterized types as an example, a call to getParamaterizedType can be made with annotations
 		   to create @NonNull List<@NonNull String> in one stroke. Or a parameterized type can be created first
 		   and then annotated via getAnnotatedType. In the former case, the tables get looked up with List as
 		   the key, in the latter with List<String> as the key.
-		   
+
 		   Binary vs source, substitutions, annotation re-attribution from SE7 locations etc trigger these
 		   alternate code paths. Unless care is exercised, we will end up with duplicate objects (that share
 		   the same TypeBinding.id => correctness is not an issue, but memory wastage is)
@@ -527,16 +527,16 @@
 		}
 		return derivedType;
 	}
-	
+
 	/* Return a unique annotation binding for an annotation with either no or all default element-value pairs.
-	   We may return a resolved annotation when requested for unresolved one, but not vice versa. 
+	   We may return a resolved annotation when requested for unresolved one, but not vice versa.
 	*/
 	public final AnnotationBinding getAnnotationType(ReferenceBinding annotationType, boolean requiredResolved) {
 		AnnotationBinding annotation = (AnnotationBinding) this.annotationTypes.get(annotationType);
 		if (annotation == null) {
 			if (requiredResolved)
 				annotation = new AnnotationBinding(annotationType, Binding.NO_ELEMENT_VALUE_PAIRS);
-			else 
+			else
 				annotation = new UnresolvedAnnotationBinding(annotationType, Binding.NO_ELEMENT_VALUE_PAIRS, this.environment);
 			this.annotationTypes.put(annotationType, annotation);
 		}
@@ -566,7 +566,7 @@
 		this.types = new TypeBinding[TypeIds.T_LastWellKnownTypeId * 2][];
 		this.parameterizedTypes = new HashedParameterizedTypes();
 	}
-	
+
 	public void updateCaches(UnresolvedReferenceBinding unresolvedType, ReferenceBinding resolvedType) {
 		final int unresolvedTypeId = unresolvedType.id;
 		if (resolvedType.id != TypeIds.NoId) {
@@ -603,13 +603,13 @@
 		TypeBinding keyType = intersectingTypes[0];
 		if (keyType == null || intersectingTypesLength == 1)
 			return keyType;
-					
+
 		TypeBinding[] derivedTypes = getDerivedTypes(keyType);
 		int i, length = derivedTypes.length;
 		next:
 		for (i = 0; i < length; i++) {
 			TypeBinding derivedType = derivedTypes[i];
-			if (derivedType == null) 
+			if (derivedType == null)
 				break;
 			if (!derivedType.isIntersectionType18())
 				continue;
@@ -619,12 +619,12 @@
 			for (int j = 0; j < intersectingTypesLength; j++) {
 				if (intersectingTypes[j] != priorIntersectingTypes[j]) //$IDENTITY-COMPARISON$
 					continue next;
-			}	
+			}
 			return derivedType;
 		}
 		return cacheDerivedType(keyType, new IntersectionTypeBinding18(intersectingTypes, this.environment));
 	}
-	
+
 	/**
 	 * If a TVB was created with a dummy declaring element and needs to be fixed now,
 	 * make sure that this update affects all early clones, too.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
index bb3ca2a..c502bfe 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for
@@ -76,7 +76,7 @@
 	public ReferenceBinding[] superInterfaces; // MUST NOT be modified directly, use setter !
 	public char[] genericTypeSignature;
 	LookupEnvironment environment;
-	
+
 	public TypeVariableBinding(char[] sourceName, Binding declaringElement, int rank, LookupEnvironment environment) {
 		this.sourceName = sourceName;
 		this.declaringElement = declaringElement;
@@ -87,7 +87,7 @@
 		this.typeBits = TypeIds.BitUninitialized;
 		computeId(environment);
 	}
-	
+
 	// for subclass CaptureBinding
 	protected TypeVariableBinding(char[] sourceName, LookupEnvironment environment) {
 		this.sourceName = sourceName;
@@ -295,7 +295,8 @@
 	}
 
 	private BoundCheckStatus nullBoundCheck(Scope scope, TypeBinding argumentType, TypeBinding substitutedSuperType, Substitution substitution, ASTNode location, BoundCheckStatus previousStatus) {
-		if (NullAnnotationMatching.analyse(this, argumentType, substitutedSuperType, substitution, -1, null, CheckMode.BOUND_CHECK).isAnyMismatch()) {
+		NullAnnotationMatching status = NullAnnotationMatching.analyse(this, argumentType, substitutedSuperType, substitution, -1, null, CheckMode.BOUND_CHECK);
+		if (status.isAnyMismatch() && !status.isAnnotatedToUnannotated()) {
 			if (location != null)
 				scope.problemReporter().nullityMismatchTypeArgument(this, argumentType, location);
 			return BoundCheckStatus.NULL_PROBLEM;
@@ -409,7 +410,7 @@
 	    }
 	    return this.superclass.constantPoolName(); // java/lang/Object
 	}
-	
+
 	@Override
 	public TypeBinding clone(TypeBinding enclosingType) {
 		return new TypeVariableBinding(this);
@@ -591,7 +592,7 @@
 
 	// to prevent infinite recursion when inspecting recursive generics:
 	boolean inRecursiveFunction = false;
-	
+
 	@Override
 	public boolean enterRecursiveFunction() {
 		if (this.inRecursiveFunction)
@@ -606,7 +607,7 @@
 
 	// to prevent infinite recursion when inspecting recursive generics:
 	boolean inRecursiveProjectionFunction = false;
-	
+
 	public boolean enterRecursiveProjectionFunction() {
 		if (this.inRecursiveProjectionFunction)
 			return false;
@@ -622,7 +623,7 @@
 		// handle recursive calls:
 		if (this.inRecursiveFunction) // be optimistic, since this node is not an inference variable
 			return true;
-		
+
 		this.inRecursiveFunction = true;
 		try {
 			if (this.superclass != null && !this.superclass.isProperType(admitCapture18)) {
@@ -714,7 +715,7 @@
 	public int kind() {
 		return Binding.TYPE_PARAMETER;
 	}
-	
+
 	@Override
 	public boolean mentionsAny(TypeBinding[] parameters, int idx) {
 		if (this.inRecursiveFunction)
@@ -779,7 +780,7 @@
 			return this;
 
 		long nullTagBits = this.tagBits & TagBits.AnnotationNullMASK;
-		
+
 		TypeBinding oldSuperclass = this.superclass, oldFirstInterface = null;
 		if (this.superclass != null) {
 			ReferenceBinding resolveType = (ReferenceBinding) BinaryTypeBinding.resolveType(this.superclass, this.environment, true /* raw conversion */);
@@ -830,7 +831,7 @@
 		this.modifiers &= ~ExtraCompilerModifiers.AccUnresolved;
 		return this;
 	}
-	
+
 	@Override
 	public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) {
 		if (getClass() == TypeVariableBinding.class) {
@@ -854,12 +855,12 @@
 	public ReferenceBinding superclass() {
 		return this.superclass;
 	}
-	
+
 	@Override
 	public ReferenceBinding[] superInterfaces() {
 		return this.superInterfaces;
 	}
-	
+
 	/**
 	 * @see java.lang.Object#toString()
 	 */
@@ -954,7 +955,7 @@
 		AnnotationBinding[] newAnnotations = this.environment.filterNullTypeAnnotations(this.typeAnnotations);
 		if (newAnnotations.length > 0)
 			return this.environment.createAnnotatedType(unannotated, newAnnotations);
-		return unannotated; 
+		return unannotated;
 	}
 	/**
 	 * Upper bound doesn't perform erasure
@@ -991,7 +992,7 @@
 						this.firstBound = nullMismatchOnBound(parameter, this.firstBound, superNullTagBits, nullTagBits, scope);
 				}
 			}
-		}	
+		}
 		ReferenceBinding[] interfaces = this.superInterfaces;
 		int length;
 		if (interfaces != null && (length = interfaces.length) != 0) {
@@ -1143,9 +1144,9 @@
 
 	@Override
 	public boolean isFreeTypeVariable() {
-		return this.environment.usesNullTypeAnnotations() 
-				&& this.environment.globalOptions.pessimisticNullAnalysisForFreeTypeVariablesEnabled 
-				&& (this.tagBits & TagBits.AnnotationNullMASK) == 0;	
+		return this.environment.usesNullTypeAnnotations()
+				&& this.environment.globalOptions.pessimisticNullAnalysisForFreeTypeVariablesEnabled
+				&& (this.tagBits & TagBits.AnnotationNullMASK) == 0;
 	}
 
 	@Override
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 fd4246d..52256b9 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contributions for
@@ -123,7 +123,7 @@
 				environment.problemReporter.isClassPathCorrect(
 					this.compoundName,
 					environment.root.unitBeingCompleted,
-					environment.missingClassFileLocation);
+					environment.missingClassFileLocation, false);
 			}
 			// create a proxy for the missing BinaryType
 			targetType = environment.createMissingType(null, this.compoundName);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java
index 0b2f979..f244106 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VariableBinding.java
@@ -43,9 +43,9 @@
 	public Constant constant() {
 		return this.constant;
 	}
-	
+
 	/**
-	 * Call this variant during resolve / analyse, so we can handle the case 
+	 * Call this variant during resolve / analyse, so we can handle the case
 	 * when a tentative lambda resolve triggers resolving of outside code.
 	 */
 	public Constant constant(Scope scope) {
@@ -66,7 +66,7 @@
 	public final boolean isFinal() {
 		return (this.modifiers & ClassFileConstants.AccFinal) != 0;
 	}
-	
+
 	public final boolean isEffectivelyFinal() {
 		return (this.tagBits & TagBits.IsEffectivelyFinal) != 0;
 	}
@@ -74,14 +74,14 @@
 	/** Answer true if null annotations are enabled and this field is specified @NonNull */
 	public boolean isNonNull() {
 		return (this.tagBits & TagBits.AnnotationNonNull) != 0
-				|| (this.type != null 
+				|| (this.type != null
 					&& (this.type.tagBits & TagBits.AnnotationNonNull) != 0);
 	}
 
 	/** Answer true if null annotations are enabled and this field is specified @Nullable */
 	public boolean isNullable() {
 		return (this.tagBits & TagBits.AnnotationNullable) != 0
-				|| (this.type != null 
+				|| (this.type != null
 				&& (this.type.tagBits & TagBits.AnnotationNullable) != 0);
 	}
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VoidTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VoidTypeBinding.java
index be4354b..76d61ff 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VoidTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/VoidTypeBinding.java
@@ -21,17 +21,17 @@
 	VoidTypeBinding() {
 		super(TypeIds.T_void, TypeConstants.VOID, new char[] { 'V' });
 	}
-	
+
 	@Override
 	public TypeBinding clone(TypeBinding enclosingType) {
 		return this;  // enforce solitude.
 	}
-	
+
 	@Override
 	public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) {
 		return; // reject misguided attempt.
 	}
-	
+
 	@Override
 	public TypeBinding unannotated() {
 		return this;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
index 3e5dd9c..872c7ac 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -75,12 +75,12 @@
 	TypeBinding bound() {
 		return this.bound;
 	}
-	
+
 	@Override
 	int boundKind() {
 		return this.boundKind;
 	}
-	
+
 	public TypeBinding allBounds() {
 		if (this.otherBounds == null || this.otherBounds.length == 0)
 			return this.bound;
@@ -93,8 +93,8 @@
 		}
 		return this.environment.createIntersectionType18(allBounds);
 	}
-	
-	
+
+
 	@Override
 	public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNullAnnotations) {
 		this.tagBits |= TagBits.HasTypeAnnotations;
@@ -211,17 +211,17 @@
 		return nullTagBits;
 	}
 
-	
+
 	@Override
 	public ReferenceBinding actualType() {
 		return this.genericType;
 	}
-	
+
 	@Override
 	TypeBinding[] additionalBounds() {
 		return this.otherBounds;
 	}
-	
+
 	@Override
 	public int kind() {
 		return this.otherBounds == null ? Binding.WILDCARD_TYPE : Binding.INTERSECTION_TYPE;
@@ -549,7 +549,7 @@
 	public TypeBinding clone(TypeBinding immaterial) {
 		return new WildcardBinding(this.genericType, this.rank, this.bound, this.otherBounds, this.boundKind, this.environment);
 	}
-	
+
 	@Override
 	public String annotatedDebugName() {
 		StringBuffer buffer = new StringBuffer(16);
@@ -642,7 +642,7 @@
 			this.fPackage = someGenericType.getPackage();
 		}
 		if (someBound != null) {
-			this.tagBits |= someBound.tagBits & (TagBits.HasTypeVariable | TagBits.HasMissingType | TagBits.ContainsNestedTypeReferences | 
+			this.tagBits |= someBound.tagBits & (TagBits.HasTypeVariable | TagBits.HasMissingType | TagBits.ContainsNestedTypeReferences |
 					TagBits.HasNullTypeAnnotation | TagBits.HasCapturedWildcard);
 		}
 		if (someOtherBounds != null) {
@@ -774,7 +774,7 @@
 	int rank() {
 		return this.rank;
 	}
-	
+
     @Override
 	public char[] readableName() {
         switch (this.boundKind) {
@@ -1022,7 +1022,7 @@
 		if (!hasNullTypeAnnotations())
 			return this;
 		AnnotationBinding[] newAnnotations = this.environment.filterNullTypeAnnotations(getTypeAnnotations());
-		return this.environment.createWildcard(this.genericType, this.rank, this.bound, this.otherBounds, this.boundKind, newAnnotations);			
+		return this.environment.createWildcard(this.genericType, this.rank, this.bound, this.otherBounds, this.boundKind, newAnnotations);
 	}
 	@Override
 	public TypeBinding uncapture(Scope scope) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java
index 4f7a7b9..436943c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java
@@ -18,6 +18,7 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.InvalidInputException;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.util.Util;
 
@@ -56,7 +57,7 @@
 	public boolean reportProblems;
 	protected long complianceLevel;
 	protected long sourceLevel;
-	
+
 	// Support for {@inheritDoc}
 	protected long [] inheritedPositions;
 	protected int inheritedPositionsPtr;
@@ -102,6 +103,14 @@
 	protected int astLengthPtr;
 	protected int[] astLengthStack;
 
+	// Uses stack
+	protected int usesReferencesPtr = -1;
+	protected TypeReference[] usesReferencesStack;
+
+	// Provides stack
+	protected int providesReferencesPtr = -1;
+	protected TypeReference[] providesReferencesStack;
+
 
 	protected AbstractCommentParser(Parser sourceParser) {
 		this.sourceParser = sourceParser;
@@ -329,7 +338,7 @@
 								}
 								refreshInlineTagPosition(previousPosition);
 							}
-							if (!isFormatterParser && !considerTagAsPlainText) 
+							if (!isFormatterParser && !considerTagAsPlainText)
 								this.textStart = this.index;
 							setInlineTagStarted(false);
 						} else {
@@ -501,7 +510,7 @@
 		return Util.getLineNumber(position, this.lineEnds, 0, this.lineEnds.length-1);
 	}
 
-	private int getTokenEndPosition() {
+	protected int getTokenEndPosition() {
 		if (this.scanner.getCurrentTokenEndPosition() > this.lineEnd) {
 			return this.lineEnd;
 		} else {
@@ -1084,7 +1093,7 @@
 
 				case TerminalTokens.TokenNameRestrictedIdentifierYield:
 					throw new InvalidInputException(); // unexpected.
-					
+
 				case TerminalTokens.TokenNameDOT :
 					if ((iToken & 1) == 0) { // dots must be even tokens
 						throw new InvalidInputException();
@@ -1590,7 +1599,7 @@
 		}
 		this.inheritedPositions[this.inheritedPositionsPtr++] = position;
 	}
-	
+
 	/*
 	 * Refresh start position and length of an inline tag.
 	 */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ConflictedParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ConflictedParser.java
index 96b25b8..a4d9736 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ConflictedParser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ConflictedParser.java
@@ -14,7 +14,7 @@
 package org.eclipse.jdt.internal.compiler.parser;
 
 public interface ConflictedParser {
-	
+
 	/* Return true if at the configuration the parser finds itself in, token would need to be disambiguated.
 	   At Java SE 8 time, we have three tokens that need to clarified: the use of '( and that of '<' and finally
 	   whether an @ begins a SE8 style type annotation or a SE5 declaration annotation. Where they can co-exist,
@@ -27,5 +27,5 @@
 	 * appear as terminals in ModuleDeclaration, and are identifiers everywhere else)
 	 */
 	boolean isParsingModuleDeclaration();
-	boolean isParsingJava13();
+	boolean isParsingJava14();
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java
index 8663cab..388eb09 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocParser.java
@@ -17,7 +17,23 @@
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.InvalidInputException;
-import org.eclipse.jdt.internal.compiler.ast.*;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
+import org.eclipse.jdt.internal.compiler.ast.Expression;
+import org.eclipse.jdt.internal.compiler.ast.IJavadocTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.Javadoc;
+import org.eclipse.jdt.internal.compiler.ast.JavadocAllocationExpression;
+import org.eclipse.jdt.internal.compiler.ast.JavadocArgumentExpression;
+import org.eclipse.jdt.internal.compiler.ast.JavadocArrayQualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.JavadocArraySingleTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.JavadocFieldReference;
+import org.eclipse.jdt.internal.compiler.ast.JavadocImplicitTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.JavadocMessageSend;
+import org.eclipse.jdt.internal.compiler.ast.JavadocQualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.JavadocReturnStatement;
+import org.eclipse.jdt.internal.compiler.ast.JavadocSingleNameReference;
+import org.eclipse.jdt.internal.compiler.ast.JavadocSingleTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypeReference;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.util.Util;
 
@@ -27,6 +43,7 @@
 public class JavadocParser extends AbstractCommentParser {
 	private static final JavadocSingleNameReference[] NO_SINGLE_NAME_REFERENCE = new JavadocSingleNameReference[0];
 	private static final JavadocSingleTypeReference[] NO_SINGLE_TYPE_REFERENCE = new JavadocSingleTypeReference[0];
+	private static final JavadocQualifiedTypeReference[] NO_QUALIFIED_TYPE_REFERENCE = new JavadocQualifiedTypeReference[0];
 	private static final TypeReference[] NO_TYPE_REFERENCE = new TypeReference[0];
 	private static final Expression[] NO_EXPRESSION = new Expression[0];
 
@@ -45,7 +62,7 @@
 	// returns whether this JavadocParser should report errors or not (overrides reportProblems)
 	// see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=192449"
 	public boolean shouldReportProblems = true;
-	
+
 	// flag to let the parser know that the current tag is waiting for a description
 	// see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=222900"
 	private int tagWaitingForDescription;
@@ -467,7 +484,7 @@
 				}
 				break;
 		}
-		
+
 		// Read tag name
 		char[] tagName = new char[32];
 		int length = 0;
@@ -615,7 +632,7 @@
 					this.tagValue = TAG_LINKPLAIN_VALUE;
 					if (this.inlineTagStarted) {
 						valid = parseReference();
-					} 
+					}
 				} else if (length == TAG_LITERAL_LENGTH && this.inlineTagStarted && CharOperation.equals(TAG_LITERAL, tagName, 0, length)) {
 					this.tagValue = TAG_LITERAL_VALUE;
 					this.tagWaitingForDescription = this.tagValue;
@@ -629,7 +646,9 @@
 					}
 				} else if (length == TAG_PROVIDES_LENGTH && CharOperation.equals(TAG_PROVIDES, tagName, 0, length)) {
 					this.tagValue = TAG_PROVIDES_VALUE;
-					this.tagWaitingForDescription = this.tagValue;
+					if (!this.inlineTagStarted) {
+						valid = parseProvidesReference();
+					}
 				}
 				break;
 			case 'r':
@@ -677,7 +696,9 @@
 			case 'u':
 				if (length == TAG_USES_LENGTH && CharOperation.equals(TAG_USES, tagName, 0, length)) {
 					this.tagValue = TAG_USES_VALUE;
-					this.tagWaitingForDescription = this.tagValue;
+					if (!this.inlineTagStarted) {
+						valid = parseUsesReference();
+					}
 				}
 				break;
 			case 'v':
@@ -934,7 +955,7 @@
 		// Set positions
 		if (this.inheritedPositions != null && this.inheritedPositionsPtr != this.inheritedPositions.length) {
 			// Compact array by shrinking.
-			System.arraycopy(this.inheritedPositions, 0, 
+			System.arraycopy(this.inheritedPositions, 0,
 					this.inheritedPositions = new long[this.inheritedPositionsPtr], 0, this.inheritedPositionsPtr);
 		}
 		this.docComment.inheritedPositions = this.inheritedPositions;
@@ -951,6 +972,18 @@
 			System.arraycopy(this.invalidParamReferencesStack, 0, this.docComment.invalidParameters, 0, this.invalidParamReferencesPtr+1);
 		}
 
+		this.docComment.usesReferences = this.usesReferencesPtr >= 0 ? new IJavadocTypeReference[this.usesReferencesPtr+1] : NO_QUALIFIED_TYPE_REFERENCE;
+		for (int i = 0; i <= this.usesReferencesPtr; ++i) {
+			TypeReference ref = this.usesReferencesStack[i];
+			this.docComment.usesReferences[i] = (IJavadocTypeReference)ref;
+		}
+
+		this.docComment.providesReferences = this.providesReferencesPtr >= 0 ? new IJavadocTypeReference[this.providesReferencesPtr+1] : NO_QUALIFIED_TYPE_REFERENCE;
+		for (int i = 0; i <= this.providesReferencesPtr; ++i) {
+			TypeReference ref = this.providesReferencesStack[i];
+			this.docComment.providesReferences[i] = (IJavadocTypeReference)ref;
+		}
+
 		// If no nodes stored return
 		if (this.astLengthPtr == -1) {
 			return;
@@ -1013,4 +1046,76 @@
 			System.arraycopy(this.docComment.paramTypeParameters, paramTypeParamPtr, this.docComment.paramTypeParameters = new JavadocSingleTypeReference[size - paramTypeParamPtr], 0, size - paramTypeParamPtr);
 		}
 	}
+
+	/*
+	 * Parse @uses tag declaration
+	 */
+	protected boolean parseUsesReference() {
+		int start = this.scanner.currentPosition;
+		try {
+			Object typeRef = parseQualifiedName(true);
+			if (this.abort) return false; // May be aborted by specialized parser
+			if (typeRef == null) {
+				if (this.reportProblems)
+					this.sourceParser.problemReporter().javadocMissingUsesClassName(this.tagSourceStart, this.tagSourceEnd, this.sourceParser.modifiers);
+			} else {
+				return pushUsesReference(typeRef);
+			}
+		} catch (InvalidInputException ex) {
+			if (this.reportProblems) this.sourceParser.problemReporter().javadocInvalidUsesClass(start, getTokenEndPosition());
+		}
+		return false;
+	}
+
+	protected boolean pushUsesReference(Object typeRef) {
+		if (this.usesReferencesPtr == -1l) {
+			this.usesReferencesStack = new TypeReference[10];
+		}
+		int stackLength = this.usesReferencesStack.length;
+		if (++this.usesReferencesPtr >= stackLength) {
+			System.arraycopy(
+				this.usesReferencesStack, 0,
+				this.usesReferencesStack = new TypeReference[stackLength + AST_STACK_INCREMENT], 0,
+				stackLength);
+		}
+		this.usesReferencesStack[this.usesReferencesPtr] = (TypeReference)typeRef;
+		return true;
+	}
+
+	/*
+	 * Parse @uses tag declaration
+	 */
+	protected boolean parseProvidesReference() {
+		int start = this.scanner.currentPosition;
+		try {
+			Object typeRef = parseQualifiedName(true);
+			if (this.abort) return false; // May be aborted by specialized parser
+			if (typeRef == null) {
+				if (this.reportProblems)
+					this.sourceParser.problemReporter().javadocMissingProvidesClassName(this.tagSourceStart, this.tagSourceEnd, this.sourceParser.modifiers);
+			} else {
+				return pushProvidesReference(typeRef);
+			}
+		} catch (InvalidInputException ex) {
+			if (this.reportProblems) this.sourceParser.problemReporter().javadocInvalidProvidesClass(start, getTokenEndPosition());
+		}
+		return false;
+	}
+
+	protected boolean pushProvidesReference(Object typeRef) {
+		if (this.providesReferencesPtr == -1l) {
+			this.providesReferencesStack = new TypeReference[10];
+		}
+		int stackLength = this.providesReferencesStack.length;
+		if (++this.providesReferencesPtr >= stackLength) {
+			System.arraycopy(
+				this.providesReferencesStack, 0,
+				this.providesReferencesStack = new TypeReference[stackLength + AST_STACK_INCREMENT], 0,
+				stackLength);
+		}
+		this.providesReferencesStack[this.providesReferencesPtr] = (TypeReference)typeRef;
+		return true;
+
+	}
+
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java
index 60d4058..19360cd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/JavadocTagConstants.java
@@ -195,7 +195,9 @@
 		{},
 		//since 12
 		{},
-		//since 12
+		//since 13
+		{},
+		//since 14
 		{}
 	};
 	public static final char[][][] INLINE_TAGS = {
@@ -225,7 +227,9 @@
 		{},
 		//since 12
 		{TAG_SYSTEM_PROPERTY},
-		//since 12
+		//since 13
+		{},
+		//since 14
 		{}
 	};
 	public final static int INLINE_TAGS_LENGTH = INLINE_TAGS.length;
@@ -330,8 +334,8 @@
 		TAG_INDEX,
 		TAG_HIDDEN,
 		TAG_SUMMARY,
-		TAG_API_NOTE, 
-		TAG_IMPL_SPEC, 
+		TAG_API_NOTE,
+		TAG_IMPL_SPEC,
 		TAG_IMPL_NOTE,
 	};
 	public static final char[][] METHOD_TAGS = {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
index 8fc52cc..c661e8f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Parser.java
@@ -140,7 +140,8 @@
 			this.options.sourceLevel /*sourceLevel*/, 
 			this.options.taskTags/*taskTags*/,
 			this.options.taskPriorities/*taskPriorities*/,
-			this.options.isTaskCaseSensitive/*taskCaseSensitive*/);
+			this.options.isTaskCaseSensitive/*taskCaseSensitive*/,
+			this.options.enablePreviewFeatures /*isPreviewEnabled*/);
 	}
 
 //*************New display debugging method
@@ -1287,2367 +1288,2455 @@
 			    consumeEnterCompilationUnit();  
 				break;
 	 
-	    case 186 : if (DEBUG) { System.out.println("CatchHeader ::= catch LPAREN CatchFormalParameter RPAREN"); }  //$NON-NLS-1$
+	    case 187 : if (DEBUG) { System.out.println("CatchHeader ::= catch LPAREN CatchFormalParameter RPAREN"); }  //$NON-NLS-1$
 			    consumeCatchHeader();  
 				break;
 	 
-	    case 188 : if (DEBUG) { System.out.println("ImportDeclarations ::= ImportDeclarations..."); }  //$NON-NLS-1$
+	    case 189 : if (DEBUG) { System.out.println("ImportDeclarations ::= ImportDeclarations..."); }  //$NON-NLS-1$
 			    consumeImportDeclarations();  
 				break;
 	 
-	    case 190 : if (DEBUG) { System.out.println("TypeDeclarations ::= TypeDeclarations TypeDeclaration"); }  //$NON-NLS-1$
+	    case 191 : if (DEBUG) { System.out.println("TypeDeclarations ::= TypeDeclarations TypeDeclaration"); }  //$NON-NLS-1$
 			    consumeTypeDeclarations();  
 				break;
 	 
-	    case 191 : if (DEBUG) { System.out.println("PackageDeclaration ::= PackageDeclarationName SEMICOLON"); }  //$NON-NLS-1$
+	    case 192 : if (DEBUG) { System.out.println("PackageDeclaration ::= PackageDeclarationName SEMICOLON"); }  //$NON-NLS-1$
 			    consumePackageDeclaration();  
 				break;
 	 
-	    case 192 : if (DEBUG) { System.out.println("PackageDeclarationName ::= Modifiers package..."); }  //$NON-NLS-1$
+	    case 193 : if (DEBUG) { System.out.println("PackageDeclarationName ::= Modifiers package..."); }  //$NON-NLS-1$
 			    consumePackageDeclarationNameWithModifiers();  
 				break;
 	 
-	    case 193 : if (DEBUG) { System.out.println("PackageDeclarationName ::= PackageComment package Name"); }  //$NON-NLS-1$
+	    case 194 : if (DEBUG) { System.out.println("PackageDeclarationName ::= PackageComment package Name"); }  //$NON-NLS-1$
 			    consumePackageDeclarationName();  
 				break;
 	 
-	    case 194 : if (DEBUG) { System.out.println("PackageComment ::="); }  //$NON-NLS-1$
+	    case 195 : if (DEBUG) { System.out.println("PackageComment ::="); }  //$NON-NLS-1$
 			    consumePackageComment();  
 				break;
 	 
-	    case 199 : if (DEBUG) { System.out.println("SingleTypeImportDeclaration ::=..."); }  //$NON-NLS-1$
+	    case 200 : if (DEBUG) { System.out.println("SingleTypeImportDeclaration ::=..."); }  //$NON-NLS-1$
 			    consumeImportDeclaration();  
 				break;
 	 
-	    case 200 : if (DEBUG) { System.out.println("SingleTypeImportDeclarationName ::= import Name..."); }  //$NON-NLS-1$
+	    case 201 : if (DEBUG) { System.out.println("SingleTypeImportDeclarationName ::= import Name..."); }  //$NON-NLS-1$
 			    consumeSingleTypeImportDeclarationName();  
 				break;
 	 
-	    case 201 : if (DEBUG) { System.out.println("TypeImportOnDemandDeclaration ::=..."); }  //$NON-NLS-1$
+	    case 202 : if (DEBUG) { System.out.println("TypeImportOnDemandDeclaration ::=..."); }  //$NON-NLS-1$
 			    consumeImportDeclaration();  
 				break;
 	 
-	    case 202 : if (DEBUG) { System.out.println("TypeImportOnDemandDeclarationName ::= import Name DOT..."); }  //$NON-NLS-1$
+	    case 203 : if (DEBUG) { System.out.println("TypeImportOnDemandDeclarationName ::= import Name DOT..."); }  //$NON-NLS-1$
 			    consumeTypeImportOnDemandDeclarationName();  
 				break;
 	 
-	     case 205 : if (DEBUG) { System.out.println("TypeDeclaration ::= SEMICOLON"); }  //$NON-NLS-1$
+	     case 206 : if (DEBUG) { System.out.println("TypeDeclaration ::= SEMICOLON"); }  //$NON-NLS-1$
 			    consumeEmptyTypeDeclaration();  
 				break;
 	 
-	    case 209 : if (DEBUG) { System.out.println("Modifiers ::= Modifiers Modifier"); }  //$NON-NLS-1$
+	    case 211 : if (DEBUG) { System.out.println("Modifiers ::= Modifiers Modifier"); }  //$NON-NLS-1$
 			    consumeModifiers2();  
 				break;
 	 
-	    case 222 : if (DEBUG) { System.out.println("Modifier ::= Annotation"); }  //$NON-NLS-1$
+	    case 224 : if (DEBUG) { System.out.println("Modifier ::= Annotation"); }  //$NON-NLS-1$
 			    consumeAnnotationAsModifier();  
 				break;
 	 
-	    case 235 : if (DEBUG) { System.out.println("AspectDeclaration ::= AspectHeader AspectBody"); }  //$NON-NLS-1$
+	    case 237 : if (DEBUG) { System.out.println("AspectDeclaration ::= AspectHeader AspectBody"); }  //$NON-NLS-1$
 			    consumeAspectDeclaration();  
 				break;
 	 
-	    case 236 : if (DEBUG) { System.out.println("AspectHeader ::= AspectHeaderName ClassHeaderExtendsopt"); }  //$NON-NLS-1$
+	    case 238 : if (DEBUG) { System.out.println("AspectHeader ::= AspectHeaderName ClassHeaderExtendsopt"); }  //$NON-NLS-1$
 			    consumeAspectHeader();  
 				break;
 	 
-	    case 239 : if (DEBUG) { System.out.println("AspectHeaderName ::= AspectHeaderName1 TypeParameters"); }  //$NON-NLS-1$
+	    case 241 : if (DEBUG) { System.out.println("AspectHeaderName ::= AspectHeaderName1 TypeParameters"); }  //$NON-NLS-1$
 			    consumeAspectHeaderNameWithTypeParameters(false);  
 				break;
 	 
-	    case 240 : if (DEBUG) { System.out.println("AspectHeaderName ::= AspectHeaderName2 TypeParameters"); }  //$NON-NLS-1$
+	    case 242 : if (DEBUG) { System.out.println("AspectHeaderName ::= AspectHeaderName2 TypeParameters"); }  //$NON-NLS-1$
 			    consumeAspectHeaderNameWithTypeParameters(true);  
 				break;
 	 
-	    case 241 : if (DEBUG) { System.out.println("AspectHeaderName1 ::= Modifiersopt aspect Identifier"); }  //$NON-NLS-1$
+	    case 243 : if (DEBUG) { System.out.println("AspectHeaderName1 ::= Modifiersopt aspect Identifier"); }  //$NON-NLS-1$
 			    consumeAspectHeaderName(false);  
 				break;
 	 
-	    case 242 : if (DEBUG) { System.out.println("AspectHeaderName2 ::= Modifiersopt privileged..."); }  //$NON-NLS-1$
+	    case 244 : if (DEBUG) { System.out.println("AspectHeaderName2 ::= Modifiersopt privileged..."); }  //$NON-NLS-1$
 			    consumeAspectHeaderName(true);  
 				break;
 	 
-	    case 244 : if (DEBUG) { System.out.println("AspectHeaderRest ::= AspectHeaderRestStart PseudoTokens"); }  //$NON-NLS-1$
+	    case 246 : if (DEBUG) { System.out.println("AspectHeaderRest ::= AspectHeaderRestStart PseudoTokens"); }  //$NON-NLS-1$
 			    consumeAspectHeaderRest();  
 				break;
 	 
-	    case 245 : if (DEBUG) { System.out.println("AspectHeaderRestStart ::= Identifier"); }  //$NON-NLS-1$
+	    case 247 : if (DEBUG) { System.out.println("AspectHeaderRestStart ::= Identifier"); }  //$NON-NLS-1$
 			    consumePseudoTokenIdentifier();  
 				break;
 	 
-	    case 248 : if (DEBUG) { System.out.println("AspectBodyDeclarations ::= AspectBodyDeclarations..."); }  //$NON-NLS-1$
+	    case 250 : if (DEBUG) { System.out.println("AspectBodyDeclarations ::= AspectBodyDeclarations..."); }  //$NON-NLS-1$
 			    consumeClassBodyDeclarations();  
 				break;
 	 
-	    case 249 : if (DEBUG) { System.out.println("AspectBodyDeclarationsopt ::="); }  //$NON-NLS-1$
+	    case 251 : if (DEBUG) { System.out.println("AspectBodyDeclarationsopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyClassBodyDeclarationsopt();  
 				break;
 	 
-	    case 250 : if (DEBUG) { System.out.println("AspectBodyDeclarationsopt ::= NestedType..."); }  //$NON-NLS-1$
+	    case 252 : if (DEBUG) { System.out.println("AspectBodyDeclarationsopt ::= NestedType..."); }  //$NON-NLS-1$
 			    consumeClassBodyDeclarationsopt();  
 				break;
 	 
-	    case 251 : if (DEBUG) { System.out.println("AspectBodyDeclaration ::=..."); }  //$NON-NLS-1$
+	    case 253 : if (DEBUG) { System.out.println("AspectBodyDeclaration ::=..."); }  //$NON-NLS-1$
 			    consumeClassBodyDeclarationInAspect();  
 				break;
 	 
-	    case 255 : if (DEBUG) { System.out.println("ClassBodyDeclarationNoAroundMethod ::= Diet NestedMethod"); }  //$NON-NLS-1$
+	    case 257 : if (DEBUG) { System.out.println("ClassBodyDeclarationNoAroundMethod ::= Diet NestedMethod"); }  //$NON-NLS-1$
 			    consumeClassBodyDeclaration();  
 				break;
 	 
-	    case 265 : if (DEBUG) { System.out.println("ClassMemberDeclarationNoAroundMethod ::= SEMICOLON"); }  //$NON-NLS-1$
+	    case 267 : if (DEBUG) { System.out.println("ClassMemberDeclarationNoAroundMethod ::= SEMICOLON"); }  //$NON-NLS-1$
 			    consumeEmptyTypeDeclaration();  
 				break;
 
-	    case 267 : if (DEBUG) { System.out.println("MethodDeclarationNoAround ::= MethodHeaderNoAround..."); }  //$NON-NLS-1$
+	    case 269 : if (DEBUG) { System.out.println("MethodDeclarationNoAround ::= MethodHeaderNoAround..."); }  //$NON-NLS-1$
 			    // set to true to consume a method with a body
 	 consumeMethodDeclaration(true, false);   
 				break;
 	 
-	    case 268 : if (DEBUG) { System.out.println("AbstractMethodDeclarationNoAround ::=..."); }  //$NON-NLS-1$
+	    case 270 : if (DEBUG) { System.out.println("AbstractMethodDeclarationNoAround ::=..."); }  //$NON-NLS-1$
 			    // set to false to consume a method without body
 	 consumeMethodDeclaration(false, false);  
 				break;
 	 
-	    case 269 : if (DEBUG) { System.out.println("MethodHeaderNoAround ::= MethodHeaderNameNoAround..."); }  //$NON-NLS-1$
+	    case 271 : if (DEBUG) { System.out.println("MethodHeaderNoAround ::= MethodHeaderNameNoAround..."); }  //$NON-NLS-1$
 			    consumeMethodHeader();  
 				break;
 	 
-	    case 270 : if (DEBUG) { System.out.println("MethodHeaderNameNoAround ::= Modifiersopt TypeParameters"); }  //$NON-NLS-1$
+	    case 272 : if (DEBUG) { System.out.println("MethodHeaderNameNoAround ::= Modifiersopt TypeParameters"); }  //$NON-NLS-1$
 			    consumeMethodHeaderNameWithTypeParameters(false);  
 				break;
 	 
-	    case 271 : if (DEBUG) { System.out.println("MethodHeaderNameNoAround ::= Modifiersopt Type..."); }  //$NON-NLS-1$
+	    case 273 : if (DEBUG) { System.out.println("MethodHeaderNameNoAround ::= Modifiersopt Type..."); }  //$NON-NLS-1$
 			    consumeMethodHeaderName(false);  
 				break;
 	 
-	    case 272 : if (DEBUG) { System.out.println("PointcutDeclaration ::= PointcutHeader..."); }  //$NON-NLS-1$
+	    case 274 : if (DEBUG) { System.out.println("PointcutDeclaration ::= PointcutHeader..."); }  //$NON-NLS-1$
 			    consumeEmptyPointcutDeclaration();  
 				break;
 	 
-	    case 273 : if (DEBUG) { System.out.println("PointcutDeclaration ::= PointcutHeader..."); }  //$NON-NLS-1$
+	    case 275 : if (DEBUG) { System.out.println("PointcutDeclaration ::= PointcutHeader..."); }  //$NON-NLS-1$
 			    consumePointcutDeclaration();  
 				break;
 	 
-	    case 274 : if (DEBUG) { System.out.println("PointcutHeader ::= Modifiersopt pointcut JavaIdentifier"); }  //$NON-NLS-1$
+	    case 276 : if (DEBUG) { System.out.println("PointcutHeader ::= Modifiersopt pointcut JavaIdentifier"); }  //$NON-NLS-1$
 			    consumePointcutHeader();  
 				break;
 	 
-	    case 277 : if (DEBUG) { System.out.println("AroundDeclaration ::= AroundHeader MethodBody"); }  //$NON-NLS-1$
+	    case 279 : if (DEBUG) { System.out.println("AroundDeclaration ::= AroundHeader MethodBody"); }  //$NON-NLS-1$
 			    consumeAroundDeclaration();  
 				break;
 	 
-	    case 278 : if (DEBUG) { System.out.println("AroundHeader ::= AroundHeaderName FormalParameterListopt"); }  //$NON-NLS-1$
+	    case 280 : if (DEBUG) { System.out.println("AroundHeader ::= AroundHeaderName FormalParameterListopt"); }  //$NON-NLS-1$
 			    consumeAroundHeader();  
 				break;
 	 
-	    case 279 : if (DEBUG) { System.out.println("AroundHeaderName ::= Modifiersopt Type around LPAREN"); }  //$NON-NLS-1$
+	    case 281 : if (DEBUG) { System.out.println("AroundHeaderName ::= Modifiersopt Type around LPAREN"); }  //$NON-NLS-1$
 			    consumeAroundHeaderName();  
 				break;
 	 
-	    case 280 : if (DEBUG) { System.out.println("AroundHeaderName ::= Modifiersopt around LPAREN"); }  //$NON-NLS-1$
+	    case 282 : if (DEBUG) { System.out.println("AroundHeaderName ::= Modifiersopt around LPAREN"); }  //$NON-NLS-1$
 			    consumeAroundHeaderNameMissingReturnType();  
 				break;
 	 
-	    case 281 : if (DEBUG) { System.out.println("BasicAdviceDeclaration ::= BasicAdviceHeader MethodBody"); }  //$NON-NLS-1$
+	    case 283 : if (DEBUG) { System.out.println("BasicAdviceDeclaration ::= BasicAdviceHeader MethodBody"); }  //$NON-NLS-1$
 			    consumeBasicAdviceDeclaration();  
 				break;
 	 
-	    case 284 : if (DEBUG) { System.out.println("BeforeAdviceHeader ::= BeforeAdviceHeaderName..."); }  //$NON-NLS-1$
+	    case 286 : if (DEBUG) { System.out.println("BeforeAdviceHeader ::= BeforeAdviceHeaderName..."); }  //$NON-NLS-1$
 			    consumeBasicAdviceHeader();  
 				break;
 	 
-	    case 285 : if (DEBUG) { System.out.println("AfterAdviceHeader ::= AfterAdviceHeaderName..."); }  //$NON-NLS-1$
+	    case 287 : if (DEBUG) { System.out.println("AfterAdviceHeader ::= AfterAdviceHeaderName..."); }  //$NON-NLS-1$
 			    consumeBasicAdviceHeader();  
 				break;
 	 
-	    case 286 : if (DEBUG) { System.out.println("BeforeAdviceHeaderName ::= Modifiersopt before LPAREN"); }  //$NON-NLS-1$
+	    case 288 : if (DEBUG) { System.out.println("BeforeAdviceHeaderName ::= Modifiersopt before LPAREN"); }  //$NON-NLS-1$
 			    consumeBasicAdviceHeaderName(false);  
 				break;
 	 
-	    case 287 : if (DEBUG) { System.out.println("AfterAdviceHeaderName ::= Modifiersopt after LPAREN"); }  //$NON-NLS-1$
+	    case 289 : if (DEBUG) { System.out.println("AfterAdviceHeaderName ::= Modifiersopt after LPAREN"); }  //$NON-NLS-1$
 			    consumeBasicAdviceHeaderName(true);  
 				break;
 	 
-	    case 288 : if (DEBUG) { System.out.println("ExtraParamopt ::= Identifier LPAREN FormalParameter..."); }  //$NON-NLS-1$
+	    case 290 : if (DEBUG) { System.out.println("ExtraParamopt ::= Identifier LPAREN FormalParameter..."); }  //$NON-NLS-1$
 			    consumeExtraParameterWithFormal();  
 				break;
 	 
-	    case 289 : if (DEBUG) { System.out.println("ExtraParamopt ::= Identifier LPAREN RPAREN"); }  //$NON-NLS-1$
+	    case 291 : if (DEBUG) { System.out.println("ExtraParamopt ::= Identifier LPAREN RPAREN"); }  //$NON-NLS-1$
 			    consumeExtraParameterNoFormal();  
 				break;
 	 
-	    case 290 : if (DEBUG) { System.out.println("ExtraParamopt ::= Identifier"); }  //$NON-NLS-1$
+	    case 292 : if (DEBUG) { System.out.println("ExtraParamopt ::= Identifier"); }  //$NON-NLS-1$
 			    consumeExtraParameterNoFormal();  
 				break;
 	 
-	    case 292 : if (DEBUG) { System.out.println("OnType ::= JavaIdentifier"); }  //$NON-NLS-1$
+	    case 294 : if (DEBUG) { System.out.println("OnType ::= JavaIdentifier"); }  //$NON-NLS-1$
 			    consumeZeroTypeAnnotations();  
 				break;
 	 
-	    case 293 : if (DEBUG) { System.out.println("OnType ::= OnType DOT JavaIdentifier"); }  //$NON-NLS-1$
+	    case 295 : if (DEBUG) { System.out.println("OnType ::= OnType DOT JavaIdentifier"); }  //$NON-NLS-1$
 			    consumeZeroTypeAnnotations(); consumeQualifiedName();  
 				break;
 	 
-	    case 298 : if (DEBUG) { System.out.println("InterTypeMethodDeclaration ::= InterTypeMethodHeader..."); }  //$NON-NLS-1$
+	    case 300 : if (DEBUG) { System.out.println("InterTypeMethodDeclaration ::= InterTypeMethodHeader..."); }  //$NON-NLS-1$
 			    // set to true to consume a method with a body
 	  consumeInterTypeMethodDeclaration(true);   
 				break;
 	 
-	    case 299 : if (DEBUG) { System.out.println("InterTypeMethodHeader ::= InterTypeMethodHeaderName..."); }  //$NON-NLS-1$
+	    case 301 : if (DEBUG) { System.out.println("InterTypeMethodHeader ::= InterTypeMethodHeaderName..."); }  //$NON-NLS-1$
 			    consumeInterTypeMethodHeader();  
 				break;
 	 
-	    case 300 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt Type OnType"); }  //$NON-NLS-1$
+	    case 302 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt Type OnType"); }  //$NON-NLS-1$
 			    consumeInterTypeMethodHeaderName(false,false);  
 				break;
 	 
-	    case 301 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt Type OnType"); }  //$NON-NLS-1$
+	    case 303 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt Type OnType"); }  //$NON-NLS-1$
 			    consumeInterTypeMethodHeaderNameIllegallyUsingTypePattern("*");  
 				break;
 	 
-	    case 302 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt Type OnType"); }  //$NON-NLS-1$
+	    case 304 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt Type OnType"); }  //$NON-NLS-1$
 			    consumeInterTypeMethodHeaderNameIllegallyUsingTypePattern("+");  
 				break;
 	 
-	    case 303 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt Type OnType"); }  //$NON-NLS-1$
+	    case 305 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt Type OnType"); }  //$NON-NLS-1$
 			    consumeInterTypeMethodHeaderName(false,true);  
 				break;
 	 
-	    case 304 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
+	    case 306 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
 			    consumeInterTypeMethodHeaderName(true,false);  
 				break;
 	 
-	    case 305 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
+	    case 307 : if (DEBUG) { System.out.println("InterTypeMethodHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
 			    consumeInterTypeMethodHeaderName(true,true);  
 				break;
 	 
-	    case 306 : if (DEBUG) { System.out.println("AbstractInterTypeMethodDeclaration ::=..."); }  //$NON-NLS-1$
+	    case 308 : if (DEBUG) { System.out.println("AbstractInterTypeMethodDeclaration ::=..."); }  //$NON-NLS-1$
 			    // set to false to consume a method without body
 	  consumeInterTypeMethodDeclaration(false);  
 				break;
 	 
-	    case 307 : if (DEBUG) { System.out.println("TypeParametersAsReference ::= TypeParameters"); }  //$NON-NLS-1$
+	    case 309 : if (DEBUG) { System.out.println("TypeParametersAsReference ::= TypeParameters"); }  //$NON-NLS-1$
 			    convertTypeParametersToSingleTypeReferences();  
 				break;
 	 
-	    case 308 : if (DEBUG) { System.out.println("InterTypeConstructorDeclaration ::=..."); }  //$NON-NLS-1$
+	    case 310 : if (DEBUG) { System.out.println("InterTypeConstructorDeclaration ::=..."); }  //$NON-NLS-1$
 			    // set to true to consume a method with a body
 	  consumeInterTypeConstructorDeclaration();   
 				break;
 	 
-	    case 309 : if (DEBUG) { System.out.println("InterTypeConstructorHeader ::=..."); }  //$NON-NLS-1$
+	    case 311 : if (DEBUG) { System.out.println("InterTypeConstructorHeader ::=..."); }  //$NON-NLS-1$
 			    consumeInterTypeConstructorHeader();  
 				break;
 	 
-	    case 310 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt Name DOT"); }  //$NON-NLS-1$
+	    case 312 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt Name DOT"); }  //$NON-NLS-1$
 			    consumeInterTypeConstructorHeaderName(false,false);  
 				break;
 	 
-	    case 311 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt Name DOT"); }  //$NON-NLS-1$
+	    case 313 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt Name DOT"); }  //$NON-NLS-1$
 			    consumeInterTypeConstructorHeaderNameIllegallyUsingTypePattern("*");  
 				break;
 	 
-	    case 312 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt Name..."); }  //$NON-NLS-1$
+	    case 314 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt Name..."); }  //$NON-NLS-1$
 			    consumeInterTypeConstructorHeaderNameIllegallyUsingTypePattern("+");  
 				break;
 	 
-	    case 313 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
+	    case 315 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
 			    consumeInterTypeConstructorHeaderName(true,false);  
 				break;
 	 
-	    case 314 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
+	    case 316 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
 			    consumeInterTypeConstructorHeaderName(false,true);  
 				break;
 	 
-	    case 315 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
+	    case 317 : if (DEBUG) { System.out.println("InterTypeConstructorHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
 			    consumeInterTypeConstructorHeaderName(true,true);  
 				break;
 	 
-	    case 316 : if (DEBUG) { System.out.println("InterTypeFieldDeclaration ::= InterTypeFieldHeader..."); }  //$NON-NLS-1$
+	    case 318 : if (DEBUG) { System.out.println("InterTypeFieldDeclaration ::= InterTypeFieldHeader..."); }  //$NON-NLS-1$
 			    consumeInterTypeFieldDeclaration();  
 				break;
 	 
-	    case 317 : if (DEBUG) { System.out.println("InterTypeFieldHeader ::= Modifiersopt Type OnType DOT..."); }  //$NON-NLS-1$
+	    case 319 : if (DEBUG) { System.out.println("InterTypeFieldHeader ::= Modifiersopt Type OnType DOT..."); }  //$NON-NLS-1$
 			    consumeInterTypeFieldHeader(false);  
 				break;
 	 
-	    case 318 : if (DEBUG) { System.out.println("InterTypeFieldHeader ::= Modifiersopt Type OnType DOT..."); }  //$NON-NLS-1$
+	    case 320 : if (DEBUG) { System.out.println("InterTypeFieldHeader ::= Modifiersopt Type OnType DOT..."); }  //$NON-NLS-1$
 			    consumeInterTypeFieldHeaderIllegallyAttemptingToUseATypePattern("*");  
 				break;
 	 
-	    case 319 : if (DEBUG) { System.out.println("InterTypeFieldHeader ::= Modifiersopt Type OnType PLUS"); }  //$NON-NLS-1$
+	    case 321 : if (DEBUG) { System.out.println("InterTypeFieldHeader ::= Modifiersopt Type OnType PLUS"); }  //$NON-NLS-1$
 			    consumeInterTypeFieldHeaderIllegallyAttemptingToUseATypePattern("+");  
 				break;
 	 
-	    case 320 : if (DEBUG) { System.out.println("InterTypeFieldHeader ::= Modifiersopt Type OnType..."); }  //$NON-NLS-1$
+	    case 322 : if (DEBUG) { System.out.println("InterTypeFieldHeader ::= Modifiersopt Type OnType..."); }  //$NON-NLS-1$
 			    consumeInterTypeFieldHeader(true);  
 				break;
 	 
-	    case 321 : if (DEBUG) { System.out.println("InterTypeFieldBody ::="); }  //$NON-NLS-1$
+	    case 323 : if (DEBUG) { System.out.println("InterTypeFieldBody ::="); }  //$NON-NLS-1$
 			    consumeExitITDVariableWithoutInitializer();  
 				break;
 	 
-	    case 322 : if (DEBUG) { System.out.println("InterTypeFieldBody ::= EQUAL ForceNoDiet..."); }  //$NON-NLS-1$
+	    case 324 : if (DEBUG) { System.out.println("InterTypeFieldBody ::= EQUAL ForceNoDiet..."); }  //$NON-NLS-1$
 			    consumeExitITDVariableWithInitializer();  
 				break;
 	 
-	    case 324 : if (DEBUG) { System.out.println("DeclareDeclaration ::= DeclareHeader PseudoTokens..."); }  //$NON-NLS-1$
+	    case 326 : if (DEBUG) { System.out.println("DeclareDeclaration ::= DeclareHeader PseudoTokens..."); }  //$NON-NLS-1$
 			    consumeDeclareDeclaration();  
 				break;
 	 
-	    case 325 : if (DEBUG) { System.out.println("DeclareHeader ::= declare Identifier COLON"); }  //$NON-NLS-1$
+	    case 327 : if (DEBUG) { System.out.println("DeclareHeader ::= declare Identifier COLON"); }  //$NON-NLS-1$
 			    consumeDeclareHeader();  
 				break;
 	 
-	    case 326 : if (DEBUG) { System.out.println("DeclareDeclaration ::= DeclareAnnotationHeader..."); }  //$NON-NLS-1$
+	    case 328 : if (DEBUG) { System.out.println("DeclareDeclaration ::= DeclareAnnotationHeader..."); }  //$NON-NLS-1$
 			    consumeDeclareAnnotation(' ');  
 				break;
 	 
-	    case 327 : if (DEBUG) { System.out.println("DeclareDeclaration ::= DeclareAnnotationHeader..."); }  //$NON-NLS-1$
+	    case 329 : if (DEBUG) { System.out.println("DeclareDeclaration ::= DeclareAnnotationHeader..."); }  //$NON-NLS-1$
 			    consumeDeclareAnnotation('+');  
 				break;
 	 
-	    case 328 : if (DEBUG) { System.out.println("DeclareDeclaration ::= DeclareAnnotationHeader..."); }  //$NON-NLS-1$
+	    case 330 : if (DEBUG) { System.out.println("DeclareDeclaration ::= DeclareAnnotationHeader..."); }  //$NON-NLS-1$
 			    consumeDeclareAnnotation('-');  
 				break;
 	 
-	    case 331 : if (DEBUG) { System.out.println("DeclareAnnotationHeader ::= declare AT Identifier COLON"); }  //$NON-NLS-1$
+	    case 333 : if (DEBUG) { System.out.println("DeclareAnnotationHeader ::= declare AT Identifier COLON"); }  //$NON-NLS-1$
 			    consumeDeclareAnnotationHeader();  
 				break;
 	 
-	    case 334 : if (DEBUG) { System.out.println("PseudoTokens ::= PseudoTokens ColonPseudoToken"); }  //$NON-NLS-1$
+	    case 336 : if (DEBUG) { System.out.println("PseudoTokens ::= PseudoTokens ColonPseudoToken"); }  //$NON-NLS-1$
 			    consumePseudoTokens();  
 				break;
 	 
-	    case 335 : if (DEBUG) { System.out.println("PseudoTokens ::= PseudoTokens PseudoToken"); }  //$NON-NLS-1$
+	    case 337 : if (DEBUG) { System.out.println("PseudoTokens ::= PseudoTokens PseudoToken"); }  //$NON-NLS-1$
 			    consumePseudoTokens();  
 				break;
 	 
-	    case 337 : if (DEBUG) { System.out.println("PseudoTokensNoColon ::= PseudoTokensNoColon PseudoToken"); }  //$NON-NLS-1$
+	    case 339 : if (DEBUG) { System.out.println("PseudoTokensNoColon ::= PseudoTokensNoColon PseudoToken"); }  //$NON-NLS-1$
 			    consumePseudoTokens();  
 				break;
 	 
-	    case 338 : if (DEBUG) { System.out.println("ColonPseudoToken ::= COLON"); }  //$NON-NLS-1$
+	    case 340 : if (DEBUG) { System.out.println("ColonPseudoToken ::= COLON"); }  //$NON-NLS-1$
 			    consumePseudoToken(":");  
 				break;
 	 
-	    case 339 : if (DEBUG) { System.out.println("PseudoToken ::= JavaIdentifier"); }  //$NON-NLS-1$
+	    case 341 : if (DEBUG) { System.out.println("PseudoToken ::= JavaIdentifier"); }  //$NON-NLS-1$
 			    consumePseudoTokenIdentifier();  
 				break;
 	 
-	    case 340 : if (DEBUG) { System.out.println("PseudoToken ::= LPAREN"); }  //$NON-NLS-1$
+	    case 342 : if (DEBUG) { System.out.println("PseudoToken ::= LPAREN"); }  //$NON-NLS-1$
 			    consumePseudoToken("(");  
 				break;
 	 
-	    case 341 : if (DEBUG) { System.out.println("PseudoToken ::= RPAREN"); }  //$NON-NLS-1$
+	    case 343 : if (DEBUG) { System.out.println("PseudoToken ::= RPAREN"); }  //$NON-NLS-1$
 			    consumePseudoToken(")");  
 				break;
 	 
-	    case 342 : if (DEBUG) { System.out.println("PseudoToken ::= DOT"); }  //$NON-NLS-1$
+	    case 344 : if (DEBUG) { System.out.println("PseudoToken ::= DOT"); }  //$NON-NLS-1$
 			    consumePseudoToken(".");  
 				break;
 	 
-	    case 343 : if (DEBUG) { System.out.println("PseudoToken ::= MULTIPLY"); }  //$NON-NLS-1$
+	    case 345 : if (DEBUG) { System.out.println("PseudoToken ::= MULTIPLY"); }  //$NON-NLS-1$
 			    consumePseudoToken("*");  
 				break;
 	 
-	    case 344 : if (DEBUG) { System.out.println("PseudoToken ::= PLUS"); }  //$NON-NLS-1$
+	    case 346 : if (DEBUG) { System.out.println("PseudoToken ::= PLUS"); }  //$NON-NLS-1$
 			    consumePseudoToken("+");  
 				break;
 	 
-	    case 345 : if (DEBUG) { System.out.println("PseudoToken ::= EQUAL"); }  //$NON-NLS-1$
+	    case 347 : if (DEBUG) { System.out.println("PseudoToken ::= EQUAL"); }  //$NON-NLS-1$
 			    consumePseudoToken("=");  
 				break;
 	 
-	    case 346 : if (DEBUG) { System.out.println("PseudoToken ::= AND_AND"); }  //$NON-NLS-1$
+	    case 348 : if (DEBUG) { System.out.println("PseudoToken ::= AND_AND"); }  //$NON-NLS-1$
 			    consumePseudoToken("&&");  
 				break;
 	 
-	    case 347 : if (DEBUG) { System.out.println("PseudoToken ::= OR_OR"); }  //$NON-NLS-1$
+	    case 349 : if (DEBUG) { System.out.println("PseudoToken ::= OR_OR"); }  //$NON-NLS-1$
 			    consumePseudoToken("||");  
 				break;
 	 
-	    case 348 : if (DEBUG) { System.out.println("PseudoToken ::= NOT"); }  //$NON-NLS-1$
+	    case 350 : if (DEBUG) { System.out.println("PseudoToken ::= NOT"); }  //$NON-NLS-1$
 			    consumePseudoToken("!");  
 				break;
 	 
-	    case 349 : if (DEBUG) { System.out.println("PseudoToken ::= COMMA"); }  //$NON-NLS-1$
+	    case 351 : if (DEBUG) { System.out.println("PseudoToken ::= COMMA"); }  //$NON-NLS-1$
 			    consumePseudoToken(",");  
 				break;
 	 
-	    case 350 : if (DEBUG) { System.out.println("PseudoToken ::= LBRACKET"); }  //$NON-NLS-1$
+	    case 352 : if (DEBUG) { System.out.println("PseudoToken ::= LBRACKET"); }  //$NON-NLS-1$
 			    consumePseudoToken("[");  
 				break;
 	 
-	    case 351 : if (DEBUG) { System.out.println("PseudoToken ::= RBRACKET"); }  //$NON-NLS-1$
+	    case 353 : if (DEBUG) { System.out.println("PseudoToken ::= RBRACKET"); }  //$NON-NLS-1$
 			    consumePseudoToken("]");  
 				break;
 	 
-	    case 352 : if (DEBUG) { System.out.println("PseudoToken ::= AT"); }  //$NON-NLS-1$
+	    case 354 : if (DEBUG) { System.out.println("PseudoToken ::= AT"); }  //$NON-NLS-1$
 			    consumePseudoToken("@");  
 				break;
 	 
-	    case 353 : if (DEBUG) { System.out.println("PseudoToken ::= ELLIPSIS"); }  //$NON-NLS-1$
+	    case 355 : if (DEBUG) { System.out.println("PseudoToken ::= ELLIPSIS"); }  //$NON-NLS-1$
 			    consumePseudoToken("...");  
 				break;
 	 
-	    case 354 : if (DEBUG) { System.out.println("PseudoToken ::= QUESTION"); }  //$NON-NLS-1$
+	    case 356 : if (DEBUG) { System.out.println("PseudoToken ::= QUESTION"); }  //$NON-NLS-1$
 			    consumePseudoToken("?");  
 				break;
 	 
-	    case 355 : if (DEBUG) { System.out.println("PseudoToken ::= LESS"); }  //$NON-NLS-1$
+	    case 357 : if (DEBUG) { System.out.println("PseudoToken ::= LESS"); }  //$NON-NLS-1$
 			    consumePseudoToken("<");  
 				break;
 	 
-	    case 356 : if (DEBUG) { System.out.println("PseudoToken ::= GREATER"); }  //$NON-NLS-1$
+	    case 358 : if (DEBUG) { System.out.println("PseudoToken ::= GREATER"); }  //$NON-NLS-1$
 			    consumePseudoToken(">");  
 				break;
 	 
-	    case 357 : if (DEBUG) { System.out.println("PseudoToken ::= RIGHT_SHIFT"); }  //$NON-NLS-1$
+	    case 359 : if (DEBUG) { System.out.println("PseudoToken ::= RIGHT_SHIFT"); }  //$NON-NLS-1$
 			    consumePseudoToken(">>");  
 				break;
 	 
-	    case 358 : if (DEBUG) { System.out.println("PseudoToken ::= UNSIGNED_RIGHT_SHIFT"); }  //$NON-NLS-1$
+	    case 360 : if (DEBUG) { System.out.println("PseudoToken ::= UNSIGNED_RIGHT_SHIFT"); }  //$NON-NLS-1$
 			    consumePseudoToken(">>>");  
 				break;
 	 
-	    case 359 : if (DEBUG) { System.out.println("PseudoToken ::= AND"); }  //$NON-NLS-1$
+	    case 361 : if (DEBUG) { System.out.println("PseudoToken ::= AND"); }  //$NON-NLS-1$
 			    consumePseudoToken("&");  
 				break;
 	 
-	    case 360 : if (DEBUG) { System.out.println("PseudoToken ::= NOT_EQUAL"); }  //$NON-NLS-1$
+	    case 362 : if (DEBUG) { System.out.println("PseudoToken ::= NOT_EQUAL"); }  //$NON-NLS-1$
 			    consumePseudoToken("!=");  
 				break;
 	 
-	    case 361 : if (DEBUG) { System.out.println("PseudoToken ::= PrimitiveType"); }  //$NON-NLS-1$
+	    case 363 : if (DEBUG) { System.out.println("PseudoToken ::= PrimitiveType"); }  //$NON-NLS-1$
 			    consumePseudoTokenPrimitiveType();  
 				break;
 	 
-	    case 362 : if (DEBUG) { System.out.println("PseudoToken ::= SimpleModifier"); }  //$NON-NLS-1$
+	    case 364 : if (DEBUG) { System.out.println("PseudoToken ::= SimpleModifier"); }  //$NON-NLS-1$
 			    consumePseudoTokenModifier();  
 				break;
 	 
-	    case 363 : if (DEBUG) { System.out.println("PseudoToken ::= Literal"); }  //$NON-NLS-1$
+	    case 365 : if (DEBUG) { System.out.println("PseudoToken ::= Literal"); }  //$NON-NLS-1$
 			    consumePseudoTokenLiteral();  
 				break;
 	 
-	    case 364 : if (DEBUG) { System.out.println("PseudoToken ::= this"); }  //$NON-NLS-1$
+	    case 366 : if (DEBUG) { System.out.println("PseudoToken ::= this"); }  //$NON-NLS-1$
 			    consumePseudoToken("this", 1, true);  
 				break;
 	 
-	    case 365 : if (DEBUG) { System.out.println("PseudoToken ::= class"); }  //$NON-NLS-1$
+	    case 367 : if (DEBUG) { System.out.println("PseudoToken ::= class"); }  //$NON-NLS-1$
 			    consumePseudoToken("class", 1, true);  
 				break;
 	 
-	    case 366 : if (DEBUG) { System.out.println("PseudoToken ::= super"); }  //$NON-NLS-1$
+	    case 368 : if (DEBUG) { System.out.println("PseudoToken ::= super"); }  //$NON-NLS-1$
 			    consumePseudoToken("super", 1, true);  
 				break;
 	 
-	    case 367 : if (DEBUG) { System.out.println("PseudoToken ::= if LPAREN Expression RPAREN"); }  //$NON-NLS-1$
+	    case 369 : if (DEBUG) { System.out.println("PseudoToken ::= if LPAREN Expression RPAREN"); }  //$NON-NLS-1$
 			    consumePseudoTokenIf();  
 				break;
 	 
-	    case 368 : if (DEBUG) { System.out.println("PseudoToken ::= assert"); }  //$NON-NLS-1$
+	    case 370 : if (DEBUG) { System.out.println("PseudoToken ::= assert"); }  //$NON-NLS-1$
 			    consumePseudoToken("assert", 1, true);  
 				break;
 	 
-	    case 369 : if (DEBUG) { System.out.println("PseudoToken ::= import"); }  //$NON-NLS-1$
+	    case 371 : if (DEBUG) { System.out.println("PseudoToken ::= import"); }  //$NON-NLS-1$
 			    consumePseudoToken("import", 1, true);  
 				break;
 	 
-	    case 370 : if (DEBUG) { System.out.println("PseudoToken ::= package"); }  //$NON-NLS-1$
+	    case 372 : if (DEBUG) { System.out.println("PseudoToken ::= package"); }  //$NON-NLS-1$
 			    consumePseudoToken("package", 1, true);  
 				break;
 	 
-	    case 371 : if (DEBUG) { System.out.println("PseudoToken ::= throw"); }  //$NON-NLS-1$
+	    case 373 : if (DEBUG) { System.out.println("PseudoToken ::= throw"); }  //$NON-NLS-1$
 			    consumePseudoToken("throw", 1, true);  
 				break;
 	 
-	    case 372 : if (DEBUG) { System.out.println("PseudoToken ::= new"); }  //$NON-NLS-1$
+	    case 374 : if (DEBUG) { System.out.println("PseudoToken ::= new"); }  //$NON-NLS-1$
 			    consumePseudoToken("new", 1, true);  
 				break;
 	 
-	    case 373 : if (DEBUG) { System.out.println("PseudoToken ::= do"); }  //$NON-NLS-1$
+	    case 375 : if (DEBUG) { System.out.println("PseudoToken ::= do"); }  //$NON-NLS-1$
 			    consumePseudoToken("do", 1, true);  
 				break;
 	 
-	    case 374 : if (DEBUG) { System.out.println("PseudoToken ::= for"); }  //$NON-NLS-1$
+	    case 376 : if (DEBUG) { System.out.println("PseudoToken ::= for"); }  //$NON-NLS-1$
 			    consumePseudoToken("for", 1, true);  
 				break;
 	 
-	    case 375 : if (DEBUG) { System.out.println("PseudoToken ::= switch"); }  //$NON-NLS-1$
+	    case 377 : if (DEBUG) { System.out.println("PseudoToken ::= switch"); }  //$NON-NLS-1$
 			    consumePseudoToken("switch", 1, true);  
 				break;
 	 
-	    case 376 : if (DEBUG) { System.out.println("PseudoToken ::= try"); }  //$NON-NLS-1$
+	    case 378 : if (DEBUG) { System.out.println("PseudoToken ::= try"); }  //$NON-NLS-1$
 			    consumePseudoToken("try", 1, true);  
 				break;
 	 
-	    case 377 : if (DEBUG) { System.out.println("PseudoToken ::= while"); }  //$NON-NLS-1$
+	    case 379 : if (DEBUG) { System.out.println("PseudoToken ::= while"); }  //$NON-NLS-1$
 			    consumePseudoToken("while", 1, true);  
 				break;
 	 
-	    case 378 : if (DEBUG) { System.out.println("PseudoToken ::= break"); }  //$NON-NLS-1$
+	    case 380 : if (DEBUG) { System.out.println("PseudoToken ::= break"); }  //$NON-NLS-1$
 			    consumePseudoToken("break", 1, true);  
 				break;
 	 
-	    case 379 : if (DEBUG) { System.out.println("PseudoToken ::= continue"); }  //$NON-NLS-1$
+	    case 381 : if (DEBUG) { System.out.println("PseudoToken ::= continue"); }  //$NON-NLS-1$
 			    consumePseudoToken("continue", 1, true);  
 				break;
 	 
-	    case 380 : if (DEBUG) { System.out.println("PseudoToken ::= return"); }  //$NON-NLS-1$
+	    case 382 : if (DEBUG) { System.out.println("PseudoToken ::= return"); }  //$NON-NLS-1$
 			    consumePseudoToken("return", 1, true);  
 				break;
 	 
-	    case 381 : if (DEBUG) { System.out.println("PseudoToken ::= case"); }  //$NON-NLS-1$
+	    case 383 : if (DEBUG) { System.out.println("PseudoToken ::= case"); }  //$NON-NLS-1$
 			    consumePseudoToken("case", 1, true);  
 				break;
 	 
-	    case 382 : if (DEBUG) { System.out.println("PseudoToken ::= catch"); }  //$NON-NLS-1$
+	    case 384 : if (DEBUG) { System.out.println("PseudoToken ::= catch"); }  //$NON-NLS-1$
 			    consumePseudoToken("catch", 0, true);  
 				break;
 	 
-	    case 383 : if (DEBUG) { System.out.println("PseudoToken ::= instanceof"); }  //$NON-NLS-1$
+	    case 385 : if (DEBUG) { System.out.println("PseudoToken ::= instanceof"); }  //$NON-NLS-1$
 			    consumePseudoToken("instanceof", 0, true);  
 				break;
 	 
-	    case 384 : if (DEBUG) { System.out.println("PseudoToken ::= else"); }  //$NON-NLS-1$
+	    case 386 : if (DEBUG) { System.out.println("PseudoToken ::= else"); }  //$NON-NLS-1$
 			    consumePseudoToken("else", 0, true);  
 				break;
 	 
-	    case 385 : if (DEBUG) { System.out.println("PseudoToken ::= extends"); }  //$NON-NLS-1$
+	    case 387 : if (DEBUG) { System.out.println("PseudoToken ::= extends"); }  //$NON-NLS-1$
 			    consumePseudoToken("extends", 0, true);  
 				break;
 	 
-	    case 386 : if (DEBUG) { System.out.println("PseudoToken ::= finally"); }  //$NON-NLS-1$
+	    case 388 : if (DEBUG) { System.out.println("PseudoToken ::= finally"); }  //$NON-NLS-1$
 			    consumePseudoToken("finally", 0, true);  
 				break;
 	 
-	    case 387 : if (DEBUG) { System.out.println("PseudoToken ::= implements"); }  //$NON-NLS-1$
+	    case 389 : if (DEBUG) { System.out.println("PseudoToken ::= implements"); }  //$NON-NLS-1$
 			    consumePseudoToken("implements", 0, true);  
 				break;
 	 
-	    case 388 : if (DEBUG) { System.out.println("PseudoToken ::= throws"); }  //$NON-NLS-1$
+	    case 390 : if (DEBUG) { System.out.println("PseudoToken ::= throws"); }  //$NON-NLS-1$
 			    consumePseudoToken("throws", 0, true);  
 				break;
 	 
-	    case 389 : if (DEBUG) { System.out.println("ClassDeclaration ::= ClassHeader ClassBody"); }  //$NON-NLS-1$
+	    case 391 : if (DEBUG) { System.out.println("ClassDeclaration ::= ClassHeader ClassBody"); }  //$NON-NLS-1$
 			    consumeClassDeclaration();  
 				break;
 	 
-	    case 390 : if (DEBUG) { System.out.println("IntertypeClassDeclaration ::= IntertypeClassHeader..."); }  //$NON-NLS-1$
+	    case 392 : if (DEBUG) { System.out.println("IntertypeClassDeclaration ::= IntertypeClassHeader..."); }  //$NON-NLS-1$
 			    consumeIntertypeClassDeclaration();  
 				break;
 	 
-	    case 391 : if (DEBUG) { System.out.println("IntertypeClassHeader ::= IntertypeClassHeaderName..."); }  //$NON-NLS-1$
+	    case 393 : if (DEBUG) { System.out.println("IntertypeClassHeader ::= IntertypeClassHeaderName..."); }  //$NON-NLS-1$
 			    consumeIntertypeClassHeader();  
 				break;
 	 
-	    case 392 : if (DEBUG) { System.out.println("IntertypeClassHeaderName ::= IntertypeClassHeaderName1"); }  //$NON-NLS-1$
+	    case 394 : if (DEBUG) { System.out.println("IntertypeClassHeaderName ::= IntertypeClassHeaderName1"); }  //$NON-NLS-1$
 			    consumeIntertypeTypeHeaderNameWithTypeParameters();  
 				break;
 	 
-	    case 394 : if (DEBUG) { System.out.println("IntertypeClassHeaderName1 ::= Modifiersopt class OnType"); }  //$NON-NLS-1$
+	    case 396 : if (DEBUG) { System.out.println("IntertypeClassHeaderName1 ::= Modifiersopt class OnType"); }  //$NON-NLS-1$
 			    consumeIntertypeClassHeaderName(false);  
 				break;
 	 
-	    case 395 : if (DEBUG) { System.out.println("InterTypeClassHeaderName1 ::= Modifiersopt class OnType"); }  //$NON-NLS-1$
+	    case 397 : if (DEBUG) { System.out.println("InterTypeClassHeaderName1 ::= Modifiersopt class OnType"); }  //$NON-NLS-1$
 			    consumeIntertypeClassHeaderName(true);  
 				break;
 	 
-	    case 396 : if (DEBUG) { System.out.println("ClassHeader ::= ClassHeaderName ClassHeaderExtendsopt..."); }  //$NON-NLS-1$
+	    case 398 : if (DEBUG) { System.out.println("ClassHeader ::= ClassHeaderName ClassHeaderExtendsopt..."); }  //$NON-NLS-1$
 			    consumeClassHeader();  
 				break;
 	 
-	    case 397 : if (DEBUG) { System.out.println("ClassHeaderName ::= ClassHeaderName1 TypeParameters"); }  //$NON-NLS-1$
+	    case 399 : if (DEBUG) { System.out.println("ClassHeaderName ::= ClassHeaderName1 TypeParameters"); }  //$NON-NLS-1$
 			    consumeTypeHeaderNameWithTypeParameters();  
 				break;
 	 
-	    case 399 : if (DEBUG) { System.out.println("ClassHeaderName1 ::= Modifiersopt class JavaIdentifier"); }  //$NON-NLS-1$
+	    case 401 : if (DEBUG) { System.out.println("ClassHeaderName1 ::= Modifiersopt class JavaIdentifier"); }  //$NON-NLS-1$
 			    consumeClassHeaderName1();  
 				break;
 	 
-	    case 400 : if (DEBUG) { System.out.println("ClassHeaderExtends ::= extends ClassType"); }  //$NON-NLS-1$
+	    case 402 : if (DEBUG) { System.out.println("ClassHeaderExtends ::= extends ClassType"); }  //$NON-NLS-1$
 			    consumeClassHeaderExtends();  
 				break;
 	 
-	    case 401 : if (DEBUG) { System.out.println("ClassHeaderImplements ::= implements InterfaceTypeList"); }  //$NON-NLS-1$
+	    case 403 : if (DEBUG) { System.out.println("ClassHeaderImplements ::= implements InterfaceTypeList"); }  //$NON-NLS-1$
 			    consumeClassHeaderImplements();  
 				break;
 	 
-	    case 403 : if (DEBUG) { System.out.println("InterfaceTypeList ::= InterfaceTypeList COMMA..."); }  //$NON-NLS-1$
+	    case 405 : if (DEBUG) { System.out.println("InterfaceTypeList ::= InterfaceTypeList COMMA..."); }  //$NON-NLS-1$
 			    consumeInterfaceTypeList();  
 				break;
 	 
-	    case 404 : if (DEBUG) { System.out.println("InterfaceType ::= ClassOrInterfaceType"); }  //$NON-NLS-1$
+	    case 406 : if (DEBUG) { System.out.println("InterfaceType ::= ClassOrInterfaceType"); }  //$NON-NLS-1$
 			    consumeInterfaceType();  
 				break;
 	 
-	    case 407 : if (DEBUG) { System.out.println("ClassBodyDeclarations ::= ClassBodyDeclarations..."); }  //$NON-NLS-1$
+	    case 409 : if (DEBUG) { System.out.println("ClassBodyDeclarations ::= ClassBodyDeclarations..."); }  //$NON-NLS-1$
 			    consumeClassBodyDeclarations();  
 				break;
 	 
-	    case 411 : if (DEBUG) { System.out.println("ClassBodyDeclaration ::= Diet NestedMethod..."); }  //$NON-NLS-1$
+	    case 413 : if (DEBUG) { System.out.println("ClassBodyDeclaration ::= Diet NestedMethod..."); }  //$NON-NLS-1$
 			    consumeClassBodyDeclaration();  
 				break;
 	 
-	    case 412 : if (DEBUG) { System.out.println("Diet ::="); }  //$NON-NLS-1$
+	    case 414 : if (DEBUG) { System.out.println("Diet ::="); }  //$NON-NLS-1$
 			    consumeDiet();  
 				break;
 
-	    case 413 : if (DEBUG) { System.out.println("Initializer ::= Diet NestedMethod CreateInitializer..."); }  //$NON-NLS-1$
+	    case 415 : if (DEBUG) { System.out.println("Initializer ::= Diet NestedMethod CreateInitializer..."); }  //$NON-NLS-1$
 			    consumeClassBodyDeclaration();  
 				break;
 	 
-	    case 414 : if (DEBUG) { System.out.println("CreateInitializer ::="); }  //$NON-NLS-1$
+	    case 416 : if (DEBUG) { System.out.println("CreateInitializer ::="); }  //$NON-NLS-1$
 			    consumeCreateInitializer();  
 				break;
 
-	    case 421 : if (DEBUG) { System.out.println("ClassMemberDeclaration ::= SEMICOLON"); }  //$NON-NLS-1$
+	    case 424 : if (DEBUG) { System.out.println("ClassMemberDeclaration ::= SEMICOLON"); }  //$NON-NLS-1$
 			    consumeEmptyTypeDeclaration();  
 				break;
 
-	    case 424 : if (DEBUG) { System.out.println("FieldDeclaration ::= Modifiersopt Type..."); }  //$NON-NLS-1$
+	    case 427 : if (DEBUG) { System.out.println("FieldDeclaration ::= Modifiersopt Type..."); }  //$NON-NLS-1$
 			    consumeFieldDeclaration();  
 				break;
 	 
-	    case 426 : if (DEBUG) { System.out.println("VariableDeclarators ::= VariableDeclarators COMMA..."); }  //$NON-NLS-1$
+	    case 429 : if (DEBUG) { System.out.println("VariableDeclarators ::= VariableDeclarators COMMA..."); }  //$NON-NLS-1$
 			    consumeVariableDeclarators();  
 				break;
 	 
-	    case 429 : if (DEBUG) { System.out.println("EnterVariable ::="); }  //$NON-NLS-1$
+	    case 432 : if (DEBUG) { System.out.println("EnterVariable ::="); }  //$NON-NLS-1$
 			    consumeEnterVariable();  
 				break;
 	 
-	    case 430 : if (DEBUG) { System.out.println("ExitVariableWithInitialization ::="); }  //$NON-NLS-1$
+	    case 433 : if (DEBUG) { System.out.println("ExitVariableWithInitialization ::="); }  //$NON-NLS-1$
 			    consumeExitVariableWithInitialization();  
 				break;
 	 
-	    case 431 : if (DEBUG) { System.out.println("ExitVariableWithoutInitialization ::="); }  //$NON-NLS-1$
+	    case 434 : if (DEBUG) { System.out.println("ExitVariableWithoutInitialization ::="); }  //$NON-NLS-1$
 			    consumeExitVariableWithoutInitialization();  
 				break;
 	 
-	    case 432 : if (DEBUG) { System.out.println("ForceNoDiet ::="); }  //$NON-NLS-1$
+	    case 435 : if (DEBUG) { System.out.println("ForceNoDiet ::="); }  //$NON-NLS-1$
 			    consumeForceNoDiet();  
 				break;
 	 
-	    case 433 : if (DEBUG) { System.out.println("RestoreDiet ::="); }  //$NON-NLS-1$
+	    case 436 : if (DEBUG) { System.out.println("RestoreDiet ::="); }  //$NON-NLS-1$
 			    consumeRestoreDiet();  
 				break;
 	 
-	    case 438 : if (DEBUG) { System.out.println("MethodDeclaration ::= MethodHeader MethodBody"); }  //$NON-NLS-1$
+	    case 441 : if (DEBUG) { System.out.println("MethodDeclaration ::= MethodHeader MethodBody"); }  //$NON-NLS-1$
 			    // set to true to consume a method with a body
 	 consumeMethodDeclaration(true, false);  
 				break;
 	 
-	    case 439 : if (DEBUG) { System.out.println("MethodDeclaration ::= DefaultMethodHeader MethodBody"); }  //$NON-NLS-1$
+	    case 442 : if (DEBUG) { System.out.println("MethodDeclaration ::= DefaultMethodHeader MethodBody"); }  //$NON-NLS-1$
 			    // set to true to consume a method with a body
 	 consumeMethodDeclaration(true, true);  
 				break;
 	 
-	    case 440 : if (DEBUG) { System.out.println("AbstractMethodDeclaration ::= MethodHeader SEMICOLON"); }  //$NON-NLS-1$
+	    case 443 : if (DEBUG) { System.out.println("AbstractMethodDeclaration ::= MethodHeader SEMICOLON"); }  //$NON-NLS-1$
 			    // set to false to consume a method without body
 	 consumeMethodDeclaration(false, false);  
 				break;
 	 
-	    case 441 : if (DEBUG) { System.out.println("MethodHeader ::= MethodHeaderName FormalParameterListopt"); }  //$NON-NLS-1$
+	    case 444 : if (DEBUG) { System.out.println("MethodHeader ::= MethodHeaderName FormalParameterListopt"); }  //$NON-NLS-1$
 			    consumeMethodHeader();  
 				break;
 	 
-	    case 442 : if (DEBUG) { System.out.println("DefaultMethodHeader ::= DefaultMethodHeaderName..."); }  //$NON-NLS-1$
+	    case 445 : if (DEBUG) { System.out.println("DefaultMethodHeader ::= DefaultMethodHeaderName..."); }  //$NON-NLS-1$
 			    consumeMethodHeader();  
 				break;
 	 
-	    case 443 : if (DEBUG) { System.out.println("MethodHeaderName ::= Modifiersopt TypeParameters Type..."); }  //$NON-NLS-1$
+	    case 446 : if (DEBUG) { System.out.println("MethodHeaderName ::= Modifiersopt TypeParameters Type..."); }  //$NON-NLS-1$
 			    consumeMethodHeaderNameWithTypeParameters(false);  
 				break;
 	 
-	    case 444 : if (DEBUG) { System.out.println("MethodHeaderName ::= Modifiersopt Type JavaIdentifier..."); }  //$NON-NLS-1$
+	    case 447 : if (DEBUG) { System.out.println("MethodHeaderName ::= Modifiersopt Type JavaIdentifier..."); }  //$NON-NLS-1$
 			    consumeMethodHeaderName(false);  
 				break;
 	 
-	    case 445 : if (DEBUG) { System.out.println("DefaultMethodHeaderName ::= ModifiersWithDefault..."); }  //$NON-NLS-1$
+	    case 448 : if (DEBUG) { System.out.println("DefaultMethodHeaderName ::= ModifiersWithDefault..."); }  //$NON-NLS-1$
 			    consumeMethodHeaderNameWithTypeParameters(false);  
 				break;
 	 
-	    case 446 : if (DEBUG) { System.out.println("DefaultMethodHeaderName ::= ModifiersWithDefault Type..."); }  //$NON-NLS-1$
+	    case 449 : if (DEBUG) { System.out.println("DefaultMethodHeaderName ::= ModifiersWithDefault Type..."); }  //$NON-NLS-1$
 			    consumeMethodHeaderName(false);  
 				break;
 	 
-	    case 447 : if (DEBUG) { System.out.println("ModifiersWithDefault ::= Modifiersopt default..."); }  //$NON-NLS-1$
+	    case 450 : if (DEBUG) { System.out.println("ModifiersWithDefault ::= Modifiersopt default..."); }  //$NON-NLS-1$
 			    consumePushCombineModifiers();  
 				break;
 	 
-	    case 448 : if (DEBUG) { System.out.println("MethodHeaderRightParen ::= RPAREN"); }  //$NON-NLS-1$
+	    case 451 : if (DEBUG) { System.out.println("MethodHeaderRightParen ::= RPAREN"); }  //$NON-NLS-1$
 			    consumeMethodHeaderRightParen();  
 				break;
 	 
-	    case 449 : if (DEBUG) { System.out.println("MethodHeaderExtendedDims ::= Dimsopt"); }  //$NON-NLS-1$
+	    case 452 : if (DEBUG) { System.out.println("MethodHeaderExtendedDims ::= Dimsopt"); }  //$NON-NLS-1$
 			    consumeMethodHeaderExtendedDims();  
 				break;
 	 
-	    case 450 : if (DEBUG) { System.out.println("MethodHeaderThrowsClause ::= throws ClassTypeList"); }  //$NON-NLS-1$
+	    case 453 : if (DEBUG) { System.out.println("MethodHeaderThrowsClause ::= throws ClassTypeList"); }  //$NON-NLS-1$
 			    consumeMethodHeaderThrowsClause();  
 				break;
 	 
-	    case 451 : if (DEBUG) { System.out.println("ConstructorHeader ::= ConstructorHeaderName..."); }  //$NON-NLS-1$
+	    case 454 : if (DEBUG) { System.out.println("ConstructorHeader ::= ConstructorHeaderName..."); }  //$NON-NLS-1$
 			    consumeConstructorHeader();  
 				break;
 	 
-	    case 452 : if (DEBUG) { System.out.println("ConstructorHeaderName ::= Modifiersopt TypeParameters..."); }  //$NON-NLS-1$
+	    case 455 : if (DEBUG) { System.out.println("ConstructorHeaderName ::= Modifiersopt TypeParameters..."); }  //$NON-NLS-1$
 			    consumeConstructorHeaderNameWithTypeParameters();  
 				break;
 	 
-	    case 453 : if (DEBUG) { System.out.println("ConstructorHeaderName ::= Modifiersopt Identifier LPAREN"); }  //$NON-NLS-1$
+	    case 456 : if (DEBUG) { System.out.println("ConstructorHeaderName ::= Modifiersopt Identifier LPAREN"); }  //$NON-NLS-1$
 			    consumeConstructorHeaderName();  
 				break;
 	 
-	    case 454 : if (DEBUG) { System.out.println("ConstructorHeaderName ::= Modifiersopt aspect LPAREN"); }  //$NON-NLS-1$
+	    case 457 : if (DEBUG) { System.out.println("ConstructorHeaderName ::= Modifiersopt aspect LPAREN"); }  //$NON-NLS-1$
 			    consumeConstructorHeaderName();  
 				break;
 	 
-	    case 456 : if (DEBUG) { System.out.println("FormalParameterList ::= FormalParameterList COMMA..."); }  //$NON-NLS-1$
+	    case 459 : if (DEBUG) { System.out.println("FormalParameterList ::= FormalParameterList COMMA..."); }  //$NON-NLS-1$
 			    consumeFormalParameterList();  
 				break;
 	 
-	    case 457 : if (DEBUG) { System.out.println("FormalParameter ::= Modifiersopt Type..."); }  //$NON-NLS-1$
+	    case 460 : if (DEBUG) { System.out.println("FormalParameter ::= Modifiersopt Type..."); }  //$NON-NLS-1$
 			    consumeFormalParameter(false);  
 				break;
 	 
-	    case 458 : if (DEBUG) { System.out.println("FormalParameter ::= Modifiersopt Type..."); }  //$NON-NLS-1$
+	    case 461 : if (DEBUG) { System.out.println("FormalParameter ::= Modifiersopt Type..."); }  //$NON-NLS-1$
 			    consumeFormalParameter(true);  
 				break;
 	 
-	    case 459 : if (DEBUG) { System.out.println("FormalParameter ::= Modifiersopt Type AT308DOTDOTDOT..."); }  //$NON-NLS-1$
+	    case 462 : if (DEBUG) { System.out.println("FormalParameter ::= Modifiersopt Type AT308DOTDOTDOT..."); }  //$NON-NLS-1$
 			    consumeFormalParameter(true);  
 				break;
 	 
-	    case 460 : if (DEBUG) { System.out.println("CatchFormalParameter ::= Modifiersopt CatchType..."); }  //$NON-NLS-1$
+	    case 463 : if (DEBUG) { System.out.println("CatchFormalParameter ::= Modifiersopt CatchType..."); }  //$NON-NLS-1$
 			    consumeCatchFormalParameter();  
 				break;
 	 
-	    case 461 : if (DEBUG) { System.out.println("CatchType ::= UnionType"); }  //$NON-NLS-1$
+	    case 464 : if (DEBUG) { System.out.println("CatchType ::= UnionType"); }  //$NON-NLS-1$
 			    consumeCatchType();  
 				break;
 	 
-	    case 462 : if (DEBUG) { System.out.println("UnionType ::= Type"); }  //$NON-NLS-1$
+	    case 465 : if (DEBUG) { System.out.println("UnionType ::= Type"); }  //$NON-NLS-1$
 			    consumeUnionTypeAsClassType();  
 				break;
 	 
-	    case 463 : if (DEBUG) { System.out.println("UnionType ::= UnionType OR Type"); }  //$NON-NLS-1$
+	    case 466 : if (DEBUG) { System.out.println("UnionType ::= UnionType OR Type"); }  //$NON-NLS-1$
 			    consumeUnionType();  
 				break;
 	 
-	    case 465 : if (DEBUG) { System.out.println("ClassTypeList ::= ClassTypeList COMMA ClassTypeElt"); }  //$NON-NLS-1$
+	    case 468 : if (DEBUG) { System.out.println("ClassTypeList ::= ClassTypeList COMMA ClassTypeElt"); }  //$NON-NLS-1$
 			    consumeClassTypeList();  
 				break;
 	 
-	    case 466 : if (DEBUG) { System.out.println("ClassTypeElt ::= ClassType"); }  //$NON-NLS-1$
+	    case 469 : if (DEBUG) { System.out.println("ClassTypeElt ::= ClassType"); }  //$NON-NLS-1$
 			    consumeClassTypeElt();  
 				break;
 	 
-	    case 467 : if (DEBUG) { System.out.println("MethodBody ::= NestedMethod LBRACE BlockStatementsopt..."); }  //$NON-NLS-1$
+	    case 470 : if (DEBUG) { System.out.println("MethodBody ::= NestedMethod LBRACE BlockStatementsopt..."); }  //$NON-NLS-1$
 			    consumeMethodBody();  
 				break;
 	 
-	    case 468 : if (DEBUG) { System.out.println("NestedMethod ::="); }  //$NON-NLS-1$
+	    case 471 : if (DEBUG) { System.out.println("NestedMethod ::="); }  //$NON-NLS-1$
 			    consumeNestedMethod();  
 				break;
 	 
-	    case 469 : if (DEBUG) { System.out.println("StaticInitializer ::= StaticOnly Block"); }  //$NON-NLS-1$
+	    case 472 : if (DEBUG) { System.out.println("StaticInitializer ::= StaticOnly Block"); }  //$NON-NLS-1$
 			    consumeStaticInitializer();  
 				break;
 
-	    case 470 : if (DEBUG) { System.out.println("StaticOnly ::= static"); }  //$NON-NLS-1$
+	    case 473 : if (DEBUG) { System.out.println("StaticOnly ::= static"); }  //$NON-NLS-1$
 			    consumeStaticOnly();  
 				break;
 	 
-	    case 471 : if (DEBUG) { System.out.println("ConstructorDeclaration ::= ConstructorHeader MethodBody"); }  //$NON-NLS-1$
+	    case 474 : if (DEBUG) { System.out.println("ConstructorDeclaration ::= ConstructorHeader MethodBody"); }  //$NON-NLS-1$
 			    consumeConstructorDeclaration() ;  
 				break;
 	 
-	    case 472 : if (DEBUG) { System.out.println("ConstructorDeclaration ::= ConstructorHeader SEMICOLON"); }  //$NON-NLS-1$
+	    case 475 : if (DEBUG) { System.out.println("ConstructorDeclaration ::= ConstructorHeader SEMICOLON"); }  //$NON-NLS-1$
 			    consumeInvalidConstructorDeclaration() ;  
 				break;
 	 
-	    case 473 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= this LPAREN..."); }  //$NON-NLS-1$
+	    case 476 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= this LPAREN..."); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocation(0, THIS_CALL);  
 				break;
 	 
-	    case 474 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= OnlyTypeArguments this"); }  //$NON-NLS-1$
+	    case 477 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= OnlyTypeArguments this"); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocationWithTypeArguments(0,THIS_CALL);  
 				break;
 	 
-	    case 475 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= super LPAREN..."); }  //$NON-NLS-1$
+	    case 478 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= super LPAREN..."); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocation(0,SUPER_CALL);  
 				break;
 	 
-	    case 476 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= OnlyTypeArguments..."); }  //$NON-NLS-1$
+	    case 479 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= OnlyTypeArguments..."); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocationWithTypeArguments(0,SUPER_CALL);  
 				break;
 	 
-	    case 477 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Primary DOT super..."); }  //$NON-NLS-1$
+	    case 480 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Primary DOT super..."); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocation(1, SUPER_CALL);  
 				break;
 	 
-	    case 478 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Primary DOT..."); }  //$NON-NLS-1$
+	    case 481 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Primary DOT..."); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocationWithTypeArguments(1, SUPER_CALL);  
 				break;
 	 
-	    case 479 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Name DOT super LPAREN"); }  //$NON-NLS-1$
+	    case 482 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Name DOT super LPAREN"); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocation(2, SUPER_CALL);  
 				break;
 	 
-	    case 480 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Name DOT..."); }  //$NON-NLS-1$
+	    case 483 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Name DOT..."); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocationWithTypeArguments(2, SUPER_CALL);  
 				break;
 	 
-	    case 481 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Primary DOT this..."); }  //$NON-NLS-1$
+	    case 484 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Primary DOT this..."); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocation(1, THIS_CALL);  
 				break;
 	 
-	    case 482 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Primary DOT..."); }  //$NON-NLS-1$
+	    case 485 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Primary DOT..."); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocationWithTypeArguments(1, THIS_CALL);  
 				break;
 	 
-	    case 483 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Name DOT this LPAREN"); }  //$NON-NLS-1$
+	    case 486 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Name DOT this LPAREN"); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocation(2, THIS_CALL);  
 				break;
 	 
-	    case 484 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Name DOT..."); }  //$NON-NLS-1$
+	    case 487 : if (DEBUG) { System.out.println("ExplicitConstructorInvocation ::= Name DOT..."); }  //$NON-NLS-1$
 			    consumeExplicitConstructorInvocationWithTypeArguments(2, THIS_CALL);  
 				break;
 	 
-	    case 485 : if (DEBUG) { System.out.println("InterfaceDeclaration ::= InterfaceHeader InterfaceBody"); }  //$NON-NLS-1$
+	    case 488 : if (DEBUG) { System.out.println("InterfaceDeclaration ::= InterfaceHeader InterfaceBody"); }  //$NON-NLS-1$
 			    consumeInterfaceDeclaration();  
 				break;
 	 
-	    case 486 : if (DEBUG) { System.out.println("InterfaceHeader ::= InterfaceHeaderName..."); }  //$NON-NLS-1$
+	    case 489 : if (DEBUG) { System.out.println("InterfaceHeader ::= InterfaceHeaderName..."); }  //$NON-NLS-1$
 			    consumeInterfaceHeader();  
 				break;
 	 
-	    case 487 : if (DEBUG) { System.out.println("InterfaceHeaderName ::= InterfaceHeaderName1..."); }  //$NON-NLS-1$
+	    case 490 : if (DEBUG) { System.out.println("InterfaceHeaderName ::= InterfaceHeaderName1..."); }  //$NON-NLS-1$
 			    consumeTypeHeaderNameWithTypeParameters();  
 				break;
 	 
-	    case 489 : if (DEBUG) { System.out.println("InterfaceHeaderName1 ::= Modifiersopt interface..."); }  //$NON-NLS-1$
+	    case 492 : if (DEBUG) { System.out.println("InterfaceHeaderName1 ::= Modifiersopt interface..."); }  //$NON-NLS-1$
 			    consumeInterfaceHeaderName1();  
 				break;
 	 
-	    case 490 : if (DEBUG) { System.out.println("InterfaceHeaderExtends ::= extends InterfaceTypeList"); }  //$NON-NLS-1$
+	    case 493 : if (DEBUG) { System.out.println("InterfaceHeaderExtends ::= extends InterfaceTypeList"); }  //$NON-NLS-1$
 			    consumeInterfaceHeaderExtends();  
 				break;
 	 
-	    case 493 : if (DEBUG) { System.out.println("InterfaceMemberDeclarations ::=..."); }  //$NON-NLS-1$
+	    case 496 : if (DEBUG) { System.out.println("InterfaceMemberDeclarations ::=..."); }  //$NON-NLS-1$
 			    consumeInterfaceMemberDeclarations();  
 				break;
 	 
-	    case 494 : if (DEBUG) { System.out.println("InterfaceMemberDeclaration ::= SEMICOLON"); }  //$NON-NLS-1$
+	    case 497 : if (DEBUG) { System.out.println("InterfaceMemberDeclaration ::= SEMICOLON"); }  //$NON-NLS-1$
 			    consumeEmptyTypeDeclaration();  
 				break;
 	 
-	    case 496 : if (DEBUG) { System.out.println("InterfaceMemberDeclaration ::= DefaultMethodHeader..."); }  //$NON-NLS-1$
+	    case 499 : if (DEBUG) { System.out.println("InterfaceMemberDeclaration ::= DefaultMethodHeader..."); }  //$NON-NLS-1$
 			    consumeInterfaceMethodDeclaration(false);  
 				break;
 	 
-	    case 497 : if (DEBUG) { System.out.println("InterfaceMemberDeclaration ::= MethodHeader MethodBody"); }  //$NON-NLS-1$
+	    case 500 : if (DEBUG) { System.out.println("InterfaceMemberDeclaration ::= MethodHeader MethodBody"); }  //$NON-NLS-1$
 			    consumeInterfaceMethodDeclaration(false);  
 				break;
 	 
-	    case 498 : if (DEBUG) { System.out.println("InterfaceMemberDeclaration ::= DefaultMethodHeader..."); }  //$NON-NLS-1$
+	    case 501 : if (DEBUG) { System.out.println("InterfaceMemberDeclaration ::= DefaultMethodHeader..."); }  //$NON-NLS-1$
 			    consumeInterfaceMethodDeclaration(true);  
 				break;
 	 
-	    case 499 : if (DEBUG) { System.out.println("InvalidConstructorDeclaration ::= ConstructorHeader..."); }  //$NON-NLS-1$
+	    case 502 : if (DEBUG) { System.out.println("InvalidConstructorDeclaration ::= ConstructorHeader..."); }  //$NON-NLS-1$
 			    consumeInvalidConstructorDeclaration(true);  
 				break;
 	 
-	    case 500 : if (DEBUG) { System.out.println("InvalidConstructorDeclaration ::= ConstructorHeader..."); }  //$NON-NLS-1$
+	    case 503 : if (DEBUG) { System.out.println("InvalidConstructorDeclaration ::= ConstructorHeader..."); }  //$NON-NLS-1$
 			    consumeInvalidConstructorDeclaration(false);  
 				break;
 	 
-	    case 511 : if (DEBUG) { System.out.println("PushLeftBrace ::="); }  //$NON-NLS-1$
+	    case 514 : if (DEBUG) { System.out.println("RecordDeclaration ::= RecordHeaderPart RecordBody"); }  //$NON-NLS-1$
+			    consumeRecordDeclaration();  
+				break;
+	 
+	    case 515 : if (DEBUG) { System.out.println("RecordHeaderPart ::= RecordHeaderName RecordHeader..."); }  //$NON-NLS-1$
+			    consumeRecordHeaderPart();  
+				break;
+	 
+	    case 516 : if (DEBUG) { System.out.println("RecordHeaderName ::= RecordHeaderName1 TypeParameters"); }  //$NON-NLS-1$
+			    consumeRecordHeaderNameWithTypeParameters();  
+				break;
+	 
+	    case 518 : if (DEBUG) { System.out.println("RecordHeaderName1 ::= Modifiersopt..."); }  //$NON-NLS-1$
+			    consumeRecordHeaderName1();  
+				break;
+	 
+	    case 519 : if (DEBUG) { System.out.println("RecordComponentHeaderRightParen ::= RPAREN"); }  //$NON-NLS-1$
+			    consumeRecordComponentHeaderRightParen();  
+				break;
+	 
+	    case 520 : if (DEBUG) { System.out.println("RecordHeader ::= LPAREN RecordComponentsopt..."); }  //$NON-NLS-1$
+			    consumeRecordHeader();  
+				break;
+	 
+	    case 521 : if (DEBUG) { System.out.println("RecordComponentsopt ::="); }  //$NON-NLS-1$
+			    consumeRecordComponentsopt();  
+				break;
+	 
+	    case 524 : if (DEBUG) { System.out.println("RecordComponents ::= RecordComponents COMMA..."); }  //$NON-NLS-1$
+			    consumeRecordComponents();  
+				break;
+	 
+	    case 526 : if (DEBUG) { System.out.println("RecordComponent ::= Modifiersopt Type..."); }  //$NON-NLS-1$
+			    consumeRecordComponent(false);  
+				break;
+	 
+	    case 527 : if (DEBUG) { System.out.println("VariableArityRecordComponent ::= Modifiersopt Type..."); }  //$NON-NLS-1$
+			    consumeRecordComponent(true);  
+				break;
+	 
+	    case 528 : if (DEBUG) { System.out.println("VariableArityRecordComponent ::= Modifiersopt Type..."); }  //$NON-NLS-1$
+			    consumeRecordComponent(true);  
+				break;
+	 
+	    case 529 : if (DEBUG) { System.out.println("RecordBody ::= LBRACE RecordBodyDeclarationopt RBRACE"); }  //$NON-NLS-1$
+			    consumeRecordBody();  
+				break;
+	 
+	    case 530 : if (DEBUG) { System.out.println("RecordBodyDeclarationopt ::="); }  //$NON-NLS-1$
+			    consumeEmptyRecordBodyDeclaration();  
+				break;
+	 
+	    case 533 : if (DEBUG) { System.out.println("RecordBodyDeclarations ::= RecordBodyDeclarations..."); }  //$NON-NLS-1$
+			    consumeRecordBodyDeclarations();  
+				break;
+	 
+	    case 534 : if (DEBUG) { System.out.println("RecordBodyDeclaration ::= ClassBodyDeclaration"); }  //$NON-NLS-1$
+			    consumeRecordBodyDeclaration();  
+				break;
+	 
+	    case 535 : if (DEBUG) { System.out.println("RecordBodyDeclaration ::= CompactConstructorDeclaration"); }  //$NON-NLS-1$
+			    consumeRecordBodyDeclaration();  
+				break;
+	 
+	    case 536 : if (DEBUG) { System.out.println("CompactConstructorDeclaration ::=..."); }  //$NON-NLS-1$
+			    consumeCompactConstructorDeclaration();  
+				break;
+	 
+	    case 537 : if (DEBUG) { System.out.println("CompactConstructorHeader ::=..."); }  //$NON-NLS-1$
+			    consumeCompactConstructorHeader();  
+				break;
+	 
+	    case 538 : if (DEBUG) { System.out.println("CompactConstructorHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
+			    consumeCompactConstructorHeaderName();  
+				break;
+	 
+	    case 539 : if (DEBUG) { System.out.println("CompactConstructorHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
+			    consumeCompactConstructorHeaderNameWithTypeParameters();  
+				break;
+	 
+	    case 541 : if (DEBUG) { System.out.println("InstanceofExpression ::= InstanceofExpression instanceof"); }  //$NON-NLS-1$
+			    consumeInstanceOfExpression();  
+				break;
+	 
+	    case 545 : if (DEBUG) { System.out.println("TypeTestPattern ::= Type Identifier"); }  //$NON-NLS-1$
+			    consumeTypeTestPattern();  
+				break;
+	 
+	    case 547 : if (DEBUG) { System.out.println("PushLeftBrace ::="); }  //$NON-NLS-1$
 			    consumePushLeftBrace();  
 				break;
 	 
-	    case 512 : if (DEBUG) { System.out.println("ArrayInitializer ::= LBRACE PushLeftBrace ,opt RBRACE"); }  //$NON-NLS-1$
+	    case 548 : if (DEBUG) { System.out.println("ArrayInitializer ::= LBRACE PushLeftBrace ,opt RBRACE"); }  //$NON-NLS-1$
 			    consumeEmptyArrayInitializer();  
 				break;
 	 
-	    case 513 : if (DEBUG) { System.out.println("ArrayInitializer ::= LBRACE PushLeftBrace..."); }  //$NON-NLS-1$
+	    case 549 : if (DEBUG) { System.out.println("ArrayInitializer ::= LBRACE PushLeftBrace..."); }  //$NON-NLS-1$
 			    consumeArrayInitializer();  
 				break;
 	 
-	    case 514 : if (DEBUG) { System.out.println("ArrayInitializer ::= LBRACE PushLeftBrace..."); }  //$NON-NLS-1$
+	    case 550 : if (DEBUG) { System.out.println("ArrayInitializer ::= LBRACE PushLeftBrace..."); }  //$NON-NLS-1$
 			    consumeArrayInitializer();  
 				break;
 	 
-	    case 516 : if (DEBUG) { System.out.println("VariableInitializers ::= VariableInitializers COMMA..."); }  //$NON-NLS-1$
+	    case 552 : if (DEBUG) { System.out.println("VariableInitializers ::= VariableInitializers COMMA..."); }  //$NON-NLS-1$
 			    consumeVariableInitializers();  
 				break;
 	 
-	    case 517 : if (DEBUG) { System.out.println("Block ::= OpenBlock LBRACE BlockStatementsopt RBRACE"); }  //$NON-NLS-1$
+	    case 553 : if (DEBUG) { System.out.println("Block ::= OpenBlock LBRACE BlockStatementsopt RBRACE"); }  //$NON-NLS-1$
 			    consumeBlock();  
 				break;
 	 
-	    case 518 : if (DEBUG) { System.out.println("OpenBlock ::="); }  //$NON-NLS-1$
+	    case 554 : if (DEBUG) { System.out.println("OpenBlock ::="); }  //$NON-NLS-1$
 			    consumeOpenBlock() ;  
 				break;
 	 
-	    case 519 : if (DEBUG) { System.out.println("BlockStatements ::= BlockStatement"); }  //$NON-NLS-1$
+	    case 555 : if (DEBUG) { System.out.println("BlockStatements ::= BlockStatement"); }  //$NON-NLS-1$
 			    consumeBlockStatement() ;  
 				break;
 	 
-	    case 520 : if (DEBUG) { System.out.println("BlockStatements ::= BlockStatements BlockStatement"); }  //$NON-NLS-1$
+	    case 556 : if (DEBUG) { System.out.println("BlockStatements ::= BlockStatements BlockStatement"); }  //$NON-NLS-1$
 			    consumeBlockStatements() ;  
 				break;
 	 
-	    case 527 : if (DEBUG) { System.out.println("BlockStatement ::= InterfaceDeclaration"); }  //$NON-NLS-1$
+	    case 564 : if (DEBUG) { System.out.println("BlockStatement ::= InterfaceDeclaration"); }  //$NON-NLS-1$
 			    consumeInvalidInterfaceDeclaration();  
 				break;
 	 
-	    case 528 : if (DEBUG) { System.out.println("BlockStatement ::= AnnotationTypeDeclaration"); }  //$NON-NLS-1$
+	    case 565 : if (DEBUG) { System.out.println("BlockStatement ::= AnnotationTypeDeclaration"); }  //$NON-NLS-1$
 			    consumeInvalidAnnotationTypeDeclaration();  
 				break;
 	 
-	    case 529 : if (DEBUG) { System.out.println("BlockStatement ::= EnumDeclaration"); }  //$NON-NLS-1$
+	    case 566 : if (DEBUG) { System.out.println("BlockStatement ::= EnumDeclaration"); }  //$NON-NLS-1$
 			    consumeInvalidEnumDeclaration();  
 				break;
 	 
-	    case 530 : if (DEBUG) { System.out.println("LocalVariableDeclarationStatement ::=..."); }  //$NON-NLS-1$
+	    case 567 : if (DEBUG) { System.out.println("LocalVariableDeclarationStatement ::=..."); }  //$NON-NLS-1$
 			    consumeLocalVariableDeclarationStatement();  
 				break;
 	 
-	    case 531 : if (DEBUG) { System.out.println("LocalVariableDeclaration ::= Type PushModifiers..."); }  //$NON-NLS-1$
+	    case 568 : if (DEBUG) { System.out.println("LocalVariableDeclaration ::= Type PushModifiers..."); }  //$NON-NLS-1$
 			    consumeLocalVariableDeclaration();  
 				break;
 	 
-	    case 532 : if (DEBUG) { System.out.println("LocalVariableDeclaration ::= Modifiers Type..."); }  //$NON-NLS-1$
+	    case 569 : if (DEBUG) { System.out.println("LocalVariableDeclaration ::= Modifiers Type..."); }  //$NON-NLS-1$
 			    consumeLocalVariableDeclaration();  
 				break;
 	 
-	    case 533 : if (DEBUG) { System.out.println("PushModifiers ::="); }  //$NON-NLS-1$
+	    case 570 : if (DEBUG) { System.out.println("PushModifiers ::="); }  //$NON-NLS-1$
 			    consumePushModifiers();  
 				break;
 	 
-	    case 534 : if (DEBUG) { System.out.println("PushModifiersForHeader ::="); }  //$NON-NLS-1$
+	    case 571 : if (DEBUG) { System.out.println("PushModifiersForHeader ::="); }  //$NON-NLS-1$
 			    consumePushModifiersForHeader();  
 				break;
 	 
-	    case 535 : if (DEBUG) { System.out.println("PushRealModifiers ::="); }  //$NON-NLS-1$
+	    case 572 : if (DEBUG) { System.out.println("PushRealModifiers ::="); }  //$NON-NLS-1$
 			    consumePushRealModifiers();  
 				break;
 	 
-	    case 563 : if (DEBUG) { System.out.println("EmptyStatement ::= SEMICOLON"); }  //$NON-NLS-1$
+	    case 600 : if (DEBUG) { System.out.println("EmptyStatement ::= SEMICOLON"); }  //$NON-NLS-1$
 			    consumeEmptyStatement();  
 				break;
 	 
-	    case 564 : if (DEBUG) { System.out.println("LabeledStatement ::= Label COLON Statement"); }  //$NON-NLS-1$
+	    case 601 : if (DEBUG) { System.out.println("LabeledStatement ::= Label COLON Statement"); }  //$NON-NLS-1$
 			    consumeStatementLabel() ;  
 				break;
 	 
-	    case 565 : if (DEBUG) { System.out.println("LabeledStatementNoShortIf ::= Label COLON..."); }  //$NON-NLS-1$
+	    case 602 : if (DEBUG) { System.out.println("LabeledStatementNoShortIf ::= Label COLON..."); }  //$NON-NLS-1$
 			    consumeStatementLabel() ;  
 				break;
 	 
-	    case 566 : if (DEBUG) { System.out.println("Label ::= JavaIdentifier"); }  //$NON-NLS-1$
+	    case 603 : if (DEBUG) { System.out.println("Label ::= JavaIdentifier"); }  //$NON-NLS-1$
 			    consumeLabel() ;  
 				break;
 	 
-	     case 567 : if (DEBUG) { System.out.println("ExpressionStatement ::= StatementExpression SEMICOLON"); }  //$NON-NLS-1$
+	     case 604 : if (DEBUG) { System.out.println("ExpressionStatement ::= StatementExpression SEMICOLON"); }  //$NON-NLS-1$
 			    consumeExpressionStatement();  
 				break;
 	 
-	    case 576 : if (DEBUG) { System.out.println("IfThenStatement ::= if LPAREN Expression RPAREN..."); }  //$NON-NLS-1$
+	    case 613 : if (DEBUG) { System.out.println("IfThenStatement ::= if LPAREN Expression RPAREN..."); }  //$NON-NLS-1$
 			    consumeStatementIfNoElse();  
 				break;
 	 
-	    case 577 : if (DEBUG) { System.out.println("IfThenElseStatement ::= if LPAREN Expression RPAREN..."); }  //$NON-NLS-1$
+	    case 614 : if (DEBUG) { System.out.println("IfThenElseStatement ::= if LPAREN Expression RPAREN..."); }  //$NON-NLS-1$
 			    consumeStatementIfWithElse();  
 				break;
 	 
-	    case 578 : if (DEBUG) { System.out.println("IfThenElseStatementNoShortIf ::= if LPAREN Expression..."); }  //$NON-NLS-1$
+	    case 615 : if (DEBUG) { System.out.println("IfThenElseStatementNoShortIf ::= if LPAREN Expression..."); }  //$NON-NLS-1$
 			    consumeStatementIfWithElse();  
 				break;
 	 
-	    case 579 : if (DEBUG) { System.out.println("SwitchStatement ::= switch LPAREN Expression RPAREN..."); }  //$NON-NLS-1$
+	    case 616 : if (DEBUG) { System.out.println("SwitchStatement ::= switch LPAREN Expression RPAREN..."); }  //$NON-NLS-1$
 			    consumeStatementSwitch() ;  
 				break;
 	 
-	    case 580 : if (DEBUG) { System.out.println("SwitchBlock ::= LBRACE RBRACE"); }  //$NON-NLS-1$
+	    case 617 : if (DEBUG) { System.out.println("SwitchBlock ::= LBRACE RBRACE"); }  //$NON-NLS-1$
 			    consumeEmptySwitchBlock() ;  
 				break;
 	 
-	    case 583 : if (DEBUG) { System.out.println("SwitchBlock ::= LBRACE SwitchBlockStatements..."); }  //$NON-NLS-1$
+	    case 620 : if (DEBUG) { System.out.println("SwitchBlock ::= LBRACE SwitchBlockStatements..."); }  //$NON-NLS-1$
 			    consumeSwitchBlock() ;  
 				break;
 	 
-	    case 585 : if (DEBUG) { System.out.println("SwitchBlockStatements ::= SwitchBlockStatements..."); }  //$NON-NLS-1$
+	    case 622 : if (DEBUG) { System.out.println("SwitchBlockStatements ::= SwitchBlockStatements..."); }  //$NON-NLS-1$
 			    consumeSwitchBlockStatements() ;  
 				break;
 	 
-	    case 587 : if (DEBUG) { System.out.println("SwitchBlockStatement ::= SwitchLabels BlockStatements"); }  //$NON-NLS-1$
+	    case 624 : if (DEBUG) { System.out.println("SwitchBlockStatement ::= SwitchLabels BlockStatements"); }  //$NON-NLS-1$
 			    consumeSwitchBlockStatement() ;  
 				break;
 	 
-	    case 589 : if (DEBUG) { System.out.println("SwitchLabels ::= SwitchLabels SwitchLabel"); }  //$NON-NLS-1$
+	    case 626 : if (DEBUG) { System.out.println("SwitchLabels ::= SwitchLabels SwitchLabel"); }  //$NON-NLS-1$
 			    consumeSwitchLabels() ;  
 				break;
 	 
-	     case 590 : if (DEBUG) { System.out.println("SwitchLabel ::= SwitchLabelCaseLhs COLON"); }  //$NON-NLS-1$
+	     case 627 : if (DEBUG) { System.out.println("SwitchLabel ::= SwitchLabelCaseLhs COLON"); }  //$NON-NLS-1$
 			    consumeCaseLabel();  
 				break;
 	 
-	     case 591 : if (DEBUG) { System.out.println("SwitchLabel ::= default COLON"); }  //$NON-NLS-1$
+	     case 628 : if (DEBUG) { System.out.println("SwitchLabel ::= default COLON"); }  //$NON-NLS-1$
 			    consumeDefaultLabel();  
 				break;
 	 
-	    case 594 : if (DEBUG) { System.out.println("SwitchExpression ::= switch LPAREN Expression RPAREN..."); }  //$NON-NLS-1$
+	    case 631 : if (DEBUG) { System.out.println("SwitchExpression ::= switch LPAREN Expression RPAREN..."); }  //$NON-NLS-1$
 			    consumeSwitchExpression() ;  
 				break;
 	 
-	     case 597 : if (DEBUG) { System.out.println("SwitchLabeledRule ::= SwitchLabeledThrowStatement"); }  //$NON-NLS-1$
+	     case 634 : if (DEBUG) { System.out.println("SwitchLabeledRule ::= SwitchLabeledThrowStatement"); }  //$NON-NLS-1$
 			    consumeSwitchLabeledRule();  
 				break;
 	 
-	     case 598 : if (DEBUG) { System.out.println("SwitchLabeledExpression ::= SwitchLabelExpr Expression"); }  //$NON-NLS-1$
+	     case 635 : if (DEBUG) { System.out.println("SwitchLabeledExpression ::= SwitchLabelExpr Expression"); }  //$NON-NLS-1$
 			    consumeSwitchLabeledExpression();  
 				break;
 	 
-	     case 599 : if (DEBUG) { System.out.println("SwitchLabeledBlock ::= SwitchLabelExpr Block"); }  //$NON-NLS-1$
+	     case 636 : if (DEBUG) { System.out.println("SwitchLabeledBlock ::= SwitchLabelExpr Block"); }  //$NON-NLS-1$
 			    consumeSwitchLabeledBlock();  
 				break;
 	 
-	     case 600 : if (DEBUG) { System.out.println("SwitchLabeledThrowStatement ::= SwitchLabelExpr..."); }  //$NON-NLS-1$
+	     case 637 : if (DEBUG) { System.out.println("SwitchLabeledThrowStatement ::= SwitchLabelExpr..."); }  //$NON-NLS-1$
 			    consumeSwitchLabeledThrowStatement();  
 				break;
 	 
-	     case 601 : if (DEBUG) { System.out.println("SwitchLabelExpr ::= default ARROW"); }  //$NON-NLS-1$
+	     case 638 : if (DEBUG) { System.out.println("SwitchLabelExpr ::= default ARROW"); }  //$NON-NLS-1$
 			    consumeDefaultLabelExpr();  
 				break;
 	 
-	     case 602 : if (DEBUG) { System.out.println("SwitchLabelExpr ::= SwitchLabelCaseLhs BeginCaseExpr..."); }  //$NON-NLS-1$
+	     case 639 : if (DEBUG) { System.out.println("SwitchLabelExpr ::= SwitchLabelCaseLhs BeginCaseExpr..."); }  //$NON-NLS-1$
 			    consumeCaseLabelExpr();  
 				break;
 	 
-	     case 603 : if (DEBUG) { System.out.println("SwitchLabelCaseLhs ::= case ConstantExpressions"); }  //$NON-NLS-1$
+	     case 640 : if (DEBUG) { System.out.println("SwitchLabelCaseLhs ::= case ConstantExpressions"); }  //$NON-NLS-1$
 			    consumeSwitchLabelCaseLhs();  
 				break;
 	 
-	    case 604 : if (DEBUG) { System.out.println("YieldStatement ::= RestrictedIdentifierYield Expression"); }  //$NON-NLS-1$
+	    case 641 : if (DEBUG) { System.out.println("YieldStatement ::= RestrictedIdentifierYield Expression"); }  //$NON-NLS-1$
 			    consumeStatementYield() ;  
 				break;
 	 
-	    case 605 : if (DEBUG) { System.out.println("WhileStatement ::= while LPAREN Expression RPAREN..."); }  //$NON-NLS-1$
+	    case 642 : if (DEBUG) { System.out.println("WhileStatement ::= while LPAREN Expression RPAREN..."); }  //$NON-NLS-1$
 			    consumeStatementWhile() ;  
 				break;
 	 
-	    case 606 : if (DEBUG) { System.out.println("WhileStatementNoShortIf ::= while LPAREN Expression..."); }  //$NON-NLS-1$
+	    case 643 : if (DEBUG) { System.out.println("WhileStatementNoShortIf ::= while LPAREN Expression..."); }  //$NON-NLS-1$
 			    consumeStatementWhile() ;  
 				break;
 	 
-	    case 607 : if (DEBUG) { System.out.println("DoStatement ::= do Statement while LPAREN Expression..."); }  //$NON-NLS-1$
+	    case 644 : if (DEBUG) { System.out.println("DoStatement ::= do Statement while LPAREN Expression..."); }  //$NON-NLS-1$
 			    consumeStatementDo() ;  
 				break;
 	 
-	    case 608 : if (DEBUG) { System.out.println("ForStatement ::= for LPAREN ForInitopt SEMICOLON..."); }  //$NON-NLS-1$
+	    case 645 : if (DEBUG) { System.out.println("ForStatement ::= for LPAREN ForInitopt SEMICOLON..."); }  //$NON-NLS-1$
 			    consumeStatementFor() ;  
 				break;
 	 
-	    case 609 : if (DEBUG) { System.out.println("ForStatementNoShortIf ::= for LPAREN ForInitopt..."); }  //$NON-NLS-1$
+	    case 646 : if (DEBUG) { System.out.println("ForStatementNoShortIf ::= for LPAREN ForInitopt..."); }  //$NON-NLS-1$
 			    consumeStatementFor() ;  
 				break;
 	 
-	    case 610 : if (DEBUG) { System.out.println("ForInit ::= StatementExpressionList"); }  //$NON-NLS-1$
+	    case 647 : if (DEBUG) { System.out.println("ForInit ::= StatementExpressionList"); }  //$NON-NLS-1$
 			    consumeForInit() ;  
 				break;
 	 
-	    case 614 : if (DEBUG) { System.out.println("StatementExpressionList ::= StatementExpressionList..."); }  //$NON-NLS-1$
+	    case 651 : if (DEBUG) { System.out.println("StatementExpressionList ::= StatementExpressionList..."); }  //$NON-NLS-1$
 			    consumeStatementExpressionList() ;  
 				break;
 	 
-	    case 615 : if (DEBUG) { System.out.println("AssertStatement ::= assert Expression SEMICOLON"); }  //$NON-NLS-1$
+	    case 652 : if (DEBUG) { System.out.println("AssertStatement ::= assert Expression SEMICOLON"); }  //$NON-NLS-1$
 			    consumeSimpleAssertStatement() ;  
 				break;
 	 
-	    case 616 : if (DEBUG) { System.out.println("AssertStatement ::= assert Expression COLON Expression"); }  //$NON-NLS-1$
+	    case 653 : if (DEBUG) { System.out.println("AssertStatement ::= assert Expression COLON Expression"); }  //$NON-NLS-1$
 			    consumeAssertStatement() ;  
 				break;
 	 
-	    case 617 : if (DEBUG) { System.out.println("BreakStatement ::= break SEMICOLON"); }  //$NON-NLS-1$
+	    case 654 : if (DEBUG) { System.out.println("BreakStatement ::= break SEMICOLON"); }  //$NON-NLS-1$
 			    consumeStatementBreak() ;  
 				break;
 	 
-	    case 618 : if (DEBUG) { System.out.println("BreakStatement ::= break Identifier SEMICOLON"); }  //$NON-NLS-1$
+	    case 655 : if (DEBUG) { System.out.println("BreakStatement ::= break Identifier SEMICOLON"); }  //$NON-NLS-1$
 			    consumeStatementBreakWithLabel() ;  
 				break;
 	 
-	    case 619 : if (DEBUG) { System.out.println("ContinueStatement ::= continue SEMICOLON"); }  //$NON-NLS-1$
+	    case 656 : if (DEBUG) { System.out.println("ContinueStatement ::= continue SEMICOLON"); }  //$NON-NLS-1$
 			    consumeStatementContinue() ;  
 				break;
 	 
-	    case 620 : if (DEBUG) { System.out.println("ContinueStatement ::= continue Identifier SEMICOLON"); }  //$NON-NLS-1$
+	    case 657 : if (DEBUG) { System.out.println("ContinueStatement ::= continue Identifier SEMICOLON"); }  //$NON-NLS-1$
 			    consumeStatementContinueWithLabel() ;  
 				break;
 	 
-	    case 621 : if (DEBUG) { System.out.println("ReturnStatement ::= return Expressionopt SEMICOLON"); }  //$NON-NLS-1$
+	    case 658 : if (DEBUG) { System.out.println("ReturnStatement ::= return Expressionopt SEMICOLON"); }  //$NON-NLS-1$
 			    consumeStatementReturn() ;  
 				break;
 	 
-	    case 622 : if (DEBUG) { System.out.println("ThrowStatement ::= throw Expression SEMICOLON"); }  //$NON-NLS-1$
+	    case 659 : if (DEBUG) { System.out.println("ThrowStatement ::= throw Expression SEMICOLON"); }  //$NON-NLS-1$
 			    consumeStatementThrow();  
 				break;
 	 
-	    case 623 : if (DEBUG) { System.out.println("ThrowExpression ::= throw Expression"); }  //$NON-NLS-1$
+	    case 660 : if (DEBUG) { System.out.println("ThrowExpression ::= throw Expression"); }  //$NON-NLS-1$
 			    consumeThrowExpression() ;  
 				break;
 	 
-	    case 624 : if (DEBUG) { System.out.println("SynchronizedStatement ::= OnlySynchronized LPAREN..."); }  //$NON-NLS-1$
+	    case 661 : if (DEBUG) { System.out.println("SynchronizedStatement ::= OnlySynchronized LPAREN..."); }  //$NON-NLS-1$
 			    consumeStatementSynchronized();  
 				break;
 	 
-	    case 625 : if (DEBUG) { System.out.println("OnlySynchronized ::= synchronized"); }  //$NON-NLS-1$
+	    case 662 : if (DEBUG) { System.out.println("OnlySynchronized ::= synchronized"); }  //$NON-NLS-1$
 			    consumeOnlySynchronized();  
 				break;
 	 
-	    case 626 : if (DEBUG) { System.out.println("TryStatement ::= try TryBlock Catches"); }  //$NON-NLS-1$
+	    case 663 : if (DEBUG) { System.out.println("TryStatement ::= try TryBlock Catches"); }  //$NON-NLS-1$
 			    consumeStatementTry(false, false);  
 				break;
 	 
-	    case 627 : if (DEBUG) { System.out.println("TryStatement ::= try TryBlock Catchesopt Finally"); }  //$NON-NLS-1$
+	    case 664 : if (DEBUG) { System.out.println("TryStatement ::= try TryBlock Catchesopt Finally"); }  //$NON-NLS-1$
 			    consumeStatementTry(true, false);  
 				break;
 	 
-	    case 628 : if (DEBUG) { System.out.println("TryStatementWithResources ::= try ResourceSpecification"); }  //$NON-NLS-1$
+	    case 665 : if (DEBUG) { System.out.println("TryStatementWithResources ::= try ResourceSpecification"); }  //$NON-NLS-1$
 			    consumeStatementTry(false, true);  
 				break;
 	 
-	    case 629 : if (DEBUG) { System.out.println("TryStatementWithResources ::= try ResourceSpecification"); }  //$NON-NLS-1$
+	    case 666 : if (DEBUG) { System.out.println("TryStatementWithResources ::= try ResourceSpecification"); }  //$NON-NLS-1$
 			    consumeStatementTry(true, true);  
 				break;
 	 
-	    case 630 : if (DEBUG) { System.out.println("ResourceSpecification ::= LPAREN Resources ;opt RPAREN"); }  //$NON-NLS-1$
+	    case 667 : if (DEBUG) { System.out.println("ResourceSpecification ::= LPAREN Resources ;opt RPAREN"); }  //$NON-NLS-1$
 			    consumeResourceSpecification();  
 				break;
 	 
-	    case 631 : if (DEBUG) { System.out.println(";opt ::="); }  //$NON-NLS-1$
+	    case 668 : if (DEBUG) { System.out.println(";opt ::="); }  //$NON-NLS-1$
 			    consumeResourceOptionalTrailingSemiColon(false);  
 				break;
 	 
-	    case 632 : if (DEBUG) { System.out.println(";opt ::= SEMICOLON"); }  //$NON-NLS-1$
+	    case 669 : if (DEBUG) { System.out.println(";opt ::= SEMICOLON"); }  //$NON-NLS-1$
 			    consumeResourceOptionalTrailingSemiColon(true);  
 				break;
 	 
-	    case 633 : if (DEBUG) { System.out.println("Resources ::= Resource"); }  //$NON-NLS-1$
+	    case 670 : if (DEBUG) { System.out.println("Resources ::= Resource"); }  //$NON-NLS-1$
 			    consumeSingleResource();  
 				break;
 	 
-	    case 634 : if (DEBUG) { System.out.println("Resources ::= Resources TrailingSemiColon Resource"); }  //$NON-NLS-1$
+	    case 671 : if (DEBUG) { System.out.println("Resources ::= Resources TrailingSemiColon Resource"); }  //$NON-NLS-1$
 			    consumeMultipleResources();  
 				break;
 	 
-	    case 635 : if (DEBUG) { System.out.println("TrailingSemiColon ::= SEMICOLON"); }  //$NON-NLS-1$
+	    case 672 : if (DEBUG) { System.out.println("TrailingSemiColon ::= SEMICOLON"); }  //$NON-NLS-1$
 			    consumeResourceOptionalTrailingSemiColon(true);  
 				break;
 	 
-	    case 636 : if (DEBUG) { System.out.println("Resource ::= Type PushModifiers VariableDeclaratorId..."); }  //$NON-NLS-1$
+	    case 673 : if (DEBUG) { System.out.println("Resource ::= Type PushModifiers VariableDeclaratorId..."); }  //$NON-NLS-1$
 			    consumeResourceAsLocalVariableDeclaration();  
 				break;
 	 
-	    case 637 : if (DEBUG) { System.out.println("Resource ::= Modifiers Type PushRealModifiers..."); }  //$NON-NLS-1$
+	    case 674 : if (DEBUG) { System.out.println("Resource ::= Modifiers Type PushRealModifiers..."); }  //$NON-NLS-1$
 			    consumeResourceAsLocalVariableDeclaration();  
 				break;
 	 
-	    case 638 : if (DEBUG) { System.out.println("Resource ::= Name"); }  //$NON-NLS-1$
+	    case 675 : if (DEBUG) { System.out.println("Resource ::= Name"); }  //$NON-NLS-1$
 			    consumeResourceAsLocalVariable();  
 				break;
 	 
-	    case 639 : if (DEBUG) { System.out.println("Resource ::= FieldAccess"); }  //$NON-NLS-1$
+	    case 676 : if (DEBUG) { System.out.println("Resource ::= FieldAccess"); }  //$NON-NLS-1$
 			    consumeResourceAsFieldAccess();  
 				break;
 	 
-	    case 641 : if (DEBUG) { System.out.println("ExitTryBlock ::="); }  //$NON-NLS-1$
+	    case 678 : if (DEBUG) { System.out.println("ExitTryBlock ::="); }  //$NON-NLS-1$
 			    consumeExitTryBlock();  
 				break;
 	 
-	    case 643 : if (DEBUG) { System.out.println("Catches ::= Catches CatchClause"); }  //$NON-NLS-1$
+	    case 680 : if (DEBUG) { System.out.println("Catches ::= Catches CatchClause"); }  //$NON-NLS-1$
 			    consumeCatches();  
 				break;
 	 
-	    case 644 : if (DEBUG) { System.out.println("CatchClause ::= catch LPAREN CatchFormalParameter RPAREN"); }  //$NON-NLS-1$
+	    case 681 : if (DEBUG) { System.out.println("CatchClause ::= catch LPAREN CatchFormalParameter RPAREN"); }  //$NON-NLS-1$
 			    consumeStatementCatch() ;  
 				break;
 	 
-	    case 646 : if (DEBUG) { System.out.println("PushLPAREN ::= LPAREN"); }  //$NON-NLS-1$
+	    case 683 : if (DEBUG) { System.out.println("PushLPAREN ::= LPAREN"); }  //$NON-NLS-1$
 			    consumeLeftParen();  
 				break;
 	 
-	    case 647 : if (DEBUG) { System.out.println("PushRPAREN ::= RPAREN"); }  //$NON-NLS-1$
+	    case 684 : if (DEBUG) { System.out.println("PushRPAREN ::= RPAREN"); }  //$NON-NLS-1$
 			    consumeRightParen();  
 				break;
 	 
-	    case 652 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= this"); }  //$NON-NLS-1$
+	    case 689 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= this"); }  //$NON-NLS-1$
 			    consumePrimaryNoNewArrayThis();  
 				break;
 	 
-	    case 653 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= PushLPAREN Expression_NotName..."); }  //$NON-NLS-1$
+	    case 690 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= PushLPAREN Expression_NotName..."); }  //$NON-NLS-1$
 			    consumePrimaryNoNewArray();  
 				break;
 	 
-	    case 654 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= PushLPAREN Name PushRPAREN"); }  //$NON-NLS-1$
+	    case 691 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= PushLPAREN Name PushRPAREN"); }  //$NON-NLS-1$
 			    consumePrimaryNoNewArrayWithName();  
 				break;
 	 
-	    case 657 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= Name DOT this"); }  //$NON-NLS-1$
+	    case 694 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= Name DOT this"); }  //$NON-NLS-1$
 			    consumePrimaryNoNewArrayNameThis();  
 				break;
 	 
-	    case 658 : if (DEBUG) { System.out.println("QualifiedSuperReceiver ::= Name DOT super"); }  //$NON-NLS-1$
+	    case 695 : if (DEBUG) { System.out.println("QualifiedSuperReceiver ::= Name DOT super"); }  //$NON-NLS-1$
 			    consumeQualifiedSuperReceiver();  
 				break;
 	 
-	    case 659 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= Name DOT class"); }  //$NON-NLS-1$
+	    case 696 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= Name DOT class"); }  //$NON-NLS-1$
 			    consumePrimaryNoNewArrayName();  
 				break;
 	 
-	    case 660 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= Name Dims DOT class"); }  //$NON-NLS-1$
+	    case 697 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= Name Dims DOT class"); }  //$NON-NLS-1$
 			    consumePrimaryNoNewArrayArrayType();  
 				break;
 	 
-	    case 661 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= PrimitiveType Dims DOT class"); }  //$NON-NLS-1$
+	    case 698 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= PrimitiveType Dims DOT class"); }  //$NON-NLS-1$
 			    consumePrimaryNoNewArrayPrimitiveArrayType();  
 				break;
 	 
-	    case 662 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= PrimitiveType DOT class"); }  //$NON-NLS-1$
+	    case 699 : if (DEBUG) { System.out.println("PrimaryNoNewArray ::= PrimitiveType DOT class"); }  //$NON-NLS-1$
 			    consumePrimaryNoNewArrayPrimitiveType();  
 				break;
 	 
-	    case 668 : if (DEBUG) { System.out.println("ReferenceExpressionTypeArgumentsAndTrunk0 ::=..."); }  //$NON-NLS-1$
+	    case 705 : if (DEBUG) { System.out.println("ReferenceExpressionTypeArgumentsAndTrunk0 ::=..."); }  //$NON-NLS-1$
 			    consumeReferenceExpressionTypeArgumentsAndTrunk(false);  
 				break;
 	 
-	    case 669 : if (DEBUG) { System.out.println("ReferenceExpressionTypeArgumentsAndTrunk0 ::=..."); }  //$NON-NLS-1$
+	    case 706 : if (DEBUG) { System.out.println("ReferenceExpressionTypeArgumentsAndTrunk0 ::=..."); }  //$NON-NLS-1$
 			    consumeReferenceExpressionTypeArgumentsAndTrunk(true);  
 				break;
 	 
-	    case 670 : if (DEBUG) { System.out.println("ReferenceExpression ::= PrimitiveType Dims COLON_COLON"); }  //$NON-NLS-1$
+	    case 707 : if (DEBUG) { System.out.println("ReferenceExpression ::= PrimitiveType Dims COLON_COLON"); }  //$NON-NLS-1$
 			    consumeReferenceExpressionTypeForm(true);  
 				break;
 	 
-	    case 671 : if (DEBUG) { System.out.println("ReferenceExpression ::= Name Dimsopt COLON_COLON..."); }  //$NON-NLS-1$
+	    case 708 : if (DEBUG) { System.out.println("ReferenceExpression ::= Name Dimsopt COLON_COLON..."); }  //$NON-NLS-1$
 			    consumeReferenceExpressionTypeForm(false);  
 				break;
 	 
-	    case 672 : if (DEBUG) { System.out.println("ReferenceExpression ::= Name BeginTypeArguments..."); }  //$NON-NLS-1$
+	    case 709 : if (DEBUG) { System.out.println("ReferenceExpression ::= Name BeginTypeArguments..."); }  //$NON-NLS-1$
 			    consumeReferenceExpressionGenericTypeForm();  
 				break;
 	 
-	    case 673 : if (DEBUG) { System.out.println("ReferenceExpression ::= Primary COLON_COLON..."); }  //$NON-NLS-1$
+	    case 710 : if (DEBUG) { System.out.println("ReferenceExpression ::= Primary COLON_COLON..."); }  //$NON-NLS-1$
 			    consumeReferenceExpressionPrimaryForm();  
 				break;
 	 
-	    case 674 : if (DEBUG) { System.out.println("ReferenceExpression ::= QualifiedSuperReceiver..."); }  //$NON-NLS-1$
+	    case 711 : if (DEBUG) { System.out.println("ReferenceExpression ::= QualifiedSuperReceiver..."); }  //$NON-NLS-1$
 			    consumeReferenceExpressionPrimaryForm();  
 				break;
 	 
-	    case 675 : if (DEBUG) { System.out.println("ReferenceExpression ::= super COLON_COLON..."); }  //$NON-NLS-1$
+	    case 712 : if (DEBUG) { System.out.println("ReferenceExpression ::= super COLON_COLON..."); }  //$NON-NLS-1$
 			    consumeReferenceExpressionSuperForm();  
 				break;
 	 
-	    case 676 : if (DEBUG) { System.out.println("NonWildTypeArgumentsopt ::="); }  //$NON-NLS-1$
+	    case 713 : if (DEBUG) { System.out.println("NonWildTypeArgumentsopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyTypeArguments();  
 				break;
 	 
-	    case 678 : if (DEBUG) { System.out.println("IdentifierOrNew ::= Identifier"); }  //$NON-NLS-1$
+	    case 715 : if (DEBUG) { System.out.println("IdentifierOrNew ::= Identifier"); }  //$NON-NLS-1$
 			    consumeIdentifierOrNew(false);  
 				break;
 	 
-	    case 679 : if (DEBUG) { System.out.println("IdentifierOrNew ::= new"); }  //$NON-NLS-1$
+	    case 716 : if (DEBUG) { System.out.println("IdentifierOrNew ::= new"); }  //$NON-NLS-1$
 			    consumeIdentifierOrNew(true);  
 				break;
 	 
-	    case 680 : if (DEBUG) { System.out.println("LambdaExpression ::= LambdaParameters ARROW LambdaBody"); }  //$NON-NLS-1$
+	    case 717 : if (DEBUG) { System.out.println("LambdaExpression ::= LambdaParameters ARROW LambdaBody"); }  //$NON-NLS-1$
 			    consumeLambdaExpression();  
 				break;
 	 
-	    case 681 : if (DEBUG) { System.out.println("NestedLambda ::="); }  //$NON-NLS-1$
+	    case 718 : if (DEBUG) { System.out.println("NestedLambda ::="); }  //$NON-NLS-1$
 			    consumeNestedLambda();  
 				break;
 	 
-	    case 682 : if (DEBUG) { System.out.println("LambdaParameters ::= Identifier NestedLambda"); }  //$NON-NLS-1$
+	    case 719 : if (DEBUG) { System.out.println("LambdaParameters ::= Identifier NestedLambda"); }  //$NON-NLS-1$
 			    consumeTypeElidedLambdaParameter(false);  
 				break;
 	 
-	    case 688 : if (DEBUG) { System.out.println("TypeElidedFormalParameterList ::=..."); }  //$NON-NLS-1$
+	    case 725 : if (DEBUG) { System.out.println("TypeElidedFormalParameterList ::=..."); }  //$NON-NLS-1$
 			    consumeFormalParameterList();  
 				break;
 	 
-	    case 689 : if (DEBUG) { System.out.println("TypeElidedFormalParameter ::= Modifiersopt Identifier"); }  //$NON-NLS-1$
+	    case 726 : if (DEBUG) { System.out.println("TypeElidedFormalParameter ::= Modifiersopt Identifier"); }  //$NON-NLS-1$
 			    consumeTypeElidedLambdaParameter(true);  
 				break;
 	 
-	    case 692 : if (DEBUG) { System.out.println("ElidedLeftBraceAndReturn ::="); }  //$NON-NLS-1$
+	    case 729 : if (DEBUG) { System.out.println("ElidedLeftBraceAndReturn ::="); }  //$NON-NLS-1$
 			    consumeElidedLeftBraceAndReturn();  
 				break;
 	 
-	    case 693 : if (DEBUG) { System.out.println("AllocationHeader ::= new ClassType LPAREN..."); }  //$NON-NLS-1$
+	    case 730 : if (DEBUG) { System.out.println("AllocationHeader ::= new ClassType LPAREN..."); }  //$NON-NLS-1$
 			    consumeAllocationHeader();  
 				break;
 	 
-	    case 694 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::= new..."); }  //$NON-NLS-1$
+	    case 731 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::= new..."); }  //$NON-NLS-1$
 			    consumeClassInstanceCreationExpressionWithTypeArguments();  
 				break;
 	 
-	    case 695 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::= new ClassType..."); }  //$NON-NLS-1$
+	    case 732 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::= new ClassType..."); }  //$NON-NLS-1$
 			    consumeClassInstanceCreationExpression();  
 				break;
 	 
-	    case 696 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::= Primary DOT new..."); }  //$NON-NLS-1$
+	    case 733 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::= Primary DOT new..."); }  //$NON-NLS-1$
 			    consumeClassInstanceCreationExpressionQualifiedWithTypeArguments() ;  
 				break;
 	 
-	    case 697 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::= Primary DOT new..."); }  //$NON-NLS-1$
+	    case 734 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::= Primary DOT new..."); }  //$NON-NLS-1$
 			    consumeClassInstanceCreationExpressionQualified() ;  
 				break;
 	 
-	    case 698 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::=..."); }  //$NON-NLS-1$
+	    case 735 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::=..."); }  //$NON-NLS-1$
 			    consumeClassInstanceCreationExpressionQualified() ;  
 				break;
 	 
-	    case 699 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::=..."); }  //$NON-NLS-1$
+	    case 736 : if (DEBUG) { System.out.println("ClassInstanceCreationExpression ::=..."); }  //$NON-NLS-1$
 			    consumeClassInstanceCreationExpressionQualifiedWithTypeArguments() ;  
 				break;
 	 
-	    case 700 : if (DEBUG) { System.out.println("EnterInstanceCreationArgumentList ::="); }  //$NON-NLS-1$
+	    case 737 : if (DEBUG) { System.out.println("EnterInstanceCreationArgumentList ::="); }  //$NON-NLS-1$
 			    consumeEnterInstanceCreationArgumentList();  
 				break;
 	 
-	    case 701 : if (DEBUG) { System.out.println("ClassInstanceCreationExpressionName ::= Name DOT new"); }  //$NON-NLS-1$
+	    case 738 : if (DEBUG) { System.out.println("ClassInstanceCreationExpressionName ::= Name DOT new"); }  //$NON-NLS-1$
 			    consumeClassInstanceCreationExpressionName() ;  
 				break;
 	 
-	    case 702 : if (DEBUG) { System.out.println("UnqualifiedClassBodyopt ::="); }  //$NON-NLS-1$
+	    case 739 : if (DEBUG) { System.out.println("UnqualifiedClassBodyopt ::="); }  //$NON-NLS-1$
 			    consumeClassBodyopt();  
 				break;
 	 
-	    case 704 : if (DEBUG) { System.out.println("UnqualifiedEnterAnonymousClassBody ::="); }  //$NON-NLS-1$
+	    case 741 : if (DEBUG) { System.out.println("UnqualifiedEnterAnonymousClassBody ::="); }  //$NON-NLS-1$
 			    consumeEnterAnonymousClassBody(false);  
 				break;
 	 
-	    case 705 : if (DEBUG) { System.out.println("QualifiedClassBodyopt ::="); }  //$NON-NLS-1$
+	    case 742 : if (DEBUG) { System.out.println("QualifiedClassBodyopt ::="); }  //$NON-NLS-1$
 			    consumeClassBodyopt();  
 				break;
 	 
-	    case 707 : if (DEBUG) { System.out.println("QualifiedEnterAnonymousClassBody ::="); }  //$NON-NLS-1$
+	    case 744 : if (DEBUG) { System.out.println("QualifiedEnterAnonymousClassBody ::="); }  //$NON-NLS-1$
 			    consumeEnterAnonymousClassBody(true);  
 				break;
 	 
-	    case 709 : if (DEBUG) { System.out.println("ArgumentList ::= ArgumentList COMMA Expression"); }  //$NON-NLS-1$
+	    case 746 : if (DEBUG) { System.out.println("ArgumentList ::= ArgumentList COMMA Expression"); }  //$NON-NLS-1$
 			    consumeArgumentList();  
 				break;
 	 
-	    case 710 : if (DEBUG) { System.out.println("ArrayCreationHeader ::= new PrimitiveType..."); }  //$NON-NLS-1$
+	    case 747 : if (DEBUG) { System.out.println("ArrayCreationHeader ::= new PrimitiveType..."); }  //$NON-NLS-1$
 			    consumeArrayCreationHeader();  
 				break;
 	 
-	    case 711 : if (DEBUG) { System.out.println("ArrayCreationHeader ::= new ClassOrInterfaceType..."); }  //$NON-NLS-1$
+	    case 748 : if (DEBUG) { System.out.println("ArrayCreationHeader ::= new ClassOrInterfaceType..."); }  //$NON-NLS-1$
 			    consumeArrayCreationHeader();  
 				break;
 	 
-	    case 712 : if (DEBUG) { System.out.println("ArrayCreationWithoutArrayInitializer ::= new..."); }  //$NON-NLS-1$
+	    case 749 : if (DEBUG) { System.out.println("ArrayCreationWithoutArrayInitializer ::= new..."); }  //$NON-NLS-1$
 			    consumeArrayCreationExpressionWithoutInitializer();  
 				break;
 	 
-	    case 713 : if (DEBUG) { System.out.println("ArrayCreationWithArrayInitializer ::= new PrimitiveType"); }  //$NON-NLS-1$
+	    case 750 : if (DEBUG) { System.out.println("ArrayCreationWithArrayInitializer ::= new PrimitiveType"); }  //$NON-NLS-1$
 			    consumeArrayCreationExpressionWithInitializer();  
 				break;
 	 
-	    case 714 : if (DEBUG) { System.out.println("ArrayCreationWithoutArrayInitializer ::= new..."); }  //$NON-NLS-1$
+	    case 751 : if (DEBUG) { System.out.println("ArrayCreationWithoutArrayInitializer ::= new..."); }  //$NON-NLS-1$
 			    consumeArrayCreationExpressionWithoutInitializer();  
 				break;
 	 
-	    case 715 : if (DEBUG) { System.out.println("ArrayCreationWithArrayInitializer ::= new..."); }  //$NON-NLS-1$
+	    case 752 : if (DEBUG) { System.out.println("ArrayCreationWithArrayInitializer ::= new..."); }  //$NON-NLS-1$
 			    consumeArrayCreationExpressionWithInitializer();  
 				break;
 	 
-	    case 717 : if (DEBUG) { System.out.println("DimWithOrWithOutExprs ::= DimWithOrWithOutExprs..."); }  //$NON-NLS-1$
+	    case 754 : if (DEBUG) { System.out.println("DimWithOrWithOutExprs ::= DimWithOrWithOutExprs..."); }  //$NON-NLS-1$
 			    consumeDimWithOrWithOutExprs();  
 				break;
 	 
-	     case 719 : if (DEBUG) { System.out.println("DimWithOrWithOutExpr ::= TypeAnnotationsopt LBRACKET..."); }  //$NON-NLS-1$
+	     case 756 : if (DEBUG) { System.out.println("DimWithOrWithOutExpr ::= TypeAnnotationsopt LBRACKET..."); }  //$NON-NLS-1$
 			    consumeDimWithOrWithOutExpr();  
 				break;
 	 
-	     case 720 : if (DEBUG) { System.out.println("Dims ::= DimsLoop"); }  //$NON-NLS-1$
+	     case 757 : if (DEBUG) { System.out.println("Dims ::= DimsLoop"); }  //$NON-NLS-1$
 			    consumeDims();  
 				break;
 	 
-	     case 723 : if (DEBUG) { System.out.println("OneDimLoop ::= LBRACKET RBRACKET"); }  //$NON-NLS-1$
+	     case 760 : if (DEBUG) { System.out.println("OneDimLoop ::= LBRACKET RBRACKET"); }  //$NON-NLS-1$
 			    consumeOneDimLoop(false);  
 				break;
 	 
-	     case 724 : if (DEBUG) { System.out.println("OneDimLoop ::= TypeAnnotations LBRACKET RBRACKET"); }  //$NON-NLS-1$
+	     case 761 : if (DEBUG) { System.out.println("OneDimLoop ::= TypeAnnotations LBRACKET RBRACKET"); }  //$NON-NLS-1$
 			    consumeOneDimLoop(true);  
 				break;
 	 
-	    case 725 : if (DEBUG) { System.out.println("FieldAccess ::= Primary DOT JavaIdentifier"); }  //$NON-NLS-1$
+	    case 762 : if (DEBUG) { System.out.println("FieldAccess ::= Primary DOT JavaIdentifier"); }  //$NON-NLS-1$
 			    consumeFieldAccess(false);  
 				break;
 	 
-	    case 726 : if (DEBUG) { System.out.println("FieldAccess ::= super DOT JavaIdentifier"); }  //$NON-NLS-1$
+	    case 763 : if (DEBUG) { System.out.println("FieldAccess ::= super DOT JavaIdentifier"); }  //$NON-NLS-1$
 			    consumeFieldAccess(true);  
 				break;
 	 
-	    case 727 : if (DEBUG) { System.out.println("FieldAccess ::= QualifiedSuperReceiver DOT..."); }  //$NON-NLS-1$
+	    case 764 : if (DEBUG) { System.out.println("FieldAccess ::= QualifiedSuperReceiver DOT..."); }  //$NON-NLS-1$
 			    consumeFieldAccess(false);  
 				break;
 	 
-	    case 728 : if (DEBUG) { System.out.println("MethodInvocation ::= NameOrAj LPAREN ArgumentListopt..."); }  //$NON-NLS-1$
+	    case 765 : if (DEBUG) { System.out.println("MethodInvocation ::= NameOrAj LPAREN ArgumentListopt..."); }  //$NON-NLS-1$
 			    consumeMethodInvocationName();  
 				break;
 	 
-	    case 729 : if (DEBUG) { System.out.println("MethodInvocation ::= Name DOT OnlyTypeArguments..."); }  //$NON-NLS-1$
+	    case 766 : if (DEBUG) { System.out.println("MethodInvocation ::= Name DOT OnlyTypeArguments..."); }  //$NON-NLS-1$
 			    consumeMethodInvocationNameWithTypeArguments();  
 				break;
 	 
-	    case 730 : if (DEBUG) { System.out.println("MethodInvocation ::= Primary DOT OnlyTypeArguments..."); }  //$NON-NLS-1$
+	    case 767 : if (DEBUG) { System.out.println("MethodInvocation ::= Primary DOT OnlyTypeArguments..."); }  //$NON-NLS-1$
 			    consumeMethodInvocationPrimaryWithTypeArguments();  
 				break;
 	 
-	    case 731 : if (DEBUG) { System.out.println("MethodInvocation ::= Primary DOT JavaIdentifier LPAREN"); }  //$NON-NLS-1$
+	    case 768 : if (DEBUG) { System.out.println("MethodInvocation ::= Primary DOT JavaIdentifier LPAREN"); }  //$NON-NLS-1$
 			    consumeMethodInvocationPrimary();  
 				break;
 	 
-	    case 732 : if (DEBUG) { System.out.println("MethodInvocation ::= QualifiedSuperReceiver DOT..."); }  //$NON-NLS-1$
+	    case 769 : if (DEBUG) { System.out.println("MethodInvocation ::= QualifiedSuperReceiver DOT..."); }  //$NON-NLS-1$
 			    consumeMethodInvocationPrimary();  
 				break;
 	 
-	    case 733 : if (DEBUG) { System.out.println("MethodInvocation ::= QualifiedSuperReceiver DOT..."); }  //$NON-NLS-1$
+	    case 770 : if (DEBUG) { System.out.println("MethodInvocation ::= QualifiedSuperReceiver DOT..."); }  //$NON-NLS-1$
 			    consumeMethodInvocationPrimaryWithTypeArguments();  
 				break;
 	 
-	    case 734 : if (DEBUG) { System.out.println("MethodInvocation ::= super DOT OnlyTypeArguments..."); }  //$NON-NLS-1$
+	    case 771 : if (DEBUG) { System.out.println("MethodInvocation ::= super DOT OnlyTypeArguments..."); }  //$NON-NLS-1$
 			    consumeMethodInvocationSuperWithTypeArguments();  
 				break;
 	 
-	    case 735 : if (DEBUG) { System.out.println("MethodInvocation ::= super DOT JavaIdentifier LPAREN..."); }  //$NON-NLS-1$
+	    case 772 : if (DEBUG) { System.out.println("MethodInvocation ::= super DOT JavaIdentifier LPAREN..."); }  //$NON-NLS-1$
 			    consumeMethodInvocationSuper();  
 				break;
 	 
-	    case 736 : if (DEBUG) { System.out.println("ArrayAccess ::= Name LBRACKET Expression RBRACKET"); }  //$NON-NLS-1$
+	    case 773 : if (DEBUG) { System.out.println("ArrayAccess ::= Name LBRACKET Expression RBRACKET"); }  //$NON-NLS-1$
 			    consumeArrayAccess(true);  
 				break;
 	 
-	    case 737 : if (DEBUG) { System.out.println("ArrayAccess ::= AjName LBRACKET Expression RBRACKET"); }  //$NON-NLS-1$
+	    case 774 : if (DEBUG) { System.out.println("ArrayAccess ::= AjName LBRACKET Expression RBRACKET"); }  //$NON-NLS-1$
 			    consumeArrayAccess(true);  
 				break;
 	 
-	    case 738 : if (DEBUG) { System.out.println("ArrayAccess ::= PrimaryNoNewArray LBRACKET Expression..."); }  //$NON-NLS-1$
+	    case 775 : if (DEBUG) { System.out.println("ArrayAccess ::= PrimaryNoNewArray LBRACKET Expression..."); }  //$NON-NLS-1$
 			    consumeArrayAccess(false);  
 				break;
 	 
-	    case 739 : if (DEBUG) { System.out.println("ArrayAccess ::= ArrayCreationWithArrayInitializer..."); }  //$NON-NLS-1$
+	    case 776 : if (DEBUG) { System.out.println("ArrayAccess ::= ArrayCreationWithArrayInitializer..."); }  //$NON-NLS-1$
 			    consumeArrayAccess(false);  
 				break;
 	 
-	    case 741 : if (DEBUG) { System.out.println("PostfixExpression ::= NameOrAj"); }  //$NON-NLS-1$
+	    case 778 : if (DEBUG) { System.out.println("PostfixExpression ::= NameOrAj"); }  //$NON-NLS-1$
 			    consumePostfixExpression();  
 				break;
 	 
-	    case 744 : if (DEBUG) { System.out.println("PostIncrementExpression ::= PostfixExpression PLUS_PLUS"); }  //$NON-NLS-1$
+	    case 781 : if (DEBUG) { System.out.println("PostIncrementExpression ::= PostfixExpression PLUS_PLUS"); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.PLUS,true);  
 				break;
 	 
-	    case 745 : if (DEBUG) { System.out.println("PostDecrementExpression ::= PostfixExpression..."); }  //$NON-NLS-1$
+	    case 782 : if (DEBUG) { System.out.println("PostDecrementExpression ::= PostfixExpression..."); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.MINUS,true);  
 				break;
 	 
-	    case 746 : if (DEBUG) { System.out.println("PushPosition ::="); }  //$NON-NLS-1$
+	    case 783 : if (DEBUG) { System.out.println("PushPosition ::="); }  //$NON-NLS-1$
 			    consumePushPosition();  
 				break;
 	 
-	    case 749 : if (DEBUG) { System.out.println("UnaryExpression ::= PLUS PushPosition UnaryExpression"); }  //$NON-NLS-1$
+	    case 786 : if (DEBUG) { System.out.println("UnaryExpression ::= PLUS PushPosition UnaryExpression"); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.PLUS);  
 				break;
 	 
-	    case 750 : if (DEBUG) { System.out.println("UnaryExpression ::= MINUS PushPosition UnaryExpression"); }  //$NON-NLS-1$
+	    case 787 : if (DEBUG) { System.out.println("UnaryExpression ::= MINUS PushPosition UnaryExpression"); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.MINUS);  
 				break;
 	 
-	    case 752 : if (DEBUG) { System.out.println("PreIncrementExpression ::= PLUS_PLUS PushPosition..."); }  //$NON-NLS-1$
+	    case 789 : if (DEBUG) { System.out.println("PreIncrementExpression ::= PLUS_PLUS PushPosition..."); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.PLUS,false);  
 				break;
 	 
-	    case 753 : if (DEBUG) { System.out.println("PreDecrementExpression ::= MINUS_MINUS PushPosition..."); }  //$NON-NLS-1$
+	    case 790 : if (DEBUG) { System.out.println("PreDecrementExpression ::= MINUS_MINUS PushPosition..."); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.MINUS,false);  
 				break;
 	 
-	    case 755 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus ::= TWIDDLE PushPosition..."); }  //$NON-NLS-1$
+	    case 792 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus ::= TWIDDLE PushPosition..."); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.TWIDDLE);  
 				break;
 	 
-	    case 756 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus ::= NOT PushPosition..."); }  //$NON-NLS-1$
+	    case 793 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus ::= NOT PushPosition..."); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.NOT);  
 				break;
 	 
-	    case 758 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN PrimitiveType Dimsopt..."); }  //$NON-NLS-1$
+	    case 795 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN PrimitiveType Dimsopt..."); }  //$NON-NLS-1$
 			    consumeCastExpressionWithPrimitiveType();  
 				break;
 	 
-	    case 759 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name..."); }  //$NON-NLS-1$
+	    case 796 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name..."); }  //$NON-NLS-1$
 			    consumeCastExpressionWithGenericsArray();  
 				break;
 	 
-	    case 760 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name..."); }  //$NON-NLS-1$
+	    case 797 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name..."); }  //$NON-NLS-1$
 			    consumeCastExpressionWithQualifiedGenericsArray();  
 				break;
 	 
-	    case 761 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name PushRPAREN..."); }  //$NON-NLS-1$
+	    case 798 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name PushRPAREN..."); }  //$NON-NLS-1$
 			    consumeCastExpressionLL1();  
 				break;
 	 
-	    case 762 : if (DEBUG) { System.out.println("CastExpression ::= BeginIntersectionCast PushLPAREN..."); }  //$NON-NLS-1$
+	    case 799 : if (DEBUG) { System.out.println("CastExpression ::= BeginIntersectionCast PushLPAREN..."); }  //$NON-NLS-1$
 			    consumeCastExpressionLL1WithBounds();  
 				break;
 	 
-	    case 763 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name Dims..."); }  //$NON-NLS-1$
+	    case 800 : if (DEBUG) { System.out.println("CastExpression ::= PushLPAREN Name Dims..."); }  //$NON-NLS-1$
 			    consumeCastExpressionWithNameArray();  
 				break;
 	 
-	    case 764 : if (DEBUG) { System.out.println("AdditionalBoundsListOpt ::="); }  //$NON-NLS-1$
+	    case 801 : if (DEBUG) { System.out.println("AdditionalBoundsListOpt ::="); }  //$NON-NLS-1$
 			    consumeZeroAdditionalBounds();  
 				break;
 	 
-	    case 768 : if (DEBUG) { System.out.println("OnlyTypeArgumentsForCastExpression ::= OnlyTypeArguments"); }  //$NON-NLS-1$
+	    case 805 : if (DEBUG) { System.out.println("OnlyTypeArgumentsForCastExpression ::= OnlyTypeArguments"); }  //$NON-NLS-1$
 			    consumeOnlyTypeArgumentsForCastExpression();  
 				break;
 	 
-	    case 769 : if (DEBUG) { System.out.println("InsideCastExpression ::="); }  //$NON-NLS-1$
+	    case 806 : if (DEBUG) { System.out.println("InsideCastExpression ::="); }  //$NON-NLS-1$
 			    consumeInsideCastExpression();  
 				break;
 	 
-	    case 770 : if (DEBUG) { System.out.println("InsideCastExpressionLL1 ::="); }  //$NON-NLS-1$
+	    case 807 : if (DEBUG) { System.out.println("InsideCastExpressionLL1 ::="); }  //$NON-NLS-1$
 			    consumeInsideCastExpressionLL1();  
 				break;
 	 
-	    case 771 : if (DEBUG) { System.out.println("InsideCastExpressionLL1WithBounds ::="); }  //$NON-NLS-1$
+	    case 808 : if (DEBUG) { System.out.println("InsideCastExpressionLL1WithBounds ::="); }  //$NON-NLS-1$
 			    consumeInsideCastExpressionLL1WithBounds ();  
 				break;
 	 
-	    case 772 : if (DEBUG) { System.out.println("InsideCastExpressionWithQualifiedGenerics ::="); }  //$NON-NLS-1$
+	    case 809 : if (DEBUG) { System.out.println("InsideCastExpressionWithQualifiedGenerics ::="); }  //$NON-NLS-1$
 			    consumeInsideCastExpressionWithQualifiedGenerics();  
 				break;
 	 
-	    case 774 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); }  //$NON-NLS-1$
+	    case 811 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.MULTIPLY);  
 				break;
 	 
-	    case 775 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); }  //$NON-NLS-1$
+	    case 812 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.DIVIDE);  
 				break;
 	 
-	    case 776 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); }  //$NON-NLS-1$
+	    case 813 : if (DEBUG) { System.out.println("MultiplicativeExpression ::= MultiplicativeExpression..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.REMAINDER);  
 				break;
 	 
-	    case 778 : if (DEBUG) { System.out.println("AdditiveExpression ::= AdditiveExpression PLUS..."); }  //$NON-NLS-1$
+	    case 815 : if (DEBUG) { System.out.println("AdditiveExpression ::= AdditiveExpression PLUS..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.PLUS);  
 				break;
 	 
-	    case 779 : if (DEBUG) { System.out.println("AdditiveExpression ::= AdditiveExpression MINUS..."); }  //$NON-NLS-1$
+	    case 816 : if (DEBUG) { System.out.println("AdditiveExpression ::= AdditiveExpression MINUS..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.MINUS);  
 				break;
 	 
-	    case 781 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression LEFT_SHIFT..."); }  //$NON-NLS-1$
+	    case 818 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression LEFT_SHIFT..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.LEFT_SHIFT);  
 				break;
 	 
-	    case 782 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression RIGHT_SHIFT..."); }  //$NON-NLS-1$
+	    case 819 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression RIGHT_SHIFT..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.RIGHT_SHIFT);  
 				break;
 	 
-	    case 783 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression UNSIGNED_RIGHT_SHIFT"); }  //$NON-NLS-1$
+	    case 820 : if (DEBUG) { System.out.println("ShiftExpression ::= ShiftExpression UNSIGNED_RIGHT_SHIFT"); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.UNSIGNED_RIGHT_SHIFT);  
 				break;
 	 
-	    case 785 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression LESS..."); }  //$NON-NLS-1$
+	    case 822 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression LESS..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.LESS);  
 				break;
 	 
-	    case 786 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression GREATER..."); }  //$NON-NLS-1$
+	    case 823 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression GREATER..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.GREATER);  
 				break;
 	 
-	    case 787 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression LESS_EQUAL"); }  //$NON-NLS-1$
+	    case 824 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression LESS_EQUAL"); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.LESS_EQUAL);  
 				break;
 	 
-	    case 788 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression..."); }  //$NON-NLS-1$
+	    case 825 : if (DEBUG) { System.out.println("RelationalExpression ::= RelationalExpression..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.GREATER_EQUAL);  
 				break;
 	 
-	    case 790 : if (DEBUG) { System.out.println("InstanceofExpression ::= InstanceofExpression instanceof"); }  //$NON-NLS-1$
+	    case 827 : if (DEBUG) { System.out.println("InstanceofExpression ::= InstanceofExpression instanceof"); }  //$NON-NLS-1$
 			    consumeInstanceOfExpression();  
 				break;
 	 
-	    case 792 : if (DEBUG) { System.out.println("EqualityExpression ::= EqualityExpression EQUAL_EQUAL..."); }  //$NON-NLS-1$
+	    case 829 : if (DEBUG) { System.out.println("EqualityExpression ::= EqualityExpression EQUAL_EQUAL..."); }  //$NON-NLS-1$
 			    consumeEqualityExpression(OperatorIds.EQUAL_EQUAL);  
 				break;
 	 
-	    case 793 : if (DEBUG) { System.out.println("EqualityExpression ::= EqualityExpression NOT_EQUAL..."); }  //$NON-NLS-1$
+	    case 830 : if (DEBUG) { System.out.println("EqualityExpression ::= EqualityExpression NOT_EQUAL..."); }  //$NON-NLS-1$
 			    consumeEqualityExpression(OperatorIds.NOT_EQUAL);  
 				break;
 	 
-	    case 795 : if (DEBUG) { System.out.println("AndExpression ::= AndExpression AND EqualityExpression"); }  //$NON-NLS-1$
+	    case 832 : if (DEBUG) { System.out.println("AndExpression ::= AndExpression AND EqualityExpression"); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.AND);  
 				break;
 	 
-	    case 797 : if (DEBUG) { System.out.println("ExclusiveOrExpression ::= ExclusiveOrExpression XOR..."); }  //$NON-NLS-1$
+	    case 834 : if (DEBUG) { System.out.println("ExclusiveOrExpression ::= ExclusiveOrExpression XOR..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.XOR);  
 				break;
 	 
-	    case 799 : if (DEBUG) { System.out.println("InclusiveOrExpression ::= InclusiveOrExpression OR..."); }  //$NON-NLS-1$
+	    case 836 : if (DEBUG) { System.out.println("InclusiveOrExpression ::= InclusiveOrExpression OR..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.OR);  
 				break;
 	 
-	    case 801 : if (DEBUG) { System.out.println("ConditionalAndExpression ::= ConditionalAndExpression..."); }  //$NON-NLS-1$
+	    case 838 : if (DEBUG) { System.out.println("ConditionalAndExpression ::= ConditionalAndExpression..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.AND_AND);  
 				break;
 	 
-	    case 803 : if (DEBUG) { System.out.println("ConditionalOrExpression ::= ConditionalOrExpression..."); }  //$NON-NLS-1$
+	    case 840 : if (DEBUG) { System.out.println("ConditionalOrExpression ::= ConditionalOrExpression..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.OR_OR);  
 				break;
 	 
-	    case 805 : if (DEBUG) { System.out.println("ConditionalExpression ::= ConditionalOrExpression..."); }  //$NON-NLS-1$
+	    case 842 : if (DEBUG) { System.out.println("ConditionalExpression ::= ConditionalOrExpression..."); }  //$NON-NLS-1$
 			    consumeConditionalExpression(OperatorIds.QUESTIONCOLON) ;  
 				break;
 	 
-	    case 808 : if (DEBUG) { System.out.println("Assignment ::= PostfixExpression AssignmentOperator..."); }  //$NON-NLS-1$
+	    case 845 : if (DEBUG) { System.out.println("Assignment ::= PostfixExpression AssignmentOperator..."); }  //$NON-NLS-1$
 			    consumeAssignment();  
 				break;
 	 
-	    case 810 : if (DEBUG) { System.out.println("Assignment ::= InvalidArrayInitializerAssignement"); }  //$NON-NLS-1$
+	    case 847 : if (DEBUG) { System.out.println("Assignment ::= InvalidArrayInitializerAssignement"); }  //$NON-NLS-1$
 			    ignoreExpressionAssignment(); 
 				break;
 	 
-	    case 811 : if (DEBUG) { System.out.println("AssignmentOperator ::= EQUAL"); }  //$NON-NLS-1$
+	    case 848 : if (DEBUG) { System.out.println("AssignmentOperator ::= EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(EQUAL);  
 				break;
 	 
-	    case 812 : if (DEBUG) { System.out.println("AssignmentOperator ::= MULTIPLY_EQUAL"); }  //$NON-NLS-1$
+	    case 849 : if (DEBUG) { System.out.println("AssignmentOperator ::= MULTIPLY_EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(MULTIPLY);  
 				break;
 	 
-	    case 813 : if (DEBUG) { System.out.println("AssignmentOperator ::= DIVIDE_EQUAL"); }  //$NON-NLS-1$
+	    case 850 : if (DEBUG) { System.out.println("AssignmentOperator ::= DIVIDE_EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(DIVIDE);  
 				break;
 	 
-	    case 814 : if (DEBUG) { System.out.println("AssignmentOperator ::= REMAINDER_EQUAL"); }  //$NON-NLS-1$
+	    case 851 : if (DEBUG) { System.out.println("AssignmentOperator ::= REMAINDER_EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(REMAINDER);  
 				break;
 	 
-	    case 815 : if (DEBUG) { System.out.println("AssignmentOperator ::= PLUS_EQUAL"); }  //$NON-NLS-1$
+	    case 852 : if (DEBUG) { System.out.println("AssignmentOperator ::= PLUS_EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(PLUS);  
 				break;
 	 
-	    case 816 : if (DEBUG) { System.out.println("AssignmentOperator ::= MINUS_EQUAL"); }  //$NON-NLS-1$
+	    case 853 : if (DEBUG) { System.out.println("AssignmentOperator ::= MINUS_EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(MINUS);  
 				break;
 	 
-	    case 817 : if (DEBUG) { System.out.println("AssignmentOperator ::= LEFT_SHIFT_EQUAL"); }  //$NON-NLS-1$
+	    case 854 : if (DEBUG) { System.out.println("AssignmentOperator ::= LEFT_SHIFT_EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(LEFT_SHIFT);  
 				break;
 	 
-	    case 818 : if (DEBUG) { System.out.println("AssignmentOperator ::= RIGHT_SHIFT_EQUAL"); }  //$NON-NLS-1$
+	    case 855 : if (DEBUG) { System.out.println("AssignmentOperator ::= RIGHT_SHIFT_EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(RIGHT_SHIFT);  
 				break;
 	 
-	    case 819 : if (DEBUG) { System.out.println("AssignmentOperator ::= UNSIGNED_RIGHT_SHIFT_EQUAL"); }  //$NON-NLS-1$
+	    case 856 : if (DEBUG) { System.out.println("AssignmentOperator ::= UNSIGNED_RIGHT_SHIFT_EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(UNSIGNED_RIGHT_SHIFT);  
 				break;
 	 
-	    case 820 : if (DEBUG) { System.out.println("AssignmentOperator ::= AND_EQUAL"); }  //$NON-NLS-1$
+	    case 857 : if (DEBUG) { System.out.println("AssignmentOperator ::= AND_EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(AND);  
 				break;
 	 
-	    case 821 : if (DEBUG) { System.out.println("AssignmentOperator ::= XOR_EQUAL"); }  //$NON-NLS-1$
+	    case 858 : if (DEBUG) { System.out.println("AssignmentOperator ::= XOR_EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(XOR);  
 				break;
 	 
-	    case 822 : if (DEBUG) { System.out.println("AssignmentOperator ::= OR_EQUAL"); }  //$NON-NLS-1$
+	    case 859 : if (DEBUG) { System.out.println("AssignmentOperator ::= OR_EQUAL"); }  //$NON-NLS-1$
 			    consumeAssignmentOperator(OR);  
 				break;
 	 
-	    case 823 : if (DEBUG) { System.out.println("Expression ::= AssignmentExpression"); }  //$NON-NLS-1$
+	    case 860 : if (DEBUG) { System.out.println("Expression ::= AssignmentExpression"); }  //$NON-NLS-1$
 			    consumeExpression();  
 				break;
 	 
-	    case 826 : if (DEBUG) { System.out.println("Expressionopt ::="); }  //$NON-NLS-1$
+	    case 863 : if (DEBUG) { System.out.println("Expressionopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyExpression();  
 				break;
 	 
-	    case 829 : if (DEBUG) { System.out.println("ConstantExpressions ::= ConstantExpressions COMMA..."); }  //$NON-NLS-1$
+	    case 866 : if (DEBUG) { System.out.println("ConstantExpressions ::= ConstantExpressions COMMA..."); }  //$NON-NLS-1$
 			    consumeConstantExpressions();  
 				break;
 	 
-	    case 833 : if (DEBUG) { System.out.println("ClassBodyDeclarationsopt ::="); }  //$NON-NLS-1$
+	    case 870 : if (DEBUG) { System.out.println("ClassBodyDeclarationsopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyClassBodyDeclarationsopt();  
 				break;
 	 
-	    case 834 : if (DEBUG) { System.out.println("ClassBodyDeclarationsopt ::= NestedType..."); }  //$NON-NLS-1$
+	    case 871 : if (DEBUG) { System.out.println("ClassBodyDeclarationsopt ::= NestedType..."); }  //$NON-NLS-1$
 			    consumeClassBodyDeclarationsopt();  
 				break;
 	 
-	     case 835 : if (DEBUG) { System.out.println("Modifiersopt ::="); }  //$NON-NLS-1$
+	     case 872 : if (DEBUG) { System.out.println("Modifiersopt ::="); }  //$NON-NLS-1$
 			    consumeDefaultModifiers();  
 				break;
 	 
-	    case 836 : if (DEBUG) { System.out.println("Modifiersopt ::= Modifiers"); }  //$NON-NLS-1$
+	    case 873 : if (DEBUG) { System.out.println("Modifiersopt ::= Modifiers"); }  //$NON-NLS-1$
 			    consumeModifiers();  
 				break;
 	 
-	    case 837 : if (DEBUG) { System.out.println("BlockStatementsopt ::="); }  //$NON-NLS-1$
+	    case 874 : if (DEBUG) { System.out.println("BlockStatementsopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyBlockStatementsopt();  
 				break;
 	 
-	     case 839 : if (DEBUG) { System.out.println("Dimsopt ::="); }  //$NON-NLS-1$
+	     case 876 : if (DEBUG) { System.out.println("Dimsopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyDimsopt();  
 				break;
 	 
-	     case 841 : if (DEBUG) { System.out.println("ArgumentListopt ::="); }  //$NON-NLS-1$
+	     case 878 : if (DEBUG) { System.out.println("ArgumentListopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyArgumentListopt();  
 				break;
 	 
-	    case 845 : if (DEBUG) { System.out.println("FormalParameterListopt ::="); }  //$NON-NLS-1$
+	    case 882 : if (DEBUG) { System.out.println("FormalParameterListopt ::="); }  //$NON-NLS-1$
 			    consumeFormalParameterListopt();  
 				break;
 	 
-	     case 849 : if (DEBUG) { System.out.println("InterfaceMemberDeclarationsopt ::="); }  //$NON-NLS-1$
+	     case 886 : if (DEBUG) { System.out.println("InterfaceMemberDeclarationsopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyInterfaceMemberDeclarationsopt();  
 				break;
 	 
-	     case 850 : if (DEBUG) { System.out.println("InterfaceMemberDeclarationsopt ::= NestedType..."); }  //$NON-NLS-1$
+	     case 887 : if (DEBUG) { System.out.println("InterfaceMemberDeclarationsopt ::= NestedType..."); }  //$NON-NLS-1$
 			    consumeInterfaceMemberDeclarationsopt();  
 				break;
 	 
-	    case 851 : if (DEBUG) { System.out.println("NestedType ::="); }  //$NON-NLS-1$
+	    case 888 : if (DEBUG) { System.out.println("NestedType ::="); }  //$NON-NLS-1$
 			    consumeNestedType();  
 				break;
 
-	     case 852 : if (DEBUG) { System.out.println("ForInitopt ::="); }  //$NON-NLS-1$
+	     case 889 : if (DEBUG) { System.out.println("ForInitopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyForInitopt();  
 				break;
 	 
-	     case 854 : if (DEBUG) { System.out.println("ForUpdateopt ::="); }  //$NON-NLS-1$
+	     case 891 : if (DEBUG) { System.out.println("ForUpdateopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyForUpdateopt();  
 				break;
 	 
-	     case 858 : if (DEBUG) { System.out.println("Catchesopt ::="); }  //$NON-NLS-1$
+	     case 895 : if (DEBUG) { System.out.println("Catchesopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyCatchesopt();  
 				break;
 	 
-	     case 860 : if (DEBUG) { System.out.println("EnumDeclaration ::= EnumHeader EnumBody"); }  //$NON-NLS-1$
+	     case 897 : if (DEBUG) { System.out.println("EnumDeclaration ::= EnumHeader EnumBody"); }  //$NON-NLS-1$
 			    consumeEnumDeclaration();  
 				break;
 	 
-	     case 861 : if (DEBUG) { System.out.println("EnumHeader ::= EnumHeaderName ClassHeaderImplementsopt"); }  //$NON-NLS-1$
+	     case 898 : if (DEBUG) { System.out.println("EnumHeader ::= EnumHeaderName ClassHeaderImplementsopt"); }  //$NON-NLS-1$
 			    consumeEnumHeader();  
 				break;
 	 
-	     case 862 : if (DEBUG) { System.out.println("EnumHeaderName ::= Modifiersopt enum JavaIdentifier"); }  //$NON-NLS-1$
+	     case 899 : if (DEBUG) { System.out.println("EnumHeaderName ::= Modifiersopt enum JavaIdentifier"); }  //$NON-NLS-1$
 			    consumeEnumHeaderName();  
 				break;
 	 
-	     case 863 : if (DEBUG) { System.out.println("EnumHeaderName ::= Modifiersopt enum JavaIdentifier..."); }  //$NON-NLS-1$
+	     case 900 : if (DEBUG) { System.out.println("EnumHeaderName ::= Modifiersopt enum JavaIdentifier..."); }  //$NON-NLS-1$
 			    consumeEnumHeaderNameWithTypeParameters();  
 				break;
 	 
-	     case 864 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumBodyDeclarationsopt RBRACE"); }  //$NON-NLS-1$
+	     case 901 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumBodyDeclarationsopt RBRACE"); }  //$NON-NLS-1$
 			    consumeEnumBodyNoConstants();  
 				break;
 	 
-	     case 865 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE COMMA EnumBodyDeclarationsopt..."); }  //$NON-NLS-1$
+	     case 902 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE COMMA EnumBodyDeclarationsopt..."); }  //$NON-NLS-1$
 			    consumeEnumBodyNoConstants();  
 				break;
 	 
-	     case 866 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumConstants COMMA..."); }  //$NON-NLS-1$
+	     case 903 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumConstants COMMA..."); }  //$NON-NLS-1$
 			    consumeEnumBodyWithConstants();  
 				break;
 	 
-	     case 867 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumConstants..."); }  //$NON-NLS-1$
+	     case 904 : if (DEBUG) { System.out.println("EnumBody ::= LBRACE EnumConstants..."); }  //$NON-NLS-1$
 			    consumeEnumBodyWithConstants();  
 				break;
 	 
-	    case 869 : if (DEBUG) { System.out.println("EnumConstants ::= EnumConstants COMMA EnumConstant"); }  //$NON-NLS-1$
+	    case 906 : if (DEBUG) { System.out.println("EnumConstants ::= EnumConstants COMMA EnumConstant"); }  //$NON-NLS-1$
 			    consumeEnumConstants();  
 				break;
 	 
-	    case 870 : if (DEBUG) { System.out.println("EnumConstantHeaderName ::= Modifiersopt Identifier"); }  //$NON-NLS-1$
+	    case 907 : if (DEBUG) { System.out.println("EnumConstantHeaderName ::= Modifiersopt Identifier"); }  //$NON-NLS-1$
 			    consumeEnumConstantHeaderName();  
 				break;
 	 
-	    case 871 : if (DEBUG) { System.out.println("EnumConstantHeader ::= EnumConstantHeaderName..."); }  //$NON-NLS-1$
+	    case 908 : if (DEBUG) { System.out.println("EnumConstantHeader ::= EnumConstantHeaderName..."); }  //$NON-NLS-1$
 			    consumeEnumConstantHeader();  
 				break;
 	 
-	    case 872 : if (DEBUG) { System.out.println("EnumConstant ::= EnumConstantHeader ForceNoDiet..."); }  //$NON-NLS-1$
+	    case 909 : if (DEBUG) { System.out.println("EnumConstant ::= EnumConstantHeader ForceNoDiet..."); }  //$NON-NLS-1$
 			    consumeEnumConstantWithClassBody();  
 				break;
 	 
-	    case 873 : if (DEBUG) { System.out.println("EnumConstant ::= EnumConstantHeader"); }  //$NON-NLS-1$
+	    case 910 : if (DEBUG) { System.out.println("EnumConstant ::= EnumConstantHeader"); }  //$NON-NLS-1$
 			    consumeEnumConstantNoClassBody();  
 				break;
 	 
-	    case 874 : if (DEBUG) { System.out.println("Arguments ::= LPAREN ArgumentListopt RPAREN"); }  //$NON-NLS-1$
+	    case 911 : if (DEBUG) { System.out.println("Arguments ::= LPAREN ArgumentListopt RPAREN"); }  //$NON-NLS-1$
 			    consumeArguments();  
 				break;
 	 
-	    case 875 : if (DEBUG) { System.out.println("Argumentsopt ::="); }  //$NON-NLS-1$
+	    case 912 : if (DEBUG) { System.out.println("Argumentsopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyArguments();  
 				break;
 	 
-	    case 877 : if (DEBUG) { System.out.println("EnumDeclarations ::= SEMICOLON ClassBodyDeclarationsopt"); }  //$NON-NLS-1$
+	    case 914 : if (DEBUG) { System.out.println("EnumDeclarations ::= SEMICOLON ClassBodyDeclarationsopt"); }  //$NON-NLS-1$
 			    consumeEnumDeclarations();  
 				break;
 	 
-	    case 878 : if (DEBUG) { System.out.println("EnumBodyDeclarationsopt ::="); }  //$NON-NLS-1$
+	    case 915 : if (DEBUG) { System.out.println("EnumBodyDeclarationsopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyEnumDeclarations();  
 				break;
 	 
-	    case 880 : if (DEBUG) { System.out.println("EnhancedForStatement ::= EnhancedForStatementHeader..."); }  //$NON-NLS-1$
+	    case 917 : if (DEBUG) { System.out.println("EnhancedForStatement ::= EnhancedForStatementHeader..."); }  //$NON-NLS-1$
 			    consumeEnhancedForStatement();  
 				break;
 	 
-	    case 881 : if (DEBUG) { System.out.println("EnhancedForStatementNoShortIf ::=..."); }  //$NON-NLS-1$
+	    case 918 : if (DEBUG) { System.out.println("EnhancedForStatementNoShortIf ::=..."); }  //$NON-NLS-1$
 			    consumeEnhancedForStatement();  
 				break;
 	 
-	    case 882 : if (DEBUG) { System.out.println("EnhancedForStatementHeaderInit ::= for LPAREN Type..."); }  //$NON-NLS-1$
+	    case 919 : if (DEBUG) { System.out.println("EnhancedForStatementHeaderInit ::= for LPAREN Type..."); }  //$NON-NLS-1$
 			    consumeEnhancedForStatementHeaderInit(false);  
 				break;
 	 
-	    case 883 : if (DEBUG) { System.out.println("EnhancedForStatementHeaderInit ::= for LPAREN Modifiers"); }  //$NON-NLS-1$
+	    case 920 : if (DEBUG) { System.out.println("EnhancedForStatementHeaderInit ::= for LPAREN Modifiers"); }  //$NON-NLS-1$
 			    consumeEnhancedForStatementHeaderInit(true);  
 				break;
 	 
-	    case 884 : if (DEBUG) { System.out.println("EnhancedForStatementHeader ::=..."); }  //$NON-NLS-1$
+	    case 921 : if (DEBUG) { System.out.println("EnhancedForStatementHeader ::=..."); }  //$NON-NLS-1$
 			    consumeEnhancedForStatementHeader();  
 				break;
 	 
-	    case 885 : if (DEBUG) { System.out.println("SingleStaticImportDeclaration ::=..."); }  //$NON-NLS-1$
+	    case 922 : if (DEBUG) { System.out.println("SingleStaticImportDeclaration ::=..."); }  //$NON-NLS-1$
 			    consumeImportDeclaration();  
 				break;
 	 
-	    case 886 : if (DEBUG) { System.out.println("SingleStaticImportDeclarationName ::= import static Name"); }  //$NON-NLS-1$
+	    case 923 : if (DEBUG) { System.out.println("SingleStaticImportDeclarationName ::= import static Name"); }  //$NON-NLS-1$
 			    consumeSingleStaticImportDeclarationName();  
 				break;
 	 
-	    case 887 : if (DEBUG) { System.out.println("StaticImportOnDemandDeclaration ::=..."); }  //$NON-NLS-1$
+	    case 924 : if (DEBUG) { System.out.println("StaticImportOnDemandDeclaration ::=..."); }  //$NON-NLS-1$
 			    consumeImportDeclaration();  
 				break;
 	 
-	    case 888 : if (DEBUG) { System.out.println("StaticImportOnDemandDeclarationName ::= import static..."); }  //$NON-NLS-1$
+	    case 925 : if (DEBUG) { System.out.println("StaticImportOnDemandDeclarationName ::= import static..."); }  //$NON-NLS-1$
 			    consumeStaticImportOnDemandDeclarationName();  
 				break;
 	 
-	    case 889 : if (DEBUG) { System.out.println("TypeArguments ::= LESS TypeArgumentList1"); }  //$NON-NLS-1$
+	    case 926 : if (DEBUG) { System.out.println("TypeArguments ::= LESS TypeArgumentList1"); }  //$NON-NLS-1$
 			    consumeTypeArguments();  
 				break;
 	 
-	    case 890 : if (DEBUG) { System.out.println("OnlyTypeArguments ::= LESS TypeArgumentList1"); }  //$NON-NLS-1$
+	    case 927 : if (DEBUG) { System.out.println("OnlyTypeArguments ::= LESS TypeArgumentList1"); }  //$NON-NLS-1$
 			    consumeOnlyTypeArguments();  
 				break;
 	 
-	    case 892 : if (DEBUG) { System.out.println("TypeArgumentList1 ::= TypeArgumentList COMMA..."); }  //$NON-NLS-1$
+	    case 929 : if (DEBUG) { System.out.println("TypeArgumentList1 ::= TypeArgumentList COMMA..."); }  //$NON-NLS-1$
 			    consumeTypeArgumentList1();  
 				break;
 	 
-	    case 894 : if (DEBUG) { System.out.println("TypeArgumentList ::= TypeArgumentList COMMA TypeArgument"); }  //$NON-NLS-1$
+	    case 931 : if (DEBUG) { System.out.println("TypeArgumentList ::= TypeArgumentList COMMA TypeArgument"); }  //$NON-NLS-1$
 			    consumeTypeArgumentList();  
 				break;
 	 
-	    case 895 : if (DEBUG) { System.out.println("TypeArgument ::= ReferenceType"); }  //$NON-NLS-1$
+	    case 932 : if (DEBUG) { System.out.println("TypeArgument ::= ReferenceType"); }  //$NON-NLS-1$
 			    consumeTypeArgument();  
 				break;
 	 
-	    case 899 : if (DEBUG) { System.out.println("ReferenceType1 ::= ReferenceType GREATER"); }  //$NON-NLS-1$
+	    case 936 : if (DEBUG) { System.out.println("ReferenceType1 ::= ReferenceType GREATER"); }  //$NON-NLS-1$
 			    consumeReferenceType1();  
 				break;
 	 
-	    case 900 : if (DEBUG) { System.out.println("ReferenceType1 ::= ClassOrInterface LESS..."); }  //$NON-NLS-1$
+	    case 937 : if (DEBUG) { System.out.println("ReferenceType1 ::= ClassOrInterface LESS..."); }  //$NON-NLS-1$
 			    consumeTypeArgumentReferenceType1();  
 				break;
 	 
-	    case 902 : if (DEBUG) { System.out.println("TypeArgumentList2 ::= TypeArgumentList COMMA..."); }  //$NON-NLS-1$
+	    case 939 : if (DEBUG) { System.out.println("TypeArgumentList2 ::= TypeArgumentList COMMA..."); }  //$NON-NLS-1$
 			    consumeTypeArgumentList2();  
 				break;
 	 
-	    case 905 : if (DEBUG) { System.out.println("ReferenceType2 ::= ReferenceType RIGHT_SHIFT"); }  //$NON-NLS-1$
+	    case 942 : if (DEBUG) { System.out.println("ReferenceType2 ::= ReferenceType RIGHT_SHIFT"); }  //$NON-NLS-1$
 			    consumeReferenceType2();  
 				break;
 	 
-	    case 906 : if (DEBUG) { System.out.println("ReferenceType2 ::= ClassOrInterface LESS..."); }  //$NON-NLS-1$
+	    case 943 : if (DEBUG) { System.out.println("ReferenceType2 ::= ClassOrInterface LESS..."); }  //$NON-NLS-1$
 			    consumeTypeArgumentReferenceType2();  
 				break;
 	 
-	    case 908 : if (DEBUG) { System.out.println("TypeArgumentList3 ::= TypeArgumentList COMMA..."); }  //$NON-NLS-1$
+	    case 945 : if (DEBUG) { System.out.println("TypeArgumentList3 ::= TypeArgumentList COMMA..."); }  //$NON-NLS-1$
 			    consumeTypeArgumentList3();  
 				break;
 	 
-	    case 911 : if (DEBUG) { System.out.println("ReferenceType3 ::= ReferenceType UNSIGNED_RIGHT_SHIFT"); }  //$NON-NLS-1$
+	    case 948 : if (DEBUG) { System.out.println("ReferenceType3 ::= ReferenceType UNSIGNED_RIGHT_SHIFT"); }  //$NON-NLS-1$
 			    consumeReferenceType3();  
 				break;
 	 
-	    case 912 : if (DEBUG) { System.out.println("Wildcard ::= TypeAnnotationsopt QUESTION"); }  //$NON-NLS-1$
+	    case 949 : if (DEBUG) { System.out.println("Wildcard ::= TypeAnnotationsopt QUESTION"); }  //$NON-NLS-1$
 			    consumeWildcard();  
 				break;
 	 
-	    case 913 : if (DEBUG) { System.out.println("Wildcard ::= TypeAnnotationsopt QUESTION WildcardBounds"); }  //$NON-NLS-1$
+	    case 950 : if (DEBUG) { System.out.println("Wildcard ::= TypeAnnotationsopt QUESTION WildcardBounds"); }  //$NON-NLS-1$
 			    consumeWildcardWithBounds();  
 				break;
 	 
-	    case 914 : if (DEBUG) { System.out.println("WildcardBounds ::= extends ReferenceType"); }  //$NON-NLS-1$
+	    case 951 : if (DEBUG) { System.out.println("WildcardBounds ::= extends ReferenceType"); }  //$NON-NLS-1$
 			    consumeWildcardBoundsExtends();  
 				break;
 	 
-	    case 915 : if (DEBUG) { System.out.println("WildcardBounds ::= super ReferenceType"); }  //$NON-NLS-1$
+	    case 952 : if (DEBUG) { System.out.println("WildcardBounds ::= super ReferenceType"); }  //$NON-NLS-1$
 			    consumeWildcardBoundsSuper();  
 				break;
 	 
-	    case 916 : if (DEBUG) { System.out.println("Wildcard1 ::= TypeAnnotationsopt QUESTION GREATER"); }  //$NON-NLS-1$
+	    case 953 : if (DEBUG) { System.out.println("Wildcard1 ::= TypeAnnotationsopt QUESTION GREATER"); }  //$NON-NLS-1$
 			    consumeWildcard1();  
 				break;
 	 
-	    case 917 : if (DEBUG) { System.out.println("Wildcard1 ::= TypeAnnotationsopt QUESTION..."); }  //$NON-NLS-1$
+	    case 954 : if (DEBUG) { System.out.println("Wildcard1 ::= TypeAnnotationsopt QUESTION..."); }  //$NON-NLS-1$
 			    consumeWildcard1WithBounds();  
 				break;
 	 
-	    case 918 : if (DEBUG) { System.out.println("WildcardBounds1 ::= extends ReferenceType1"); }  //$NON-NLS-1$
+	    case 955 : if (DEBUG) { System.out.println("WildcardBounds1 ::= extends ReferenceType1"); }  //$NON-NLS-1$
 			    consumeWildcardBounds1Extends();  
 				break;
 	 
-	    case 919 : if (DEBUG) { System.out.println("WildcardBounds1 ::= super ReferenceType1"); }  //$NON-NLS-1$
+	    case 956 : if (DEBUG) { System.out.println("WildcardBounds1 ::= super ReferenceType1"); }  //$NON-NLS-1$
 			    consumeWildcardBounds1Super();  
 				break;
 	 
-	    case 920 : if (DEBUG) { System.out.println("Wildcard2 ::= TypeAnnotationsopt QUESTION RIGHT_SHIFT"); }  //$NON-NLS-1$
+	    case 957 : if (DEBUG) { System.out.println("Wildcard2 ::= TypeAnnotationsopt QUESTION RIGHT_SHIFT"); }  //$NON-NLS-1$
 			    consumeWildcard2();  
 				break;
 	 
-	    case 921 : if (DEBUG) { System.out.println("Wildcard2 ::= TypeAnnotationsopt QUESTION..."); }  //$NON-NLS-1$
+	    case 958 : if (DEBUG) { System.out.println("Wildcard2 ::= TypeAnnotationsopt QUESTION..."); }  //$NON-NLS-1$
 			    consumeWildcard2WithBounds();  
 				break;
 	 
-	    case 922 : if (DEBUG) { System.out.println("WildcardBounds2 ::= extends ReferenceType2"); }  //$NON-NLS-1$
+	    case 959 : if (DEBUG) { System.out.println("WildcardBounds2 ::= extends ReferenceType2"); }  //$NON-NLS-1$
 			    consumeWildcardBounds2Extends();  
 				break;
 	 
-	    case 923 : if (DEBUG) { System.out.println("WildcardBounds2 ::= super ReferenceType2"); }  //$NON-NLS-1$
+	    case 960 : if (DEBUG) { System.out.println("WildcardBounds2 ::= super ReferenceType2"); }  //$NON-NLS-1$
 			    consumeWildcardBounds2Super();  
 				break;
 	 
-	    case 924 : if (DEBUG) { System.out.println("Wildcard3 ::= TypeAnnotationsopt QUESTION..."); }  //$NON-NLS-1$
+	    case 961 : if (DEBUG) { System.out.println("Wildcard3 ::= TypeAnnotationsopt QUESTION..."); }  //$NON-NLS-1$
 			    consumeWildcard3();  
 				break;
 	 
-	    case 925 : if (DEBUG) { System.out.println("Wildcard3 ::= TypeAnnotationsopt QUESTION..."); }  //$NON-NLS-1$
+	    case 962 : if (DEBUG) { System.out.println("Wildcard3 ::= TypeAnnotationsopt QUESTION..."); }  //$NON-NLS-1$
 			    consumeWildcard3WithBounds();  
 				break;
 	 
-	    case 926 : if (DEBUG) { System.out.println("WildcardBounds3 ::= extends ReferenceType3"); }  //$NON-NLS-1$
+	    case 963 : if (DEBUG) { System.out.println("WildcardBounds3 ::= extends ReferenceType3"); }  //$NON-NLS-1$
 			    consumeWildcardBounds3Extends();  
 				break;
 	 
-	    case 927 : if (DEBUG) { System.out.println("WildcardBounds3 ::= super ReferenceType3"); }  //$NON-NLS-1$
+	    case 964 : if (DEBUG) { System.out.println("WildcardBounds3 ::= super ReferenceType3"); }  //$NON-NLS-1$
 			    consumeWildcardBounds3Super();  
 				break;
 	 
-	    case 928 : if (DEBUG) { System.out.println("TypeParameterHeader ::= TypeAnnotationsopt..."); }  //$NON-NLS-1$
+	    case 965 : if (DEBUG) { System.out.println("TypeParameterHeader ::= TypeAnnotationsopt..."); }  //$NON-NLS-1$
 			    consumeTypeParameterHeader();  
 				break;
 	 
-	    case 929 : if (DEBUG) { System.out.println("TypeParameters ::= LESS TypeParameterList1"); }  //$NON-NLS-1$
+	    case 966 : if (DEBUG) { System.out.println("TypeParameters ::= LESS TypeParameterList1"); }  //$NON-NLS-1$
 			    consumeTypeParameters();  
 				break;
 	 
-	    case 931 : if (DEBUG) { System.out.println("TypeParameterList ::= TypeParameterList COMMA..."); }  //$NON-NLS-1$
+	    case 968 : if (DEBUG) { System.out.println("TypeParameterList ::= TypeParameterList COMMA..."); }  //$NON-NLS-1$
 			    consumeTypeParameterList();  
 				break;
 	 
-	    case 933 : if (DEBUG) { System.out.println("TypeParameter ::= TypeParameterHeader extends..."); }  //$NON-NLS-1$
+	    case 970 : if (DEBUG) { System.out.println("TypeParameter ::= TypeParameterHeader extends..."); }  //$NON-NLS-1$
 			    consumeTypeParameterWithExtends();  
 				break;
 	 
-	    case 934 : if (DEBUG) { System.out.println("TypeParameter ::= TypeParameterHeader extends..."); }  //$NON-NLS-1$
+	    case 971 : if (DEBUG) { System.out.println("TypeParameter ::= TypeParameterHeader extends..."); }  //$NON-NLS-1$
 			    consumeTypeParameterWithExtendsAndBounds();  
 				break;
 	 
-	    case 936 : if (DEBUG) { System.out.println("AdditionalBoundList ::= AdditionalBoundList..."); }  //$NON-NLS-1$
+	    case 973 : if (DEBUG) { System.out.println("AdditionalBoundList ::= AdditionalBoundList..."); }  //$NON-NLS-1$
 			    consumeAdditionalBoundList();  
 				break;
 	 
-	    case 937 : if (DEBUG) { System.out.println("AdditionalBound ::= AND ReferenceType"); }  //$NON-NLS-1$
+	    case 974 : if (DEBUG) { System.out.println("AdditionalBound ::= AND ReferenceType"); }  //$NON-NLS-1$
 			    consumeAdditionalBound();  
 				break;
 	 
-	    case 939 : if (DEBUG) { System.out.println("TypeParameterList1 ::= TypeParameterList COMMA..."); }  //$NON-NLS-1$
+	    case 976 : if (DEBUG) { System.out.println("TypeParameterList1 ::= TypeParameterList COMMA..."); }  //$NON-NLS-1$
 			    consumeTypeParameterList1();  
 				break;
 	 
-	    case 940 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader GREATER"); }  //$NON-NLS-1$
+	    case 977 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader GREATER"); }  //$NON-NLS-1$
 			    consumeTypeParameter1();  
 				break;
 	 
-	    case 941 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader extends..."); }  //$NON-NLS-1$
+	    case 978 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader extends..."); }  //$NON-NLS-1$
 			    consumeTypeParameter1WithExtends();  
 				break;
 	 
-	    case 942 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader extends..."); }  //$NON-NLS-1$
+	    case 979 : if (DEBUG) { System.out.println("TypeParameter1 ::= TypeParameterHeader extends..."); }  //$NON-NLS-1$
 			    consumeTypeParameter1WithExtendsAndBounds();  
 				break;
 	 
-	    case 944 : if (DEBUG) { System.out.println("AdditionalBoundList1 ::= AdditionalBoundList..."); }  //$NON-NLS-1$
+	    case 981 : if (DEBUG) { System.out.println("AdditionalBoundList1 ::= AdditionalBoundList..."); }  //$NON-NLS-1$
 			    consumeAdditionalBoundList1();  
 				break;
 	 
-	    case 945 : if (DEBUG) { System.out.println("AdditionalBound1 ::= AND ReferenceType1"); }  //$NON-NLS-1$
+	    case 982 : if (DEBUG) { System.out.println("AdditionalBound1 ::= AND ReferenceType1"); }  //$NON-NLS-1$
 			    consumeAdditionalBound1();  
 				break;
 	 
-	    case 951 : if (DEBUG) { System.out.println("UnaryExpression_NotName ::= PLUS PushPosition..."); }  //$NON-NLS-1$
+	    case 988 : if (DEBUG) { System.out.println("UnaryExpression_NotName ::= PLUS PushPosition..."); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.PLUS);  
 				break;
 	 
-	    case 952 : if (DEBUG) { System.out.println("UnaryExpression_NotName ::= MINUS PushPosition..."); }  //$NON-NLS-1$
+	    case 989 : if (DEBUG) { System.out.println("UnaryExpression_NotName ::= MINUS PushPosition..."); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.MINUS);  
 				break;
 	 
-	    case 955 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus_NotName ::= TWIDDLE..."); }  //$NON-NLS-1$
+	    case 992 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus_NotName ::= TWIDDLE..."); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.TWIDDLE);  
 				break;
 	 
-	    case 956 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus_NotName ::= NOT PushPosition"); }  //$NON-NLS-1$
+	    case 993 : if (DEBUG) { System.out.println("UnaryExpressionNotPlusMinus_NotName ::= NOT PushPosition"); }  //$NON-NLS-1$
 			    consumeUnaryExpression(OperatorIds.NOT);  
 				break;
 	 
-	    case 959 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 996 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.MULTIPLY);  
 				break;
 	 
-	    case 960 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= NameOrAj MULTIPLY"); }  //$NON-NLS-1$
+	    case 997 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= NameOrAj MULTIPLY"); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.MULTIPLY);  
 				break;
 	 
-	    case 961 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 998 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.DIVIDE);  
 				break;
 	 
-	    case 962 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= NameOrAj DIVIDE..."); }  //$NON-NLS-1$
+	    case 999 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= NameOrAj DIVIDE..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.DIVIDE);  
 				break;
 	 
-	    case 963 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1000 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.REMAINDER);  
 				break;
 	 
-	    case 964 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= NameOrAj REMAINDER"); }  //$NON-NLS-1$
+	    case 1001 : if (DEBUG) { System.out.println("MultiplicativeExpression_NotName ::= NameOrAj REMAINDER"); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.REMAINDER);  
 				break;
 	 
-	    case 966 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1003 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.PLUS);  
 				break;
 	 
-	    case 967 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::= NameOrAj PLUS..."); }  //$NON-NLS-1$
+	    case 1004 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::= NameOrAj PLUS..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.PLUS);  
 				break;
 	 
-	    case 968 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1005 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.MINUS);  
 				break;
 	 
-	    case 969 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::= NameOrAj MINUS..."); }  //$NON-NLS-1$
+	    case 1006 : if (DEBUG) { System.out.println("AdditiveExpression_NotName ::= NameOrAj MINUS..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.MINUS);  
 				break;
 	 
-	    case 971 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); }  //$NON-NLS-1$
+	    case 1008 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.LEFT_SHIFT);  
 				break;
 	 
-	    case 972 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= NameOrAj LEFT_SHIFT..."); }  //$NON-NLS-1$
+	    case 1009 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= NameOrAj LEFT_SHIFT..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.LEFT_SHIFT);  
 				break;
 	 
-	    case 973 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); }  //$NON-NLS-1$
+	    case 1010 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.RIGHT_SHIFT);  
 				break;
 	 
-	    case 974 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= NameOrAj RIGHT_SHIFT..."); }  //$NON-NLS-1$
+	    case 1011 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= NameOrAj RIGHT_SHIFT..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.RIGHT_SHIFT);  
 				break;
 	 
-	    case 975 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); }  //$NON-NLS-1$
+	    case 1012 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= ShiftExpression_NotName..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.UNSIGNED_RIGHT_SHIFT);  
 				break;
 	 
-	    case 976 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= NameOrAj..."); }  //$NON-NLS-1$
+	    case 1013 : if (DEBUG) { System.out.println("ShiftExpression_NotName ::= NameOrAj..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.UNSIGNED_RIGHT_SHIFT);  
 				break;
 	 
-	    case 978 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= ShiftExpression_NotName"); }  //$NON-NLS-1$
+	    case 1015 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.LESS);  
 				break;
 	 
-	    case 979 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= Name LESS..."); }  //$NON-NLS-1$
+	    case 1016 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= Name LESS..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.LESS);  
 				break;
 	 
-	    case 980 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= ShiftExpression_NotName"); }  //$NON-NLS-1$
+	    case 1017 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.GREATER);  
 				break;
 	 
-	    case 981 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= NameOrAj GREATER..."); }  //$NON-NLS-1$
+	    case 1018 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= NameOrAj GREATER..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.GREATER);  
 				break;
 	 
-	    case 982 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1019 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.LESS_EQUAL);  
 				break;
 	 
-	    case 983 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= NameOrAj LESS_EQUAL..."); }  //$NON-NLS-1$
+	    case 1020 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= NameOrAj LESS_EQUAL..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.LESS_EQUAL);  
 				break;
 	 
-	    case 984 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1021 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.GREATER_EQUAL);  
 				break;
 	 
-	    case 985 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= NameOrAj GREATER_EQUAL"); }  //$NON-NLS-1$
+	    case 1022 : if (DEBUG) { System.out.println("RelationalExpression_NotName ::= NameOrAj GREATER_EQUAL"); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.GREATER_EQUAL);  
 				break;
 	 
-	    case 987 : if (DEBUG) { System.out.println("InstanceofExpression_NotName ::= NameOrAj instanceof..."); }  //$NON-NLS-1$
+	    case 1024 : if (DEBUG) { System.out.println("InstanceofExpression_NotName ::= NameOrAj instanceof..."); }  //$NON-NLS-1$
 			    consumeInstanceOfExpressionWithName();  
 				break;
 	 
-	    case 988 : if (DEBUG) { System.out.println("InstanceofExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1025 : if (DEBUG) { System.out.println("InstanceofExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeInstanceOfExpression();  
 				break;
 	 
-	    case 990 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1027 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeEqualityExpression(OperatorIds.EQUAL_EQUAL);  
 				break;
 	 
-	    case 991 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::= NameOrAj EQUAL_EQUAL..."); }  //$NON-NLS-1$
+	    case 1028 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::= NameOrAj EQUAL_EQUAL..."); }  //$NON-NLS-1$
 			    consumeEqualityExpressionWithName(OperatorIds.EQUAL_EQUAL);  
 				break;
 	 
-	    case 992 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1029 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeEqualityExpression(OperatorIds.NOT_EQUAL);  
 				break;
 	 
-	    case 993 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::= NameOrAj NOT_EQUAL..."); }  //$NON-NLS-1$
+	    case 1030 : if (DEBUG) { System.out.println("EqualityExpression_NotName ::= NameOrAj NOT_EQUAL..."); }  //$NON-NLS-1$
 			    consumeEqualityExpressionWithName(OperatorIds.NOT_EQUAL);  
 				break;
 	 
-	    case 995 : if (DEBUG) { System.out.println("AndExpression_NotName ::= AndExpression_NotName AND..."); }  //$NON-NLS-1$
+	    case 1032 : if (DEBUG) { System.out.println("AndExpression_NotName ::= AndExpression_NotName AND..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.AND);  
 				break;
 	 
-	    case 996 : if (DEBUG) { System.out.println("AndExpression_NotName ::= NameOrAj AND..."); }  //$NON-NLS-1$
+	    case 1033 : if (DEBUG) { System.out.println("AndExpression_NotName ::= NameOrAj AND..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.AND);  
 				break;
 	 
-	    case 998 : if (DEBUG) { System.out.println("ExclusiveOrExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1035 : if (DEBUG) { System.out.println("ExclusiveOrExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.XOR);  
 				break;
 	 
-	    case 999 : if (DEBUG) { System.out.println("ExclusiveOrExpression_NotName ::= NameOrAj XOR..."); }  //$NON-NLS-1$
+	    case 1036 : if (DEBUG) { System.out.println("ExclusiveOrExpression_NotName ::= NameOrAj XOR..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.XOR);  
 				break;
 	 
-	    case 1001 : if (DEBUG) { System.out.println("InclusiveOrExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1038 : if (DEBUG) { System.out.println("InclusiveOrExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.OR);  
 				break;
 	 
-	    case 1002 : if (DEBUG) { System.out.println("InclusiveOrExpression_NotName ::= NameOrAj OR..."); }  //$NON-NLS-1$
+	    case 1039 : if (DEBUG) { System.out.println("InclusiveOrExpression_NotName ::= NameOrAj OR..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.OR);  
 				break;
 	 
-	    case 1004 : if (DEBUG) { System.out.println("ConditionalAndExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1041 : if (DEBUG) { System.out.println("ConditionalAndExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.AND_AND);  
 				break;
 	 
-	    case 1005 : if (DEBUG) { System.out.println("ConditionalAndExpression_NotName ::= NameOrAj AND_AND"); }  //$NON-NLS-1$
+	    case 1042 : if (DEBUG) { System.out.println("ConditionalAndExpression_NotName ::= NameOrAj AND_AND"); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.AND_AND);  
 				break;
 	 
-	    case 1007 : if (DEBUG) { System.out.println("ConditionalOrExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1044 : if (DEBUG) { System.out.println("ConditionalOrExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeBinaryExpression(OperatorIds.OR_OR);  
 				break;
 	 
-	    case 1008 : if (DEBUG) { System.out.println("ConditionalOrExpression_NotName ::= NameOrAj OR_OR..."); }  //$NON-NLS-1$
+	    case 1045 : if (DEBUG) { System.out.println("ConditionalOrExpression_NotName ::= NameOrAj OR_OR..."); }  //$NON-NLS-1$
 			    consumeBinaryExpressionWithName(OperatorIds.OR_OR);  
 				break;
 	 
-	    case 1010 : if (DEBUG) { System.out.println("ConditionalExpression_NotName ::=..."); }  //$NON-NLS-1$
+	    case 1047 : if (DEBUG) { System.out.println("ConditionalExpression_NotName ::=..."); }  //$NON-NLS-1$
 			    consumeConditionalExpression(OperatorIds.QUESTIONCOLON) ;  
 				break;
 	 
-	    case 1011 : if (DEBUG) { System.out.println("ConditionalExpression_NotName ::= NameOrAj QUESTION..."); }  //$NON-NLS-1$
+	    case 1048 : if (DEBUG) { System.out.println("ConditionalExpression_NotName ::= NameOrAj QUESTION..."); }  //$NON-NLS-1$
 			    consumeConditionalExpressionWithName(OperatorIds.QUESTIONCOLON) ;  
 				break;
 	 
-	    case 1015 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= Modifiers AT..."); }  //$NON-NLS-1$
+	    case 1052 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= Modifiers AT..."); }  //$NON-NLS-1$
 			    consumeAnnotationTypeDeclarationHeaderName() ;  
 				break;
 	 
-	    case 1016 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= Modifiers AT..."); }  //$NON-NLS-1$
+	    case 1053 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= Modifiers AT..."); }  //$NON-NLS-1$
 			    consumeAnnotationTypeDeclarationHeaderNameWithTypeParameters() ;  
 				break;
 	 
-	    case 1017 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= AT..."); }  //$NON-NLS-1$
+	    case 1054 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= AT..."); }  //$NON-NLS-1$
 			    consumeAnnotationTypeDeclarationHeaderNameWithTypeParameters() ;  
 				break;
 	 
-	    case 1018 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= AT..."); }  //$NON-NLS-1$
+	    case 1055 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeaderName ::= AT..."); }  //$NON-NLS-1$
 			    consumeAnnotationTypeDeclarationHeaderName() ;  
 				break;
 	 
-	    case 1019 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeader ::=..."); }  //$NON-NLS-1$
+	    case 1056 : if (DEBUG) { System.out.println("AnnotationTypeDeclarationHeader ::=..."); }  //$NON-NLS-1$
 			    consumeAnnotationTypeDeclarationHeader() ;  
 				break;
 	 
-	    case 1020 : if (DEBUG) { System.out.println("AnnotationTypeDeclaration ::=..."); }  //$NON-NLS-1$
+	    case 1057 : if (DEBUG) { System.out.println("AnnotationTypeDeclaration ::=..."); }  //$NON-NLS-1$
 			    consumeAnnotationTypeDeclaration() ;  
 				break;
 	 
-	    case 1022 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarationsopt ::="); }  //$NON-NLS-1$
+	    case 1059 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarationsopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyAnnotationTypeMemberDeclarationsopt() ;  
 				break;
 	 
-	    case 1023 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarationsopt ::= NestedType..."); }  //$NON-NLS-1$
+	    case 1060 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarationsopt ::= NestedType..."); }  //$NON-NLS-1$
 			    consumeAnnotationTypeMemberDeclarationsopt() ;  
 				break;
 	 
-	    case 1025 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarations ::=..."); }  //$NON-NLS-1$
+	    case 1062 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclarations ::=..."); }  //$NON-NLS-1$
 			    consumeAnnotationTypeMemberDeclarations() ;  
 				break;
 	 
-	    case 1026 : if (DEBUG) { System.out.println("AnnotationMethodHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
+	    case 1063 : if (DEBUG) { System.out.println("AnnotationMethodHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
 			    consumeMethodHeaderNameWithTypeParameters(true);  
 				break;
 	 
-	    case 1027 : if (DEBUG) { System.out.println("AnnotationMethodHeaderName ::= Modifiersopt Type..."); }  //$NON-NLS-1$
+	    case 1064 : if (DEBUG) { System.out.println("AnnotationMethodHeaderName ::= Modifiersopt Type..."); }  //$NON-NLS-1$
 			    consumeMethodHeaderName(true);  
 				break;
 	 
-	    case 1028 : if (DEBUG) { System.out.println("AnnotationMethodHeaderDefaultValueopt ::="); }  //$NON-NLS-1$
+	    case 1065 : if (DEBUG) { System.out.println("AnnotationMethodHeaderDefaultValueopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyMethodHeaderDefaultValue() ;  
 				break;
 	 
-	    case 1029 : if (DEBUG) { System.out.println("AnnotationMethodHeaderDefaultValueopt ::= DefaultValue"); }  //$NON-NLS-1$
+	    case 1066 : if (DEBUG) { System.out.println("AnnotationMethodHeaderDefaultValueopt ::= DefaultValue"); }  //$NON-NLS-1$
 			    consumeMethodHeaderDefaultValue();  
 				break;
 	 
-	    case 1030 : if (DEBUG) { System.out.println("AnnotationMethodHeader ::= AnnotationMethodHeaderName"); }  //$NON-NLS-1$
+	    case 1067 : if (DEBUG) { System.out.println("AnnotationMethodHeader ::= AnnotationMethodHeaderName"); }  //$NON-NLS-1$
 			    consumeMethodHeader();  
 				break;
 	 
-	    case 1031 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclaration ::=..."); }  //$NON-NLS-1$
+	    case 1068 : if (DEBUG) { System.out.println("AnnotationTypeMemberDeclaration ::=..."); }  //$NON-NLS-1$
 			    consumeAnnotationTypeMemberDeclaration() ;  
 				break;
 	 
-	    case 1039 : if (DEBUG) { System.out.println("AnnotationName ::= AT UnannotatableNameOrAj"); }  //$NON-NLS-1$
+	    case 1076 : if (DEBUG) { System.out.println("AnnotationName ::= AT UnannotatableNameOrAj"); }  //$NON-NLS-1$
 			    consumeAnnotationName() ;  
 				break;
 	 
-	    case 1040 : if (DEBUG) { System.out.println("NormalAnnotation ::= AnnotationName LPAREN..."); }  //$NON-NLS-1$
+	    case 1077 : if (DEBUG) { System.out.println("NormalAnnotation ::= AnnotationName LPAREN..."); }  //$NON-NLS-1$
 			    consumeNormalAnnotation(false) ;  
 				break;
 	 
-	    case 1041 : if (DEBUG) { System.out.println("MemberValuePairsopt ::="); }  //$NON-NLS-1$
+	    case 1078 : if (DEBUG) { System.out.println("MemberValuePairsopt ::="); }  //$NON-NLS-1$
 			    consumeEmptyMemberValuePairsopt() ;  
 				break;
 	 
-	    case 1044 : if (DEBUG) { System.out.println("MemberValuePairs ::= MemberValuePairs COMMA..."); }  //$NON-NLS-1$
+	    case 1081 : if (DEBUG) { System.out.println("MemberValuePairs ::= MemberValuePairs COMMA..."); }  //$NON-NLS-1$
 			    consumeMemberValuePairs() ;  
 				break;
 	 
-	    case 1045 : if (DEBUG) { System.out.println("MemberValuePair ::= SimpleNameOrAj EQUAL..."); }  //$NON-NLS-1$
+	    case 1082 : if (DEBUG) { System.out.println("MemberValuePair ::= SimpleNameOrAj EQUAL..."); }  //$NON-NLS-1$
 			    consumeMemberValuePair() ;  
 				break;
 	 
-	    case 1046 : if (DEBUG) { System.out.println("EnterMemberValue ::="); }  //$NON-NLS-1$
+	    case 1083 : if (DEBUG) { System.out.println("EnterMemberValue ::="); }  //$NON-NLS-1$
 			    consumeEnterMemberValue() ;  
 				break;
 	 
-	    case 1047 : if (DEBUG) { System.out.println("ExitMemberValue ::="); }  //$NON-NLS-1$
+	    case 1084 : if (DEBUG) { System.out.println("ExitMemberValue ::="); }  //$NON-NLS-1$
 			    consumeExitMemberValue() ;  
 				break;
 	 
-	    case 1049 : if (DEBUG) { System.out.println("MemberValue ::= NameOrAj"); }  //$NON-NLS-1$
+	    case 1086 : if (DEBUG) { System.out.println("MemberValue ::= NameOrAj"); }  //$NON-NLS-1$
 			    consumeMemberValueAsName() ;  
 				break;
 	 
-	    case 1052 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); }  //$NON-NLS-1$
+	    case 1089 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); }  //$NON-NLS-1$
 			    consumeMemberValueArrayInitializer() ;  
 				break;
 	 
-	    case 1053 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); }  //$NON-NLS-1$
+	    case 1090 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); }  //$NON-NLS-1$
 			    consumeMemberValueArrayInitializer() ;  
 				break;
 	 
-	    case 1054 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); }  //$NON-NLS-1$
+	    case 1091 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); }  //$NON-NLS-1$
 			    consumeEmptyMemberValueArrayInitializer() ;  
 				break;
 	 
-	    case 1055 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); }  //$NON-NLS-1$
+	    case 1092 : if (DEBUG) { System.out.println("MemberValueArrayInitializer ::=..."); }  //$NON-NLS-1$
 			    consumeEmptyMemberValueArrayInitializer() ;  
 				break;
 	 
-	    case 1056 : if (DEBUG) { System.out.println("EnterMemberValueArrayInitializer ::="); }  //$NON-NLS-1$
+	    case 1093 : if (DEBUG) { System.out.println("EnterMemberValueArrayInitializer ::="); }  //$NON-NLS-1$
 			    consumeEnterMemberValueArrayInitializer() ;  
 				break;
 	 
-	    case 1058 : if (DEBUG) { System.out.println("MemberValues ::= MemberValues COMMA MemberValue"); }  //$NON-NLS-1$
+	    case 1095 : if (DEBUG) { System.out.println("MemberValues ::= MemberValues COMMA MemberValue"); }  //$NON-NLS-1$
 			    consumeMemberValues() ;  
 				break;
 	 
-	    case 1059 : if (DEBUG) { System.out.println("MarkerAnnotation ::= AnnotationName"); }  //$NON-NLS-1$
+	    case 1096 : if (DEBUG) { System.out.println("MarkerAnnotation ::= AnnotationName"); }  //$NON-NLS-1$
 			    consumeMarkerAnnotation(false) ;  
 				break;
 	 
-	    case 1060 : if (DEBUG) { System.out.println("SingleMemberAnnotationMemberValue ::= MemberValue"); }  //$NON-NLS-1$
+	    case 1097 : if (DEBUG) { System.out.println("SingleMemberAnnotationMemberValue ::= MemberValue"); }  //$NON-NLS-1$
 			    consumeSingleMemberAnnotationMemberValue() ;  
 				break;
 	 
-	    case 1061 : if (DEBUG) { System.out.println("SingleMemberAnnotation ::= AnnotationName LPAREN..."); }  //$NON-NLS-1$
+	    case 1098 : if (DEBUG) { System.out.println("SingleMemberAnnotation ::= AnnotationName LPAREN..."); }  //$NON-NLS-1$
 			    consumeSingleMemberAnnotation(false) ;  
 				break;
 	 
-	    case 1062 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
+	    case 1099 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= Modifiersopt..."); }  //$NON-NLS-1$
 			    consumeRecoveryMethodHeaderNameWithTypeParameters();  
 				break;
 	 
-	    case 1063 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= Modifiersopt Type..."); }  //$NON-NLS-1$
+	    case 1100 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= Modifiersopt Type..."); }  //$NON-NLS-1$
 			    consumeRecoveryMethodHeaderName();  
 				break;
 	 
-	    case 1064 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= ModifiersWithDefault..."); }  //$NON-NLS-1$
+	    case 1101 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= ModifiersWithDefault..."); }  //$NON-NLS-1$
 			    consumeRecoveryMethodHeaderNameWithTypeParameters();  
 				break;
 	 
-	    case 1065 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= ModifiersWithDefault Type"); }  //$NON-NLS-1$
+	    case 1102 : if (DEBUG) { System.out.println("RecoveryMethodHeaderName ::= ModifiersWithDefault Type"); }  //$NON-NLS-1$
 			    consumeRecoveryMethodHeaderName();  
 				break;
 	 
-	    case 1066 : if (DEBUG) { System.out.println("RecoveryMethodHeader ::= RecoveryMethodHeaderName..."); }  //$NON-NLS-1$
+	    case 1103 : if (DEBUG) { System.out.println("RecoveryMethodHeader ::= RecoveryMethodHeaderName..."); }  //$NON-NLS-1$
 			    consumeMethodHeader();  
 				break;
 	 
-	    case 1067 : if (DEBUG) { System.out.println("RecoveryMethodHeader ::= RecoveryMethodHeaderName..."); }  //$NON-NLS-1$
+	    case 1104 : if (DEBUG) { System.out.println("RecoveryMethodHeader ::= RecoveryMethodHeaderName..."); }  //$NON-NLS-1$
 			    consumeMethodHeader();  
 				break;
 	 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java
index d3071b4..6dca2c4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ParserBasicInformation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- *  
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -18,24 +18,23 @@
 public interface ParserBasicInformation {
 
 	public final static int
-
-    ERROR_SYMBOL      = 138,
+    ERROR_SYMBOL      = 139,
     MAX_NAME_LENGTH   = 41,
-    NUM_STATES        = 1341,
+    NUM_STATES        = 1286,
 
-    NT_OFFSET         = 138,
-    SCOPE_UBOUND      = 380,
-    SCOPE_SIZE        = 381,
-    LA_STATE_OFFSET   = 20011,
+    NT_OFFSET         = 139,
+    SCOPE_UBOUND      = 395,
+    SCOPE_SIZE        = 396,
+    LA_STATE_OFFSET   = 20569,
     MAX_LA            = 1,
-    NUM_RULES         = 1067,
-    NUM_TERMINALS     = 138,
-    NUM_NON_TERMINALS = 462,
-    NUM_SYMBOLS       = 600,
-    START_STATE       = 1330,
-    EOFT_SYMBOL       = 72,
-    EOLT_SYMBOL       = 72,
-    ACCEPT_ACTION     = 20010,
-    ERROR_ACTION      = 20011;
-	
+    NUM_RULES         = 1104,
+    NUM_TERMINALS     = 139,
+    NUM_NON_TERMINALS = 482,
+    NUM_SYMBOLS       = 621,
+    START_STATE       = 1150,
+    EOFT_SYMBOL       = 100,
+    EOLT_SYMBOL       = 100,
+    ACCEPT_ACTION     = 20568,
+    ERROR_ACTION      = 20569;
+
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java
index 8a93709..6998df0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredBlock.java
@@ -160,7 +160,7 @@
  * Record a statement declaration
  */
 public RecoveredElement add(Statement stmt, int bracketBalanceValue, boolean delegatedByParent) {
-	
+
 	resetPendingModifiers();
 
 	/* do not consider a nested block starting passed the block end (if set)
@@ -307,7 +307,7 @@
 
 	// if block was not marked to be preserved or empty, then ignore it
 	if (!this.preserveContent || this.statementCount == 0) return null;
-	
+
 	Statement[] updatedStatements = new Statement[this.statementCount];
 	int updatedCount = 0;
 
@@ -362,7 +362,7 @@
 				}
 			}
 			updatedStatements[updatedCount++] = updatedStatement;
-			
+
 			if (updatedStatement instanceof LocalDeclaration) {
 				LocalDeclaration localDeclaration = (LocalDeclaration) updatedStatement;
 				if(localDeclaration.declarationSourceEnd > lastEnd) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java
index dd9a8dd..4ce9f96 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredElement.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -35,11 +35,11 @@
 	public int bracketBalance;
 	public boolean foundOpeningBrace;
 	protected Parser recoveringParser;
-	
+
 	// There is no RecoveredLambdaElement, we just keep track of entry and exit of lambdas via a counter. This allows to prevent certain incorrect mutations of current element.
 	// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=430667.
 	public int lambdaNestLevel;
-	
+
 public RecoveredElement(RecoveredElement parent, int bracketBalance){
 	this(parent, bracketBalance, null);
 }
@@ -131,7 +131,7 @@
 	if (this.parent == null) return this; // ignore
 	if (this instanceof RecoveredType) {
 		TypeDeclaration typeDeclaration = ((RecoveredType) this).typeDeclaration;
-		if (typeDeclaration != null && (typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) { 
+		if (typeDeclaration != null && (typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=291040, new X(<SelectOnMessageSend:zoo()>) { ???
 			if (statement.sourceStart > typeDeclaration.sourceStart && statement.sourceEnd < typeDeclaration.sourceEnd) {
 				return this;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredExport.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredExport.java
index dda131e..531e5a9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredExport.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredExport.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.parser;
 
@@ -23,7 +23,7 @@
 	public ExportsStatement exportReference;
 	RecoveredModuleReference[] targets;
 	int targetCount = 0;
-	
+
 	public RecoveredExport(ExportsStatement exportReference, RecoveredElement parent, int bracketBalance) {
 		super(parent, bracketBalance);
 		this.exportReference = exportReference;
@@ -49,7 +49,7 @@
 		/* if target not finished, then target becomes current */
 		if (target.sourceEnd == 0) return element;
 		return this;
-		
+
 	}
 	/*
 	 * Answer the associated parsed structure
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java
index 629d983..e97da2d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredField.java
@@ -39,7 +39,7 @@
 
 	public RecoveredAnnotation[] annotations;
 	public int annotationCount;
-	
+
 	public int modifiers;
 	public int modifiersStart;
 
@@ -71,7 +71,7 @@
 	/* default behavior is to delegate recording to parent if any */
 	resetPendingModifiers();
 	if (this.parent == null) return this; // ignore
-	
+
 	if (this.fieldDeclaration.declarationSourceStart == addedfieldDeclaration.declarationSourceStart) {
 		if (this.fieldDeclaration.initialization != null) {
 			this.updateSourceEndIfNecessary(this.fieldDeclaration.initialization.sourceEnd);
@@ -96,7 +96,7 @@
 		if (statement.sourceEnd > 0)
 				this.alreadyCompletedFieldInitialization = true;
 		// else we may still be inside the initialization, having parsed only a part of it yet
-		if (!(statement instanceof AllocationExpression) && 
+		if (!(statement instanceof AllocationExpression) &&
 				this.fieldDeclaration.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) {
 			AllocationExpression alloc = new AllocationExpression();
 			alloc.arguments = new Expression[] {(Expression) statement};
@@ -249,7 +249,7 @@
 							recoveredInitializers.expressions[recoveredInitializersCount++] = anonymousType.allocation;
 						}
 						else {
-							this.fieldDeclaration.initialization = anonymousType.allocation;							
+							this.fieldDeclaration.initialization = anonymousType.allocation;
 						}
 						int end = anonymousType.declarationSourceEnd;
 						if (end > this.fieldDeclaration.declarationSourceEnd) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=307337
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredInitializer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredInitializer.java
index 0889678..d770857 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredInitializer.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredInitializer.java
@@ -68,7 +68,7 @@
 	}
 	if (this.initializerBody == null) {
 		return this.initializerBody = new RecoveredBlock(nestedBlockDeclaration, this, bracketBalanceValue);
-	}	
+	}
 	this.initializerBody.blockDeclaration.sourceEnd = 0; /* needed to allow adding more elements to the existing initializerBody */
 	if (nestedBlockDeclaration.sourceEnd == 0) return this.initializerBody;
 	return this.initializerBody.add(nestedBlockDeclaration, bracketBalanceValue, true);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredModule.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredModule.java
index 785f099..d2f333b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredModule.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredModule.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.parser;
 
@@ -24,7 +24,7 @@
 import org.eclipse.jdt.internal.compiler.ast.UsesStatement;
 
 public class RecoveredModule extends RecoveredElement {
-	
+
 	public RecoveredExportsStatement[] exports;
 	public int exportCount;
 	public RecoveredOpensStatement[] opens;
@@ -43,7 +43,7 @@
 	}
 	@Override
 	public RecoveredElement add(ModuleStatement moduleStatement, int bracketBalanceValue) {
-		
+
 		// TODO: can't we do away with all these additions except for ProvidesStatement - to check
 		// if there are any corner cases that uses these.
 		if (moduleStatement instanceof ExportsStatement) {
@@ -61,7 +61,7 @@
 		if (moduleStatement instanceof UsesStatement) {
 			return add((UsesStatement) moduleStatement, bracketBalanceValue);
 		}
-		
+
 		return this;
 	}
 
@@ -279,7 +279,7 @@
 				providesStmts[actualCount++] = this.services[i].updatedProvidesStatement();
 			}
 			mod.services = providesStmts;
-			mod.servicesCount = actualCount;  			
+			mod.servicesCount = actualCount;
 		}
 	}
 	@Override
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredModuleReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredModuleReference.java
index e15b27e..2a357d6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredModuleReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredModuleReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.parser;
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java
index c4257c4..7849d2c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredStatement.java
@@ -29,7 +29,7 @@
 
 	public Statement statement;
 	RecoveredBlock nestedBlock;
-	
+
 public RecoveredStatement(Statement statement, RecoveredElement parent, int bracketBalance){
 	super(parent, bracketBalance);
 	this.statement = statement;
@@ -84,7 +84,7 @@
 public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValue) {
 	if (this.statement instanceof ForeachStatement) {
 		ForeachStatement foreach = (ForeachStatement) this.statement;
-		
+
 		// see RecoveredBlock.add(Block, int):
 		resetPendingModifiers();
 
@@ -103,7 +103,7 @@
 			addBlockStatement(element);
 		}
 		this.nestedBlock = element;
-		
+
 		if (nestedBlockDeclaration.sourceEnd == 0) return element;
 		return this;
 	} else {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java
index ed88f70..ae1eba0 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -40,7 +40,7 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class RecoveredType extends RecoveredStatement implements TerminalTokens {
 	public static final int MAX_TYPE_DEPTH = 256;
-	
+
 	public TypeDeclaration typeDeclaration;
 
 	public RecoveredAnnotation[] annotations;
@@ -515,7 +515,7 @@
 
 	if(knownTypes.contains(this.typeDeclaration)) return null;
 	knownTypes.add(this.typeDeclaration);
-	
+
 	int lastEnd = this.typeDeclaration.bodyStart;
 	/* update annotations */
 	if (this.modifiers != 0) {
@@ -554,7 +554,7 @@
 			this.memberTypes[this.memberTypeCount - 1].typeDeclaration.declarationSourceEnd = bodyEndValue;
 			this.memberTypes[this.memberTypeCount - 1].typeDeclaration.bodyEnd =  bodyEndValue;
 		}
-		
+
 		int updatedCount = 0;
 		for (int i = 0; i < this.memberTypeCount; i++){
 			TypeDeclaration updatedTypeDeclaration = this.memberTypes[i].updatedTypeDeclaration(depth + 1, knownTypes);
@@ -566,8 +566,8 @@
 			int length = existingCount + updatedCount;
 			System.arraycopy(memberTypeDeclarations, 0, memberTypeDeclarations = new TypeDeclaration[length], 0, length);
 		}
-		
-		if (memberTypeDeclarations.length > 0) { 
+
+		if (memberTypeDeclarations.length > 0) {
 			this.typeDeclaration.memberTypes = memberTypeDeclarations;
 			if(memberTypeDeclarations[memberTypeDeclarations.length - 1].declarationSourceEnd > lastEnd) {
 				lastEnd = memberTypeDeclarations[memberTypeDeclarations.length - 1].declarationSourceEnd;
@@ -595,14 +595,14 @@
 		for (int i = 0; i < this.fieldCount; i++){
 			fieldDeclarations[existingCount + i] = this.fields[i].updatedFieldDeclaration(depth, knownTypes);
 		}
-		
+
 		for (int i = this.fieldCount - 1; 0 < i; i--) {
 			if (fieldDeclarations[existingCount + i - 1].declarationSourceStart == fieldDeclarations[existingCount + i].declarationSourceStart) {
 				fieldDeclarations[existingCount + i - 1].declarationSourceEnd = fieldDeclarations[existingCount + i].declarationSourceEnd;
 				fieldDeclarations[existingCount + i - 1].declarationEnd = fieldDeclarations[existingCount + i].declarationEnd;
 			}
 		}
-		
+
 		this.typeDeclaration.fields = fieldDeclarations;
 		if(fieldDeclarations[fieldDeclarations.length - 1].declarationSourceEnd > lastEnd) {
 			lastEnd = fieldDeclarations[fieldDeclarations.length - 1].declarationSourceEnd;
@@ -684,6 +684,7 @@
 		if (!hasConstructor &&
 				kind != TypeDeclaration.INTERFACE_DECL &&
 				kind != TypeDeclaration.ANNOTATION_TYPE_DECL &&
+				kind != TypeDeclaration.RECORD_DECL &&
 				this.typeDeclaration.allocation == null) {// if was already reduced, then constructor
 			boolean insideFieldInitializer = false;
 			RecoveredElement parentElement = this.parent;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredTypeReference.java
index a26f32a..4355ce7 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredTypeReference.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.parser;
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredUnit.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredUnit.java
index 45d4837..6b7f3d6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredUnit.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveredUnit.java
@@ -172,7 +172,7 @@
 }
 @Override
 public RecoveredElement add(TypeDeclaration typeDeclaration, int bracketBalanceValue) {
-	
+
 	if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0){
 		if (this.typeCount > 0) {
 			// add it to the last type
@@ -295,7 +295,7 @@
 			this.types[this.typeCount - 1].typeDeclaration.declarationSourceEnd = this.unitDeclaration.sourceEnd;
 			this.types[this.typeCount - 1].typeDeclaration.bodyEnd = this.unitDeclaration.sourceEnd;
 		}
-		
+
 		Set<TypeDeclaration> knownTypes = new HashSet<>();
 		int actualCount = existingCount;
 		for (int i = 0; i < this.typeCount; i++){
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveryScanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveryScanner.java
index 7f61281..933ba79 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveryScanner.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/RecoveryScanner.java
@@ -14,6 +14,7 @@
 
 package org.eclipse.jdt.internal.compiler.parser;
 
+import java.util.Arrays;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.InvalidInputException;
 
@@ -43,7 +44,7 @@
 				scanner.previewEnabled);
 		setData(data);
 	}
-	
+
 	public RecoveryScanner(
 			boolean tokenizeWhiteSpace,
 			boolean checkNonExternalizedStringLiterals,
@@ -77,10 +78,13 @@
 			tokens[i] = tokens[length - i - 1];
 			tokens[length - i - 1] = tmp;
 		}
-		return tokens;
+		return filterTokens(tokens);
 	}
 	public void insertTokens(int[] tokens, int completedToken, int position) {
 		if(!this.record) return;
+		tokens = filterTokens(tokens);
+		if (tokens.length == 0)
+			return;
 
 		if(completedToken > -1 && Parser.statements_recovery_filter[completedToken] != 0) return;
 
@@ -99,10 +103,11 @@
 		this.data.insertedTokensPosition[this.data.insertedTokensPtr] = position;
 		this.data.insertedTokenUsed[this.data.insertedTokensPtr] = false;
 	}
-	
+
 	public void insertTokenAhead(int token, int index) {
 		if(!this.record) return;
-
+		if (token == TerminalTokens.TokenNameRestrictedIdentifierrecord)
+			return;
 		int length = this.data.insertedTokens[index].length;
 		int [] tokens = new int [length + 1];
 		System.arraycopy(this.data.insertedTokens[index], 0, tokens, 1, length);
@@ -114,8 +119,18 @@
 		replaceTokens(new int []{token}, start, end);
 	}
 
+	int[] filterTokens(int[] tokens) {
+//		if (this.sourceLevel >= ClassFileConstants.JDK14)
+//			return tokens;
+		return Arrays.stream(tokens)
+				.filter(x -> x != TerminalTokens.TokenNameRestrictedIdentifierrecord)
+				.toArray();
+	}
 	public void replaceTokens(int[] tokens, int start, int end) {
 		if(!this.record) return;
+		tokens = filterTokens(tokens);
+		if (tokens.length == 0)
+			return;
 		this.data.replacedTokensPtr++;
 		if(this.data.replacedTokensStart == null) {
 			this.data.replacedTokens = new int[10][];
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ScannerHelper.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ScannerHelper.java
index 59ec2cd..8f6b5a8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ScannerHelper.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/ScannerHelper.java
@@ -383,10 +383,7 @@
 	if(c < ScannerHelper.MAX_OBVIOUS) {
 		return (ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_DIGIT) != 0;
 	}
-	if (Character.isDigit(c)) {
-		throw new InvalidInputException(Scanner.INVALID_DIGIT);
-	}
-	return false;
+	return Character.isDigit(c);
 }
 public static int digit(char c, int radix) {
 	if (c < ScannerHelper.MAX_OBVIOUS) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalTokens.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalTokens.java
index aa6cc67..83c1d4a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalTokens.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TerminalTokens.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -32,148 +32,148 @@
 
 	// special tokens not part of grammar - not autogenerated
 	int TokenNameNotAToken = 0,
-		TokenNameWHITESPACE = 1000,
-		TokenNameCOMMENT_LINE = 1001,
-		TokenNameCOMMENT_BLOCK = 1002,
-		TokenNameCOMMENT_JAVADOC = 1003;
+							TokenNameWHITESPACE = 1000,
+							TokenNameCOMMENT_LINE = 1001,
+							TokenNameCOMMENT_BLOCK = 1002,
+							TokenNameCOMMENT_JAVADOC = 1003;
 
-	public final static int
-    TokenNameIdentifier = 14,
-    TokenNameabstract = 47,
-    TokenNameassert = 82,
-    TokenNameboolean = 116,
-    TokenNamebreak = 83,
-    TokenNamebyte = 117,
-    TokenNamecase = 93,
-    TokenNamecatch = 94,
-    TokenNamechar = 118,
-    TokenNameclass = 73,
-    TokenNamecontinue = 84,
-    TokenNameconst = 136,
-    TokenNamedefault = 99,
-    TokenNamedo = 85,
-    TokenNamedouble = 119,
-    TokenNameelse = 98,
-    TokenNameenum = 86,
-    TokenNameextends = 92,
-    TokenNamefalse = 48,
-    TokenNamefinal = 49,
-    TokenNamefinally = 97,
-    TokenNamefloat = 120,
-    TokenNamefor = 87,
-    TokenNamegoto = 137,
-    TokenNameif = 88,
-    TokenNameimplements = 103,
-    TokenNameimport = 95,
-    TokenNameinstanceof = 16,
-    TokenNameint = 121,
-    TokenNameopens = 125,
-    TokenNameinterface = 77,
-    TokenNamelong = 122,
-    TokenNamenative = 50,
-    TokenNamenew = 41,
-    TokenNamenull = 51,
-    TokenNamepackage = 91,
-    TokenNameprivate = 52,
-    TokenNameprotected = 53,
-    TokenNamepublic = 54,
-    TokenNamereturn = 89,
-    TokenNameshort = 123,
-    TokenNamestatic = 45,
-    TokenNamestrictfp = 55,
-    TokenNamesuper = 43,
-    TokenNameswitch = 68,
-    TokenNamesynchronized = 46,
-    TokenNamethis = 44,
-    TokenNamethrow = 80,
-    TokenNamethrows = 100,
-    TokenNametransient = 56,
-    TokenNametrue = 57,
-    TokenNametry = 90,
-    TokenNamevoid = 124,
-    TokenNamevolatile = 58,
-    TokenNamewhile = 81,
-    TokenNamemodule = 126,
-    TokenNameopen = 127,
-    TokenNamerequires = 128,
-    TokenNametransitive = 132,
-    TokenNameexports = 129,
-    TokenNameto = 133,
-    TokenNameuses = 130,
-    TokenNameprovides = 131,
-    TokenNamewith = 134,
-    TokenNameaspect = 27,
-    TokenNamepointcut = 29,
-    TokenNamearound = 34,
-    TokenNamebefore = 30,
-    TokenNameafter = 31,
-    TokenNamedeclare = 32,
-    TokenNameprivileged = 28,
-    TokenNameIntegerLiteral = 59,
-    TokenNameLongLiteral = 60,
-    TokenNameFloatingPointLiteral = 61,
-    TokenNameDoubleLiteral = 62,
-    TokenNameCharacterLiteral = 63,
-    TokenNameStringLiteral = 64,
-    TokenNameTextBlock = 65,
-    TokenNamePLUS_PLUS = 3,
-    TokenNameMINUS_MINUS = 4,
-    TokenNameEQUAL_EQUAL = 23,
-    TokenNameLESS_EQUAL = 18,
-    TokenNameGREATER_EQUAL = 19,
-    TokenNameNOT_EQUAL = 20,
-    TokenNameLEFT_SHIFT = 21,
-    TokenNameRIGHT_SHIFT = 12,
-    TokenNameUNSIGNED_RIGHT_SHIFT = 15,
-    TokenNamePLUS_EQUAL = 104,
-    TokenNameMINUS_EQUAL = 105,
-    TokenNameMULTIPLY_EQUAL = 106,
-    TokenNameDIVIDE_EQUAL = 107,
-    TokenNameAND_EQUAL = 108,
-    TokenNameOR_EQUAL = 109,
-    TokenNameXOR_EQUAL = 110,
-    TokenNameREMAINDER_EQUAL = 111,
-    TokenNameLEFT_SHIFT_EQUAL = 112,
-    TokenNameRIGHT_SHIFT_EQUAL = 113,
-    TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL = 114,
-    TokenNameOR_OR = 38,
-    TokenNameAND_AND = 37,
-    TokenNamePLUS = 2,
-    TokenNameMINUS = 6,
-    TokenNameNOT = 70,
-    TokenNameREMAINDER = 10,
-    TokenNameXOR = 33,
-    TokenNameAND = 22,
-    TokenNameMULTIPLY = 8,
-    TokenNameOR = 36,
-    TokenNameTWIDDLE = 74,
-    TokenNameDIVIDE = 11,
-    TokenNameGREATER = 13,
-    TokenNameLESS = 7,
-    TokenNameLPAREN = 17,
-    TokenNameRPAREN = 25,
-    TokenNameLBRACE = 66,
-    TokenNameRBRACE = 40,
-    TokenNameLBRACKET = 5,
-    TokenNameRBRACKET = 71,
-    TokenNameSEMICOLON = 26,
-    TokenNameQUESTION = 35,
-    TokenNameCOLON = 67,
-    TokenNameCOMMA = 39,
-    TokenNameDOT = 1,
-    TokenNameEQUAL = 76,
-    TokenNameAT = 42,
-    TokenNameELLIPSIS = 101,
-    TokenNameARROW = 115,
-    TokenNameCOLON_COLON = 9,
-    TokenNameBeginLambda = 69,
-    TokenNameBeginIntersectionCast = 75,
-    TokenNameBeginTypeArguments = 96,
-    TokenNameElidedSemicolonAndRightBrace = 78,
-    TokenNameAT308 = 24,
-    TokenNameAT308DOTDOTDOT = 135,
-    TokenNameBeginCaseExpr = 79,
-    TokenNameRestrictedIdentifierYield = 102,
-    TokenNameEOF = 72,
-    TokenNameERROR = 138;
+    int TokenNameIdentifier = 2,
+    	      TokenNameabstract = 36,
+    	      TokenNameassert = 79,
+    	      TokenNameboolean = 115,
+    	      TokenNamebreak = 80,
+    	      TokenNamebyte = 116,
+    	      TokenNamecase = 103,
+    	      TokenNamecatch = 104,
+    	      TokenNamechar = 117,
+    	      TokenNameclass = 70,
+    	      TokenNamecontinue = 81,
+    	      TokenNameconst = 137,
+    	      TokenNamedefault = 110,
+    	      TokenNamedo = 82,
+    	      TokenNamedouble = 118,
+    	      TokenNameelse = 111,
+    	      TokenNameenum = 76,
+    	      TokenNameextends = 102,
+    	      TokenNamefalse = 57,
+    	      TokenNamefinal = 37,
+    	      TokenNamefinally = 107,
+    	      TokenNamefloat = 119,
+    	      TokenNamefor = 83,
+    	      TokenNamegoto = 138,
+    	      TokenNameif = 84,
+    	      TokenNameimplements = 113,
+    	      TokenNameimport = 105,
+    	      TokenNameinstanceof = 31,
+    	      TokenNameint = 120,
+    	      TokenNameopens = 124,
+    	      TokenNameinterface = 73,
+    	      TokenNamelong = 121,
+    	      TokenNamenative = 38,
+    	      TokenNamenew = 39,
+    	      TokenNamenull = 58,
+    	      TokenNamepackage = 101,
+    	      TokenNameprivate = 40,
+    	      TokenNameprotected = 41,
+    	      TokenNamepublic = 42,
+    	      TokenNamereturn = 85,
+    	      TokenNameshort = 122,
+    	      TokenNamestatic = 33,
+    	      TokenNamestrictfp = 43,
+    	      TokenNamesuper = 50,
+    	      TokenNameswitch = 67,
+    	      TokenNamesynchronized = 34,
+    	      TokenNamethis = 51,
+    	      TokenNamethrow = 77,
+    	      TokenNamethrows = 108,
+    	      TokenNametransient = 44,
+    	      TokenNametrue = 59,
+    	      TokenNametry = 86,
+    	      TokenNamevoid = 123,
+    	      TokenNamevolatile = 45,
+    	      TokenNamewhile = 78,
+    	      TokenNamemodule = 125,
+    	      TokenNameopen = 126,
+    	      TokenNamerequires = 127,
+    	      TokenNametransitive = 131,
+    	      TokenNameexports = 128,
+    	      TokenNameto = 133,
+    	      TokenNameuses = 129,
+    	      TokenNameprovides = 130,
+    	      TokenNamewith = 134,
+    	      TokenNameaspect = 9,
+    	      TokenNamepointcut = 12,
+    	      TokenNamearound = 16,
+    	      TokenNamebefore = 13,
+    	      TokenNameafter = 14,
+    	      TokenNamedeclare = 15,
+    	      TokenNameprivileged = 11,
+    	      TokenNameIntegerLiteral = 60,
+    	      TokenNameLongLiteral = 61,
+    	      TokenNameFloatingPointLiteral = 62,
+    	      TokenNameDoubleLiteral = 63,
+    	      TokenNameCharacterLiteral = 64,
+    	      TokenNameStringLiteral = 65,
+    	      TokenNameTextBlock = 66,
+    	      TokenNamePLUS_PLUS = 5,
+    	      TokenNameMINUS_MINUS = 6,
+    	      TokenNameEQUAL_EQUAL = 52,
+    	      TokenNameLESS_EQUAL = 55,
+    	      TokenNameGREATER_EQUAL = 56,
+    	      TokenNameNOT_EQUAL = 32,
+    	      TokenNameLEFT_SHIFT = 53,
+    	      TokenNameRIGHT_SHIFT = 25,
+    	      TokenNameUNSIGNED_RIGHT_SHIFT = 29,
+    	      TokenNamePLUS_EQUAL = 88,
+    	      TokenNameMINUS_EQUAL = 89,
+    	      TokenNameMULTIPLY_EQUAL = 90,
+    	      TokenNameDIVIDE_EQUAL = 91,
+    	      TokenNameAND_EQUAL = 92,
+    	      TokenNameOR_EQUAL = 93,
+    	      TokenNameXOR_EQUAL = 94,
+    	      TokenNameREMAINDER_EQUAL = 95,
+    	      TokenNameLEFT_SHIFT_EQUAL = 96,
+    	      TokenNameRIGHT_SHIFT_EQUAL = 97,
+    	      TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL = 98,
+    	      TokenNameOR_OR = 30,
+    	      TokenNameAND_AND = 28,
+    	      TokenNamePLUS = 10,
+    	      TokenNameMINUS = 20,
+    	      TokenNameNOT = 71,
+    	      TokenNameREMAINDER = 22,
+    	      TokenNameXOR = 47,
+    	      TokenNameAND = 24,
+    	      TokenNameMULTIPLY = 19,
+    	      TokenNameOR = 46,
+    	      TokenNameTWIDDLE = 74,
+    	      TokenNameDIVIDE = 23,
+    	      TokenNameGREATER = 48,
+    	      TokenNameLESS = 21,
+    	      TokenNameLPAREN = 3,
+    	      TokenNameRPAREN = 17,
+    	      TokenNameLBRACE = 49,
+    	      TokenNameRBRACE = 54,
+    	      TokenNameLBRACKET = 4,
+    	      TokenNameRBRACKET = 99,
+    	      TokenNameSEMICOLON = 18,
+    	      TokenNameQUESTION = 26,
+    	      TokenNameCOLON = 72,
+    	      TokenNameCOMMA = 35,
+    	      TokenNameDOT = 1,
+    	      TokenNameEQUAL = 68,
+    	      TokenNameAT = 27,
+    	      TokenNameELLIPSIS = 109,
+    	      TokenNameARROW = 114,
+    	      TokenNameCOLON_COLON = 7,
+    	      TokenNameBeginLambda = 69,
+    	      TokenNameBeginIntersectionCast = 75,
+    	      TokenNameBeginTypeArguments = 106,
+    	      TokenNameElidedSemicolonAndRightBrace = 135,
+    	      TokenNameAT308 = 8,
+    	      TokenNameAT308DOTDOTDOT = 132,
+    	      TokenNameBeginCaseExpr = 136,
+    	      TokenNameRestrictedIdentifierYield = 112,
+    	      TokenNameRestrictedIdentifierrecord = 87,
+    	      TokenNameEOF = 100,
+    	      TokenNameERROR = 139;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TheOriginalJDTParserClass.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TheOriginalJDTParserClass.java
index 77add73..1e3f005 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TheOriginalJDTParserClass.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TheOriginalJDTParserClass.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -40,9 +40,13 @@
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
+import java.util.Set;
 import java.util.Stack;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
@@ -231,6 +235,8 @@
 						compliance = ClassFileConstants.JDK12;
 					}  else if("13".equals(token)) { //$NON-NLS-1$
 						compliance = ClassFileConstants.JDK13;
+					}  else if("14".equals(token)) { //$NON-NLS-1$
+						compliance = ClassFileConstants.JDK14;
 					} else if("recovery".equals(token)) { //$NON-NLS-1$
 						compliance = ClassFileConstants.JDK_DEFERRED;
 					}
@@ -845,6 +851,12 @@
 	protected int[] astLengthStack;
 	protected int astPtr;
 	protected ASTNode[] astStack = new ASTNode[AstStackIncrement];
+
+	protected int patternLengthPtr;
+
+	protected int[] patternLengthStack;
+	protected int patternPtr;
+	protected ASTNode[] patternStack = new ASTNode[AstStackIncrement];
 	public CompilationUnitDeclaration compilationUnit; /*the result from parse()*/
 
 	protected RecoveredElement currentElement;
@@ -922,6 +934,7 @@
 
 	protected int nestedType, dimensions, switchNestingLevel;
 	ASTNode [] noAstNodes = new ASTNode[AstStackIncrement];
+	public boolean switchWithTry = false;
 
 	Expression [] noExpressions = new Expression[ExpressionStackIncrement];
 	//modifiers dimensions nestedType etc.......
@@ -968,8 +981,7 @@
 protected /*private*/ int stateStackLengthStack[] = new int[0]; // AspectJ Extension: made protected
 protected boolean parsingJava8Plus;
 protected boolean parsingJava9Plus;
-protected boolean parsingJava12Plus;
-protected boolean parsingJava13Plus;
+protected boolean parsingJava14Plus;
 protected boolean parsingJava11Plus;
 protected int unstackedAct = ERROR_ACTION;
 private boolean haltOnSyntaxError = false;
@@ -978,6 +990,8 @@
 private boolean expectTypeAnnotation = false;
 private boolean reparsingLambdaExpression = false;
 
+private Map<RecordDeclaration, Integer[]> recordNestedMethodLevels;
+
 public TheOriginalJDTParserClass () { // AspectJ - new name
 	// Caveat Emptor: For inheritance purposes and then only in very special needs. Only minimal state is initialized !
 }
@@ -989,10 +1003,10 @@
 	initializeScanner();
 	this.parsingJava8Plus = this.options.sourceLevel >= ClassFileConstants.JDK1_8;
 	this.parsingJava9Plus = this.options.sourceLevel >= ClassFileConstants.JDK9;
-	this.parsingJava13Plus = this.options.sourceLevel >= ClassFileConstants.JDK13;
-	this.parsingJava12Plus = this.options.sourceLevel >= ClassFileConstants.JDK12;
+	this.parsingJava14Plus = this.options.sourceLevel >= ClassFileConstants.JDK14;
 	this.parsingJava11Plus = this.options.sourceLevel >= ClassFileConstants.JDK11;
 	this.astLengthStack = new int[50];
+	this.patternLengthStack = new int[20];
 	this.expressionLengthStack = new int[30];
 	this.typeAnnotationLengthStack = new int[30];
 	this.intStack = new int[50];
@@ -1003,6 +1017,8 @@
 	this.identifierPositionStack = new long[30];
 	this.variablesCounter = new int[30];
 
+	this.recordNestedMethodLevels = new HashMap<>();
+
 	// javadoc support
 	this.javadocParser = createJavadocParser();
 }
@@ -2255,16 +2271,8 @@
 	}
 	CaseStatement caseStatement = new CaseStatement(constantExpressions[0], constantExpressions[length - 1].sourceEnd, this.intStack[this.intPtr--]);
 	if (constantExpressions.length > 1) {
-		if (this.parsingJava13Plus) {
-			if (this.options.enablePreviewFeatures) {
-				if (this.options.isAnyEnabled(IrritantSet.PREVIEW) && constantExpressions.length > 1) {
-					problemReporter().previewFeatureUsed(caseStatement.sourceStart, caseStatement.sourceEnd);
-				}
-			} else {
-				problemReporter().previewFeatureNotEnabled(caseStatement.sourceStart, caseStatement.sourceEnd, "Multi constant case"); //$NON-NLS-1$
-			}
-		} else {
-			problemReporter().previewFeatureNotSupported(caseStatement.sourceStart, caseStatement.sourceEnd, "Multi constant case", CompilerOptions.VERSION_13); //$NON-NLS-1$
+		if (!this.parsingJava14Plus) {
+			problemReporter().multiConstantCaseLabelsNotSupported(caseStatement);
 		}
 	}
 	caseStatement.constantExpressions = constantExpressions;
@@ -2664,8 +2672,7 @@
 		this.lastCheckPoint = typeDecl.bodyStart;
 	}
 }
-protected void consumeClassHeaderName1() {
-	// ClassHeaderName1 ::= Modifiersopt 'class' 'Identifier'
+private void consumeClassOrRecordHeaderName1(boolean isRecord) {
 	TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
 	if (this.nestedMethod[this.nestedType] == 0) {
 		if (this.nestedType != 0) {
@@ -2690,6 +2697,7 @@
 	// we want to keep the beginning position but get rid of the end position
 	// it is only used for the ClassLiteralAccess positions.
 	typeDecl.declarationSourceStart = this.intStack[this.intPtr--];
+	typeDecl.restrictedIdentifierStart = typeDecl.declarationSourceStart;
 	this.intPtr--; // remove the end position of the class token
 
 	typeDecl.modifiersSourceStart = this.intStack[this.intPtr--];
@@ -2716,6 +2724,9 @@
 			length);
 	}
 	typeDecl.bodyStart = typeDecl.sourceEnd + 1;
+	if (isRecord) {
+		typeDecl = new RecordDeclaration(typeDecl);
+	}
 	pushOnAstStack(typeDecl);
 
 	this.listLength = 0; // will be updated when reading super-interfaces
@@ -2729,6 +2740,10 @@
 	typeDecl.javadoc = this.javadoc;
 	this.javadoc = null;
 }
+protected void consumeClassHeaderName1() {
+	// ClassHeaderName1 ::= Modifiersopt 'class' 'Identifier'
+	consumeClassOrRecordHeaderName1(false);
+}
 protected void consumeClassInstanceCreationExpression() {
 	// ClassInstanceCreationExpression ::= 'new' ClassType '(' ArgumentListopt ')' ClassBodyopt
 	classInstanceCreation(false);
@@ -3102,6 +3117,47 @@
 		}
 	}
 }
+// TODO: Refactor code for constructor and compact one once records are standardized.
+private void populateCompactConstructor(CompactConstructorDeclaration ccd) {
+	//name -- this is not really revelant but we do .....
+	ccd.selector = this.identifierStack[this.identifierPtr];
+	long selectorSource = this.identifierPositionStack[this.identifierPtr--];
+	this.identifierLengthPtr--;
+
+	//modifiers
+	ccd.declarationSourceStart = this.intStack[this.intPtr--];
+	ccd.modifiers = this.intStack[this.intPtr--];
+	// consume annotations
+	int length;
+	if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
+		System.arraycopy(
+			this.expressionStack,
+			(this.expressionPtr -= length) + 1,
+			ccd.annotations = new Annotation[length],
+			0,
+			length);
+	}
+	// javadoc
+	ccd.javadoc = this.javadoc;
+	this.javadoc = null;
+
+	//highlight starts at the selector starts
+	ccd.sourceStart = (int) (selectorSource >>> 32);
+	pushOnAstStack(ccd);
+	ccd.sourceEnd = ccd.sourceStart + ccd.selector.length - 1; // no lParen for compact constructor
+	ccd.bodyStart = ccd.sourceStart + ccd.selector.length;
+	this.listLength = 0; // initialize this.listLength before reading parameters/throws
+
+	// recovery
+	if (this.currentElement != null){
+		this.lastCheckPoint = ccd.bodyStart;
+		if ((this.currentElement instanceof RecoveredType && this.lastIgnoredToken != TokenNameDOT)
+			|| ccd.modifiers != 0){
+			this.currentElement = this.currentElement.add(ccd, 0);
+			this.lastIgnoredToken = -1;
+		}
+	}
+}
 protected void consumeConstructorHeaderNameWithTypeParameters() {
 
 	/* recovering - might be an empty message send */
@@ -3116,6 +3172,9 @@
 	// ConstructorHeaderName ::=  Modifiersopt TypeParameters 'Identifier' '('
 	ConstructorDeclaration cd = new ConstructorDeclaration(this.compilationUnit.compilationResult);
 
+	helperConstructorHeaderNameWithTypeParameters(cd);
+}
+private void helperConstructorHeaderNameWithTypeParameters(ConstructorDeclaration cd) {
 	//name -- this is not really revelant but we do .....
 	cd.selector = this.identifierStack[this.identifierPtr];
 	long selectorSource = this.identifierPositionStack[this.identifierPtr--];
@@ -3513,6 +3572,41 @@
 		this.currentElement.bracketBalance++;
 	}
 }
+private boolean isAFieldDeclarationInRecord() {
+	if (this.options.sourceLevel < ClassFileConstants.JDK14)
+		return false;
+	int recordIndex = -1;
+	Integer[] nestingTypeAndMethod = null;
+	for (int i = this.astPtr; i >= 0; --i) {
+		if (this.astStack[i] instanceof RecordDeclaration) {
+			RecordDeclaration node = (RecordDeclaration) this.astStack[i];
+			nestingTypeAndMethod = this.recordNestedMethodLevels.get(node);
+			if (nestingTypeAndMethod != null) { // record declaration is done yet
+				recordIndex = i;
+				break;
+			}
+		}
+	}
+	if (recordIndex < 0)
+		return false;
+	for (int i = recordIndex + 1; i <= this.astPtr; ++i) {
+		ASTNode node = this.astStack[i];
+		if (node instanceof TypeDeclaration) {
+			if (node.sourceEnd < 0) {
+				return false;
+			}
+		} else if (node instanceof AbstractMethodDeclaration) {
+			if (this.nestedType != nestingTypeAndMethod[0] ||
+					this.nestedMethod[this.nestedType] != nestingTypeAndMethod[1])
+				return false;
+		} else if (node instanceof FieldDeclaration) {
+			continue;
+		} else {
+			return false;
+		}
+	}
+	return true;
+}
 protected void consumeEnterVariable() {
 	// EnterVariable ::= $empty
 	// do nothing by default
@@ -3524,7 +3618,8 @@
 	Annotation [][] annotationsOnExtendedDimensions = extendedDimensions == 0 ? null : getAnnotationsOnDimensions(extendedDimensions);
 	AbstractVariableDeclaration declaration;
 	// create the ast node
-	boolean isLocalDeclaration = this.nestedMethod[this.nestedType] != 0;
+	boolean isLocalDeclaration = this.nestedMethod[this.nestedType] != 0 &&
+									!isAFieldDeclarationInRecord();
 	if (isLocalDeclaration) {
 		// create the local variable declarations
 		declaration =
@@ -4439,16 +4534,53 @@
 protected void consumeInsideCastExpressionWithQualifiedGenerics() {
 	// InsideCastExpressionWithQualifiedGenerics ::= $empty
 }
+protected void consumeTypeTestPattern() { // AspectJ raised to protected
+	TypeReference type;
+	char[] identifierName = this.identifierStack[this.identifierPtr];
+	long namePosition = this.identifierPositionStack[this.identifierPtr];
+
+	LocalDeclaration local = createLocalDeclaration(identifierName, (int) (namePosition >>> 32), (int) namePosition);
+	local.declarationSourceEnd = local.declarationEnd;
+
+	this.identifierPtr--;
+	this.identifierLengthPtr--;
+
+	type = getTypeReference(this.intStack[this.intPtr--]); //getTypeReference(0); // no type dimension
+	local.declarationSourceStart = type.sourceStart;
+	local.type = type;
+	if (!this.parsingJava14Plus) {
+		problemReporter().previewFeatureNotSupported(type.sourceStart, local.declarationEnd, "Instanceof Pattern", CompilerOptions.VERSION_13); //$NON-NLS-1$
+	} else if (!this.options.enablePreviewFeatures){
+		problemReporter().previewFeatureNotEnabled(type.sourceStart, local.declarationEnd, "Instanceof Pattern"); //$NON-NLS-1$
+	} else {
+		if (this.options.isAnyEnabled(IrritantSet.PREVIEW)) {
+			problemReporter().previewFeatureUsed(type.sourceStart, local.declarationEnd);
+		}
+	}
+	local.modifiers |= ClassFileConstants.AccFinal;
+	pushOnPatternStack(local);
+}
 protected void consumeInstanceOfExpression() {
 	// RelationalExpression ::= RelationalExpression 'instanceof' ReferenceType
 	//optimize the push/pop
 
 	//by construction, no base type may be used in getTypeReference
+	int length = this.patternLengthPtr >= 0 ?
+			this.patternLengthStack[this.patternLengthPtr--] : 0;
 	Expression exp;
+	if (length > 0) {
+		LocalDeclaration typeDecl = (LocalDeclaration) this.patternStack[this.patternPtr--];
+		this.expressionStack[this.expressionPtr] = exp =
+				new InstanceOfExpression(
+					this.expressionStack[this.expressionPtr],
+					typeDecl);
+	} else {
 	this.expressionStack[this.expressionPtr] = exp =
 		new InstanceOfExpression(
 			this.expressionStack[this.expressionPtr],
 			getTypeReference(this.intStack[this.intPtr--]));
+	}
+
 	if (exp.sourceEnd == 0) {
 		//array on base type....
 		exp.sourceEnd = this.scanner.startPosition - 1;
@@ -4459,14 +4591,25 @@
 	// RelationalExpression_NotName ::= Name instanceof ReferenceType
 	//optimize the push/pop
 
+	int length = this.patternLengthPtr >= 0 ?
+			this.patternLengthStack[this.patternLengthPtr--] : 0;
+	Expression exp;
+	if (length != 0) {
+		LocalDeclaration typeDecl = (LocalDeclaration) this.patternStack[this.patternPtr--];
+		pushOnExpressionStack(getUnspecifiedReferenceOptimized());
+		this.expressionStack[this.expressionPtr] = exp =
+				new InstanceOfExpression(
+					this.expressionStack[this.expressionPtr],
+					typeDecl);
+	} else {
 	//by construction, no base type may be used in getTypeReference
 	TypeReference reference = getTypeReference(this.intStack[this.intPtr--]);
 	pushOnExpressionStack(getUnspecifiedReferenceOptimized());
-	Expression exp;
 	this.expressionStack[this.expressionPtr] = exp =
 		new InstanceOfExpression(
 			this.expressionStack[this.expressionPtr],
 			reference);
+	}
 	if (exp.sourceEnd == 0) {
 		//array on base type....
 		exp.sourceEnd = this.scanner.startPosition - 1;
@@ -5976,6 +6119,9 @@
 }
 protected void consumeModuleDeclaration() {
 	// ModuleDeclaration ::= ModuleHeader ModuleBody
+	this.compilationUnit.javadoc = this.javadoc;
+	this.javadoc = null;
+
 	int length = this.astLengthStack[this.astLengthPtr--];
 	int[] flag = new int[length + 1]; //plus one -- see <HERE>
 	int size1 = 0, size2 = 0, size3 = 0, size4 = 0, size5 = 0;
@@ -7456,8 +7602,8 @@
 	}
 }
 protected void consumeTextBlock() {
-	if (!this.parsingJava13Plus) {
-		problemReporter().previewFeatureNotSupported(this.scanner.startPosition, this.scanner.currentPosition - 1, "Text Blocks", CompilerOptions.VERSION_13); //$NON-NLS-1$
+	if (!this.parsingJava14Plus) {
+		problemReporter().previewFeatureNotSupported(this.scanner.startPosition, this.scanner.currentPosition - 1, "Text Blocks", CompilerOptions.VERSION_14); //$NON-NLS-1$
 	} else if (!this.options.enablePreviewFeatures){
 		problemReporter().previewFeatureNotEnabled(this.scanner.startPosition, this.scanner.currentPosition - 1, "Text Blocks"); //$NON-NLS-1$
 	} else {
@@ -7515,14 +7661,8 @@
 //	SwitchLabelExpr ::= SwitchLabelCaseLhs BeginCaseExpr '->'
 	consumeCaseLabel();
 	CaseStatement caseStatement = (CaseStatement) this.astStack[this.astPtr];
-	if (!this.parsingJava13Plus) {
-		problemReporter().previewFeatureNotSupported(caseStatement.sourceStart, caseStatement.sourceEnd, "Case Labels with '->'", CompilerOptions.VERSION_13); //$NON-NLS-1$
-	} else if (!this.options.enablePreviewFeatures){
-		problemReporter().previewFeatureNotEnabled(caseStatement.sourceStart, caseStatement.sourceEnd, "Case Labels with '->'"); //$NON-NLS-1$
-	} else {
-		if (this.options.isAnyEnabled(IrritantSet.PREVIEW)) {
-			problemReporter().previewFeatureUsed(caseStatement.sourceStart, caseStatement.sourceEnd);
-		}
+	if (!this.parsingJava14Plus) {
+		problemReporter().arrowInCaseStatementsNotSupported(caseStatement);
 	}
 	caseStatement.isExpr = true;
 }
@@ -7530,14 +7670,8 @@
 //	SwitchLabelDefaultExpr ::= 'default' '->'
 	consumeDefaultLabel();
 	CaseStatement defaultStatement = (CaseStatement) this.astStack[this.astPtr];
-	if (!this.parsingJava13Plus) {
-		problemReporter().previewFeatureNotSupported(defaultStatement.sourceStart, defaultStatement.sourceEnd, "Case Labels with '->'", CompilerOptions.VERSION_13); //$NON-NLS-1$
-	} else if (!this.options.enablePreviewFeatures){
-		problemReporter().previewFeatureNotEnabled(defaultStatement.sourceStart, defaultStatement.sourceEnd, "Case Labels with '->'"); //$NON-NLS-1$
-	} else {
-		if (this.options.isAnyEnabled(IrritantSet.PREVIEW)) {
-			problemReporter().previewFeatureUsed(defaultStatement.sourceStart, defaultStatement.sourceEnd);
-		}
+	if (!this.parsingJava14Plus) {
+		problemReporter().arrowInCaseStatementsNotSupported(defaultStatement);
 	}
 	defaultStatement.isExpr = true;
 }
@@ -7547,6 +7681,7 @@
 
 	class ResultExpressionsCollector extends ASTVisitor {
 		Stack<SwitchExpression> targetSwitchExpressions;
+		Stack<TryStatement> tryStatements;
 		public ResultExpressionsCollector(SwitchExpression se) {
 			if (this.targetSwitchExpressions == null)
 				this.targetSwitchExpressions = new Stack<>();
@@ -7573,6 +7708,8 @@
 				// flag an error while resolving
 				yieldStatement.switchExpression = targetSwitchExpression;
 			}
+			if (this.tryStatements != null && !this.tryStatements.empty())
+				yieldStatement.tryStatement = this.tryStatements.peek();
 			return true;
 		}
 		@Override
@@ -7583,6 +7720,24 @@
 		public boolean visit(TypeDeclaration stmt, BlockScope blockScope) {
 			return false;
 		}
+		@Override
+		public boolean visit(LambdaExpression stmt, BlockScope blockScope) {
+			return false;
+	}
+		@Override
+		public boolean visit(TryStatement stmt, BlockScope blockScope) {
+			if (this.tryStatements == null)
+				this.tryStatements = new Stack<>();
+			this.tryStatements.push(stmt);
+			SwitchExpression targetSwitchExpression = this.targetSwitchExpressions.peek();
+			targetSwitchExpression.containsTry = true;
+			stmt.enclosingSwitchExpression = targetSwitchExpression;
+			return true;
+		}
+		@Override
+		public void endVisit(TryStatement stmt, BlockScope blockScope) {
+			this.tryStatements.pop();
+		}
 	}
 	s.resultExpressions = new ArrayList<>(0); // indicates processed
 	int l = s.statements == null ? 0 : s.statements.length;
@@ -7611,16 +7766,11 @@
 	if (this.astLengthStack[this.astLengthPtr--] != 0) {
 		SwitchExpression s = (SwitchExpression) this.astStack[this.astPtr--];
 
-		if (!this.parsingJava13Plus) {
-			problemReporter().previewFeatureNotSupported(s.sourceStart, s.sourceEnd, "Switch Expressions", CompilerOptions.VERSION_13); //$NON-NLS-1$
-		} else if (!this.options.enablePreviewFeatures) {
-			problemReporter().previewFeatureNotEnabled(s.sourceStart, s.sourceEnd, "Switch Expressions"); //$NON-NLS-1$
-		} else {
-			if (this.options.isAnyEnabled(IrritantSet.PREVIEW)) {
-				problemReporter().previewFeatureUsed(s.sourceStart, s.sourceEnd);
-			}
+		if (!this.parsingJava14Plus) {
+			problemReporter().switchExpressionsNotSupported(s);
 		}
 		collectResultExpressionsYield(s);
+		this.switchWithTry |= s.containsTry;
 		pushOnExpressionStack(s);
 	}
 }
@@ -7945,6 +8095,7 @@
 			resetModifiers();
 			pushOnIntStack(this.scanner.startPosition);
 			break;
+		case TokenNameRestrictedIdentifierrecord:
 		case TokenNameclass :
 			pushOnIntStack(this.scanner.currentPosition - 1);
 			pushOnIntStack(this.scanner.startPosition);
@@ -8496,6 +8647,500 @@
 	// Nothing to do
 	// The wildcard is created by the consumeWildcardBoundsExtends or by consumeWildcardBoundsSuper
 }
+/* Java 14 preview - records */
+protected void consumeRecordDeclaration() {
+	// RecordDeclaration ::= RecordHeaderPart RecordBody
+
+	int length;
+	if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) {
+		//there are length declarations
+		//dispatch according to the type of the declarations
+		dispatchDeclarationIntoRecordDeclaration(length);
+	}
+
+	RecordDeclaration rd = (RecordDeclaration) this.astStack[this.astPtr];
+	this.recordNestedMethodLevels.remove(rd);
+	if (!this.options.enablePreviewFeatures){
+		problemReporter().previewFeatureNotEnabled(rd.sourceStart, rd.sourceEnd, "Records"); //$NON-NLS-1$
+	} else {
+		if (this.options.isAnyEnabled(IrritantSet.PREVIEW)) {
+			problemReporter().previewFeatureUsed(rd.sourceStart, rd.sourceEnd);
+		}
+	}
+	//convert constructor that do not have the type's name into methods
+	ConstructorDeclaration cd = rd.getConstructor((Parser)this); // AspectJ - cast to Parser
+	if (cd == null) {
+		/* create canonical constructor - check for the clash later at binding time */
+		cd = rd.createDefaultConstructor(!(this.diet && this.dietInt == 0), true);
+	} else {
+		cd.bits |= ASTNode.IsCanonicalConstructor;
+	}
+
+	if (this.scanner.containsAssertKeyword) {
+		rd.bits |= ASTNode.ContainsAssertion;
+	}
+	rd.addClinit();
+	rd.bodyEnd = this.endStatementPosition;
+	if (length == 0 && !containsComment(rd.bodyStart, rd.bodyEnd)) {
+		rd.bits |= ASTNode.UndocumentedEmptyBlock;
+	}
+	TypeReference superClass = new QualifiedTypeReference(TypeConstants.JAVA_LANG_RECORD, new long[] {0});
+	superClass.bits |= ASTNode.IsSuperType;
+	rd.superclass = superClass;
+	rd.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition);
+}
+protected void consumeRecordHeaderPart() {
+	// RecordHeaderPart ::= RecordHeaderName RecordHeader ClassHeaderImplementsopt
+	TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr];
+	assert typeDecl instanceof RecordDeclaration;
+	// do nothing
+}
+protected void consumeRecordHeaderNameWithTypeParameters() {
+	// RecordHeaderName ::= RecordHeaderName1 TypeParameters
+	consumeTypeHeaderNameWithTypeParameters();
+}
+protected void consumeRecordHeaderName1() {
+	// Modifiersopt RestrictedIdentifierrecord 'Identifier'
+	consumeClassOrRecordHeaderName1(true);
+}
+protected void consumeRecordComponentHeaderRightParen() {
+	// RecordComponentHeaderRightParen ::= ')'
+	int length = this.astLengthStack[this.astLengthPtr--];
+	this.astPtr -= length;
+	RecordDeclaration rd = (RecordDeclaration) this.astStack[this.astPtr];
+	int nestedMethodLevel = this.nestedMethod[this.nestedType];
+	rd.isLocalRecord = nestedMethodLevel > 0;
+	if (rd.isLocalRecord)
+		rd.modifiers |= ClassFileConstants.AccStatic; // JLS 14 Sec 14.3
+	this.recordNestedMethodLevels.put(rd, new Integer[] {this.nestedType, nestedMethodLevel});
+	this.astStack[this.astPtr] = rd;
+//	rd.sourceEnd = 	this.rParenPos;
+	if (length != 0) {
+		Argument[] args = new Argument[length];
+		System.arraycopy(
+				this.astStack,
+				this.astPtr + 1,
+				args,
+				0,
+				length);
+		rd.setArgs(args);
+		convertToFields(rd, args);
+	}
+	rd.bodyStart = this.rParenPos+1;
+	this.listLength = 0; // reset this.listLength after having read all parameters
+	// recovery
+	if (this.currentElement != null){
+		this.lastCheckPoint = rd.bodyStart;
+		if (this.currentElement.parseTree() == rd) return;
+	}
+}
+private void convertToFields(RecordDeclaration rd, Argument[] args) {
+	int length = args.length;
+	FieldDeclaration[] fields = new FieldDeclaration[length];
+	int nFields = 0;
+	Set<String> argsSet = new HashSet<>();
+	for (int i = 0, max = args.length; i < max; i++) {
+		Argument arg = args[i];
+		arg.bits |= ASTNode.IsRecordComponent;
+		String argName = new String(arg.name);
+		if (RecordDeclaration.disallowedComponentNames.contains(argName)) {
+			problemReporter().recordIllegalComponentNameInRecord(arg, rd);
+			continue;
+		}
+		if (argsSet.contains(argName)) {
+			// flag the error at the place where duplicate params of methods would have been flagged.
+			continue;
+		}
+		if (arg.type.getLastToken() == TypeConstants.VOID) {
+			problemReporter().recordComponentCannotBeVoid(rd, arg);
+			continue;
+		}
+		if (arg.isVarArgs() && i < max - 1)
+			problemReporter().recordIllegalVararg(arg, rd);
+
+		argsSet.add(argName);
+		FieldDeclaration f = fields[nFields++] = createFieldDeclaration(arg.name, arg.sourceStart, arg.sourceEnd);
+		f.bits = arg.bits;
+		f.declarationSourceStart = arg.declarationSourceStart;
+		f.declarationEnd = arg.declarationEnd;
+		f.declarationSourceEnd = arg.declarationSourceEnd;
+		f.endPart1Position = arg.sourceEnd; //TODO BETA_JAVA14 - recheck
+		f.endPart2Position = arg.declarationSourceEnd;
+		f.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccFinal;
+		// Note: JVMS 14 S 4.7.8 The Synthetic Attribute mandates do not mark Synthetic for Record compoents.
+		// hence marking this "explicitly" as implicit.
+		f.isARecordComponent = true;
+		/*
+		 * JLS 14 Sec 8.10.1 Record Header
+		 * The record header declares a number of record components. The record components
+		 * declare the fields of the record class. Each record component in the RecordHeader
+		 * declares one private final field in the record class whose name is same as the
+		 * Identifier in the record component.
+		 *
+		 * JLS 14 Sec 8.10.3 Record Components
+		 * For each record component appearing in the record component list:
+		 * An implicitly declared private final field with the same name as the record
+		 * component and the type as the declared type of the record component.
+		 */
+		f.modifiers |= ClassFileConstants.AccPrivate | ClassFileConstants.AccFinal;
+		f.modifiersSourceStart = arg.modifiersSourceStart;
+		f.sourceStart = arg.sourceStart;
+		f.sourceEnd = arg.sourceEnd;
+		f.type = arg.type;
+		/*
+		 * JLS 14 SEC 8.10.3 Item 1 says the following:
+		 *  "This field is annotated with the annotation that appears on the corresponding
+		 *  record component, if this annotation type is applicable to a field declaration
+		 *  or type context."
+		 *
+		 *  However, at this point there is no sufficient information to conclude the ElementType
+		 *  targeted by the annotation. Hence, do a blanket assignment for now and later (read binding
+		 *  time) weed out the irrelevant ones.
+		 */
+		f.annotations = arg.annotations;
+		arg.annotations = null;
+		if ((args[i].bits & ASTNode.HasTypeAnnotations) != 0) {
+			f.bits |= ASTNode.HasTypeAnnotations;
+		}
+	}
+	if (nFields < fields.length) {
+		// Note: This happens only if there are errors in the code.
+		FieldDeclaration[] tmp = new FieldDeclaration[nFields];
+		System.arraycopy(fields	, 0, tmp, 0, nFields);
+		fields = tmp;
+	}
+	rd.fields = fields;
+	rd.nRecordComponents = fields.length;
+}
+protected void consumeRecordHeader() {
+	//RecordHeader ::= '(' RecordComponentsopt RecordComponentHeaderRightParen
+	//TODO: BETA_JAVA14_RECORD flag TypeDeclaration.RECORD_DECL ?
+}
+protected void consumeRecordComponentsopt() {
+	// RecordComponentsopt ::= $empty
+	pushOnAstLengthStack(0);
+}
+protected void consumeRecordComponents() {
+	// RecordComponents ::= RecordComponents ',' RecordComponent
+	optimizedConcatNodeLists();
+}
+// TODO: merge consumeFormalParameter and this method once record becomes a standard feature
+protected void consumeRecordComponent(boolean isVarArgs) {
+// RecordComponent ::= Modifiersopt Type VariableDeclaratorId
+//	VariableArityRecordComponent ::= Modifiersopt Type PushZeroTypeAnnotations '...' VariableDeclaratorId
+//	VariableArityRecordComponent ::= Modifiersopt Type @308... TypeAnnotations '...' VariableDeclaratorId
+// Note that there is a difference wrt VariableDeclaratorId wrt to the JLS 8.10.1 specification which specifies
+// 'identifier' - however this is identical to consumeFormalParameter where this error is caught and reported.
+	this.identifierLengthPtr--;
+	char[] identifierName = this.identifierStack[this.identifierPtr];
+	long namePositions = this.identifierPositionStack[this.identifierPtr--];
+	int extendedDimensions = this.intStack[this.intPtr--];
+	Annotation [][] annotationsOnExtendedDimensions = extendedDimensions == 0 ? null : getAnnotationsOnDimensions(extendedDimensions);
+	Annotation [] varArgsAnnotations = null;
+	int endOfEllipsis = 0;
+	int length;
+	int firstDimensions = 0;
+	if (isVarArgs) {
+		endOfEllipsis = this.intStack[this.intPtr--];
+		if ((length = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr--]) != 0) {
+			System.arraycopy(
+				this.typeAnnotationStack,
+				(this.typeAnnotationPtr -= length) + 1,
+				varArgsAnnotations = new Annotation[length],
+				0,
+				length);
+		}
+	}
+	firstDimensions = this.intStack[this.intPtr--];
+	TypeReference type = getTypeReference(firstDimensions);
+	if (isVarArgs || extendedDimensions != 0) {
+		if (isVarArgs) {
+			type = augmentTypeWithAdditionalDimensions(type, 1, varArgsAnnotations != null ? new Annotation[][] { varArgsAnnotations } : null, true);
+		}
+		if (extendedDimensions != 0) {
+			type = augmentTypeWithAdditionalDimensions(type, extendedDimensions, annotationsOnExtendedDimensions, false);
+		}
+		type.sourceEnd = type.isParameterizedTypeReference() ? this.endStatementPosition : this.endPosition;
+	}
+	if (isVarArgs) {
+		if (extendedDimensions == 0) {
+			type.sourceEnd = endOfEllipsis;
+		}
+		type.bits |= ASTNode.IsVarArgs; // set isVarArgs
+	}
+	int modifierPositions = this.intStack[this.intPtr--];
+	Argument arg;
+	arg = new Argument(
+			identifierName,
+			namePositions,
+			type,
+			this.intStack[this.intPtr--] & ~ClassFileConstants.AccDeprecated); // modifiers
+	arg.declarationSourceStart = modifierPositions;
+	arg.bits |= (type.bits & ASTNode.HasTypeAnnotations);
+	// consume annotations
+	if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
+		System.arraycopy(
+			this.expressionStack,
+			(this.expressionPtr -= length) + 1,
+			arg.annotations = new Annotation[length],
+			0,
+			length);
+		arg.bits |= ASTNode.HasTypeAnnotations;
+		RecoveredType currentRecoveryType = this.currentRecoveryType();
+		if (currentRecoveryType != null)
+			currentRecoveryType.annotationsConsumed(arg.annotations);
+	}
+	pushOnAstStack(arg);
+
+	/* if incomplete record header, this.listLength counter will not have been reset,
+		indicating that some arguments are available on the stack */
+	this.listLength++;
+	if(isVarArgs) {
+		if (!this.statementRecoveryActivated &&
+				this.options.sourceLevel < ClassFileConstants.JDK1_5 &&
+				this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) {
+				problemReporter().invalidUsageOfVarargs(arg);
+		} else if (!this.statementRecoveryActivated &&
+				extendedDimensions > 0) {
+			problemReporter().illegalExtendedDimensions(arg);
+		}
+	}
+}
+protected void consumeRecordBody() {
+	// RecordBody ::= '{' RecordBodyDeclarationopt '}'
+	// do nothing
+}
+protected void consumeEmptyRecordBodyDeclaration() {
+	// RecordBodyDeclarationopt ::= $empty
+	//TODO: Throw an error for empty record?
+	pushOnAstLengthStack(0);
+}
+protected void consumeRecordBodyDeclarations() {
+	//	RecordBodyDeclarations ::= RecordBodyDeclaration
+	//	RecordBodyDeclarations ::= RecordBodyDeclarations RecordBodyDeclaration
+	concatNodeLists();
+}
+protected void consumeRecordBodyDeclaration() {
+	// RecordBodyDeclaration ::=  ClassBodyDeclaration
+//	consumeClassBodyDeclaration();
+}
+protected void consumeCompactConstructorDeclaration() {
+	// CompactConstructorDeclaration ::= CompactConstructorHeaderName MethodHeaderThrowsClauseopt MethodBody
+
+	//must provide a default constructor call when needed
+
+	int length;
+
+	// pop the position of the {  (body of the method) pushed in block decl
+	this.intPtr--;
+	this.intPtr--;
+
+	//statements
+	this.realBlockPtr--;
+	Statement[] statements = null;
+	if ((length = this.astLengthStack[this.astLengthPtr--]) != 0) {
+		this.astPtr -= length;
+		if (!this.options.ignoreMethodBodies) {
+			System.arraycopy(
+					this.astStack,
+					this.astPtr + 1,
+					statements = new Statement[length],
+					0,
+					length);
+		}
+	}
+
+	CompactConstructorDeclaration ccd = (CompactConstructorDeclaration) this.astStack[this.astPtr];
+	ccd.statements = statements;
+
+	if (!(this.diet && this.dietInt == 0)
+			&& statements == null
+			&& !containsComment(ccd.bodyStart, this.endPosition)) {
+		ccd.bits |= ASTNode.UndocumentedEmptyBlock;
+	}
+
+	//watch for } that could be given as a unicode ! ( u007D is '}' )
+	// store the this.endPosition (position just before the '}') in case there is
+	// a trailing comment behind the end of the method
+	ccd.bodyEnd = this.endPosition;
+	ccd.declarationSourceEnd = flushCommentsDefinedPriorTo(this.endStatementPosition);
+}
+protected void consumeCompactConstructorHeader() {
+//	CompactConstructorHeader ::= CompactConstructorHeaderName MethodHeaderThrowsClauseopt
+
+	// TODO: Ideally a consumeConstructorHeader should be ok; but if this is overridden and
+	// rParentPos is used (ref model), that is incorrect since rParentPos does not exist for CCH
+	AbstractMethodDeclaration method = (AbstractMethodDeclaration)this.astStack[this.astPtr];
+
+	if (this.currentToken == TokenNameLBRACE){
+		method.bodyStart = this.scanner.currentPosition;
+	}
+	// recovery
+	if (this.currentElement != null){
+		if (this.currentToken == TokenNameSEMICOLON){ // for invalid constructors
+			method.modifiers |= ExtraCompilerModifiers.AccSemicolonBody;
+			method.declarationSourceEnd = this.scanner.currentPosition-1;
+			method.bodyEnd = this.scanner.currentPosition-1;
+			if (this.currentElement.parseTree() == method && this.currentElement.parent != null) {
+				this.currentElement = this.currentElement.parent;
+			}
+		}
+		this.restartRecovery = true; // used to avoid branching back into the regular automaton
+	}
+}
+protected void consumeCompactConstructorHeaderName() {
+	// CompactConstructorHeaderName ::= Modifiersopt 'Identifier'
+
+	/* recovering - might be an empty message send */
+	if (this.currentElement != null){
+		if (this.lastIgnoredToken == TokenNamenew){ // was an allocation expression
+			this.lastCheckPoint = this.scanner.startPosition; // force to restart at this exact position
+			this.restartRecovery = true;
+			return;
+		}
+	}
+	CompactConstructorDeclaration ccd = new CompactConstructorDeclaration(this.compilationUnit.compilationResult);
+	populateCompactConstructor(ccd);
+}
+protected void consumeCompactConstructorHeaderNameWithTypeParameters() {
+	//  CompactConstructorHeaderName ::= Modifiersopt TypeParameters 'Identifier'
+	/* recovering - might be an empty message send */
+	if (this.currentElement != null){
+		if (this.lastIgnoredToken == TokenNamenew){ // was an allocation expression
+			this.lastCheckPoint = this.scanner.startPosition; // force to restart at this exact position
+			this.restartRecovery = true;
+			return;
+		}
+	}
+	CompactConstructorDeclaration ccd = new CompactConstructorDeclaration(this.compilationUnit.compilationResult);
+	helperConstructorHeaderNameWithTypeParameters(ccd);
+}
+protected void dispatchDeclarationIntoRecordDeclaration(int length) {
+	/* they are length on this.astStack that should go into
+	   methods fields constructors lists of the typeDecl
+
+	   Return if there is a constructor declaration in the methods declaration */
+
+
+	// Looks for the size of each array .
+
+	if (length == 0)
+		return;
+	int[] flag = new int[length + 1]; //plus one -- see <HERE>
+	int nFields = 0, size2 = 0, size3 = 0;
+	boolean hasAbstractMethods = false;
+	for (int i = length - 1; i >= 0; i--) {
+		ASTNode astNode = this.astStack[this.astPtr--];
+		if (astNode instanceof AbstractMethodDeclaration) {
+			//methods and constructors have been regrouped into one single list
+			flag[i] = 2;
+			size2++;
+			if (((AbstractMethodDeclaration) astNode).isAbstract()) {
+				hasAbstractMethods = true;
+			}
+		} else if (astNode instanceof TypeDeclaration) {
+			flag[i] = 3;
+			size3++;
+		} else {
+			//field
+			flag[i] = 1;
+			nFields++;
+		}
+	}
+
+	//arrays creation
+	RecordDeclaration recordDecl = (RecordDeclaration) this.astStack[this.astPtr];
+	int nCreatedFields = recordDecl.fields != null ? recordDecl.fields.length : 0;
+	if (nFields != 0) {
+		FieldDeclaration[] tmp = new FieldDeclaration[(recordDecl.fields != null ? recordDecl.fields.length  : 0) + nFields];
+		if (recordDecl.fields != null)
+			System.arraycopy(
+					recordDecl.fields,
+					0,
+					tmp,
+					0,
+					recordDecl.fields.length);
+		recordDecl.fields = tmp;
+	}
+	if (size2 != 0) {
+		recordDecl.methods = new AbstractMethodDeclaration[size2];
+		if (hasAbstractMethods) recordDecl.bits |= ASTNode.HasAbstractMethods;
+	}
+	if (size3 != 0) {
+		recordDecl.memberTypes = new TypeDeclaration[size3];
+	}
+
+	//arrays fill up
+	nFields = nCreatedFields;
+	size2 = size3 = 0;
+	int flagI = flag[0], start = 0;
+	int length2;
+	for (int end = 0; end <= length; end++) //<HERE> the plus one allows to
+		{
+		if (flagI != flag[end]) //treat the last element as a ended flag.....
+			{ //array copy
+			switch (flagI) {
+				case 1 :
+					nFields += (length2 = end - start);
+					System.arraycopy(
+						this.astStack,
+						this.astPtr + start + 1,
+						recordDecl.fields,
+						nFields - length2,
+						length2);
+					break;
+				case 2 :
+					size2 += (length2 = end - start);
+					System.arraycopy(
+						this.astStack,
+						this.astPtr + start + 1,
+						recordDecl.methods,
+						size2 - length2,
+						length2);
+					break;
+				case 3 :
+					size3 += (length2 = end - start);
+					System.arraycopy(
+						this.astStack,
+						this.astPtr + start + 1,
+						recordDecl.memberTypes,
+						size3 - length2,
+						length2);
+					break;
+			}
+			flagI = flag[start = end];
+		}
+	}
+	checkForRecordMemberErrors(recordDecl, nCreatedFields);
+
+	if (recordDecl.memberTypes != null) {
+		for (int i = recordDecl.memberTypes.length - 1; i >= 0; i--) {
+			recordDecl.memberTypes[i].enclosingType = recordDecl;
+		}
+	}
+}
+private void checkForRecordMemberErrors(RecordDeclaration recordDecl, int nCreatedFields) {
+	if (recordDecl.fields == null)
+		return;
+	for (int i = nCreatedFields; i < recordDecl.fields.length; i++) {
+		FieldDeclaration f = recordDecl.fields[i];
+		if (f != null && !f.isStatic()) {
+			if (f instanceof Initializer)
+				problemReporter().recordInstanceInitializerBlockInRecord((Initializer) f);
+			else
+				problemReporter().recordNonStaticFieldDeclarationInRecord(f);
+		}
+	}
+	if (recordDecl.methods != null) {
+		for (int i = 0; i < recordDecl.methods.length; i++) {
+			AbstractMethodDeclaration method = recordDecl.methods[i];
+			if ((method.modifiers & ClassFileConstants.AccNative) != 0) {
+				problemReporter().recordIllegalNativeModifierInRecord(method);
+			}
+		}
+	}
+}
+/* Java 14 preview - records - end*/
 /**
  * Given the current comment stack, answer whether some comment is available in a certain exclusive range
  *
@@ -8671,8 +9316,18 @@
 	if (typeDecl.memberTypes != null) {
 		for (int i = typeDecl.memberTypes.length - 1; i >= 0; i--) {
 			typeDecl.memberTypes[i].enclosingType = typeDecl;
+			markNestedRecordStatic(typeDecl.memberTypes[i]);
+		}
 		}
 	}
+private void markNestedRecordStatic(TypeDeclaration typeDeclaration) {
+	/*
+	 * JLS 14 8.10 (Preview)
+	 * A nested record type is implicitly static.
+	 * It is permitted for the declaration of a nested record type to redundantly specify the static modifier.
+	 */
+	if (typeDeclaration instanceof RecordDeclaration)
+		typeDeclaration.modifiers |= ClassFileConstants.AccStatic;
 }
 protected void dispatchDeclarationIntoEnumDeclaration(int length) {
 
@@ -9437,6 +10092,8 @@
 	this.javadoc = null;
 	this.astPtr = -1;
 	this.astLengthPtr = -1;
+	this.patternPtr = -1;
+	this.patternLengthPtr = -1;
 	this.expressionPtr = -1;
 	this.expressionLengthPtr = -1;
 	this.typeAnnotationLengthPtr = -1;
@@ -9446,6 +10103,7 @@
 	this.intPtr = -1;
 	this.nestedMethod[this.nestedType = 0] = 0; // need to reset for further reuse
 	this.switchNestingLevel = 0;
+	this.switchWithTry = false;
 	this.variablesCounter[this.nestedType] = 0;
 	this.dimensions = 0 ;
 	this.realBlockPtr = -1;
@@ -10629,6 +11287,7 @@
 	this.variablesCounter[this.nestedType] = 0;
 	this.realBlockStack[this.realBlockPtr = 1] = 0;
 	this.switchNestingLevel = 0;
+	this.switchWithTry = false;
 }
 /**
  * Returns this parser's problem reporter initialized with its reference context.
@@ -10704,6 +11363,29 @@
 	}
 	this.astLengthStack[this.astLengthPtr] = pos;
 }
+protected void pushOnPatternStack(ASTNode pattern) {
+	/*add a new obj on top of the ast stack
+	astPtr points on the top*/
+
+	int stackLength = this.patternStack.length;
+	if (++this.patternPtr >= stackLength) {
+		System.arraycopy(
+			this.patternStack, 0,
+			this.patternStack = new ASTNode[stackLength + AstStackIncrement], 0,
+			stackLength);
+		this.patternPtr = stackLength;
+	}
+	this.patternStack[this.patternPtr] = pattern;
+
+	stackLength = this.patternLengthStack.length;
+	if (++this.patternLengthPtr >= stackLength) {
+		System.arraycopy(
+			this.patternLengthStack, 0,
+			this.patternLengthStack = new int[stackLength + AstStackIncrement], 0,
+			stackLength);
+	}
+	this.patternLengthStack[this.patternLengthPtr] = 1;
+}
 protected void pushOnAstStack(ASTNode node) {
 	/*add a new obj on top of the ast stack
 	astPtr points on the top*/
@@ -11208,6 +11890,8 @@
 
 	this.astPtr = -1;
 	this.astLengthPtr = -1;
+	this.patternPtr = -1;
+	this.patternLengthPtr = -1;
 	this.expressionPtr = -1;
 	this.expressionLengthPtr = -1;
 	this.typeAnnotationLengthPtr = -1;
@@ -11219,6 +11903,7 @@
 	this.nestedMethod[this.nestedType = 0] = 0; // need to reset for further reuse
 	this.variablesCounter[this.nestedType] = 0;
 	this.switchNestingLevel = 0;
+	this.switchWithTry = false;
 	
 	this.dimensions = 0 ;
 	this.realBlockStack[this.realBlockPtr = 0] = 0;
@@ -11230,6 +11915,7 @@
 	this.genericsLengthPtr = -1;
 	this.genericsPtr = -1;
 	this.valueLambdaNestDepth = -1;
+	this.recordNestedMethodLevels = new HashMap<>();
 }
 /*
  * Reset context so as to resume to regular parse loop
@@ -11436,6 +12122,8 @@
 	this.identifierLengthPtr = parser.identifierLengthPtr;
 	this.astPtr = parser.astPtr;
 	this.astLengthPtr = parser.astLengthPtr;
+	this.patternPtr = parser.patternPtr;
+	this.patternLengthPtr = parser.patternLengthPtr;
 	this.expressionPtr = parser.expressionPtr;
 	this.expressionLengthPtr = parser.expressionLengthPtr;
 	this.genericsPtr = parser.genericsPtr;
@@ -11446,6 +12134,7 @@
 	this.intPtr = parser.intPtr;
 	this.nestedType = parser.nestedType;
 	this.switchNestingLevel = parser.switchNestingLevel;
+	this.switchWithTry = parser.switchWithTry;
 	this.realBlockPtr = parser.realBlockPtr;
 	this.valueLambdaNestDepth = parser.valueLambdaNestDepth;
 	
@@ -11522,8 +12211,8 @@
 	}
 }
 @Override
-public boolean isParsingJava13() {
-	return this.parsingJava13Plus;
+public boolean isParsingJava14() {
+	return this.parsingJava14Plus;
 }
 @Override
 public boolean isParsingModuleDeclaration() {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TheOriginalJDTScannerClass.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TheOriginalJDTScannerClass.java
index 0c9b1a1..be6a156 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TheOriginalJDTScannerClass.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/TheOriginalJDTScannerClass.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -578,9 +578,6 @@
 	return result;
 }
 protected final boolean scanForTextBlockBeginning() {
-	if (this.activeParser != null && !this.activeParser.isParsingJava13()) {
-		return false;
-	}
 	try {
 		// Don't change the position and current character unless we are certain
 		// to be dealing with a text block. For producing all errors like before
@@ -592,7 +589,6 @@
 			while (ScannerHelper.isWhitespace(c)) {
 				switch (c) {
 					case 10 : /* \ u000a: LINE FEED               */
-					case 13 : /* \ u000d: CARRIAGE RETURN         */
 						this.currentCharacter = c;
 						this.currentPosition = temp;
 						return true;
@@ -628,6 +624,7 @@
 			all = new char[0];
 		}
 	}
+	all = normalize(all);
 	// 2. Split into lines. Consider both \n and \r as line separators
 	char[][] lines = CharOperation.splitOn('\n', all);
 	int size = lines.length;
@@ -639,8 +636,10 @@
 			break;
 		}
 		char[][] sub = CharOperation.splitOn('\r', line);
+		if (sub.length == 0) {
+			list.add(line);
+		} else {
 		for (char[] cs : sub) {
-			if (cs.length > 0) {
 				list.add(cs);
 			}
 		}
@@ -664,6 +663,8 @@
 				}
 			}
 		}
+ 		// The last line with closing delimiter is part of the
+ 		// determining line list even if empty
 		if (!blank || (i+1 == size)) {
 			if (prefix < 0 || whitespaces < prefix) {
  				prefix = whitespaces;
@@ -671,42 +672,165 @@
 		}
 	}
 	// 3.2. Remove the common white space prefix
-	// 4. Handle escape sequences (already done while processing
+	// 4. Handle escape sequences  that are not already done in getNextToken0()
 	if (prefix == -1)
 		prefix = 0;
-	char[] result = new char[0];
+	StringBuilder result = new StringBuilder();
+	boolean newLine = false;
 	for(int i = 0; i < lines.length; i++) {
 		char[] l  = lines[i];
 		// Remove the common prefix from each line
 		// And remove all trailing whitespace
 		// Finally append the \n at the end of the line (except the last line)
 		int length = l.length;
-		int trail = length - 1;
-		for(int j = trail; j>0; j--) {
-			if (!ScannerHelper.isWhitespace(l[j])) {
-				trail = j;
+		int trail = length;
+		for(;trail > 0;) {
+			if (!ScannerHelper.isWhitespace(l[trail-1])) {
 				break;
 			}
+			trail--;
 		}
-		int newSize = (length == 0 || prefix > trail) ? 0 : (trail - prefix + 1);
-		char[] nl;
 		if (i >= (size - 1)) {
-			if (trail <= 0 || newSize == 0)
+			if (newLine) result.append('\n');
+			if (trail < prefix)
 				continue;
-			nl = new char[newSize];
-			System.arraycopy(l, prefix, nl, 0, newSize); 
+			newLine = getLineContent(result, l, prefix, trail-1, false, true);
 		} else {
-			newSize += 1;
-			nl = new char[newSize];
-			nl[newSize - 1] = '\n';
-			if (newSize > 1)
-				System.arraycopy(l, prefix, nl, 0, newSize - 1);
+			if (i > 0 && newLine)
+				result.append('\n');
+			if (trail <= prefix) {
+				newLine = true;
+			} else {
+				boolean merge = length > 0 && l[length - 1] == '\\';
+				newLine = getLineContent(result, l, prefix, trail-1, merge, false);
 		}
-		result = CharOperation.concat(result, nl);
+	}
 	}
 	//	get rid of all the cached values
 	this.rawStart = -1;
-	return result;
+	return result.toString().toCharArray();
+}
+private char[] normalize(char[] content) {
+	StringBuilder result = new StringBuilder();
+	boolean isCR = false;
+	for (char c : content) {
+		switch (c) {
+			case '\r':
+				result.append(c);
+				isCR = true;
+				break;
+			case '\n':
+				if (!isCR) {
+					result.append(c);
+				}
+				isCR = false;
+				break;
+			default:
+				result.append(c);
+				isCR = false;
+				break;
+		}
+	}
+	return result.toString().toCharArray();
+}
+// This method is for handling the left over escaped characters during the first
+// scanning (scanForStringLiteral). Admittedly this goes over the text block
+// content again char by char, but this is required in order to correctly
+// treat all the white space and line endings
+private boolean getLineContent(StringBuilder result, char[] line, int start, int end, boolean merge, boolean lastLine) {
+	int lastPointer = 0;
+	for(int i = start; i < end; i++) {
+		char c = line[i];
+		if (c == '\\') {
+			if (i < end) {
+				if (lastPointer + 1 == i) {
+					lastPointer = i+1;
+				} else {
+					result.append(CharOperation.subarray(line, lastPointer == 0 ? start : lastPointer+1, i));
+				}
+				switch (line[++i]) {
+					case '\\' :
+						result.append('\\');
+						if (i == end)
+							merge = false;
+						//i = lastPointer;
+						lastPointer = i;
+						break;
+					case 's' :
+						result.append(' ');
+						lastPointer = i;
+						break;
+					case 'n' :
+						result.append('\n');
+						lastPointer = i;
+						break;
+					case 'r' :
+						result.append('\r');
+						lastPointer = i;
+						break;
+					case 'f' :
+						result.append('\f');
+						lastPointer = i;
+						break;
+					default :
+						// Direct copy from scanEscapeCharacter
+						int pos = i;
+						char ch = line[pos];
+						int number = ScannerHelper.getHexadecimalValue(ch);
+						if (number >= 0 && number <= 7) {
+							boolean zeroToThreeNot = number > 3;
+							try {
+								if (ScannerHelper.isDigit(ch = line[++pos])) {
+									int digit = ScannerHelper.getHexadecimalValue(ch);
+									if (digit >= 0 && digit <= 7) {
+										number = (number * 8) + digit;
+										if (ScannerHelper.isDigit(ch = line[++pos])) {
+											if (zeroToThreeNot) {
+												// has read \NotZeroToThree OctalDigit Digit --> ignore last character
+											} else {
+												digit = ScannerHelper.getHexadecimalValue(ch);
+												if (digit >= 0 && digit <= 7){ // has read \ZeroToThree OctalDigit OctalDigit
+													number = (number * 8) + digit;
+												} else {
+													// has read \ZeroToThree OctalDigit NonOctalDigit --> ignore last character
+												}
+											}
+										} else {
+											// has read \OctalDigit NonDigit--> ignore last character
+										}
+									} else {
+										// has read \OctalDigit NonOctalDigit--> ignore last character
+									}
+								} else {
+									// has read \OctalDigit --> ignore last character
+								}
+							} catch (InvalidInputException e) {
+								// Unlikely as this has already been processed in scanForStringLiteral()
+							}
+							if (number < 255) {
+								ch = (char) number;
+								//replaceEscapedChar(result, line, start, end, i, lastPointer, ch);
+							}
+							result.append(ch);
+							lastPointer = i = pos -1;
+						} else {
+							// Dealing with just '\'
+							result.append(c);
+							lastPointer = --i;
+						}
+				}
+			}
+		}
+	}
+	end = merge ? end : end >= line.length ? end : end + 1;
+	char[] chars = lastPointer == 0 ?
+			CharOperation.subarray(line, start, end) :
+				CharOperation.subarray(line, lastPointer + 1, end);
+	// The below check is because CharOperation.subarray tend to return null when the
+	// boundaries produce a zero sized char[]
+	if (chars != null)
+		result.append(chars);
+	return (!merge && !lastLine);
 }
 public final String getCurrentStringLiteral() {
 	//return the token REAL source (aka unicodes are precomputed).
@@ -1658,155 +1782,7 @@
 					}
 					throw new InvalidInputException(INVALID_CHARACTER_CONSTANT);
 				case '"' :
-					boolean isTextBlock = false;
-					int lastQuotePos = 0;
-					try {
-						// consume next character
-						this.unicodeAsBackSlash = false;
-						boolean isUnicode = false;
-						isTextBlock = scanForTextBlockBeginning();
-						if (!isTextBlock) {
-							if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
-									&& (this.source[this.currentPosition] == 'u')) {
-								getNextUnicodeChar();
-								isUnicode = true;
-							} else {
-								if (this.withoutUnicodePtr != 0) {
-									unicodeStore();
-								}
-							}
-						}
-						this.rawStart = this.currentPosition - this.startPosition;
-						int terminators = 0;
-						while (this.currentPosition <= this.eofPosition) {
-							if (this.currentCharacter == '"') {
-								if (!isTextBlock) {
-									return TerminalTokens.TokenNameStringLiteral;
-								}
-								lastQuotePos = this.currentPosition;
-								// look for text block delimiter
-								if (scanForTextBlockClose()) {
-									// Account for just the snippet being passed around
-									// If already at the EOF, bail out.
-									if (this.currentPosition + 2 < this.source.length && this.source[this.currentPosition + 2] == '"') {
-										terminators++;
-										if (terminators > 2)
-											throw new InvalidInputException(UNTERMINATED_TEXT_BLOCK);
-									} else {
-										this.currentPosition += 2;
-										return TerminalTokens.TokenNameTextBlock;
-									}
-								}
-								if (this.withoutUnicodePtr != 0) {
-									unicodeStore();
-								}
-							} else {
-								terminators = 0;
-							}
-							if (!isTextBlock && (this.currentCharacter == '\n' || this.currentCharacter == '\r')) {
-								// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
-								if (isUnicode) {
-									int start = this.currentPosition;
-									for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
-										if (this.currentPosition >= this.eofPosition) {
-											this.currentPosition = start;
-											break;
-										}
-										if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
-											isUnicode = true;
-											getNextUnicodeChar();
-										} else {
-											isUnicode = false;
-										}
-										if (!isUnicode && this.currentCharacter == '\n') {
-											this.currentPosition--; // set current position on new line character
-											break;
-										}
-										if (this.currentCharacter == '\"') {
-											throw new InvalidInputException(INVALID_CHAR_IN_STRING);
-										}
-									}
-								} else {
-									this.currentPosition--; // set current position on new line character
-								}
-								throw new InvalidInputException(INVALID_CHAR_IN_STRING);
-							}
-							if (this.currentCharacter == '\\') {
-								if (this.unicodeAsBackSlash) {
-									this.withoutUnicodePtr--;
-									// consume next character
-									this.unicodeAsBackSlash = false;
-									if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
-										getNextUnicodeChar();
-										isUnicode = true;
-										this.withoutUnicodePtr--;
-									} else {
-										isUnicode = false;
-									}
-								} else {
-									if (this.withoutUnicodePtr == 0) {
-										unicodeInitializeBuffer(this.currentPosition - this.startPosition);
-									}
-									this.withoutUnicodePtr --;
-									this.currentCharacter = this.source[this.currentPosition++];
-								}
-								// we need to compute the escape character in a separate buffer
-								scanEscapeCharacter();
-								if (this.withoutUnicodePtr != 0) {
-									unicodeStore();
-								}
-							}
-							// consume next character
-							if (this.currentPosition >= this.eofPosition) {
-								break;
-							}
-							this.unicodeAsBackSlash = false;
-							if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
-								&& (this.source[this.currentPosition] == 'u')) {
-								getNextUnicodeChar();
-								isUnicode = true;
-							} else {
-								isUnicode = false;
-								if (isTextBlock && this.currentCharacter == '"')
-									continue;
-								if (this.withoutUnicodePtr != 0) {
-									unicodeStore();
-								}
-							}
-						}
-						if (isTextBlock) {
-							if (lastQuotePos > 0)
-								this.currentPosition = lastQuotePos;
-							this.currentPosition = (lastQuotePos > 0) ? lastQuotePos : this.startPosition + this.rawStart;
-							throw new InvalidInputException(UNTERMINATED_TEXT_BLOCK);
-						} else {
-							throw new InvalidInputException(UNTERMINATED_STRING);
-						}
-					} catch (IndexOutOfBoundsException e) {
-						if (isTextBlock) {
-							this.currentPosition = (lastQuotePos > 0) ? lastQuotePos : this.startPosition + this.rawStart;
-							throw new InvalidInputException(UNTERMINATED_TEXT_BLOCK);
-						} else {
-							this.currentPosition--;
-							throw new InvalidInputException(UNTERMINATED_STRING);
-						}
-					} catch (InvalidInputException e) {
-						if (e.getMessage().equals(INVALID_ESCAPE)) {
-							// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
-							for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
-								if (this.currentPosition + lookAhead == this.eofPosition)
-									break;
-								if (this.source[this.currentPosition + lookAhead] == '\n')
-									break;
-								if (this.source[this.currentPosition + lookAhead] == '\"') {
-									this.currentPosition += lookAhead + 1;
-									break;
-								}
-							}
-
-						}
-						throw e; // rethrow
-					}
+					return scanForStringLiteral();
 				case '/' :
 					if (!this.skipComments) {
 						int test = getNextChar('/', '*');
@@ -2065,6 +2041,241 @@
 	}
 	return TokenNameEOF;
 }
+private int scanForStringLiteral() throws InvalidInputException {
+	boolean isTextBlock = false;
+	int lastQuotePos = 0;
+
+	// consume next character
+	this.unicodeAsBackSlash = false;
+	boolean isUnicode = false;
+	isTextBlock = scanForTextBlockBeginning();
+	if (isTextBlock) {
+		try {
+			this.rawStart = this.currentPosition - this.startPosition;
+			int terminators = 0;
+			while (this.currentPosition <= this.eofPosition) {
+				if (this.currentCharacter == '"') {
+					lastQuotePos = this.currentPosition;
+					// look for text block delimiter
+					if (scanForTextBlockClose()) {
+							// Account for just the snippet being passed around
+							// If already at the EOF, bail out.
+						if (this.currentPosition + 2 < this.source.length && this.source[this.currentPosition + 2] == '"') {
+							terminators++;
+							if (terminators > 2)
+								throw new InvalidInputException(UNTERMINATED_TEXT_BLOCK);
+						} else {
+							this.currentPosition += 2;
+							return TerminalTokens.TokenNameTextBlock;
+						}
+					}
+					if (this.withoutUnicodePtr != 0) {
+						unicodeStore();
+					}
+				} else {
+					terminators = 0;
+				}
+				outer: if (this.currentCharacter == '\\') {
+					switch(this.source[this.currentPosition]) {
+						case 'n' :
+						case 'r' :
+						case 'f' :
+							break outer;
+						case '\n' :
+						case '\r' :
+							this.currentCharacter = '\\';
+							this.currentPosition++;
+							break;
+						case '\\' :
+							this.currentPosition++;
+							break;
+						default :
+							if (this.unicodeAsBackSlash) {
+								this.withoutUnicodePtr--;
+								// consume next character
+								if (this.currentPosition >= this.eofPosition) {
+									break;
+								}
+								this.unicodeAsBackSlash = false;
+								if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+										&& (this.source[this.currentPosition] == 'u')) {
+									getNextUnicodeChar();
+									isUnicode = true;
+									this.withoutUnicodePtr--;
+								} else {
+									isUnicode = false;
+								}
+							} else {
+								if (this.withoutUnicodePtr == 0) {
+									unicodeInitializeBuffer(this.currentPosition - this.startPosition);
+								}
+								this.withoutUnicodePtr --;
+								this.currentCharacter = this.source[this.currentPosition++];
+							}
+							int oldPos = this.currentPosition - 1;
+							scanEscapeCharacter();
+							switch (this.currentCharacter) {
+								case ' ':
+									if (this.withoutUnicodePtr == 0) {
+										unicodeInitializeBuffer(this.currentPosition - this.startPosition);
+									}
+									// Kludge, retain the '\' and also
+									// when scanEscapeCharacter reads space in form of \040 and
+									// set the next character to 's'
+									// so, we get an escaped scape, i.e. \s, which will later be
+									// replaced by space
+									unicodeStore('\\');
+									this.currentCharacter = 's';
+									break;
+								case '\r':
+								case '\n':
+									if (this.withoutUnicodePtr == 0) {
+										unicodeInitializeBuffer(this.currentPosition - this.startPosition);
+									}
+									unicodeStore('\\');
+									this.currentPosition = oldPos;
+									this.currentCharacter = this.source[this.currentPosition];
+									break outer;
+
+							}
+					}
+					if (this.withoutUnicodePtr != 0) {
+						unicodeStore();
+					}
+				}
+				// consume next character
+				this.unicodeAsBackSlash = false;
+				if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+						&& (this.source[this.currentPosition] == 'u')) {
+					getNextUnicodeChar();
+					isUnicode = true;
+				} else {
+					isUnicode = false;
+					if (this.currentCharacter == '"'/* || skipWhitespace*/)
+						continue;
+					if (this.withoutUnicodePtr != 0) {
+						unicodeStore();
+					}
+				}
+			}
+			if (lastQuotePos > 0)
+				this.currentPosition = lastQuotePos;
+			this.currentPosition = (lastQuotePos > 0) ? lastQuotePos : this.startPosition + this.rawStart;
+			throw new InvalidInputException(UNTERMINATED_TEXT_BLOCK);
+		} catch (IndexOutOfBoundsException e) {
+			this.currentPosition = (lastQuotePos > 0) ? lastQuotePos : this.startPosition + this.rawStart;
+			throw new InvalidInputException(UNTERMINATED_TEXT_BLOCK);
+		}
+	} else {
+		try {
+			// consume next character
+			this.unicodeAsBackSlash = false;
+			isUnicode = false;
+			if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+					&& (this.source[this.currentPosition] == 'u')) {
+				getNextUnicodeChar();
+				isUnicode = true;
+			} else {
+				if (this.withoutUnicodePtr != 0) {
+					unicodeStore();
+				}
+			}
+
+			while (this.currentCharacter != '"') {
+				if (this.currentPosition >= this.eofPosition) {
+					throw new InvalidInputException(UNTERMINATED_STRING);
+				}
+				/**** \r and \n are not valid in string literals ****/
+				if ((this.currentCharacter == '\n') || (this.currentCharacter == '\r')) {
+					// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+					if (isUnicode) {
+						int start = this.currentPosition;
+						for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
+							if (this.currentPosition >= this.eofPosition) {
+								this.currentPosition = start;
+								break;
+							}
+							if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
+								isUnicode = true;
+								getNextUnicodeChar();
+							} else {
+								isUnicode = false;
+							}
+							if (!isUnicode && this.currentCharacter == '\n') {
+								this.currentPosition--; // set current position on new line character
+								break;
+							}
+							if (this.currentCharacter == '\"') {
+								throw new InvalidInputException(INVALID_CHAR_IN_STRING);
+							}
+						}
+					} else {
+						this.currentPosition--; // set current position on new line character
+					}
+					throw new InvalidInputException(INVALID_CHAR_IN_STRING);
+				}
+				if (this.currentCharacter == '\\') {
+					if (this.unicodeAsBackSlash) {
+						this.withoutUnicodePtr--;
+						// consume next character
+						this.unicodeAsBackSlash = false;
+						if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\') && (this.source[this.currentPosition] == 'u')) {
+							getNextUnicodeChar();
+							isUnicode = true;
+							this.withoutUnicodePtr--;
+						} else {
+							isUnicode = false;
+						}
+					} else {
+						if (this.withoutUnicodePtr == 0) {
+							unicodeInitializeBuffer(this.currentPosition - this.startPosition);
+						}
+						this.withoutUnicodePtr --;
+						this.currentCharacter = this.source[this.currentPosition++];
+					}
+					// we need to compute the escape character in a separate buffer
+					scanEscapeCharacter();
+					if (this.withoutUnicodePtr != 0) {
+						unicodeStore();
+					}
+				}
+				// consume next character
+				this.unicodeAsBackSlash = false;
+				if (((this.currentCharacter = this.source[this.currentPosition++]) == '\\')
+						&& (this.source[this.currentPosition] == 'u')) {
+					getNextUnicodeChar();
+					isUnicode = true;
+				} else {
+					isUnicode = false;
+					if (this.withoutUnicodePtr != 0) {
+						unicodeStore();
+					}
+				}
+
+			}
+		} catch (IndexOutOfBoundsException e) {
+			this.currentPosition--;
+			throw new InvalidInputException(UNTERMINATED_STRING);
+		} catch (InvalidInputException e) {
+			if (e.getMessage().equals(INVALID_ESCAPE)) {
+				// relocate if finding another quote fairly close: thus unicode '/u000D' will be fully consumed
+				for (int lookAhead = 0; lookAhead < 50; lookAhead++) {
+					if (this.currentPosition + lookAhead == this.eofPosition)
+						break;
+					if (this.source[this.currentPosition + lookAhead] == '\n')
+						break;
+					if (this.source[this.currentPosition + lookAhead] == '\"') {
+						this.currentPosition += lookAhead + 1;
+						break;
+					}
+				}
+
+			}
+			throw e; // rethrow
+		}
+		return TokenNameStringLiteral;
+	}
+}
 public void getNextUnicodeChar()
 	throws InvalidInputException {
 	//VOID
@@ -3123,6 +3334,9 @@
 		case '\'' :
 			this.currentCharacter = '\'';
 			break;
+		case 's' :
+			this.currentCharacter = ' ';
+			break;
 		case '\\' :
 			this.currentCharacter = '\\';
 			break;
@@ -3721,13 +3935,18 @@
 		case 'r' : //return requires
 			switch (length) {
 				case 6:
-					if ((data[++index] == 'e')
-						&& (data[++index] == 't')
+					if (data[++index] == 'e') {
+						if ((data[++index] == 't')
 						&& (data[++index] == 'u')
 						&& (data[++index] == 'r')
-						&& (data[++index] == 'n')) {
+							&& (data[++index] == 'n'))
 						return TokenNamereturn;
-					} else 
+						else if ((data[index] == 'c')
+							&& (data[++index] == 'o')
+							&& (data[++index] == 'r')
+							&& (data[++index] == 'd'))
+								return disambiguatedRestrictedIdentifierrecord(TokenNameRestrictedIdentifierrecord);
+					}
 						return TokenNameIdentifier;
 				case 8:
 					if (areRestrictedModuleKeywordsActive()
@@ -4357,6 +4576,8 @@
 			return "Identifier(" + new String(getCurrentTokenSource()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$
 		case TokenNameRestrictedIdentifierYield :
 			return "yield"; //$NON-NLS-1$
+		case TokenNameRestrictedIdentifierrecord :
+			return "record"; //$NON-NLS-1$
 		case TokenNameabstract :
 			return "abstract"; //$NON-NLS-1$
 		case TokenNameboolean :
@@ -4679,7 +4900,8 @@
 		case TerminalTokens.TokenNamewhile:
 			return true;
 		case TerminalTokens.TokenNameRestrictedIdentifierYield:
-			// making explicit - yield not a (restricted) keyword but restricted identifier.
+		case TerminalTokens.TokenNameRestrictedIdentifierrecord:
+			// making explicit - not a (restricted) keyword but restricted identifier.
 			//$FALL-THROUGH$
 		default:
 			return false;
@@ -5076,6 +5298,64 @@
 			return false;
 	}
 }
+int disambiguatedRestrictedIdentifierrecord(int restrictedIdentifierToken) {
+	// and here's the kludge
+	if (restrictedIdentifierToken != TokenNameRestrictedIdentifierrecord)
+		return restrictedIdentifierToken;
+	if (this.sourceLevel < ClassFileConstants.JDK14 || !this.previewEnabled)
+		return TokenNameIdentifier;
+
+	return disambiguaterecordWithLookAhead() ?
+			restrictedIdentifierToken : TokenNameIdentifier;
+}
+private int getNextTokenAfterTypeParameterHeader() {
+	int count = 1;
+	try {
+		int token;
+		while ((token = this.vanguardScanner.getNextToken()) != TokenNameNotAToken) {
+			if (token == TokenNameEOF)
+				break;
+			if (token == TokenNameLESS)
+				++count;
+			if (token == TokenNameGREATER)
+				--count;
+			if (token == TokenNameRIGHT_SHIFT)
+				count= count -2;
+			if (token == TokenNameUNSIGNED_RIGHT_SHIFT)
+				count= count -3;
+			if (count <= 0)
+				return this.vanguardScanner.getNextToken();
+		}
+	} catch (InvalidInputException e) {
+		if (e.getMessage().equals(INVALID_CHAR_IN_STRING)) {
+			//Ignore
+		} else {
+			// Shouldn't happen, but log the error
+			e.printStackTrace();
+		}
+	}
+	return TokenNameEOF;
+}
+private boolean disambiguaterecordWithLookAhead() {
+	getVanguardParser();
+	this.vanguardScanner.resetTo(this.currentPosition, this.eofPosition - 1);
+	try {
+		int lookAhead1 = this.vanguardScanner.getNextToken();
+		if (lookAhead1 == TokenNameIdentifier) {
+			int lookAhead2 = this.vanguardScanner.getNextToken();
+			lookAhead2 = lookAhead2 == TokenNameLESS ? getNextTokenAfterTypeParameterHeader() : lookAhead2;
+			return lookAhead2 == TokenNameLPAREN;
+		}
+	} catch (InvalidInputException e) {
+		if (e.getMessage().equals(INVALID_CHAR_IN_STRING)) {
+			//Ignore
+		} else {
+			// Shouldn't happen, but log the error
+			e.printStackTrace();
+		}
+	}
+	return false; // IIE event;
+}
 private boolean disambiguateYieldWithLookAhead() {
 	getVanguardParser();
 	this.vanguardScanner.resetTo(this.currentPosition, this.eofPosition - 1);
@@ -5146,7 +5426,7 @@
 	// and here's the kludge
 	if (restrictedIdentifierToken != TokenNameRestrictedIdentifierYield)
 		return restrictedIdentifierToken;
-	if (this.sourceLevel < ClassFileConstants.JDK13 || !this.previewEnabled)
+	if (this.sourceLevel < ClassFileConstants.JDK14)
 		return TokenNameIdentifier;
 
 	return mayBeAtAnYieldStatement() && disambiguateYieldWithLookAhead() ?
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/diagnose/DiagnoseParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/diagnose/DiagnoseParser.java
index 6bbd228..3b92f97 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/diagnose/DiagnoseParser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/diagnose/DiagnoseParser.java
@@ -2576,7 +2576,7 @@
 	}
 
 	@Override
-	public boolean isParsingJava13() {
-		return this.parser.isParsingJava13();
+	public boolean isParsingJava14() {
+		return this.parser.isParsingJava14();
 	}
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc
index 3be25d4..0ffe18d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser1.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser10.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser10.rsc
index 369e44a..ccfc07e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser10.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser10.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser11.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser11.rsc
index 994c4f1..eba7f49 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser11.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser11.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc
index 3eb334a..57e3411 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser12.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc
index dba3e58..030e3b3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser13.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc
index e2c78cd..edc8100 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser14.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc
index 53b49b1..d709aac 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser15.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc
index 3e8afac..cad2cb9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser16.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc
index 0478d34..92d8eaa 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser17.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc
index 2d3eea8..83f6c52 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser18.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc
index 0a622a1..3f20b35 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser19.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc
index a5e3ab0..d0a3d06 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser2.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser20.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser20.rsc
index ee87dd0..bf4c616 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser20.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser20.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc
index 1ab9d47..dc7860c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser21.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser22.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser22.rsc
index 63f8a49..ed9c956 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser22.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser22.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser23.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser23.rsc
index 0a41a0e..89dc4fe 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser23.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser23.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser24.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser24.rsc
index 00f7d61..90d4378 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser24.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser24.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc
index cbf599b..b41cd54 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser3.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc
index ad0c4ed..4173eef 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser4.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc
index 11e7f79..ff12376 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser5.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc
index 34ed4dc..ebb9ecf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser6.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser7.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser7.rsc
index 54b8fbf..e9d6406 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser7.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser7.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc
index 57893da..ee3a6fc 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser8.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc
index 2ef7efb..cbdb444 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/parser9.rsc
Binary files differ
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props
index e0988bd..03f6235 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/readableNames.props
@@ -105,6 +105,9 @@
 ClassTypeElt=ClassType
 ClassTypeList=ClassTypeList
 ColonPseudoToken=any allowable token in pointcut or type pattern, except ':'
+CompactConstructorDeclaration=CompactConstructorDeclaration
+CompactConstructorHeader=CompactConstructorDeclaration
+CompactConstructorHeaderName=CompactConstructorHeaderName
 CompilationUnit=CompilationUnit
 ConditionalAndExpression=Expression
 ConditionalAndExpression_NotName=Expression
@@ -316,6 +319,19 @@
 QualifiedClassBodyopt=ClassBody
 QualifiedEnterAnonymousClassBody=EnterAnonymousClassBody
 QualifiedName=QualifiedName
+RecordBody=RecordBody
+RecordBodyDeclaration=RecordBodyDeclaration
+RecordBodyDeclarationopt=RecordBodyDeclarationopt
+RecordBodyDeclarations=RecordBodyDeclarations
+RecordComponent=RecordComponent
+RecordComponentHeaderRightParen=)
+RecordComponents=RecordComponents
+RecordComponentsopt=RecordComponentsopt
+RecordDeclaration=RecordDeclaration
+RecordHeader=RecordHeader
+RecordHeaderName1=RecordHeaderName
+RecordHeaderName=RecordHeaderName
+RecordHeaderPart=RecordHeaderPart
 RecoveryMethodHeader=MethodHeader
 RecoveryMethodHeaderName=MethodHeaderName
 ReduceImports=ReduceImports
@@ -403,6 +419,7 @@
 TypeParameterList=TypeParameterList
 TypeParameters=TypeParameters
 TypeParametersAsReference=type parameter list
+TypeTestPattern=TypeTestPattern
 UnannotatableName=UnannotatableQualifiedName
 UnannotatableNameOrAj=name
 UnaryExpression=Expression
@@ -412,6 +429,7 @@
 UnionType=UnionType
 UnqualifiedClassBodyopt=ClassBody
 UnqualifiedEnterAnonymousClassBody=EnterAnonymousClassBody
+VariableArityRecordComponent=VariableArityRecordComponent
 VariableDeclarator=VariableDeclarator
 VariableDeclaratorId=VariableDeclaratorId
 VariableDeclaratorIdOrThis=VariableDeclaratorId
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemHandler.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemHandler.java
index 7b29363..e883b15 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemHandler.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemHandler.java
@@ -43,7 +43,7 @@
 	public IErrorHandlingPolicy policy;
 	public final IProblemFactory problemFactory;
 	public final CompilerOptions options;
-	
+
 	/* When temporarily switching policies, store here the original root policy (for temporary resume). */
 	private IErrorHandlingPolicy rootPolicy;
 
@@ -128,7 +128,7 @@
 		return;
 
 	 boolean mandatory = (severity & (ProblemSeverities.Error | ProblemSeverities.Optional)) == ProblemSeverities.Error;
-	 if ((severity & ProblemSeverities.InternalError) == 0 && this.policy.ignoreAllErrors()) { 
+	 if ((severity & ProblemSeverities.InternalError) == 0 && this.policy.ignoreAllErrors()) {
 		 // Error is not to be exposed, but clients may need still notification as to whether there are silently-ignored-errors.
 		 // if no reference context, we need to abort from the current compilation process
 		 if (referenceContext == null) {
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 847aa2b..a94f992 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -1,6 +1,6 @@
 // AspectJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -150,6 +150,7 @@
 import org.eclipse.jdt.internal.compiler.ast.QualifiedSuperReference;
 import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
 import org.eclipse.jdt.internal.compiler.ast.Receiver;
+import org.eclipse.jdt.internal.compiler.ast.RecordDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.Reference;
 import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression;
 import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
@@ -222,6 +223,9 @@
 	  CONSTRUCTOR_ACCESS = 0x8,
 	  METHOD_ACCESS = 0xC;
 
+	private static String RESTRICTED_IDENTIFIER_RECORD = "RestrictedIdentifierrecord"; //$NON-NLS-1$
+	private static String RECORD = "record"; //$NON-NLS-1$
+
 public ProblemReporter(IErrorHandlingPolicy policy, CompilerOptions options, IProblemFactory problemFactory) {
 	super(policy, options, problemFactory);
 }
@@ -484,6 +488,7 @@
 			return CompilerOptions.NonNullTypeVariableFromLegacyInvocation;
 
 		case IProblem.ParameterLackingNonNullAnnotation:
+		case IProblem.InheritedParameterLackingNonNullAnnotation:
 			return CompilerOptions.NonnullParameterAnnotationDropped;
 
 		case IProblem.RequiredNonNullButProvidedPotentialNull:
@@ -495,6 +500,9 @@
 		case IProblem.ReferenceExpressionReturnNullRedefUnchecked:
 		case IProblem.UnsafeNullnessCast:
 			return CompilerOptions.NullUncheckedConversion;
+		case IProblem.AnnotatedTypeArgumentToUnannotated:
+		case IProblem.AnnotatedTypeArgumentToUnannotatedSuperHint:
+			return CompilerOptions.AnnotatedTypeArgumentToUnannotated;
 		case IProblem.RedundantNullAnnotation:
 		case IProblem.RedundantNullDefaultAnnotation:
 		case IProblem.RedundantNullDefaultAnnotationModule:
@@ -552,6 +560,14 @@
 		case IProblem.JavadocInvalidThrowsClassName:
 		case IProblem.JavadocDuplicateThrowsClassName:
 		case IProblem.JavadocMissingThrowsClassName:
+		case IProblem.JavadocDuplicateProvidesTag:
+		case IProblem.JavadocDuplicateUsesTag:
+		case IProblem.JavadocInvalidUsesClass:
+		case IProblem.JavadocInvalidUsesClassName:
+		case IProblem.JavadocInvalidProvidesClass:
+		case IProblem.JavadocInvalidProvidesClassName:
+		case IProblem.JavadocMissingProvidesClassName:
+		case IProblem.JavadocMissingUsesClassName:
 		case IProblem.JavadocMissingSeeReference:
 		case IProblem.JavadocInvalidValueReference:
 		case IProblem.JavadocUndefinedField:
@@ -595,8 +611,10 @@
 			return CompilerOptions.InvalidJavadoc;
 
 		case IProblem.JavadocMissingParamTag:
+		case IProblem.JavadocMissingProvidesTag:
 		case IProblem.JavadocMissingReturnTag:
 		case IProblem.JavadocMissingThrowsTag:
+		case IProblem.JavadocMissingUsesTag:
 			return CompilerOptions.MissingJavadocTags;
 
 		case IProblem.JavadocMissing:
@@ -795,6 +813,7 @@
 			case CompilerOptions.NullUncheckedConversion :
 			case CompilerOptions.MissingNonNullByDefaultAnnotation:
 			case CompilerOptions.NonnullParameterAnnotationDropped:
+			case CompilerOptions.AnnotatedTypeArgumentToUnannotated:
 				return CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM;
 			case CompilerOptions.RedundantNullAnnotation :
 				return CategorizedProblem.CAT_UNNECESSARY_CODE;
@@ -808,6 +827,7 @@
 		case IProblem.IsClassPathCorrect :
 		case IProblem.CorruptedSignature :
 		case IProblem.UndefinedModuleAddReads :
+		case IProblem.MissingNullAnnotationImplicitlyUsed :
 			return CategorizedProblem.CAT_BUILDPATH;
 		case IProblem.ProblemNotAnalysed :
 			return CategorizedProblem.CAT_UNNECESSARY_CODE;
@@ -1940,13 +1960,6 @@
 		annotation.sourceStart,
 		annotation.sourceEnd);
 }
-public void explitAnnotationTargetRequired(Annotation annotation) {
-	this.handle(IProblem.ExplicitAnnotationTargetRequired,
-			NoArgument,
-			NoArgument,
-			annotation.sourceStart,
-			annotation.sourceEnd);
-}
 public void polymorphicMethodNotBelow17(ASTNode node) {
 	this.handle(
 			IProblem.PolymorphicMethodNotBelow17,
@@ -2094,12 +2107,20 @@
 }
 public void duplicateInitializationOfFinalLocal(LocalVariableBinding local, ASTNode location) {
 	String[] arguments = new String[] { new String(local.readableName())};
+	if ((local.modifiers & ExtraCompilerModifiers.AccPatternVariable) == 0) {
 	this.handle(
 		IProblem.DuplicateFinalLocalInitialization,
 		arguments,
 		arguments,
 		nodeSourceStart(local, location),
 		nodeSourceEnd(local, location));
+	} else {
+		this.handle(IProblem.PatternVariableNotInScope,
+			arguments,
+			arguments,
+			nodeSourceStart(local, location),
+			nodeSourceEnd(local, location));
+}
 }
 public void duplicateMethodInType(AbstractMethodDeclaration methodDecl, boolean equalParameters, int severity) {
     MethodBinding method = methodDecl.binding;
@@ -5028,7 +5049,7 @@
 			first.sourceStart,
 			last.sourceEnd);
 }
-public void isClassPathCorrect(char[][] wellKnownTypeName, CompilationUnitDeclaration compUnitDecl, Object location) {
+public void isClassPathCorrect(char[][] wellKnownTypeName, CompilationUnitDeclaration compUnitDecl, Object location, boolean implicitAnnotationUse) {
 	// ProblemReporter is not designed to be reentrant. Just in case, we discovered a build path problem while we are already 
 	// in the midst of reporting some other problem, save and restore reference context thereby mimicking a stack.
 	// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=442755.
@@ -5049,7 +5070,7 @@
 	}
 	try {
 		this.handle(
-				IProblem.IsClassPathCorrect,
+				implicitAnnotationUse ? IProblem.MissingNullAnnotationImplicitlyUsed : IProblem.IsClassPathCorrect,
 				arguments,
 				arguments,
 				start,
@@ -5115,7 +5136,8 @@
 		case TerminalTokens.TokenNamewhile:
 			return true;
 		case TerminalTokens.TokenNameRestrictedIdentifierYield:
-			// making explicit - yield not a (restricted) keyword but restricted identifier.
+		case TerminalTokens.TokenNameRestrictedIdentifierrecord:
+			// making explicit - not a (restricted) keyword but restricted identifier.
 			//$FALL-THROUGH$
 		default:
 			return false;
@@ -5225,6 +5247,9 @@
 			sourceEnd);
 	}
 }
+public void javadocDuplicatedProvidesTag(int sourceStart, int sourceEnd){
+	this.handle(IProblem.JavadocDuplicateProvidesTag, NoArgument, NoArgument, sourceStart, sourceEnd);
+}
 public void javadocDuplicatedReturnTag(int sourceStart, int sourceEnd){
 	this.handle(IProblem.JavadocDuplicateReturnTag, NoArgument, NoArgument, sourceStart, sourceEnd);
 }
@@ -5251,6 +5276,11 @@
 			typeReference.sourceEnd);
 	}
 }
+public void javadocDuplicatedUsesTag(
+
+		int sourceStart, int sourceEnd){
+	this.handle(IProblem.JavadocDuplicateUsesTag, NoArgument, NoArgument, sourceStart, sourceEnd);
+}
 public void javadocEmptyReturnTag(int sourceStart, int sourceEnd, int modifiers) {
 	int severity = computeSeverity(IProblem.JavadocEmptyReturnTag);
 	if (severity == ProblemSeverities.Ignore) return;
@@ -5698,6 +5728,24 @@
 public void javadocInvalidParamTypeParameter(int sourceStart, int sourceEnd) {
 	this.handle(IProblem.JavadocInvalidParamTagTypeParameter, NoArgument, NoArgument, sourceStart, sourceEnd);
 }
+public void javadocInvalidProvidesClass(int sourceStart, int sourceEnd) {
+	this.handle(IProblem.JavadocInvalidProvidesClass, NoArgument, NoArgument, sourceStart, sourceEnd);
+}
+
+public void javadocInvalidProvidesClassName(TypeReference typeReference, int modifiers) {
+	int severity = computeSeverity(IProblem.JavadocInvalidProvidesClassName);
+	if (severity == ProblemSeverities.Ignore) return;
+	if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) {
+		String[] arguments = new String[] {String.valueOf(typeReference.resolvedType.sourceName())};
+		this.handle(
+			IProblem.JavadocInvalidProvidesClassName,
+			arguments,
+			arguments,
+			severity,
+			typeReference.sourceStart,
+			typeReference.sourceEnd);
+	}
+}
 public void javadocInvalidReference(int sourceStart, int sourceEnd) {
 	this.handle(IProblem.JavadocInvalidSeeReference, NoArgument, NoArgument, sourceStart, sourceEnd);
 }
@@ -5776,6 +5824,24 @@
 			location.sourceEnd);
 	}
 }
+public void javadocInvalidUsesClass(int sourceStart, int sourceEnd) {
+	this.handle(IProblem.JavadocInvalidUsesClass, NoArgument, NoArgument, sourceStart, sourceEnd);
+}
+
+public void javadocInvalidUsesClassName(TypeReference typeReference, int modifiers) {
+	int severity = computeSeverity(IProblem.JavadocInvalidUsesClassName);
+	if (severity == ProblemSeverities.Ignore) return;
+	if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) {
+		String[] arguments = new String[] {String.valueOf(typeReference.resolvedType.sourceName())};
+		this.handle(
+			IProblem.JavadocInvalidUsesClassName,
+			arguments,
+			arguments,
+			severity,
+			typeReference.sourceStart,
+			typeReference.sourceEnd);
+	}
+}
 public void javadocInvalidValueReference(int sourceStart, int sourceEnd, int modifiers) {
 	if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers))
 		this.handle(IProblem.JavadocInvalidValueReference, NoArgument, NoArgument, sourceStart, sourceEnd);
@@ -5806,6 +5872,20 @@
 		}
 	}
 }
+public void javadocModuleMissing(int sourceStart, int sourceEnd, int severity){
+	if (severity == ProblemSeverities.Ignore) return;
+	boolean report = this.options.getSeverity(CompilerOptions.MissingJavadocComments) != ProblemSeverities.Ignore;
+	if (report) {
+			String[] arguments = new String[] { "module" }; //$NON-NLS-1$
+			this.handle(
+				IProblem.JavadocMissing,
+				arguments,
+				arguments,
+				severity,
+				sourceStart,
+				sourceEnd);
+	}
+}
 public void javadocMissingHashCharacter(int sourceStart, int sourceEnd, String ref){
 	int severity = computeSeverity(IProblem.JavadocMissingHashCharacter);
 	if (severity == ProblemSeverities.Ignore) return;
@@ -5843,6 +5923,26 @@
 			sourceEnd);
 	}
 }
+public void javadocMissingProvidesClassName(int sourceStart, int sourceEnd, int modifiers){
+	if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) {
+		this.handle(IProblem.JavadocMissingProvidesClassName, NoArgument, NoArgument, sourceStart, sourceEnd);
+	}
+}
+public void javadocMissingProvidesTag(TypeReference typeRef, int sourceStart, int sourceEnd, int modifiers){
+	int severity = computeSeverity(IProblem.JavadocMissingProvidesTag);
+	if (severity == ProblemSeverities.Ignore) return;
+	boolean report = this.options.getSeverity(CompilerOptions.MissingJavadocTags) != ProblemSeverities.Ignore;
+	if (report) {
+		String[] arguments = new String[] { String.valueOf(typeRef.resolvedType.sourceName()) };
+		this.handle(
+			IProblem.JavadocMissingProvidesTag,
+			arguments,
+			arguments,
+			severity,
+			sourceStart,
+			sourceEnd);
+	}
+}
 public void javadocMissingReference(int sourceStart, int sourceEnd, int modifiers){
 	if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers))
 		this.handle(IProblem.JavadocMissingSeeReference, NoArgument, NoArgument, sourceStart, sourceEnd);
@@ -5893,6 +5993,27 @@
 			typeRef.sourceEnd);
 	}
 }
+public void javadocMissingUsesClassName(int sourceStart, int sourceEnd, int modifiers){
+	if (javadocVisibility(this.options.reportInvalidJavadocTagsVisibility, modifiers)) {
+		this.handle(IProblem.JavadocMissingUsesClassName, NoArgument, NoArgument, sourceStart, sourceEnd);
+	}
+}
+
+public void javadocMissingUsesTag(TypeReference typeRef, int sourceStart, int sourceEnd, int modifiers){
+	int severity = computeSeverity(IProblem.JavadocMissingUsesTag);
+	if (severity == ProblemSeverities.Ignore) return;
+	boolean report = this.options.getSeverity(CompilerOptions.MissingJavadocTags) != ProblemSeverities.Ignore;
+	if (report) {
+		String[] arguments = new String[] { String.valueOf(typeRef.resolvedType.sourceName()) };
+		this.handle(
+			IProblem.JavadocMissingUsesTag,
+			arguments,
+			arguments,
+			severity,
+			sourceStart,
+			sourceEnd);
+	}
+}
 public void javadocUndeclaredParamTagName(char[] token, int sourceStart, int sourceEnd, int modifiers) {
 	int severity = computeSeverity(IProblem.JavadocInvalidParamName);
 	if (severity == ProblemSeverities.Ignore) return;
@@ -7534,7 +7655,7 @@
 	char[] errorTokenSource,
 	String errorTokenName,
 	String expectedToken){
-	syntaxError(
+	handleSyntaxError(
 		IProblem.ParsingError,
 		start,
 		end,
@@ -8108,6 +8229,60 @@
 		superclass.sourceStart,
 		superclass.sourceEnd);
 }
+private boolean handleSyntaxErrorOnNewTokens(
+	int id,
+	int start,
+	int end,
+	int currentKind,
+	char[] errorTokenSource,
+	String errorTokenName,
+	String expectedToken) {
+	boolean val = false;
+	if (isIdentifier(currentKind)) {
+		String eTokenName = new String(errorTokenSource);
+		String origExpectedToken = expectedToken;
+		expectedToken = replaceIfSynthetic(expectedToken);
+		if (isIdentifier(currentKind)) {
+			if (RESTRICTED_IDENTIFIER_RECORD.equals(origExpectedToken) && RECORD.equals(eTokenName)) {
+				if (this.options.sourceLevel < ClassFileConstants.JDK14) {
+					previewFeatureNotSupported(start, end, RECORD, CompilerOptions.VERSION_14);
+					val = true;
+				} else if (!this.options.enablePreviewFeatures) {
+					previewFeatureNotEnabled(start, end, RECORD);
+					val = true;
+				}
+			}
+		}
+	}
+	return val;
+}
+private void handleSyntaxError(
+	int id,
+	int start,
+	int end,
+	int currentKind,
+	char[] errorTokenSource,
+	String errorTokenName,
+	String expectedToken) {
+	if (!handleSyntaxErrorOnNewTokens(
+			IProblem.ParsingError,
+			start,
+			end,
+			currentKind,
+			errorTokenSource,
+			errorTokenName,
+			expectedToken
+			)) {
+		syntaxError(
+			IProblem.ParsingError,
+			start,
+			end,
+			currentKind,
+			errorTokenSource,
+			errorTokenName,
+			expectedToken);
+	}
+}
 private void syntaxError(
 	int id,
 	int startPosition,
@@ -8158,6 +8333,8 @@
 		return "("; //$NON-NLS-1$
 	if (token.equals("RestrictedIdentifierYield")) //$NON-NLS-1$
 		return "yield"; //$NON-NLS-1$
+	if (token.equals(RESTRICTED_IDENTIFIER_RECORD))
+		return RECORD;
 	return token;
 }
 public void task(String tag, String message, String priority, int start, int end){
@@ -8605,6 +8782,7 @@
 		nodeSourceEnd(field, location));
 }
 public void uninitializedLocalVariable(LocalVariableBinding binding, ASTNode location, Scope scope) {
+	if ((binding.modifiers & ExtraCompilerModifiers.AccPatternVariable) == 0) {
 	binding.markAsUninitializedIn(scope);
 	String[] arguments = new String[] {new String(binding.readableName())};
 	this.handle(
@@ -8613,6 +8791,16 @@
 		arguments,
 		nodeSourceStart(binding, location),
 		nodeSourceEnd(binding, location));
+	} else {
+		String[] arguments = new String[] {new String(binding.readableName())};
+		this.handle(
+				IProblem.PatternVariableNotInScope,
+						arguments,
+						arguments,
+						nodeSourceStart(binding, location),
+						nodeSourceEnd(binding, location));
+
+}
 }
 private boolean methodHasMissingSwitchDefault() {
 	MethodScope methodScope = null;
@@ -9794,7 +9982,8 @@
 }
 public void potentiallyUnclosedCloseable(FakedTrackingVariable trackVar, ASTNode location) {
 	String[] args = { trackVar.nameForReporting(location, this.referenceContext) };
-	if (location == null) {
+	if (location == null || trackVar.acquisition != null) {
+		// if acquisition is set, the problem is not location specific
 		this.handle(
 			IProblem.PotentiallyUnclosedCloseable,
 			args,
@@ -9994,20 +10183,26 @@
 		argument.type.sourceEnd);
 }
 public void parameterLackingNonnullAnnotation(Argument argument, ReferenceBinding declaringClass, char[][] inheritedAnnotationName) {
-	int sourceStart = 0, sourceEnd = 0;
-	if (argument != null) {
-		sourceStart = argument.type.sourceStart;
-		sourceEnd = argument.type.sourceEnd;
-	} else if (this.referenceContext instanceof TypeDeclaration) {
-		sourceStart = ((TypeDeclaration) this.referenceContext).sourceStart;
-		sourceEnd =   ((TypeDeclaration) this.referenceContext).sourceEnd;
-	}
 	this.handle(
 		IProblem.ParameterLackingNonNullAnnotation, 
 		new String[] { new String(declaringClass.readableName()), CharOperation.toString(inheritedAnnotationName)},
 		new String[] { new String(declaringClass.shortReadableName()), new String(inheritedAnnotationName[inheritedAnnotationName.length-1])},
-		sourceStart,
-		sourceEnd);
+		argument.type.sourceStart,
+		argument.type.sourceEnd);
+}
+public void inheritedParameterLackingNonnullAnnotation(MethodBinding currentMethod, int paramRank, ReferenceBinding specificationType,
+		ASTNode location, char[][] annotationName) {
+	this.handle(IProblem.InheritedParameterLackingNonNullAnnotation,
+		new String[] {
+			String.valueOf(paramRank), new String(currentMethod.readableName()),
+			new String(specificationType.readableName()), CharOperation.toString(annotationName)
+		},
+		new String[] {
+			String.valueOf(paramRank), new String(currentMethod.shortReadableName()),
+			new String(specificationType.shortReadableName()), new String(annotationName[annotationName.length-1])
+		},
+		location.sourceStart, location.sourceEnd
+		);
 }
 public void illegalParameterRedefinition(Argument argument, ReferenceBinding declaringClass, TypeBinding inheritedParameter) {
 	int sourceStart = argument.type.sourceStart;
@@ -10165,8 +10360,14 @@
 public void cannotImplementIncompatibleNullness(ReferenceContext context, MethodBinding currentMethod, MethodBinding inheritedMethod, boolean showReturn) {
 	int sourceStart = 0, sourceEnd = 0;
 	if (context instanceof TypeDeclaration) {
-		sourceStart = ((TypeDeclaration) context).sourceStart;
-		sourceEnd =   ((TypeDeclaration) context).sourceEnd;
+		TypeDeclaration type = (TypeDeclaration) context;
+		if (type.superclass != null) {
+			sourceStart = type.superclass.sourceStart;
+			sourceEnd =   type.superclass.sourceEnd;
+		} else {
+			sourceStart = type.sourceStart;
+			sourceEnd =   type.sourceEnd;
+		}
 	}
 	String[] problemArguments = {
 			showReturn 
@@ -10489,9 +10690,9 @@
 		nullityMismatchIsNull(expression, requiredType);
 		return;
 	}
+	if ((requiredType.tagBits & TagBits.AnnotationNonNull) != 0) { // some problems need a closer look to report the best possible message:
 	// try to improve nonnull vs. nullable:
 	if (status.isPotentiallyNullMismatch()
-			&& (requiredType.tagBits & TagBits.AnnotationNonNull) != 0 
 			&& (providedType.tagBits & TagBits.AnnotationNullable) == 0)
 	{
 		if(this.options.pessimisticNullAnalysisForFreeTypeVariablesEnabled && providedType.isTypeVariable() && !providedType.hasNullTypeAnnotations()) {
@@ -10502,6 +10703,16 @@
 		nullityMismatchPotentiallyNull(expression, requiredType, this.options.nonNullAnnotationName);
 		return;
 	}
+		VariableBinding var = expression.localVariableBinding();
+		if (var == null && expression instanceof Reference) {
+			var = ((Reference)expression).lastFieldBinding();
+		}
+		if(var != null && var.type.isFreeTypeVariable()) {
+			nullityMismatchVariableIsFreeTypeVariable(var, expression);
+			return;
+		}
+	}
+
 	String[] arguments;
 	String[] shortArguments;
 		
@@ -10509,17 +10720,21 @@
 	String superHint = null;
 	String superHintShort = null;
 	if (status.superTypeHint != null && requiredType.isParameterizedType()) {
-		problemId = (status.isUnchecked()
+		problemId = (status.isAnnotatedToUnannotated()
+					? IProblem.AnnotatedTypeArgumentToUnannotatedSuperHint
+					: (status.isUnchecked()
 			? IProblem.NullityUncheckedTypeAnnotationDetailSuperHint
-			: IProblem.NullityMismatchingTypeAnnotationSuperHint);
+						: IProblem.NullityMismatchingTypeAnnotationSuperHint));
 		superHint = status.superTypeHintName(this.options, false);
 		superHintShort = status.superTypeHintName(this.options, true);
 	} else {
-		problemId = (status.isUnchecked()
+		problemId = (status.isAnnotatedToUnannotated()
+					? IProblem.AnnotatedTypeArgumentToUnannotated
+					: (status.isUnchecked()
 			? IProblem.NullityUncheckedTypeAnnotationDetail
 			: (requiredType.isTypeVariable() && !requiredType.hasNullTypeAnnotations())
 				? IProblem.NullityMismatchAgainstFreeTypeVariable
-				: IProblem.NullityMismatchingTypeAnnotation);
+							: IProblem.NullityMismatchingTypeAnnotation));
 		if (problemId == IProblem.NullityMismatchAgainstFreeTypeVariable) {
 			arguments      = new String[] { null, null, new String(requiredType.sourceName()) }; // don't show bounds here
 			shortArguments = new String[] { null, null, new String(requiredType.sourceName()) };
@@ -11130,8 +11345,6 @@
 			moduleReference.sourceEnd);
 }
 public void switchExpressionIncompatibleResultExpressions(SwitchExpression expression) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	TypeBinding type = expression.resultExpressions.get(0).resolvedType;
 	this.handle(
 		IProblem.SwitchExpressionsYieldIncompatibleResultExpressionTypes,
@@ -11141,8 +11354,6 @@
 		expression.sourceEnd);
 }
 public void switchExpressionEmptySwitchBlock(SwitchExpression expression) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionsYieldEmptySwitchBlock,
 		NoArgument,
@@ -11151,8 +11362,6 @@
 		expression.sourceEnd);
 }
 public void switchExpressionNoResultExpressions(SwitchExpression expression) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionsYieldNoResultExpression,
 		NoArgument,
@@ -11161,8 +11370,6 @@
 		expression.sourceEnd);
 }
 public void switchExpressionSwitchLabeledBlockCompletesNormally(Block block) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionaYieldSwitchLabeledBlockCompletesNormally,
 		NoArgument,
@@ -11171,8 +11378,6 @@
 		block.sourceEnd);
 }
 public void switchExpressionLastStatementCompletesNormally(Statement stmt) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionaYieldSwitchLabeledBlockCompletesNormally,
 		NoArgument,
@@ -11181,8 +11386,6 @@
 		stmt.sourceEnd);
 }
 public void switchExpressionIllegalLastStatement(Statement stmt) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionsYieldIllegalLastStatement,
 		NoArgument,
@@ -11191,8 +11394,6 @@
 		stmt.sourceEnd);
 }
 public void switchExpressionTrailingSwitchLabels(Statement stmt) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionsYieldTrailingSwitchLabels,
 		NoArgument,
@@ -11201,8 +11402,6 @@
 		stmt.sourceEnd);
 }
 public void switchExpressionMixedCase(ASTNode statement) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchPreviewMixedCase,
 		NoArgument,
@@ -11211,8 +11410,6 @@
 		statement.sourceEnd);
 }
 public void switchExpressionBreakNotAllowed(ASTNode statement) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionsYieldBreakNotAllowed,
 		NoArgument,
@@ -11229,8 +11426,6 @@
 		statement.sourceEnd);
 }
 public void switchExpressionsYieldUnqualifiedMethodError(ASTNode statement) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionsYieldUnqualifiedMethodError,
 		NoArgument,
@@ -11239,8 +11434,6 @@
 		statement.sourceEnd);
 }
 public void switchExpressionsYieldOutsideSwitchExpression(ASTNode statement) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionsYieldOutsideSwitchExpression,
 		NoArgument,
@@ -11249,8 +11442,6 @@
 		statement.sourceEnd);
 }
 public void switchExpressionsYieldRestrictedGeneralWarning(ASTNode statement) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionsYieldRestrictedGeneralWarning,
 		NoArgument,
@@ -11259,8 +11450,6 @@
 		statement.sourceEnd);
 }
 public void switchExpressionsYieldIllegalStatement(ASTNode statement) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionsYieldIllegalStatement,
 		NoArgument,
@@ -11277,8 +11466,6 @@
 		statement.sourceEnd);
 }
 public void switchExpressionsYieldTypeDeclarationError(ASTNode statement) {
-	if (!this.options.enablePreviewFeatures)
-		return;
 	this.handle(
 		IProblem.SwitchExpressionsYieldTypeDeclarationError,
 		NoArgument,
@@ -11286,4 +11473,317 @@
 		statement.sourceStart,
 		statement.sourceEnd);
 }
+public void multiConstantCaseLabelsNotSupported(ASTNode statement) {
+	this.handle(
+		IProblem.MultiConstantCaseLabelsNotSupported,
+		NoArgument,
+		NoArgument,
+		statement.sourceStart,
+		statement.sourceEnd);
 }
+public void arrowInCaseStatementsNotSupported(ASTNode statement) {
+	this.handle(
+		IProblem.ArrowInCaseStatementsNotSupported,
+		NoArgument,
+		NoArgument,
+		statement.sourceStart,
+		statement.sourceEnd);
+}
+public void switchExpressionsNotSupported(ASTNode statement) {
+	this.handle(
+		IProblem.SwitchExpressionsNotSupported,
+		NoArgument,
+		NoArgument,
+		statement.sourceStart,
+		statement.sourceEnd);
+}
+public void switchExpressionsBreakOutOfSwitchExpression(ASTNode statement) {
+	this.handle(
+		IProblem.SwitchExpressionsBreakOutOfSwitchExpression,
+		NoArgument,
+		NoArgument,
+		statement.sourceStart,
+		statement.sourceEnd);
+}
+public void switchExpressionsContinueOutOfSwitchExpression(ASTNode statement) {
+	this.handle(
+		IProblem.SwitchExpressionsContinueOutOfSwitchExpression,
+		NoArgument,
+		NoArgument,
+		statement.sourceStart,
+		statement.sourceEnd);
+}
+public void illegalModifierForInnerRecord(SourceTypeBinding type) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	String[] arguments = new String[] {new String(type.sourceName())};
+	this.handle(
+		IProblem.RecordIllegalModifierForInnerRecord,
+		arguments,
+		arguments,
+		type.sourceStart(),
+		type.sourceEnd());
+}
+public void illegalModifierForRecord(SourceTypeBinding type) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	String[] arguments = new String[] {new String(type.sourceName())};
+	this.handle(
+		IProblem.RecordIllegalModifierForRecord,
+		arguments,
+		arguments,
+		type.sourceStart(),
+		type.sourceEnd());
+}
+public void recordNonStaticFieldDeclarationInRecord(FieldDeclaration field) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordNonStaticFieldDeclarationInRecord,
+		new String[] { new String(field.name) },
+		new String[] { new String(field.name) },
+		field.sourceStart,
+		field.sourceEnd);
+}
+public void recordAccessorMethodHasThrowsClause(ASTNode methodDeclaration) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordAccessorMethodHasThrowsClause,
+		NoArgument,
+		NoArgument,
+		methodDeclaration.sourceStart,
+		methodDeclaration.sourceEnd);
+}
+public void recordCanonicalConstructorNotPublic(AbstractMethodDeclaration methodDecl) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordCanonicalConstructorShouldBePublic,
+		new String[] {
+				new String(methodDecl.selector)
+			},
+			new String[] {
+				new String(methodDecl.selector)
+			},
+		methodDecl.sourceStart,
+		methodDecl.sourceEnd);
+}
+public void recordCompactConstructorHasReturnStatement(ReturnStatement stmt) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordCompactConstructorHasReturnStatement,
+		NoArgument,
+		NoArgument,
+		stmt.sourceStart,
+		stmt.sourceEnd);
+}
+public void recordIllegalComponentNameInRecord(Argument arg, RecordDeclaration rd) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordIllegalComponentNameInRecord,
+		new String[] {
+				new String(arg.name), new String(rd.name)
+			},
+			new String[] {
+					new String(arg.name), new String(rd.name)
+			},
+		arg.sourceStart,
+		arg.sourceEnd);
+}
+public void recordDuplicateComponent(Argument arg) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordDuplicateComponent,
+		new String[] { new String(arg.name)},
+		new String[] { new String(arg.name)},
+		arg.sourceStart,
+		arg.sourceEnd);
+}
+public void recordIllegalNativeModifierInRecord(AbstractMethodDeclaration method) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordIllegalNativeModifierInRecord,
+		new String[] { new String(method.selector)},
+		new String[] { new String(method.selector)},
+		method.sourceStart,
+		method.sourceEnd);
+}
+public void recordInstanceInitializerBlockInRecord(Initializer initializer) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordInstanceInitializerBlockInRecord,
+		NoArgument,
+		NoArgument,
+		initializer.sourceStart,
+		initializer.sourceEnd);
+}
+public void recordIsAReservedTypeName(ASTNode decl) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordIsAReservedTypeName,
+		NoArgument,
+		NoArgument,
+		decl.sourceStart,
+		decl.sourceEnd);
+}
+public void recordIllegalAccessorReturnType(ASTNode returnType, TypeBinding type) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordIllegalAccessorReturnType,
+		new String[] {new String(type.readableName())},
+		new String[] {new String(type.shortReadableName())},
+		returnType.sourceStart,
+		returnType.sourceEnd);
+}
+public void recordAccessorMethodShouldNotBeGeneric(ASTNode methodDecl) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordAccessorMethodShouldNotBeGeneric,
+		NoArgument,
+		NoArgument,
+		methodDecl.sourceStart,
+		methodDecl.sourceEnd);
+}
+public void recordAccessorMethodShouldBePublic(ASTNode methodDecl) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordAccessorMethodShouldBePublic,
+		NoArgument,
+		NoArgument,
+		methodDecl.sourceStart,
+		methodDecl.sourceEnd);
+}
+public void recordCanonicalConstructorShouldNotBeGeneric(AbstractMethodDeclaration methodDecl) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordCanonicalConstructorShouldNotBeGeneric,
+		new String[] { new String(methodDecl.selector)},
+		new String[] { new String(methodDecl.selector)},
+		methodDecl.sourceStart,
+		methodDecl.sourceEnd);
+}
+public void recordCanonicalConstructorShouldBePublic(MethodDeclaration methodDecl) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordCanonicalConstructorShouldBePublic,
+		new String[] { new String(methodDecl.selector)},
+		new String[] { new String(methodDecl.selector)},
+		methodDecl.sourceStart,
+		methodDecl.sourceEnd);
+}
+public void recordCanonicalConstructorHasThrowsClause(AbstractMethodDeclaration methodDecl) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordCanonicalConstructorHasThrowsClause,
+		new String[] { new String(methodDecl.selector)},
+		new String[] { new String(methodDecl.selector)},
+		methodDecl.sourceStart,
+		methodDecl.sourceEnd);
+}
+public void recordCanonicalConstructorHasReturnStatement(ASTNode methodDecl) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordCanonicalConstructorHasReturnStatement,
+		NoArgument,
+		NoArgument,
+		methodDecl.sourceStart,
+		methodDecl.sourceEnd);
+}
+public void recordCanonicalConstructorHasExplicitConstructorCall(ASTNode methodDecl) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordCanonicalConstructorHasExplicitConstructorCall,
+		NoArgument,
+		NoArgument,
+		methodDecl.sourceStart,
+		methodDecl.sourceEnd);
+}
+public void recordCompactConstructorHasExplicitConstructorCall(ASTNode methodDecl) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordCompactConstructorHasExplicitConstructorCall,
+		NoArgument,
+		NoArgument,
+		methodDecl.sourceStart,
+		methodDecl.sourceEnd);
+}
+public void recordNestedRecordInherentlyStatic(SourceTypeBinding type) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordNestedRecordInherentlyStatic,
+		NoArgument,
+		NoArgument,
+		type.sourceStart(),
+		type.sourceEnd());
+}
+public void recordAccessorMethodShouldNotBeStatic(ASTNode methodDecl) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	this.handle(
+		IProblem.RecordAccessorMethodShouldNotBeStatic,
+		NoArgument,
+		NoArgument,
+		methodDecl.sourceStart,
+		methodDecl.sourceEnd);
+}
+public void recordCannotExtendRecord(SourceTypeBinding type, TypeReference superclass, TypeBinding superTypeBinding) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	String name = new String(type.sourceName());
+	String superTypeFullName = new String(superTypeBinding.readableName());
+	String superTypeShortName = new String(superTypeBinding.shortReadableName());
+	if (superTypeShortName.equals(name)) superTypeShortName = superTypeFullName;
+	this.handle(
+		IProblem.RecordCannotExtendRecord,
+		new String[] {superTypeFullName, name},
+		new String[] {superTypeShortName, name},
+		superclass.sourceStart,
+		superclass.sourceEnd);
+}
+public void recordComponentCannotBeVoid(ASTNode recordDecl, Argument arg) {
+	if (!this.options.enablePreviewFeatures)
+		return;
+	String[] arguments = new String[] { new String(arg.name) };
+	this.handle(
+		IProblem.RecordComponentCannotBeVoid,
+		arguments,
+		arguments,
+		recordDecl.sourceStart,
+		recordDecl.sourceEnd);
+}
+public void recordIllegalVararg(Argument argType, RecordDeclaration recordDecl) {
+	String[] arguments = new String[] {CharOperation.toString(argType.type.getTypeName()), new String(recordDecl.name)};
+	this.handle(
+		IProblem.RecordIllegalVararg,
+		arguments,
+		arguments,
+		argType.sourceStart,
+		argType.sourceEnd);
+}
+public void recordStaticReferenceToOuterLocalVariable(LocalVariableBinding local, ASTNode node) {
+	String[] arguments = new String[] {new String(local.readableName())};
+	this.handle(
+		IProblem.RecordStaticReferenceToOuterLocalVariable,
+		arguments,
+		arguments,
+		node.sourceStart,
+		node.sourceEnd);
+}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemSeverities.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemSeverities.java
index df43410..3c36c29 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemSeverities.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemSeverities.java
@@ -29,6 +29,6 @@
 	final int Ignore = 256; // during handling only
 	final int InternalError = 512;  // always exposed, even when silent error handling policy is in effect.
 	final int Info = 1024; // When bit is set, the unit or project is not flagged.
-	
+
 	final int CoreSeverityMASK = Warning | Error | Info | Ignore;
 }
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 47d1778..8548e40 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
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2019 IBM Corporation and others.
+# Copyright (c) 2000, 2020 IBM Corporation and others.
 #
 # This program and the accompanying materials
 # are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
 # https://www.eclipse.org/legal/epl-2.0/
 #
 # SPDX-License-Identifier: EPL-2.0
-# 
+#
 # Contributors:
 #     IBM Corporation - initial API and implementation
 #		Benjamin Muskalla - Contribution for bug 239066
@@ -822,6 +822,7 @@
 943 = Nullness default is redundant with a default specified for the enclosing module {0}
 944 = Redundant null check: The field {0} is a nonnull constant
 945 = Null comparison always yields false: The field {0} is a nonnull constant
+946 = Parameter {0} of method {1} lacks a @{3} annotation as specified in type {2}
 
 
 951 = Potential null pointer access: array element may be null
@@ -855,7 +856,9 @@
 979 = Null type safety: required ''@{0}'' but this expression has type ''{1}'', a free type variable that may represent a ''@{2}'' type
 980 = Unsafe interpretation of method return type as ''@{0}'' based on the receiver type ''{1}''. Type ''{2}'' doesn''t seem to be designed with null type annotations in mind
 981 = Unsafe interpretation of method return type as ''@{0}'' based on substitution ''{1}={2}''. Declaring type ''{3}'' doesn''t seem to be designed with null type annotations in mind
-
+982 = Annotation type ''{0}'' cannot be found on the build path, which is implicitly needed for null analysis
+983 = Unsafe null type conversion (type annotations): The value of type ''{1}'' is made accessible using the less-annotated type ''{0}''
+984 = Unsafe null type conversion (type annotations): The value of type ''{1}'' is made accessible using the less-annotated type ''{0}'', corresponding supertype is ''{2}''
 
 # Java 8
 1001 = Syntax error, modifiers and annotations are not allowed for the lambda parameter {0} as its type is elided
@@ -996,7 +999,7 @@
 1611 = A Switch expression should cover all possible values
 1612 = 'continue' or 'return' cannot be the last statement in a Switch expression case body
 
-# Switch-Expressions Java 13 Preview
+# Switch-Expressions Java 14
 1700 = Incompatible switch results expressions {0}
 1701 = A switch expression should have a non-empty switch block
 1702 = A switch expression should have at least one result expression
@@ -1016,6 +1019,55 @@
 1716 = yield statement is illegal here
 1717 = yield may be a restricted identifier in future and may be disallowed as a type name
 1718 = yield is a restricted identifier and cannot be used as type name
+1719 = Multi-constant case labels supported from Java 14 onwards only
+1720 = Arrow in case statement supported from Java 14 onwards only
+1721 = Switch Expressions are supported from Java 14 onwards only
+1722 = Breaking out of switch expressions not permitted
+1723 = Continue out of switch expressions not permitted
+# Java 14 Preview - begin
+# Records
+1730 = Illegal modifier for the record {0}; only public, private, protected, static, final and strictfp are permitted
+1731 = Illegal modifier for the record {0}; only public, final and strictfp are permitted
+1732 = Illegal component name {0} in record {1};
+1733 = User declared non-static fields {0} are not permitted in a record
+1734 = Throws clause not allowed for explicitly declared accessor method
+1735 = Throws clause not allowed for canonical constructor {0}
+1736 = The canonical constructor {0} of a record declaration must be declared public.
+1737 = Multiple canonical constructors {0} are not allowed
+1738 = The body of a compact constructor must not contain a return statement
+1739 = Duplicate component {0} in record
+1740 = Illegal modifier native for method {0}; native methods are not allowed in record
+1741 = Instance Initializer is not allowed in a record declaration
+1742 = Record is a restricted identifier and hence not a valid type name
+1743 = Illegal return type of accessor; should be the same as the declared type {0} of the record component
+1744 = The accessor method must not be generic
+1745 = The accessor method must be declared public
+1746 = Canonical constructor {0} of a record declaration should not be generic
+1747 = The body of a canonical constructor must not contain a return statement
+1748 = The body of a canonical constructor must not contain an explicit constructor call
+1749 = The body of a compact constructor must not contain an explicit constructor call
+1750 = Nested Record is (implicitly) static and hence enclosing type should be static
+1751 = The accessor method must not be static
+1752 = The type {1} may not subclass {0} explicitly
+1753 = void is an invalid type for the component {0} of a record
+1754 = The variable argument type {0} of the record {1} must be the last parameter
+1755 = Cannot make a static reference to the non-static variable {0} from a local record
+
+1760 = The pattern variable {0} is not in scope in this location
+
+# Java 14 Preview - end
+
+# Additional doc
+1800 = Missing uses tag
+1801 = Duplicate uses tag
+1802 = Missing uses class name
+1803 = Invalid uses class name
+1804 = Invalid uses class
+1805 = Missing provides tag
+1806 = Duplicate provides tag
+1807 = Missing provides class name
+1808 = Invalid provides class name
+1809 = Invalid provides class
 
 ### ELABORATIONS
 ## Access restrictions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfInteger.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfInteger.java
index 4c8165c..2000a44 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfInteger.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfInteger.java
@@ -136,7 +136,7 @@
 		}
 		this.keyTable[index] = intKey;
 		this.valueTable[index] = value;
-	
+
 		// assumes the threshold is never equal to the size of the table
 		if (++this.elementSize > this.threshold) {
 			rehash();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfModule.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfModule.java
index 5cd85c9..f382a76 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfModule.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfModule.java
@@ -7,10 +7,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.util;
 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObject.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObject.java
index a30af49..79d6dc5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObject.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/HashtableOfObject.java
@@ -136,7 +136,7 @@
 		}
 		this.keyTable[index] = key;
 		this.valueTable[index] = value;
-	
+
 		// assumes the threshold is never equal to the size of the table
 		if (++this.elementSize > this.threshold) {
 			rehash();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java
index 5216b59..2234ec8 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/JRTUtil.java
@@ -70,7 +70,7 @@
 
 		public FileVisitResult visitFile(T file, T mod, BasicFileAttributes attrs) throws IOException;
 		/**
-		 * Invoked when a root directory of a module being visited. The element returned 
+		 * Invoked when a root directory of a module being visited. The element returned
 		 * contains only the module name segment - e.g. "java.base". Clients can use this to control
 		 * how the JRT needs to be processed, for e.g., clients can skip a particular module
 		 * by returning FileVisitResult.SKIP_SUBTREE
@@ -83,17 +83,17 @@
 		public FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) throws IOException {
 			return FileVisitResult.CONTINUE;
 		}
-	
+
 		@Override
 		public FileVisitResult visitFile(T file, BasicFileAttributes attrs) throws IOException {
 			return FileVisitResult.CONTINUE;
 		}
-	
+
 		@Override
 		public FileVisitResult visitFileFailed(T file, IOException exc) throws IOException {
 			return FileVisitResult.CONTINUE;
 		}
-	
+
 		@Override
 		public FileVisitResult postVisitDirectory(T dir, IOException exc) throws IOException {
 			return FileVisitResult.CONTINUE;
@@ -123,7 +123,7 @@
 					images.put(key, system = JrtFileSystem.getNewJrtFileSystem(image, release));
 				} catch (IOException e) {
 					e.printStackTrace();
-					// Needs better error handling downstream? But for now, make sure 
+					// Needs better error handling downstream? But for now, make sure
 					// a dummy JrtFileSystem is not created.
 				}
 			}
@@ -143,9 +143,9 @@
 	 *
 	 * The file system contains the following top level directories:
 	 *  /modules/$MODULE/$PATH
-	 *  /packages/$PACKAGE/$MODULE 
+	 *  /packages/$PACKAGE/$MODULE
 	 *  The latter provides quick look up of the module that contains a particular package. However,
-	 *  this method only notifies its clients of the entries within the modules (latter) sub-directory. 
+	 *  this method only notifies its clients of the entries within the modules (latter) sub-directory.
 	 *  Clients can decide which notifications they want to receive. See {@link JRTUtil#NOTIFY_ALL},
 	 *  {@link JRTUtil#NOTIFY_FILES}, {@link JRTUtil#NOTIFY_PACKAGES} and {@link JRTUtil#NOTIFY_MODULES}.
 	 *
@@ -218,7 +218,7 @@
 	 *
 	 * @param jrt the path to the root of the JRE whose libraries we are interested in.
 	 * @param release the older release where classes and modules should be searched for.
-	 * @throws IOException 
+	 * @throws IOException
 	 */
 	JrtFileSystemWithOlderRelease(File jrt, String release) throws IOException {
 		super(jrt);
@@ -227,7 +227,7 @@
 	}
 	@Override
 	void initialize(File jdk) throws IOException {
-		// Just to make sure we don't do anything in super.initialize() 
+		// Just to make sure we don't do anything in super.initialize()
 		// before setting this.release
 	}
 	void initialize(File jdk, String rel) throws IOException {
@@ -322,7 +322,7 @@
 			}
 		}
 	}
-	
+
 }
 class JrtFileSystem {
 	private final Map<String, String> packageToModule = new HashMap<String, String>();
@@ -333,16 +333,16 @@
 	Path modRoot = null;
 	String jdkHome = null;
 	public static JrtFileSystem getNewJrtFileSystem(File jrt, String release) throws IOException {
-		return (release == null) ? new JrtFileSystem(jrt) : 
+		return (release == null) ? new JrtFileSystem(jrt) :
 				new JrtFileSystemWithOlderRelease(jrt, release);
-				
+
 	}
 	/**
 	 * The jrt file system is based on the location of the JRE home whose libraries
 	 * need to be loaded.
 	 *
 	 * @param jrt the path to the root of the JRE whose libraries we are interested in.
-	 * @throws IOException 
+	 * @throws IOException
 	 */
 	JrtFileSystem(File jrt) throws IOException {
 		initialize(jrt);
@@ -547,7 +547,7 @@
 							JRTUtil.MODULE_TO_LOAD.indexOf(mod.toString()) == -1)) {
 						return FileVisitResult.SKIP_SUBTREE;
 					}
-					return ((notify & JRTUtil.NOTIFY_MODULES) == 0) ? 
+					return ((notify & JRTUtil.NOTIFY_MODULES) == 0) ?
 							FileVisitResult.CONTINUE : visitor.visitModule(dir, JRTUtil.sanitizedFileName(mod));
 				}
 				if ((notify & JRTUtil.NOTIFY_PACKAGES) == 0) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/ManifestAnalyzer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/ManifestAnalyzer.java
index eb72d85..79119d3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/ManifestAnalyzer.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/ManifestAnalyzer.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -32,13 +32,13 @@
 		"Class-Path:".toCharArray(); //$NON-NLS-1$
 	private int classpathSectionsCount;
 	private ArrayList calledFilesNames;
-	
+
 	/**
 	 * Analyzes the manifest contents. The given input stream is read using a UTF-8 encoded reader.
 	 * If the contents of the input stream is not encoded using a UTF-8 encoding, the analysis will fail.
-	 * 
+	 *
 	 * @param inputStream the given input stream.
-	 * 
+	 *
 	 * @return <code>true</code> if the analysis is successful, <code>false</code> otherwise.
 	 * @throws IOException if an exception occurs while analyzing the file
 	 */
@@ -49,9 +49,9 @@
 
 	/**
 	 * Analyzes the manifest contents.
-	 * 
+	 *
 	 * @param chars the content of the manifest
-	 * 
+	 *
 	 * @return <code>true</code> if the analysis is successful, <code>false</code> otherwise.
 	 */
 	public boolean analyzeManifestContents(char[] chars) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Sorting.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Sorting.java
index 692e8ab..4d55dc6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Sorting.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Sorting.java
@@ -38,7 +38,7 @@
 		ReferenceBinding[] unsorted = new ReferenceBinding[len];
 		ReferenceBinding[] sorted = new ReferenceBinding[len];
 		System.arraycopy(types, 0, unsorted, 0, len);
-		
+
 		int o = 0;
 		for(int i=0; i<len; i++)
 			o = sort(unsorted, i, sorted, o);
@@ -119,6 +119,6 @@
 			public int compare(InferenceVariable iv1, InferenceVariable iv2) {
 				return iv1.rank - iv2.rank;
 			}
-		});		
+		});
 	}
 }
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
index 108bb30..a274a29 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
@@ -1,6 +1,6 @@
 // AspectJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -323,9 +323,32 @@
 	 */
 	static final int JLS13_INTERNAL = JLS13;
 
+	/**
+	 * Constant for indicating the AST API that handles JLS14.
+	 * <p>
+	 * This API is capable of handling all constructs in the
+	 * Java language as described in the Java Language
+	 * Specification, Java SE 14 Edition (JLS14).
+	 * JLS14 is a superset of all earlier versions of the
+	 * Java language, and the JLS14 API can be used to manipulate
+	 * programs written in all versions of the Java language
+	 * up to and including Java SE 14(aka JDK 14).
+	 * </p>
+	 *
+	 * @since 3.22
+	 */
+	public static final int JLS14 = 14;
+
+	/**
+	 * Internal synonym for {@link #JLS14}. Use to alleviate
+	 * deprecation warnings once JLS14 is deprecated
+	 * @since 3.22
+	 */
+	static final int JLS14_INTERNAL = JLS14;
+
 	@SuppressWarnings("unused")
 	/* Used for Java doc only*/
-	private static final int JLS_Latest = JLS13;
+	private static final int JLS_Latest = JLS14;
 	
 	/*
 	 * Must not collide with a value for ICompilationUnit constants
@@ -1008,6 +1031,21 @@
 						true/*taskCaseSensitive*/,
 						previewEnabled);
 				break;
+			case JLS14_INTERNAL :
+				this.apiLevel = level;
+				// initialize a scanner
+				compliance = ClassFileConstants.getComplianceLevelForJavaVersion(ClassFileConstants.MAJOR_VERSION_14);
+				this.scanner = new Scanner(
+						true /*comment*/,
+						true /*whitespace*/,
+						false /*nls*/,
+						compliance /*sourceLevel*/,
+						compliance /*complianceLevel*/,
+						null/*taskTag*/,
+						null/*taskPriorities*/,
+						true/*taskCaseSensitive*/,
+						previewEnabled);
+				break;
 			default:
 				throw new IllegalArgumentException("Unsupported JLS level"); //$NON-NLS-1$
 		}
@@ -1086,6 +1124,7 @@
         t.put(JavaCore.VERSION_11, ClassFileConstants.JDK11);
         t.put(JavaCore.VERSION_12, ClassFileConstants.JDK12);
         t.put(JavaCore.VERSION_13, ClassFileConstants.JDK13);
+        t.put(JavaCore.VERSION_14, ClassFileConstants.JDK14);
         return Collections.unmodifiableMap(t);
 	}
 	private static Map<String, Integer> getApiLevelMapTable() {
@@ -1103,6 +1142,7 @@
         t.put(JavaCore.VERSION_11, JLS11_INTERNAL);
         t.put(JavaCore.VERSION_12, JLS12_INTERNAL);
         t.put(JavaCore.VERSION_13, JLS13_INTERNAL);
+        t.put(JavaCore.VERSION_14, JLS14_INTERNAL);
         return Collections.unmodifiableMap(t);
 	}
 	/**
@@ -3610,11 +3650,21 @@
 
 	/**
 	 * 
+	 * @return If previewEnabled flag is set to <code>true</code>, return <code>true</code> else <code>false</code>
+	 * @since 3.21
+	 * @noreference This method is not intended to be referenced by clients.
+	 */
+	public boolean isPreviewEnabledSet() {
+		return this.previewEnabled;
+	}
+
+	/**
+	 *
 	 * @return If preview is enabled and apiLevel is latest, return <code>true</code> else <code>false</code>
 	 * @since 3.19
 	 */
 	public boolean isPreviewEnabled() {
-		if (this.apiLevel == AST.JLS13_INTERNAL && this.previewEnabled) {
+		if (this.apiLevel == AST.JLS_Latest && this.previewEnabled) {
 			return true;
 		}
 		return false;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
index acd4f86..ac31cee 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
@@ -1,6 +1,6 @@
 // AspectJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -38,6 +38,7 @@
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.Argument;
+import org.eclipse.jdt.internal.compiler.ast.CompactConstructorDeclaration;
 import org.eclipse.jdt.internal.compiler.ast.FieldReference;
 import org.eclipse.jdt.internal.compiler.ast.ForeachStatement;
 import org.eclipse.jdt.internal.compiler.ast.IntersectionCastTypeReference;
@@ -71,6 +72,7 @@
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
 import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
 import org.eclipse.jdt.internal.core.dom.SourceRangeVerifier;
+import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
 import org.eclipse.jdt.internal.core.util.Util;
 
 /**
@@ -249,6 +251,88 @@
 		convert(typeDeclaration.javadoc, typeDecl);
 	}
 
+	protected void buildBodyDeclarations(
+			org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration,
+			RecordDeclaration recordDeclaration,
+			boolean isInterface) {
+		// add body declaration in the lexical order
+		org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] members = typeDeclaration.memberTypes;
+		org.eclipse.jdt.internal.compiler.ast.FieldDeclaration[] fields = typeDeclaration.fields;
+		org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration[] methods = typeDeclaration.methods;
+
+		int fieldsLength = fields == null? 0 : fields.length;
+		int methodsLength = methods == null? 0 : methods.length;
+		int membersLength = members == null ? 0 : members.length;
+		int fieldsIndex = 0;
+		int methodsIndex = 0;
+		int membersIndex = 0;
+
+		while ((fieldsIndex < fieldsLength)
+			|| (membersIndex < membersLength)
+			|| (methodsIndex < methodsLength)) {
+			org.eclipse.jdt.internal.compiler.ast.FieldDeclaration nextFieldDeclaration = null;
+			org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration nextMethodDeclaration = null;
+			org.eclipse.jdt.internal.compiler.ast.TypeDeclaration nextMemberDeclaration = null;
+
+			int position = Integer.MAX_VALUE;
+			int nextDeclarationType = -1;
+			if (fieldsIndex < fieldsLength) {
+				nextFieldDeclaration = fields[fieldsIndex];
+				if (!nextFieldDeclaration.isARecordComponent) {
+					if (nextFieldDeclaration.declarationSourceStart < position) {
+							position = nextFieldDeclaration.declarationSourceStart;
+							nextDeclarationType = 0; // FIELD
+					}
+				} else {
+					fieldsIndex++;
+				}
+
+			}
+			if (methodsIndex < methodsLength) {
+				nextMethodDeclaration = methods[methodsIndex];
+				if ((nextMethodDeclaration.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.IsImplicit) == 0) {
+					if (nextMethodDeclaration.declarationSourceStart < position) {
+						position = nextMethodDeclaration.declarationSourceStart;
+						nextDeclarationType = 1; // METHOD
+					}
+
+			  } else {
+				  methodsIndex++;
+			  }
+
+			}
+			if (membersIndex < membersLength) {
+				nextMemberDeclaration = members[membersIndex];
+				if (nextMemberDeclaration.declarationSourceStart < position) {
+					position = nextMemberDeclaration.declarationSourceStart;
+					nextDeclarationType = 2; // MEMBER
+				}
+			}
+			switch (nextDeclarationType) {
+				case 0 :
+					checkAndAddMultipleFieldDeclaration(fields, fieldsIndex, recordDeclaration.bodyDeclarations());
+					fieldsIndex++;
+					break;
+				case 1 :
+					methodsIndex++;
+					if (!nextMethodDeclaration.isDefaultConstructor() && !nextMethodDeclaration.isClinit()) {
+						recordDeclaration.bodyDeclarations().add(convert(isInterface, nextMethodDeclaration));
+					}
+					break;
+				case 2 :
+					membersIndex++;
+					ASTNode node = convert(nextMemberDeclaration);
+					if (node == null) {
+						recordDeclaration.setFlags(recordDeclaration.getFlags() | ASTNode.MALFORMED);
+					} else {
+						recordDeclaration.bodyDeclarations().add(node);
+					}
+			}
+		}
+		// Convert javadoc
+		convert(typeDeclaration.javadoc, recordDeclaration);
+	}
+
 	protected void buildBodyDeclarations(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration enumDeclaration2, EnumDeclaration enumDeclaration) {
 		// add body declaration in the lexical order
 		org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] members = enumDeclaration2.memberTypes;
@@ -555,9 +639,15 @@
 		final SimpleName methodName = new SimpleName(this.ast);
 		methodName.internalSetIdentifier(new String(methodDeclaration.selector));
 		int start = methodDeclaration.sourceStart;
-		int end = retrieveIdentifierEndPosition(start, methodDeclaration.sourceEnd);
+		int end;
+		if (DOMASTUtil.isRecordDeclarationSupported(this.ast) && methodDeclaration instanceof CompactConstructorDeclaration) {
+			methodDecl.setCompactConstructor(true);
+			end = start + methodDeclaration.selector.length -1;
+		}else {
+			 end = retrieveIdentifierEndPosition(start, methodDeclaration.sourceEnd);
 		if (end < start)
 			end = start + methodDeclaration.selector.length;// naive recovery with method name
+		}
 		methodName.setSourceRange(start, end - start + 1);
 		methodDecl.setName(methodName);
 		org.eclipse.jdt.internal.compiler.ast.TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions;
@@ -597,6 +687,7 @@
 		org.eclipse.jdt.internal.compiler.ast.Argument[] parameters = methodDeclaration.arguments;
 		int parametersLength = parameters == null ? 0 : parameters.length;
 		if (parametersLength > 0) {
+			if (!(DOMASTUtil.isRecordDeclarationSupported(this.ast) && methodDecl.isCompactConstructor())) {
 			SingleVariableDeclaration parameter;
 			int i = 0;
 			do {
@@ -607,6 +698,7 @@
 				methodHeaderEnd = parameter.getStartPosition() + parameter.getLength();
 			}
 		}
+		}
 		org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall explicitConstructorCall = null;
 		if (isConstructor) {
 			if (isInterface) {
@@ -682,10 +774,11 @@
 				}
 				int statementsLength = statements == null ? 0 : statements.length;
 				for (int i = 0; i < statementsLength; i++) {
-					if (statements[i] instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) {
+					org.eclipse.jdt.internal.compiler.ast.Statement astStatement = statements[i];
+					if (astStatement instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) {
 						checkAndAddMultipleLocalDeclaration(statements, i, block.statements());
-					} else {
-						final Statement statement = convert(statements[i]);
+					} else if ((astStatement.bits & org.eclipse.jdt.internal.compiler.ast.ASTNode.IsImplicit) == 0 ){ // Don't convert Implicit statements
+						final Statement statement = convert(astStatement);
 						if (statement != null) {
 							block.statements().add(statement);
 						}
@@ -1337,7 +1430,7 @@
 
 	public SwitchCase convert(org.eclipse.jdt.internal.compiler.ast.CaseStatement statement) {
 		SwitchCase switchCase = new SwitchCase(this.ast);
-		if (this.ast.isPreviewEnabled()) {
+		if (this.ast.apiLevel >= AST.JLS14) {
 			org.eclipse.jdt.internal.compiler.ast.Expression[] expressions = statement.constantExpressions;
 			if (expressions == null || expressions.length == 0) {
 				switchCase.expressions().clear();
@@ -1354,7 +1447,7 @@
 				internalSetExpression(switchCase, convert(constantExpression));
 		}
 		}
-		if (this.ast.isPreviewEnabled()) {
+		if (this.ast.apiLevel >= AST.JLS14) {
 			switchCase.setSwitchLabeledRule(statement.isExpr);
 		}
 		switchCase.setSourceRange(statement.sourceStart, statement.sourceEnd - statement.sourceStart + 1);
@@ -2090,6 +2183,10 @@
 		instanceOfExpression.setRightOperand(convertType);
 		int startPosition = leftExpression.getStartPosition();
 		int sourceEnd = convertType.getStartPosition() + convertType.getLength() - 1;
+		if (DOMASTUtil.isInstanceofExpressionPatternSupported(this.ast) && expression.elementVariable != null) {
+			instanceOfExpression.setPatternVariable(convertToSingleVariableDeclaration(expression.elementVariable));
+			sourceEnd= expression.elementVariable.sourceEnd;
+		}
 		instanceOfExpression.setSourceRange(startPosition, sourceEnd - startPosition + 1);
 		return instanceOfExpression;
 	}
@@ -2848,13 +2945,18 @@
 		}
 		if (statement instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
 			ASTNode result = convert((org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) statement);
-			if (result == null || !(result instanceof TypeDeclaration)) {
+			if (result == null || !(result instanceof TypeDeclaration || result instanceof RecordDeclaration)) {
 				return createFakeEmptyStatement(statement);
 			}
+			TypeDeclarationStatement typeDeclarationStatement = new TypeDeclarationStatement(this.ast);
+			if (result instanceof TypeDeclaration) {
 			// annotation and enum type declarations are not returned by the parser inside method bodies
 			TypeDeclaration typeDeclaration = (TypeDeclaration) result;
-			TypeDeclarationStatement typeDeclarationStatement = new TypeDeclarationStatement(this.ast);
 			typeDeclarationStatement.setDeclaration(typeDeclaration);
+			} else {
+				RecordDeclaration recordDeclaration = (RecordDeclaration) result;
+				typeDeclarationStatement.setDeclaration(recordDeclaration);
+			}
 			switch(this.ast.apiLevel) {
 				case AST.JLS2_INTERNAL :
 					TypeDeclaration typeDecl = typeDeclarationStatement.internalGetTypeDeclaration();
@@ -2903,7 +3005,7 @@
 	}
 
 	public Expression convert(org.eclipse.jdt.internal.compiler.ast.SwitchExpression expression) {
-		if (!this.ast.isPreviewEnabled()) {
+		if (this.ast.apiLevel < AST.JLS14) {
 			return createFakeNullLiteral(expression);		
 		}
 		SwitchExpression switchExpression = new SwitchExpression(this.ast);
@@ -3095,7 +3197,12 @@
 					return convertToAnnotationDeclaration(typeDeclaration);
 				}
 		}
-
+		if (typeDeclaration.isRecord()) {
+			if (!DOMASTUtil.isRecordDeclarationSupported(this.ast)) {
+				return null;
+			}
+			return convertToRecordDeclaration(typeDeclaration);
+		}
 		checkCanceled();
 		// AspectJ Extension - use factory method and not ctor
 		// old code:
@@ -3261,7 +3368,7 @@
 	}
 
 	public Statement convert(org.eclipse.jdt.internal.compiler.ast.YieldStatement statement) {
-		if (!this.ast.isPreviewEnabled()) {
+		if (this.ast.apiLevel < AST.JLS14) {
 			return createFakeEmptyStatement(statement);		
 		}
 		YieldStatement yieldStatement = new YieldStatement(this.ast);
@@ -3414,6 +3521,45 @@
 		}
 		return enumDeclaration2;
 	}
+
+	private RecordDeclaration convertToRecordDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration) {
+		checkCanceled();
+		// record declaration cannot be built if the source is not >= 14, since record is then seen as an identifier
+		final RecordDeclaration recordDeclaration = new RecordDeclaration(this.ast);
+		setModifiers(recordDeclaration, typeDeclaration);
+		final SimpleName typeName = new SimpleName(this.ast);
+		typeName.internalSetIdentifier(new String(typeDeclaration.name));
+		typeName.setSourceRange(typeDeclaration.sourceStart, typeDeclaration.name.length);
+		recordDeclaration.setName(typeName);
+		recordDeclaration.setSourceRange(typeDeclaration.declarationSourceStart, typeDeclaration.bodyEnd - typeDeclaration.declarationSourceStart + 1);
+		recordDeclaration.setRestrictedIdentifierStartPosition(typeDeclaration.restrictedIdentifierStart);
+
+		org.eclipse.jdt.internal.compiler.ast.TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
+		if (superInterfaces != null) {
+			for (TypeReference superInterface : superInterfaces) {
+				recordDeclaration.superInterfaceTypes().add(convertType(superInterface));
+			}
+		}
+		org.eclipse.jdt.internal.compiler.ast.TypeParameter[] typeParameters = typeDeclaration.typeParameters;
+		if (typeParameters != null) {
+			for (org.eclipse.jdt.internal.compiler.ast.TypeParameter typeParameter : typeParameters) {
+				recordDeclaration.typeParameters().add(convert(typeParameter));
+			}
+		}
+		Argument[] args = ((org.eclipse.jdt.internal.compiler.ast.RecordDeclaration)typeDeclaration).getArgs();
+		if (args != null) {
+			for (Argument arg : args) {
+				recordDeclaration.recordComponents().add(convert(arg));
+			}
+		}
+		buildBodyDeclarations(typeDeclaration, recordDeclaration, false);
+		if (this.resolveBindings) {
+			recordNodes(recordDeclaration, typeDeclaration);
+			recordNodes(typeName, typeDeclaration);
+			recordDeclaration.resolveBinding();
+		}
+		return recordDeclaration;
+	}
 	public Expression convertToExpression(org.eclipse.jdt.internal.compiler.ast.Statement statement) {
 		if (statement instanceof org.eclipse.jdt.internal.compiler.ast.Expression &&
 				((org.eclipse.jdt.internal.compiler.ast.Expression) statement).isTrulyExpression()) {
@@ -5458,6 +5604,11 @@
 		this.setModifiers(enumDeclaration, enumDeclaration2.annotations, enumDeclaration2.sourceStart);
 	}
 
+    protected void setModifiers(RecordDeclaration recordDeclaration, org.eclipse.jdt.internal.compiler.ast.TypeDeclaration recordDeclaration2) {
+        this.scanner.resetTo(recordDeclaration2.declarationSourceStart, recordDeclaration2.sourceStart);
+        this.setModifiers(recordDeclaration, recordDeclaration2.annotations, recordDeclaration2.sourceStart);
+    }
+
 	protected void setModifiers(EnumConstantDeclaration enumConstantDeclaration, org.eclipse.jdt.internal.compiler.ast.FieldDeclaration fieldDeclaration) {
 		switch(this.ast.apiLevel) {
 			case AST.JLS2_INTERNAL :
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
index 5e7935a..6393acd 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTMatcher.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -16,6 +16,8 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
+
 /**
  * Concrete superclass and default implementation of an AST subtree matcher.
  * <p>
@@ -1179,9 +1181,11 @@
 			return false;
 		}
 		InstanceofExpression o = (InstanceofExpression) other;
-		return (
-				safeSubtreeMatch(node.getLeftOperand(), o.getLeftOperand())
-				&& safeSubtreeMatch(node.getRightOperand(), o.getRightOperand()));
+		return
+			safeSubtreeMatch(node.getLeftOperand(), o.getLeftOperand())
+			&& safeSubtreeMatch(node.getRightOperand(), o.getRightOperand())
+			&& ((DOMASTUtil.isInstanceofExpressionPatternSupported(node.getAST())) ? safeSubtreeMatch(node.getPatternVariable(), o.getPatternVariable())
+					: true);
 	}
 
 	/**
@@ -1290,7 +1294,7 @@
 	 * other object is a node of the same type with structurally isomorphic
 	 * child subtrees. Subclasses may override this method as needed.
 	 * </p>
-	 * 
+	 *
 	 * @param node the node
 	 * @param other the other object, or <code>null</code>
 	 * @return <code>true</code> if the subtree matches, or
@@ -1513,7 +1517,10 @@
 								&& safeSubtreeListMatch(node.thrownExceptionTypes(), o.thrownExceptionTypes())
 						: node.getExtraDimensions() == o.getExtraDimensions()
 								&& safeSubtreeListMatch(node.internalThrownExceptions(), o.internalThrownExceptions()))
-				&& safeSubtreeMatch(node.getBody(), o.getBody());
+				&& safeSubtreeMatch(node.getBody(), o.getBody())
+				&& (DOMASTUtil.isRecordDeclarationSupported(node.getAST())
+						? node.isCompactConstructor() == o.isCompactConstructor()
+						: true);
 	}
 
 	/**
@@ -1972,6 +1979,36 @@
 	 * @return <code>true</code> if the subtree matches, or
 	 *   <code>false</code> if they do not match or the other object has a
 	 *   different node type or is <code>null</code>
+	 * @since 3.22
+	 */
+	public boolean match(RecordDeclaration node, Object other) {
+		if (!(other instanceof RecordDeclaration)) {
+			return false;
+		}
+		RecordDeclaration o = (RecordDeclaration) other;
+		return (
+			safeSubtreeMatch(node.getJavadoc(), o.getJavadoc())
+				&& safeSubtreeListMatch(node.modifiers(), o.modifiers())
+				&& safeSubtreeMatch(node.getName(), o.getName())
+				&& safeSubtreeListMatch(node.superInterfaceTypes(), o.superInterfaceTypes())
+				&& safeSubtreeMatch(node.typeParameters(), o.typeParameters())
+				&& safeSubtreeListMatch(node.bodyDeclarations(), o.bodyDeclarations())
+				&& safeSubtreeMatch(node.recordComponents(), o.recordComponents()));
+	}
+
+	/**
+	 * Returns whether the given node and the other object match.
+	 * <p>
+	 * The default implementation provided by this class tests whether the
+	 * other object is a node of the same type with structurally isomorphic
+	 * child subtrees. Subclasses may override this method as needed.
+	 * </p>
+	 *
+	 * @param node the node
+	 * @param other the other object, or <code>null</code>
+	 * @return <code>true</code> if the subtree matches, or
+	 *   <code>false</code> if they do not match or the other object has a
+	 *   different node type or is <code>null</code>
 	 *
 	 *   @since 3.14
 	 */
@@ -2235,7 +2272,7 @@
 	 * @return <code>true</code> if the subtree matches, or
 	 *   <code>false</code> if they do not match or the other object has a
 	 *   different node type or is <code>null</code>
-	 *   
+	 *
 	 *   @since 3.10
 	 */
 	public boolean match(SuperMethodReference node, Object other) {
@@ -2267,11 +2304,11 @@
 			return false;
 		}
 		SwitchCase o = (SwitchCase) other;
-		return ( node.getAST().isPreviewEnabled()
+		return ( node.getAST().apiLevel >= AST.JLS14
 				? safeSubtreeListMatch(node.expressions(), o.expressions())
 						: compareDeprecatedSwitchExpression(node, o));
 	}
-	
+
 	/**
 	 * Return whether the deprecated comment strings of the given java doc are equals.
 	 * <p>
@@ -2289,7 +2326,7 @@
 	 * other object is a node of the same type with structurally isomorphic
 	 * child subtrees. Subclasses may override this method as needed.
 	 * </p>
-	 * 
+	 *
 	 * @param node the node
 	 * @param other the other object, or <code>null</code>
 	 * @return <code>true</code> if the subtree matches, or
@@ -2403,7 +2440,7 @@
 		TextBlock o = (TextBlock) other;
 		return safeEquals(node.getEscapedValue(), o.getEscapedValue());
 	}
-	
+
 	/**
 	 * Returns whether the given node and the other object match.
 	 * <p>
@@ -2839,7 +2876,7 @@
 				&& node.isUpperBound() == o.isUpperBound()
 				&& safeSubtreeMatch(node.getBound(), o.getBound());
 	}
-	
+
 	/**
 	 * Returns whether the given node and the other object match.
 	 * <p>
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java
index 1df43ab..57decce 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTNode.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -129,7 +129,7 @@
 	/*
 	 * ATTENTION: When doing anything to the ASTNode hierarchy, do not try to
 	 * reinvent the wheel.
-	 * 
+	 *
 	 * Look out for precedents with
 	 * - the same structural property type
 	 * - for child node properties: the same optionality (can be null / lazy initialization blurbs and impl.)
@@ -137,9 +137,9 @@
 	 * - a similar history (added in JLSx API, below JLSx only, replaced by {@link #xx})
 	 * ..., and copy what was done there. Most of the code and
 	 * Javadoc in this package should look like it was created by a code generator.
-	 * 
+	 *
 	 * In subclasses of ASTNode, order properties by order of occurrence in source.
-	 * In general classes that list all AST node types, order alphabetically.  
+	 * In general classes that list all AST node types, order alphabetically.
 	 */
 
 	/*
@@ -179,27 +179,27 @@
 
 	/*
 	 * INSTRUCTIONS FOR ADDING A NEW PROPERTY TO AN AST NODE TYPE
-	 * 
+	 *
 	 * For concrete node types, use e.g. properties of SimpleName or ClassInstanceCreation
 	 * as templates:
-	 * 
+	 *
 	 * 1. Copy/paste the field, property descriptor, and getter/setter.
-	 * 
+	 *
 	 * 2. Adjust everything to the new property name and type. In the field's
 	 * Javadoc, properly document default value, initialization, and applicable
 	 * API levels.
-	 * 
+	 *
 	 * 3. Add/remove @since tags as necessary.
-	 * 
+	 *
 	 * 4. Search for references to the members in the template, and add similar
 	 * references in corresponding places for the new property.
-	 * 
-	 * 
+	 *
+	 *
 	 * For abstract node types, use AbstractTypeDeclaration as a template:
-	 * 
+	 *
 	 * 1. Same steps as above, but take extra care to copy and adjust the
-	 * *internal*() methods as well. 
-	 * 
+	 * *internal*() methods as well.
+	 *
 	 * 2. Search for references to the members in the template, and add similar
 	 * references in corresponding places for the new property (e.g. property
 	 * descriptor in each leaf type).
@@ -207,17 +207,17 @@
 
 	/*
 	 * INSTRUCTIONS FOR REPLACING/DEPRECATING A PROPERTY OF AN AST NODE
-	 * 
+	 *
 	 * To replace a simple property with a child list property, see e.g. how
 	 * SingleVariableDeclaration replaced MODIFIERS_PROPERTY with
 	 * MODIFIERS2_PROPERTY.
-	 * 
+	 *
 	 * 1. Reuse the old property id.
-	 * 
+	 *
 	 * 2. Deprecate all references to the old property, except for the old
 	 * getter, which should compute the value from the new property in
 	 * later API levels.
-	 * 
+	 *
 	 * To completely replace a property, see how ClassInstanceCreation replaced
 	 * NAME_PROPERTY with TYPE_PROPERTY.
 	 */
@@ -913,7 +913,7 @@
 	 * @since 3.14
 	 */
 	public static final int REQUIRES_DIRECTIVE = 94;
-	
+
 	/**
 	 * Node type constant indicating a node of type
 	 * <code>ExportsDirective</code>.
@@ -929,7 +929,7 @@
 	 * @since 3.14
 	 */
 	public static final int OPENS_DIRECTIVE = 96;
-	
+
 	/**
 	 * Node type constant indicating a node of type
 	 * <code>UsesDirective</code>.
@@ -953,7 +953,7 @@
 	 * @since 3.14
 	 */
 	public static final int MODULE_MODIFIER = 99;
-	
+
 	/**
 	 * Node type constant indicating a node of type
 	 * <code>SwitchExpression</code>.
@@ -961,7 +961,7 @@
 	 * @since 3.18
 	 */
 	public static final int SWITCH_EXPRESSION = 100;
-	
+
 	/**
 	 * Node type constant indicating a node of type
 	 * <code>YieldStatement</code>.
@@ -969,7 +969,7 @@
 	 * @since 3.20
 	 */
 	public static final int YIELD_STATEMENT = 101;
-	
+
 	/**
 	 * Node type constant indicating a node of type
 	 * <code>TextBlock</code>.
@@ -979,6 +979,15 @@
 	public static final int TEXT_BLOCK = 102;
 
 	/**
+	 * Node type constant indicating a node of type
+	 * <code>RecordDeclaration</code>.
+	 * @see RecordDeclaration
+	 * @since 3.22
+	 */
+	public static final int RECORD_DECLARATION = 103;
+
+
+	/**
 	 * Returns the node class for the corresponding node type.
 	 *
 	 * @param nodeType AST node type
@@ -1126,6 +1135,8 @@
 				return QualifiedName.class;
 			case QUALIFIED_TYPE :
 				return QualifiedType.class;
+			case RECORD_DECLARATION :
+				return RecordDeclaration.class;
 			case REQUIRES_DIRECTIVE :
 				return RequiresDirective.class;
 			case RETURN_STATEMENT :
@@ -1960,7 +1971,7 @@
 	 */
 	abstract List internalStructuralPropertiesForType(int apiLevel);
 
-		
+
 	/**
 	 * Returns a list of property descriptors for this node type.
 	 * Clients must not modify the result. This abstract method
@@ -1980,7 +1991,7 @@
 	List internalStructuralPropertiesForType(int apiLevel, boolean previewEnabled) {
 		return internalStructuralPropertiesForType(apiLevel);
 	}
-	
+
 	/**
 	 * Internal helper method that starts the building a list of
 	 * property descriptors for the given node type.
@@ -2032,7 +2043,7 @@
      * <p>
      * Use this method to prevent access to new properties that have been added in JLS3.
      * </p>
-     * 
+     *
 	 * @exception UnsupportedOperationException if this operation is used in a JLS2 AST
 	 * @since 3.0
      */
@@ -2048,7 +2059,7 @@
      * <p>
      * Use this method to prevent access to new properties that have been added in JLS4.
      * </p>
-     * 
+     *
 	 * @exception UnsupportedOperationException if this operation is used in a JLS2 or JLS3 AST
 	 * @since 3.7
 	 */
@@ -2057,14 +2068,14 @@
 			throw new UnsupportedOperationException("Operation only supported in JLS4 and later AST"); //$NON-NLS-1$
 		}
 	}
-	
+
 	/**
      * Checks that this AST operation is not used when
      * building JLS2 or JLS3 or JLS4 level ASTs.
      * <p>
      * Use this method to prevent access to new properties that have been added in JLS8.
      * </p>
-     * 
+     *
 	 * @exception UnsupportedOperationException if this operation is used below JLS8
 	 * @since 3.10
 	 */
@@ -2112,14 +2123,14 @@
      * </p>
      *
 	 * @exception UnsupportedOperationException if this operation is used below JLS11
-	 * @since 3.14 
+	 * @since 3.14
 	 */
 	final void unsupportedBelow11() {
 		if (this.ast.apiLevel < AST.JLS11_INTERNAL) {
 			throw new UnsupportedOperationException("Operation only supported in ASTs with level JLS11 and above"); //$NON-NLS-1$
 		}
 	}
-	
+
 	/**
      * Checks that this AST operation is not used when
      * building JLS2, JLS3, JLS4, JLS8, JLS9,JLS10 or JLS11 level ASTs.
@@ -2129,14 +2140,31 @@
      *
 	 * @exception UnsupportedOperationException if this operation is used below JLS12
 	 * @deprecated
-	 * @since 3.16 
+	 * @since 3.16
 	 */
 	final void unsupportedBelow12() {
 		if (this.ast.apiLevel < AST.JLS12_INTERNAL) {
 			throw new UnsupportedOperationException("Operation only supported in ASTs with level JLS12 and above"); //$NON-NLS-1$
 		}
 	}
-	
+
+	/**
+     * Checks that this AST operation is not used when
+     * building JLS2, JLS3, JLS4, JLS8, JLS9, JLS10, JLS11, JLS12 or JSL13 level ASTs.
+     * <p>
+     * Use this method to prevent access to new properties that have been added in JLS14
+     * </p>
+     *
+	 * @exception UnsupportedOperationException if this operation is used below JLS14
+	 * @since 3.22
+	 */
+	final void unsupportedBelow14() {
+		if (this.ast.apiLevel < AST.JLS14_INTERNAL) {
+			throw new UnsupportedOperationException("Operation only supported in ASTs with level JLS14 and above"); //$NON-NLS-1$
+		}
+	}
+
+
 	/**
      * Checks that this AST operation is not used when
      * building ASTs without previewEnabled flag.
@@ -2152,7 +2180,7 @@
 			throw new UnsupportedOperationException("Operation only supported in ASTs with previewEnabled flag as true"); //$NON-NLS-1$
 		}
 	}
-	
+
 	/**
      * Checks that this AST operation is only used when
      * building JLS2 level ASTs.
@@ -2176,7 +2204,7 @@
      * <p>
      * Use this method to prevent access to deprecated properties (deprecated in JLS8).
      * </p>
-     * 
+     *
 	 * @exception UnsupportedOperationException if this operation is used in an AST later than JLS4
      * @since 3.10
      */
@@ -2186,7 +2214,7 @@
 	  	throw new UnsupportedOperationException("Operation only supported in JLS2, JLS3 and JLS4 ASTs"); //$NON-NLS-1$
 	  }
 	}
-	
+
 	/**
      * Checks that this AST operation is only used when
      * building JLS12 level ASTs.
@@ -2203,7 +2231,7 @@
 	  	throw new UnsupportedOperationException("Operation only supported in JLS12 AST"); //$NON-NLS-1$
 	  }
 	}
-	
+
 	/**
  	 * Checks that this AST operation is only used when
      * building JLS13 level ASTs.
@@ -2219,6 +2247,22 @@
 			throw new UnsupportedOperationException("Operation only supported in JLS13 AST"); //$NON-NLS-1$
 		}
 	}
+
+	/**
+ 	 * Checks that this AST operation is only used when
+     * building JLS13 level ASTs.
+     * <p>
+     * Use this method to prevent access to new properties available only in JLS14.
+     * </p>
+     *
+	 * @exception UnsupportedOperationException if this operation is not used in JLS14
+	 * @since 3.20
+	 */
+	final void supportedOnlyIn14() {
+		if (this.ast.apiLevel != AST.JLS14_INTERNAL) {
+			throw new UnsupportedOperationException("Operation only supported in JLS14 AST"); //$NON-NLS-1$
+		}
+	}
 	/**
 	 * Sets or clears this node's parent node and location.
 	 * <p>
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
index cdf568e..00f2c20 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
@@ -1,6 +1,6 @@
 // AspectJ
 /*******************************************************************************
- * Copyright (c) 2004, 2019 IBM Corporation and others.
+ * Copyright (c) 2004, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -46,6 +46,7 @@
 import org.eclipse.jdt.internal.compiler.parser.Scanner;
 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
 import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
 import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil;
 import org.eclipse.jdt.internal.core.util.RecordedParsingInformation;
 import org.eclipse.jdt.internal.core.util.Util;
@@ -264,20 +265,7 @@
 	 * declared on {@link AST}
 	 */
 	ASTParser(int level) {
-		switch(level) {
-			case AST.JLS2_INTERNAL:
-			case AST.JLS3_INTERNAL:
-			case AST.JLS4_INTERNAL:
-			case AST.JLS8_INTERNAL:
-			case AST.JLS9_INTERNAL:
-			case AST.JLS10_INTERNAL:
-			case AST.JLS11_INTERNAL:
-			case AST.JLS12_INTERNAL:
-			case AST.JLS13_INTERNAL:
-				break;
-			default:
-				throw new IllegalArgumentException();
-		}
+		DOMASTUtil.checkASTLevel(level);
 		this.apiLevel = level;
 		initializeDefaults();
 	}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java
index bb5494e..b0e323c 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTVisitor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -1346,6 +1346,24 @@
 	 * Visits the given type-specific AST node.
 	 * <p>
 	 * The default implementation does nothing and return true.
+	 * Subclasses may re-implement.
+	 * </p>
+	 *
+	 * @param node the node to visit
+	 * @return <code>true</code> if the children of this node should be
+	 * visited, and <code>false</code> if the children of this node should
+	 * be skipped
+	 * @since 3.22
+	 * @noreference This method is not intended to be referenced by clients.
+	 */
+	public boolean visit(RecordDeclaration node) {
+		return true;
+	}
+
+	/**
+	 * Visits the given type-specific AST node.
+	 * <p>
+	 * The default implementation does nothing and return true.
 	 * Subclasses may reimplement.
 	 * </p>
 	 *
@@ -1521,7 +1539,7 @@
 	public boolean visit(SwitchCase node) {
 		return true;
 	}
-	
+
 	/**
 	 * Visits the given type-specific AST node.
 	 * <p>
@@ -1540,7 +1558,7 @@
 	public boolean visit(SwitchExpression node) {
 		return true;
 	}
-	
+
 	/**
 	 * Visits the given type-specific AST node.
 	 * <p>
@@ -1610,7 +1628,7 @@
 	public boolean visit(TextBlock node) {
 		return true;
 	}
-	
+
 	/**
 	 * Visits the given type-specific AST node.
 	 * <p>
@@ -1735,7 +1753,7 @@
 	 * @return <code>true</code> if the children of this node should be
 	 * visited, and <code>false</code> if the children of this node should
 	 * be skipped
-	 * 
+	 *
 	 * @since 3.10
 	 */
 	public boolean visit(TypeMethodReference node) {
@@ -1892,7 +1910,7 @@
 	public boolean visit(YieldStatement node) {
 		return true;
 	}
-	
+
 	/**
 	 * End of visit the given type-specific AST node.
 	 * <p>
@@ -2412,7 +2430,7 @@
 	public void endVisit(LambdaExpression node) {
 		// default implementation: do nothing
 	}
-	
+
 	/**
 	 * End of visit the given type-specific AST node.
 	 * <p>
@@ -2749,6 +2767,21 @@
 	/**
 	 * End of visit the given type-specific AST node.
 	 * <p>
+	 * The default implementation does nothing. Subclasses may re implement.
+	 * </p>
+	 *
+	 * @param node the node to visit
+	 * @since 3.22
+	 * @noreference This method is not intended to be referenced by clients.
+	 */
+	public void endVisit(RecordDeclaration node) {
+		// default implementation: do nothing
+	}
+
+
+	/**
+	 * End of visit the given type-specific AST node.
+	 * <p>
 	 * The default implementation does nothing. Subclasses may reimplement.
 	 * </p>
 	 *
@@ -2944,7 +2977,7 @@
 	public void endVisit(TextBlock node) {
 		// default implementation: do nothing
 	}
-	
+
 	/**
 	 * End of visit the given type-specific AST node.
 	 * <p>
@@ -3036,7 +3069,7 @@
 	 * </p>
 	 *
 	 * @param node the node to visit
-	 * 
+	 *
 	 * @since 3.10
 	 */
 	public void endVisit(TypeMethodReference node) {
@@ -3155,7 +3188,7 @@
 	public void endVisit(WildcardType node) {
 		// default implementation: do nothing
 	}
-	
+
 	/**
 	 * End of visit the given type-specific AST node.
 	 * <p>
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotatableType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotatableType.java
index 1a4281b..ce7bd4d 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotatableType.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AnnotatableType.java
@@ -18,7 +18,7 @@
 /**
  * Abstract base class of AST nodes that represent an annotatable type (added in JLS8 API).
  * <p>
- * Introduced in JLS8, type references that can be annotated are represented by 
+ * Introduced in JLS8, type references that can be annotated are represented by
  * AnnotatableType. For the list of types extending AnnotatableType, see {@link Type}.
  * </p>
  * <p>
@@ -32,7 +32,7 @@
  */
 @SuppressWarnings({"rawtypes"})
 public abstract class AnnotatableType extends Type {
-	
+
 	/**
 	 * The annotations (element type: {@link Annotation}).
 	 * Null in JLS < 8. Added in JLS8; defaults to an empty list
@@ -91,7 +91,7 @@
 	 * Syntactically, type annotations can also be part of an associated declaration node's
 	 * <code>modifiers()</code> list.
 	 * </p>
-	 * 
+	 *
 	 * @return the live list of annotations (element type: {@link Annotation})
 	 * @exception UnsupportedOperationException if this operation is used below JLS8
 	 * @see ITypeBinding#getTypeAnnotations()
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayType.java
index 395a08a..e496670 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayType.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ArrayType.java
@@ -24,10 +24,10 @@
  * be an array type) and a list of dimensions, each of which may have a list of annotations.
  * </p>
  * <pre>
- * ArrayType: 
+ * ArrayType:
  *    Type Dimension <b>{</b> Dimension <b>}</b>
  * </pre>
- * 
+ *
  * In JLS4 and before, array types were expressed in a recursive manner, one dimension at a time:
  * <pre>
  * ArrayType:
@@ -42,7 +42,7 @@
  * is an <u><code>@A</code></u>-array of<br>
  * <code><u>int </u>&nbsp;&nbsp;&nbsp;&nbsp;<u> @B[] @C[]</u></code>,
  * but such a component type is not representable by nested <code>ArrayType</code>s with contiguous source ranges.
- * 
+ *
  * @since 2.0
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
@@ -63,14 +63,14 @@
 	 * @since 3.10
 	 */
 	public static final ChildPropertyDescriptor ELEMENT_TYPE_PROPERTY =
-			new ChildPropertyDescriptor(ArrayType.class, "elementType", Type.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$	
-	
+			new ChildPropertyDescriptor(ArrayType.class, "elementType", Type.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$
+
 	/**
 	 * The "dimensions" structural property of this node type (element type: {@link Dimension}) (added in JLS8 API).
 	 * @since 3.10
 	 */
 	public static final ChildListPropertyDescriptor DIMENSIONS_PROPERTY =
-			new ChildListPropertyDescriptor(ArrayType.class, "dimensions", Dimension.class, CYCLE_RISK); //$NON-NLS-1$	
+			new ChildListPropertyDescriptor(ArrayType.class, "dimensions", Dimension.class, CYCLE_RISK); //$NON-NLS-1$
 	/**
 	 * A list of property descriptors (element type:
 	 * {@link StructuralPropertyDescriptor}),
@@ -131,7 +131,7 @@
 	 * (element type: {@link Dimension}).
 	 * Null before JLS8. Added in JLS8; defaults to a list with one element
 	 * (see constructor).
-	 * 
+	 *
 	 * @since 3.10
 	 */
 	private ASTNode.NodeList dimensions = null;
@@ -219,7 +219,7 @@
 		ArrayType result;
 		if (this.ast.apiLevel < AST.JLS8_INTERNAL) {
 			result = new ArrayType(target);
-			result.setComponentType((Type) getComponentType().clone(target));			
+			result.setComponentType((Type) getComponentType().clone(target));
 		} else {
 			result = new ArrayType(target, 0);
 			result.setElementType((Type) getElementType().clone(target));
@@ -242,7 +242,7 @@
 		if (visitChildren) {
 			// visit children in normal left to right reading order
 			if (this.ast.apiLevel < AST.JLS8_INTERNAL) {
-				acceptChild(visitor, getComponentType());				
+				acceptChild(visitor, getComponentType());
 			} else {
 				acceptChild(visitor, getElementType());
 				acceptChildren(visitor, this.dimensions);
@@ -374,7 +374,7 @@
 			dimension++;
 			t = ((ArrayType) t).getComponentType();
 		}
-		return dimension;			
+		return dimension;
 	}
 
 	/**
@@ -382,7 +382,7 @@
 	 * <p>
 	 * For the array type to be plausible, the list should contain at least one element.
 	 * </p>
-	 * 
+	 *
 	 * @return the live list of dimensions with optional annotations (element type: {@link Dimension})
 	 * @exception UnsupportedOperationException if this operation is used below JLS8
 	 * @since 3.10
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingComparator.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingComparator.java
index 58ea665..8110b45 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingComparator.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingComparator.java
@@ -144,7 +144,7 @@
 			return moduleBinding2 == null;
 		if (moduleBinding2 == null)
 			return false;
-		return CharOperation.equals(moduleBinding.moduleName, moduleBinding2.moduleName); 
+		return CharOperation.equals(moduleBinding.moduleName, moduleBinding2.moduleName);
 	}
 
 	static boolean isEqual(VariableBinding variableBinding, VariableBinding variableBinding2) {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingResolver.java
index ef2783f..043b8b5 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BindingResolver.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -296,7 +296,7 @@
 	boolean isResolvedTypeInferredFromExpectedType(ClassInstanceCreation classInstanceCreation) {
 		return false;
 	}
-	
+
 	/**
 	 * Returns the compiler lookup environment used by this binding resolver.
 	 * Returns <code>null</code> if none.
@@ -695,7 +695,7 @@
 	 * @param module declaration of interest
 	 * @return the binding for the given module declaration, or
 	 *    <code>null</code> if no binding is available
-	 *    
+	 *
 	 * @since 3.14
 	 */
 	IModuleBinding resolveModule(ModuleDeclaration module) {
@@ -873,6 +873,29 @@
 	}
 
 	/**
+	 * Resolves the given record declaration and returns the binding
+	 * for it.
+	 * <p>
+	 * The implementation of <code>RecordDeclaration.resolveBinding</code>
+	 * forwards to this method. How the record declaration resolves is often
+	 * a function of the context in which the declaration node is embedded
+	 * as well as the record declaration subtree itself.
+	 * </p>
+	 * <p>
+	 * The default implementation of this method returns <code>null</code>.
+	 * Subclasses may re implement.
+	 * </p>
+	 *
+	 * @param type the record declaration of interest
+	 * @return the binding for the given record declaration, or <code>null</code>
+	 *    if no binding is available
+	 * @since 3.22
+	 */
+	ITypeBinding resolveType(RecordDeclaration type) {
+		return null;
+	}
+
+	/**
 	 * Resolves the given type and returns the type binding for it.
 	 * <p>
 	 * The implementation of <code>Type.resolveBinding</code>
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BreakStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BreakStatement.java
index 25ca48c..ac51659 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BreakStatement.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/BreakStatement.java
@@ -23,7 +23,7 @@
  * <pre>
  * BreakStatement:
  *    <b>break</b> [ Identifier ] <b>;</b>
- *    
+ *
  *    Break statement allows expression as part of Java 12 preview feature (JEP 325)
  *		<b>break</b> <b>{ Identifier | Expression }</b>
  * </pre>
@@ -40,7 +40,7 @@
 	 */
 	public static final ChildPropertyDescriptor LABEL_PROPERTY =
 		new ChildPropertyDescriptor(BreakStatement.class, "label", SimpleName.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$
-	
+
 	/**
 	 * The "expression" structural property of this node type (child type: {@link Expression}). (added in JEP 325).
 	 * @noreference This property is not intended to be referenced by clients as it is a part of Java preview feature.
@@ -56,7 +56,7 @@
 	 * or null if uninitialized.
 	 */
 	private static final List PROPERTY_DESCRIPTORS;
-	
+
 	/**
 	 * <code>true</code> indicates implicit and <code>false</code> indicates not implicit.
 	 */
@@ -83,7 +83,7 @@
 	public static List propertyDescriptors(int apiLevel) {
 		return PROPERTY_DESCRIPTORS;
 	}
-	
+
 	/**
 	 * Returns a list of structural property descriptors for this node type.
 	 * Clients must not modify the result.
@@ -106,7 +106,7 @@
 	 * The label, or <code>null</code> if none; none by default.
 	 */
 	private SimpleName optionalLabel = null;
-	
+
 	/**
 	 * The expression; <code>null</code> for none
 	 */
@@ -129,7 +129,7 @@
 	final List internalStructuralPropertiesForType(int apiLevel) {
 		return propertyDescriptors(apiLevel);
 	}
-	
+
 	@Override
 	final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) {
 		if (property == LABEL_PROPERTY) {
@@ -139,7 +139,7 @@
 				setLabel((SimpleName) child);
 				return null;
 			}
-		} 
+		}
 		if (property == EXPRESSION_PROPERTY) {
 			if (get) {
 				return getExpression();
@@ -208,7 +208,7 @@
 		this.optionalLabel = label;
 		postReplaceChild(oldChild, label, LABEL_PROPERTY);
 	}
-	
+
 	/**
 	 * Returns the expression of this break statement, or <code>null</code> if
 	 * there is none.
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java
index 476435d..d9090f4 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java
@@ -40,12 +40,12 @@
  * CompilationUnit:
  *     OrdinaryCompilationUnit
  *     ModularCompilationUnit
- *     
+ *
  * OrdinaryCompilationUnit:
  *     [ PackageDeclaration ]
  *         { ImportDeclaration }
  *         { TypeDeclaration | EnumDeclaration | AnnotationTypeDeclaration | <b>;</b> }
- * 
+ *
  * ModularCompilationUnit:
  *     {ImportDeclaration}
  *         ModuleDeclaration
@@ -672,18 +672,18 @@
 
 	/**
 	 * Internal method
-	 * 
+	 *
 	 * This method return internal data used to perform statements recovery.
-	 * 
+	 *
 	 * @return internal data used to perform statements recovery.
-	 * 
+	 *
 	 * @noreference This method is not intended to be referenced by clients.
 	 * @since 3.5
 	 */
 	public Object getStatementsRecoveryData() {
 		return this.statementsRecoveryData;
 	}
-	
+
 	/**
 	 * The Java type root (a {@link org.eclipse.jdt.core.ICompilationUnit compilation unit} or a {@link org.eclipse.jdt.core.IClassFile class file})
 	 * this compilation unit was created from, or <code>null</code> if it was not created from a Java type root.
@@ -1111,13 +1111,13 @@
 		}
 		this.problems = problems;
 	}
-	
+
 	/**
 	 * Internal method
-	 * 
+	 *
 	 * Sets internal data used to perform statements recovery.
 	 * @param data
-	 * 
+	 *
 	 * @since 3.5
 	 */
 	void setStatementsRecoveryData(Object data) {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CreationReference.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CreationReference.java
index fd93395..52a16c3 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CreationReference.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CreationReference.java
@@ -18,10 +18,10 @@
 
 /**
  * Creation reference expression AST node type (added in JLS8 API).
- * 
+ *
  * <pre>
  * CreationReference:
- *     Type <b>::</b> 
+ *     Type <b>::</b>
  *         [ <b>&lt;</b> Type { <b>,</b> Type } <b>&gt;</b> ]
  *         <b>new</b>
  * </pre>
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultASTVisitor.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultASTVisitor.java
index 333d5b5..f692074 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultASTVisitor.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultASTVisitor.java
@@ -742,7 +742,7 @@
 	public boolean visit(SwitchCase node) {
 		return visitNode(node);
 	}
-	
+
 	@Override
 	public boolean visit(SwitchExpression node) {
 		return visitNode(node);
@@ -767,7 +767,7 @@
 	public boolean visit(TextBlock node) {
 		return visitNode(node);
 	}
-	
+
 	@Override
 	public boolean visit(TextElement node) {
 		return visitNode(node);
@@ -817,7 +817,7 @@
 	public boolean visit(UnionType node) {
 		return visitNode(node);
 	}
-	
+
 	@Override
 	public boolean visit(VariableDeclarationExpression node) {
 		return visitNode(node);
@@ -842,7 +842,7 @@
 	public boolean visit(WildcardType node) {
 		return visitNode(node);
 	}
-	
+
 	@Override
 	public boolean visit(YieldStatement node) {
 		return visitNode(node);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
index ee36dc5..c58babc 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
@@ -160,12 +160,12 @@
 	 * Toggle controlling whether DOM bindings should be created when missing internal compiler bindings..
 	 */
 	boolean isRecoveringBindings;
-	
+
 	/**
 	 * Set to <code>true</code> if initialized from a java project
 	 */
 	boolean fromJavaProject;
-	
+
 	/**
 	 * Constructor for DefaultBindingResolver.
 	 */
@@ -339,7 +339,7 @@
 		TypeReference[][] typeArguments = typeReference.typeArguments;
 		int value = 0;
 		org.eclipse.jdt.internal.compiler.ast.Annotation[][] typeAnnotations = typeReference.annotations;
-		int length = typeReference.tokens.length;	
+		int length = typeReference.tokens.length;
 		for (int i = 0; i < length; ++i) {
 			if (value != 0 || (typeArguments != null && typeArguments[i] != null) ||
 				(typeAnnotations != null && typeAnnotations[i] != null )) {
@@ -1474,7 +1474,7 @@
 			QualifiedSuperReference qualifiedSuperReference = (QualifiedSuperReference) node;
 			return this.getTypeBinding(qualifiedSuperReference.qualification.resolvedType);
 		} else if (node instanceof LocalDeclaration) {
-			return name.getAST().apiLevel() >= AST.JLS10_INTERNAL && name instanceof SimpleName && ((SimpleName) name).isVar()  ? 
+			return name.getAST().apiLevel() >= AST.JLS10_INTERNAL && name instanceof SimpleName && ((SimpleName) name).isVar()  ?
 					resolveTypeBindingForName(name) :
 					this.getVariableBinding(((LocalDeclaration)node).binding);
 		} else if (node instanceof JavadocFieldReference) {
@@ -1585,7 +1585,7 @@
 
 	/**
 	 * @see BindingResolver#resolveModule(ModuleDeclaration)
-	 * @since 3.14	
+	 * @since 3.14
 	 */
 	@Override
 	IModuleBinding resolveModule(ModuleDeclaration module) {
@@ -1678,6 +1678,27 @@
 	}
 
 	@Override
+	ITypeBinding resolveType(RecordDeclaration type) {
+		final Object node = this.newAstToOldAst.get(type);
+		if (node instanceof org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) {
+			org.eclipse.jdt.internal.compiler.ast.TypeDeclaration typeDeclaration = (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) node;
+			ITypeBinding typeBinding = this.getTypeBinding(typeDeclaration.binding);
+			if (typeBinding == null) {
+				return null;
+			}
+			this.bindingsToAstNodes.put(typeBinding, type);
+			String key = typeBinding.getKey();
+			if (key != null) {
+				this.bindingTables.bindingKeysToBindings.put(key, typeBinding);
+			}
+			return typeBinding;
+		}
+		return null;
+	}
+
+
+
+	@Override
 	synchronized ITypeBinding resolveType(Type type) {
 		// retrieve the old ast node
 		org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(type);
@@ -1989,7 +2010,7 @@
 			actualDimensions += typeBinding.getDimensions();
 		}
 		if (!(leafComponentType instanceof TypeBinding)) return null;
-		org.eclipse.jdt.internal.compiler.lookup.TypeBinding leafTypeBinding = 
+		org.eclipse.jdt.internal.compiler.lookup.TypeBinding leafTypeBinding =
 											((TypeBinding) leafComponentType).binding;
 		if (leafTypeBinding instanceof VoidTypeBinding) {
 			throw new IllegalArgumentException();
@@ -2005,7 +2026,7 @@
 											actualDimensions));
 		}
 	}
-	
+
 	private org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] insertAnnotations(
 							org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] annots, int dimensions) {
 		if (dimensions == 0 || annots == null || annots.length == 0) {
@@ -2021,7 +2042,7 @@
 			}
 			if (dimensions < 0) dimensions = 0; // Just means there were no annotations
 		}
-		org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] newAnnots = 
+		org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[] newAnnots =
 				new org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding[annots.length - index + dimensions];
 
 		System.arraycopy(annots, index, newAnnots, dimensions, annots.length - index);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultValuePairBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultValuePairBinding.java
index 8ef3e6f..5a5ea0c 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultValuePairBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultValuePairBinding.java
@@ -16,9 +16,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.core.dom;
 
-import org.eclipse.jdt.core.dom.BindingResolver;
-import org.eclipse.jdt.core.dom.IMethodBinding;
-
 /**
  * Member value pair which compose of default values.
  */
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Dimension.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Dimension.java
index d829829..ff9341f 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Dimension.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Dimension.java
@@ -26,7 +26,7 @@
  * <li>extra dimension in the following node types:
  * {@link SingleVariableDeclaration}, {@link VariableDeclarationFragment}, {@link MethodDeclaration}</li>
  * </ul>
- * 
+ *
  * <pre>
  * Dimension:
  * 	{ Annotation } <b>[]</b>
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DoStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DoStatement.java
index dcfcb5e..1e2c5db 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DoStatement.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DoStatement.java
@@ -44,7 +44,7 @@
 	 */
 	public static final ChildPropertyDescriptor EXPRESSION_PROPERTY =
 			new ChildPropertyDescriptor(DoStatement.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$
-	
+
 	/**
 	 * A list of property descriptors (element type:
 	 * {@link StructuralPropertyDescriptor}),
@@ -79,7 +79,7 @@
 	 * The body statement; lazily initialized; defaults to an empty block.
 	 */
 	private Statement body = null;
-	
+
 	/**
 	 * The expression; lazily initialized; defaults to an unspecified, but
 	 * legal, expression.
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java
index 0d2e1c5..b559ead 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java
@@ -488,7 +488,7 @@
 						} else if (length == TAG_LITERAL_LENGTH && CharOperation.equals(TAG_LITERAL, tagName)) {
 							this.tagValue = TAG_LITERAL_VALUE;
 						}
-						
+
 						if (this.tagValue != NO_TAG_VALUE && this.tagValue != TAG_LITERAL_VALUE)  {
 							if (this.inlineTagStarted) {
 								valid = parseReference();
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnhancedForStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnhancedForStatement.java
index 095b0c2..1b8051a 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnhancedForStatement.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/EnhancedForStatement.java
@@ -25,7 +25,7 @@
  *    <b>for</b> <b>(</b> FormalParameter <b>:</b> Expression <b>)</b>
  * 			Statement
  * </pre>
- * 
+ *
  * <p>The FormalParameter is represented by a {@link SingleVariableDeclaration}
  * (without an initializer).</p>
  *
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExportsDirective.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExportsDirective.java
index b4fc31f..f5f3f29 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExportsDirective.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExportsDirective.java
@@ -23,7 +23,7 @@
  * </pre>
  *
  * @since 3.14
- * 
+ *
  * @noextend This class is not intended to be subclassed by clients.
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExpressionMethodReference.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExpressionMethodReference.java
index 5defe3e..10333f4 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExpressionMethodReference.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ExpressionMethodReference.java
@@ -20,7 +20,7 @@
  * Expression method reference AST node type (added in JLS8 API).
  * <pre>
  * ExpressionMethodReference:
- *     Expression <b>::</b> 
+ *     Expression <b>::</b>
  *         [ <b>&lt;</b> Type { <b>,</b> Type } <b>&gt;</b> ]
  *         Identifier
  * </pre>
@@ -38,7 +38,7 @@
 		new ChildPropertyDescriptor(ExpressionMethodReference.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$
 
 	/**
-	 * The "typeArguments" structural property of this node type (element type: {@link Type}) 
+	 * The "typeArguments" structural property of this node type (element type: {@link Type})
 	 */
 	public static final ChildListPropertyDescriptor TYPE_ARGUMENTS_PROPERTY =
 		internalTypeArgumentsFactory(ExpressionMethodReference.class);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IBinding.java
index 5afebd2..05a9ed5 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IBinding.java
@@ -120,7 +120,7 @@
 	 * <p>
 	 * <b>Note:</b> This method only returns declaration annotations.
 	 * <em>Type annotations</em> in the sense of JLS8 9.7.4 are <em>not</em> returned.
-	 * Type annotations can be retrieved via {@link ITypeBinding#getTypeAnnotations()}. 
+	 * Type annotations can be retrieved via {@link ITypeBinding#getTypeAnnotations()}.
 	 * </p>
 	 *
 	 * @return the list of resolved declaration annotations, or the empty list if there are no
@@ -341,7 +341,7 @@
 	 * different clusters of bindings, the binding objects may or may
 	 * not be different objects; in these cases, the binding keys
 	 * are used where available.
-	 * 
+	 *
 	 * <p>
 	 * Note that type bindings that only differ in their {@link ITypeBinding#getTypeAnnotations() type annotations}
 	 * have the same {@link IBinding#getKey() key}, and hence this method returns
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IDocElement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IDocElement.java
index 7e61430..a2e25bd 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IDocElement.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IDocElement.java
@@ -15,7 +15,7 @@
 package org.eclipse.jdt.core.dom;
 
 /**
- * Common marker interface for AST nodes that represent fragments in doc elements. 
+ * Common marker interface for AST nodes that represent fragments in doc elements.
  * These are node types that can legitimately be included in {@link TagElement#fragments()}.
  * <pre>
  * IDocElement:
@@ -25,7 +25,7 @@
  *   {@link TagElement}
  *   {@link TextElement}
  * </pre>
- * 
+ *
  * @since 3.11, internal interface since 3.0
  * @see TagElement#fragments()
  * @noextend This interface is not intended to be extended by clients.
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java
index 0848679..3b01fb8 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java
@@ -97,7 +97,7 @@
 	 * <li>If the lambda expression is declared in the body of a method,
 	 *   answers the binding of that declaring method.
 	 * </li>
-	 * <li>Otherwise, if the lambda expression is declared in the 
+	 * <li>Otherwise, if the lambda expression is declared in the
 	 *   initializer of a field, answers the binding of that declaring field.
 	 * </li>
 	 * <li>Otherwise, if the lambda expression is declared in a static initializer or an
@@ -146,8 +146,8 @@
 	 * <p>
 	 * <b>Note:</b> This method only returns declaration annotations.
 	 * <em>Type annotations</em> in the sense of JLS8 9.7.4 are <em>not</em> returned.
-	 * Type annotations can be retrieved from a parameter type 
-	 * via {@link ITypeBinding#getTypeAnnotations()}. 
+	 * Type annotations can be retrieved from a parameter type
+	 * via {@link ITypeBinding#getTypeAnnotations()}.
 	 * </p>
 	 *
 	 * @param paramIndex the index of the parameter of interest
@@ -183,22 +183,22 @@
 	public ITypeBinding[] getParameterTypes();
 
 	/**
-	 * Returns the type of this method's receiver or <code>null</code> 
+	 * Returns the type of this method's receiver or <code>null</code>
 	 * if there is no receiver declared explicitly.
-	 * 
-	 * @return the type of this method's receiver or <code>null</code> 
+	 *
+	 * @return the type of this method's receiver or <code>null</code>
 	 * if there is no receiver declared explicitly.
-	 * 
+	 *
 	 * @since 3.10
 	 */
 	public ITypeBinding getDeclaredReceiverType();
-	
+
 	/**
 	 * Returns the binding for the return type of this method. Returns the
 	 * special primitive <code>void</code> return type for constructors.
 	 * <p>
-	 * For methods, the type binding that is returned contains type annotations 
-	 * if any. For e.g. the following code would get the type annotations on a 
+	 * For methods, the type binding that is returned contains type annotations
+	 * if any. For e.g. the following code would get the type annotations on a
 	 * method: <br><br>
 	 *  <code> IAnnotationBinding[] annots = getReturnType().getTypeAnnotations() </code>
 	 * </p>
@@ -383,13 +383,13 @@
 	 * @since 3.1
 	 */
 	public boolean overrides(IMethodBinding method);
-	
+
 
 	/**
 	 * Returns a list of variable bindings representing the synthetic outer
-	 * local variables. Returns an empty array for non-lambda expressions or if 
+	 * local variables. Returns an empty array for non-lambda expressions or if
 	 * this method does not have any synthetic parameters.
-	 * 
+	 *
 	 * @return a (possibly empty) list of variable bindings for the synthetic
 	 * outer locals of this method if this is a lambda expression, else an empty array.
 	 * @since 3.18
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IModuleBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IModuleBinding.java
index fbd6f20..bb6ebd1 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IModuleBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IModuleBinding.java
@@ -38,7 +38,7 @@
 	/**
 	 * Returns all required modules.
 	 * <p>The resulting bindings are in no particular order.</p>
-	 * 
+	 *
 	 * @return all required modules
 	 */
 	public abstract IModuleBinding[] getRequiredModules();
@@ -52,9 +52,9 @@
 	public abstract IPackageBinding[] getExportedPackages();
 
 	/**
-	 * If this module exports the given package to specific modules, returns the array of names of 
+	 * If this module exports the given package to specific modules, returns the array of names of
 	 * modules, otherwise returns an empty array.
-	 * 
+	 *
 	 * @param packageBinding a package binding for which targeted modules are declared
 	 * @return array of names of targeted modules
 	 */
@@ -81,7 +81,7 @@
 	/**
 	 * Returns the services used by this module.
 	 * <p>The resulting bindings are in no particular order.</p>
-	 * 
+	 *
 	 * @return array of type bindings
 	 */
 	public abstract ITypeBinding[] getUses();
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IPackageBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IPackageBinding.java
index f91a7c7..d620045 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IPackageBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IPackageBinding.java
@@ -57,7 +57,7 @@
 	 * Returns the binding of the module associated with this package binding.
 	 * @return the binding of the module associated with this package, or
 	 * <code>null</code> if none
-	 * 
+	 *
 	 * @since 3.14
 	 */
 	public default IModuleBinding getModule() {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java
index 5a6ea7a..e7cd8ec 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ITypeBinding.java
@@ -95,7 +95,7 @@
 	 * @since 3.1
 	 */
 	public ITypeBinding getBound();
-	
+
 	/**
 	 * Returns the generic type associated with this wildcard type, if it has one.
 	 * Returns <code>null</code> if this is not a wildcard type.
@@ -116,7 +116,7 @@
 	 * @since 3.5
 	 */
 	public int getRank();
-	
+
 	/**
 	 * Returns the binding representing the component type of this array type,
 	 * or <code>null</code> if this is not an array type binding. The component
@@ -285,14 +285,14 @@
 	 *
 	 * <p>The module of a recovered type reference binding is the module
 	 * associated with the package returned by {@link #getPackage()} ie either
-	 * the module associated with the package of the enclosing type, or, 
-	 * if the type name is the name of a {@linkplain AST#resolveWellKnownType(String) 
-	 * well-known type},  the module associated with the package of the matching 
+	 * the module associated with the package of the enclosing type, or,
+	 * if the type name is the name of a {@linkplain AST#resolveWellKnownType(String)
+	 * well-known type},  the module associated with the package of the matching
 	 * well-known type.</p>
 	 *
 	 * @return the binding of the module associated with the package
-	 * in which this class, interface, enum, or annotation type is declared, 
-	 * or <code>null</code> if this type binding represents a primitive type, an array type, 
+	 * in which this class, interface, enum, or annotation type is declared,
+	 * or <code>null</code> if this type binding represents a primitive type, an array type,
 	 * the null type, a type variable, a wildcard type or a capture binding.
 	 *
 	 * @since 3.14
@@ -313,9 +313,9 @@
 	 * Returns the binding representing the element type of this array type,
 	 * or <code>null</code> if this is not an array type binding. The element
 	 * type of an array type is never itself an array type.
-	 * 
+	 *
 	 * To get the type annotations on dimensions, clients should repeatedly
-	 *  call getComponentType() and get the type annotations from there. 
+	 *  call getComponentType() and get the type annotations from there.
 	 *
 	 * @return the element type binding, or <code>null</code> if this is
 	 *   not an array type
@@ -349,17 +349,17 @@
 	 * @since 3.1
 	 */
 	public ITypeBinding getErasure();
-	
+
 	/**
-	 * Returns the single abstract method that constitutes the single function 
-	 * contract (aside from any redeclarations of methods of <code>java.lang.Object</code>) 
-	 * of the receiver interface type or <code>null</code> if there is no such contract or if the receiver 
+	 * Returns the single abstract method that constitutes the single function
+	 * contract (aside from any redeclarations of methods of <code>java.lang.Object</code>)
+	 * of the receiver interface type or <code>null</code> if there is no such contract or if the receiver
 	 * is not an interface.
 	 * <p>
 	 * The returned method binding may be synthetic and its {@link #getDeclaringClass() declaring type}
 	 * may be a super interface type of this type binding.
 	 * </p>
-	 * 
+	 *
 	 * @return the single abstract method that represents the single function contract, or
 	 * <code>null</code> if the receiver is not a functional interface type
 	 *
@@ -570,19 +570,19 @@
 	public ITypeBinding getSuperclass();
 
 	/**
-	 * Returns the type annotations that this type reference is annotated with. Since JLS8, 
-	 * multiple instances of type bindings may be created if they are annotated with 
+	 * Returns the type annotations that this type reference is annotated with. Since JLS8,
+	 * multiple instances of type bindings may be created if they are annotated with
 	 * different type use annotations.
 	 * <p>
-	 * For example, the following three type references would produce three distinct type 
+	 * For example, the following three type references would produce three distinct type
 	 * bindings for java.lang.String that share the same key:
 	 * <ul>
 	 * <li>java.lang.@Marker1 String</li>
 	 * <li>java.lang.@Marker2 String</li>
 	 * <li>java.lang.String</li>
 	 * </ul>
-	 * To get the type annotations on dimensions, clients should repeatedly call 
-	 * {@link #getComponentType()} and get the type annotations from there. 
+	 * To get the type annotations on dimensions, clients should repeatedly call
+	 * {@link #getComponentType()} and get the type annotations from there.
 
 	 * @return type annotations specified on this type reference, or an empty array if
 	 * no type use annotations are found.
@@ -615,7 +615,7 @@
 	public ITypeBinding[] getTypeArguments();
 
 	/**
-	 * Returns the upper type bounds of this type variable, wildcard, capture, or intersectionType. 
+	 * Returns the upper type bounds of this type variable, wildcard, capture, or intersectionType.
 	 * If the variable, wildcard, or capture had no explicit bound, then it returns an empty list.
      * <p>
      * Note that per construction, it can only contain one class or array type,
@@ -803,6 +803,15 @@
 	public boolean isEnum();
 
 	/**
+	 * Returns whether this type binding represents a record type.
+	 *
+	 * @return <code>true</code> if this object represents a record type,
+	 *    and <code>false</code> otherwise
+	 * @noreference
+	 */
+	public boolean isRecord();
+
+	/**
 	 * Returns whether this type binding originated in source code.
 	 * Returns <code>false</code> for all primitive types, the null type,
 	 * array types, and for all classes, interfaces, enums, annotation
@@ -854,8 +863,8 @@
 	 * Returns whether this type binding represents an intersection binding.
 	 * <p>
 	 * Intersection types can be derived from type parameter bounds and cast
-	 * expressions; they also arise in the processes of capture conversion 
-	 * and least upper bound computation as specified in section 4.9 of 
+	 * expressions; they also arise in the processes of capture conversion
+	 * and least upper bound computation as specified in section 4.9 of
 	 * <em>The Java Language Specification, Java SE 8 Edition</em> (JLS8).
 	 * </p>
 	 * <p>
@@ -879,11 +888,11 @@
 	 * of another class or interface. A local class is a subspecies of nested
 	 * type, and mutually exclusive with member types. For anonymous
 	 * classes, which are considered a subspecies of local classes, this method
-	 * returns true. 
+	 * returns true.
 	 * </p>
 	 * <p>
-	 * Note: This deviates from JLS3 14.3, which states that anonymous types are 
-	 * not local types since they do not have a name. Also note that interfaces 
+	 * Note: This deviates from JLS3 14.3, which states that anonymous types are
+	 * not local types since they do not have a name. Also note that interfaces
 	 * and annotation types cannot be local.
 	 * </p>
 	 *
@@ -1078,5 +1087,5 @@
 	 * @see #isUpperbound()
 	 */
 	public boolean isWildcardType();
-	
+
 }
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InstanceofExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InstanceofExpression.java
index ca36f3a..5e61a65 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InstanceofExpression.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/InstanceofExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -17,6 +17,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
+
 /**
  * Instanceof expression AST node type.
  * <pre>
@@ -45,18 +47,38 @@
 		new ChildPropertyDescriptor(InstanceofExpression.class, "rightOperand", Type.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$
 
 	/**
+	 * The "patternVariable" structural property of this node type (child type: {@link SingleVariableDeclaration}) (added in JLS14 API).
+	 * @noreference This property is not intended to be referenced by clients as it is a part of Java preview feature.
+	 * @since 3.22
+	 */
+	public static final ChildPropertyDescriptor PATTERN_VARIABLE_PROPERTY =
+		new ChildPropertyDescriptor(InstanceofExpression.class, "patternVariable", SingleVariableDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$
+	/**
 	 * A list of property descriptors (element type:
 	 * {@link StructuralPropertyDescriptor}),
 	 * or null if uninitialized.
 	 */
 	private static final List PROPERTY_DESCRIPTORS;
 
+	/**
+	 * A list of property descriptors (element type:
+	 * {@link StructuralPropertyDescriptor}),
+	 * or null if uninitialized.
+	 */
+	private static final List PROPERTY_DESCRIPTORS_14;
+
 	static {
 		List properyList = new ArrayList(3);
 		createPropertyList(InstanceofExpression.class, properyList);
 		addProperty(LEFT_OPERAND_PROPERTY, properyList);
 		addProperty(RIGHT_OPERAND_PROPERTY, properyList);
 		PROPERTY_DESCRIPTORS = reapPropertyList(properyList);
+		properyList = new ArrayList(4);
+		createPropertyList(InstanceofExpression.class, properyList);
+		addProperty(LEFT_OPERAND_PROPERTY, properyList);
+		addProperty(RIGHT_OPERAND_PROPERTY, properyList);
+		addProperty(PATTERN_VARIABLE_PROPERTY, properyList);
+		PROPERTY_DESCRIPTORS_14 = reapPropertyList(properyList);
 	}
 
 	/**
@@ -71,10 +93,28 @@
 	 * @since 3.0
 	 */
 	public static List propertyDescriptors(int apiLevel) {
-		return PROPERTY_DESCRIPTORS;
+		return propertyDescriptors(apiLevel, false);
 	}
 
 	/**
+	 * Returns a list of structural property descriptors for this node type.
+	 * Clients must not modify the result.
+	 *
+	 * @param apiLevel the API level; one of the
+	 * <code>AST.JLS*</code> constants
+	 * @param previewEnabled the previewEnabled flag
+	 * @return a list of property descriptors (element type:
+	 * {@link StructuralPropertyDescriptor})
+	 * @noreference This method is not intended to be referenced by clients.
+	 * @since 3.22
+	 */
+	public static List propertyDescriptors(int apiLevel, boolean previewEnabled) {
+		if (DOMASTUtil.isInstanceofExpressionPatternSupported(apiLevel, previewEnabled)) {
+			return PROPERTY_DESCRIPTORS_14;
+		}
+		return PROPERTY_DESCRIPTORS;
+	}
+	/**
 	 * The left operand; lazily initialized; defaults to an unspecified,
 	 * but legal, simple name.
 	 */
@@ -87,6 +127,11 @@
 	private Type rightOperand = null;
 
 	/**
+	 * The patternVariable declaration.
+	 */
+	private SingleVariableDeclaration patternVariable = null;
+
+	/**
 	 * Creates a new AST node for an instanceof expression owned by the given
 	 * AST. By default, the node has unspecified (but legal) operator,
 	 * left and right operands.
@@ -103,6 +148,11 @@
 	}
 
 	@Override
+	final List internalStructuralPropertiesForType(int apiLevel, boolean previewEnabled) {
+		return propertyDescriptors(apiLevel, previewEnabled);
+	}
+
+	@Override
 	final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) {
 		if (property == LEFT_OPERAND_PROPERTY) {
 			if (get) {
@@ -120,6 +170,14 @@
 				return null;
 			}
 		}
+		if (property == PATTERN_VARIABLE_PROPERTY) {
+			if (get) {
+				return getPatternVariable();
+			} else {
+				setPatternVariable((SingleVariableDeclaration) child);
+				return null;
+			}
+		}
 		// allow default implementation to flag the error
 		return super.internalGetSetChildProperty(property, get, child);
 	}
@@ -135,6 +193,9 @@
 		result.setSourceRange(getStartPosition(), getLength());
 		result.setLeftOperand((Expression) getLeftOperand().clone(target));
 		result.setRightOperand((Type) getRightOperand().clone(target));
+		if (DOMASTUtil.isInstanceofExpressionPatternSupported(target)) {
+			result.setPatternVariable((SingleVariableDeclaration) getPatternVariable().clone(target));
+		}
 		return result;
 	}
 
@@ -151,6 +212,9 @@
 			// visit children in normal left to right reading order
 			acceptChild(visitor, getLeftOperand());
 			acceptChild(visitor, getRightOperand());
+			if (DOMASTUtil.isInstanceofExpressionPatternSupported(this.ast)) {
+				acceptChild(visitor, getPatternVariable());
+			}
 		}
 		visitor.endVisit(this);
 	}
@@ -235,10 +299,46 @@
 		postReplaceChild(oldChild, referenceType, RIGHT_OPERAND_PROPERTY);
 	}
 
+	/**
+	 * Returns the patternVariable of this instanceof expression.
+	 *
+	 * @return the patternVariable node
+	 * @exception UnsupportedOperationException if this operation is used other than JLS14
+	 * @exception UnsupportedOperationException if this expression is used with previewEnabled flag as false
+	 * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
+	 * @nooverride This method is not intended to be re-implemented or extended by clients as it is a part of Java preview feature.
+	 */
+	public SingleVariableDeclaration getPatternVariable() {
+		supportedOnlyIn14();
+		unsupportedWithoutPreviewError();
+		return this.patternVariable;
+	}
+
+	/**
+	 * Sets the patternVariable of this instanceof expression.
+	 *
+	 * @param referencePatternVariable the right operand node
+	 * @exception IllegalArgumentException if:
+	 * @exception UnsupportedOperationException if this operation is used other than JLS14
+	 * @exception UnsupportedOperationException if this expression is used with previewEnabled flag as false
+	 * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
+	 * @nooverride This method is not intended to be re-implemented or extended by clients as it is a part of Java preview feature.
+	 */
+	public void setPatternVariable(SingleVariableDeclaration referencePatternVariable) {
+		supportedOnlyIn14();
+		unsupportedWithoutPreviewError();
+		if (referencePatternVariable == null) {
+			throw new IllegalArgumentException();
+		}
+		ASTNode oldChild = this.patternVariable;
+		preReplaceChild(oldChild, referencePatternVariable, PATTERN_VARIABLE_PROPERTY);
+		this.patternVariable = referencePatternVariable;
+		postReplaceChild(oldChild, referencePatternVariable, PATTERN_VARIABLE_PROPERTY);
+	}
 	@Override
 	int memSize() {
 		// treat Operator as free
-		return BASE_NODE_SIZE + 2 * 4;
+		return BASE_NODE_SIZE + 3 * 4;
 	}
 
 	@Override
@@ -246,6 +346,7 @@
 		return
 			memSize()
 			+ (this.leftOperand == null ? 0 : getLeftOperand().treeSize())
-			+ (this.rightOperand == null ? 0 : getRightOperand().treeSize());
+			+ (this.rightOperand == null ? 0 : getRightOperand().treeSize())
+			+ (this.patternVariable == null ? 0 : getPatternVariable().treeSize());
 	}
 }
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IntersectionType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IntersectionType.java
index 5d45767..88be23b 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IntersectionType.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IntersectionType.java
@@ -74,7 +74,7 @@
 	/**
 	 * Creates a new unparented node for an intersection type owned by the given AST.
 	 * By default, it has no types.<p>
-	 * 
+	 *
 	 * N.B. This constructor is package-private.
 	 * </p>
 	 *
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LambdaExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LambdaExpression.java
index 67774f3..3e95c44 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LambdaExpression.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/LambdaExpression.java
@@ -24,14 +24,14 @@
  *    <b>(</b> [ Identifier { <b>,</b> Identifier } ] <b>)</b> <b>-></b> Body
  *    <b>(</b> [ FormalParameter { <b>,</b> FormalParameter } ] <b>)</b> <b>-></b> Body
  * </pre>
- * 
- *<p> 
+ *
+ *<p>
  * The first two forms use {@link VariableDeclarationFragment} for the parameter or parameters,
  * while the third form uses {@link SingleVariableDeclaration}.</p>
  *<p>The Body can be either a {@link Block} or an {@link Expression}.</p>
  *
  * @since 3.10
- * @noinstantiate This class is not intended to be instantiated by clients 
+ * @noinstantiate This class is not intended to be instantiated by clients
  */
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class LambdaExpression extends Expression {
@@ -55,7 +55,7 @@
 	 */
 	public static final ChildListPropertyDescriptor PARAMETERS_PROPERTY =
 		new ChildListPropertyDescriptor(LambdaExpression.class, "parameters", VariableDeclaration.class, CYCLE_RISK); //$NON-NLS-1$
-	
+
 	/**
 	 * The "body" structural property of this node type (child type: {@link ASTNode},
 	 * must be either a {@link Block} or an {@link Expression}).
@@ -69,7 +69,7 @@
 	 * or null if uninitialized.
 	 */
 	private static final List PROPERTY_DESCRIPTORS_8_0;
-	
+
 	static {
 		List propertyList = new ArrayList(4);
 		createPropertyList(LambdaExpression.class, propertyList);
@@ -78,7 +78,7 @@
 		addProperty(BODY_PROPERTY, propertyList);
 		PROPERTY_DESCRIPTORS_8_0 = reapPropertyList(propertyList);
 	}
-	
+
 	/**
 	 * Returns a list of structural property descriptors for this node type.
 	 * Clients must not modify the result.
@@ -93,7 +93,7 @@
 
 	/**
 	 * Indicates whether parentheses are present or not.
-	 * Defaults to <code>true</code>. 
+	 * Defaults to <code>true</code>.
 	 */
 	private boolean hasParentheses = true;
 
@@ -208,7 +208,7 @@
 	 * just a single {@link VariableDeclarationFragment}.
 	 * ASTRewrite may ignore this property if necessary.
 	 * </p>
-	 * 
+	 *
 	 * @return <code>true</code> if this lambda expression has parentheses around
 	 * its parameters and <code>false</code> otherwise
 	 */
@@ -250,7 +250,7 @@
 
 	/**
 	 * Returns the body of this lambda expression.
-	 * 
+	 *
 	 * @return the lambda expression body, which can be either a {@link Block} or an {@link Expression}
 	 */
 	public ASTNode getBody() {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberValuePairBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberValuePairBinding.java
index a312d15..5241ae6 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberValuePairBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MemberValuePairBinding.java
@@ -154,7 +154,7 @@
 			this.value = NoValue;
 		IMethodBinding methodBinding = getMethodBinding();
 		if (methodBinding.getReturnType().isArray() && !this.value.getClass().isArray()) {
-			this.value = new Object[] { this.value }; 
+			this.value = new Object[] { this.value };
 		}
 	}
 
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
index aaad277..16b33c0 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
@@ -232,7 +232,7 @@
 						((metaTagBits & TagBits.AnnotationTargetMASK) != 0)) {
 					continue;
 				}
-				
+
 				final IAnnotationBinding annotationInstance = this.resolver.getAnnotationInstance(internalAnnotation);
 				if (annotationInstance == null) {
 					continue;
@@ -241,7 +241,7 @@
 			}
 			if (convertedAnnotationCount == length) return tempAnnotations;
 			if (convertedAnnotationCount == 0) return AnnotationBinding.NoAnnotations;
-			
+
 			System.arraycopy(tempAnnotations, 0, (tempAnnotations = new IAnnotationBinding[convertedAnnotationCount]), 0, convertedAnnotationCount);
 			return tempAnnotations;
 		}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodDeclaration.java
index 18148f3..150e0d3 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodDeclaration.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodDeclaration.java
@@ -1,5 +1,6 @@
+// AspectJ
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -17,6 +18,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
+
 /**
  * Method declaration AST node type. A method declaration
  * is the union of a method declaration and a constructor declaration.
@@ -36,6 +39,10 @@
  *        <b>)</b> { Dimension }
  *        [ <b>throws</b> Type { <b>,</b> Type } ]
  *        ( Block | <b>;</b> )
+ * CompactConstructorDeclaration:
+ *    [ Javadoc ] ExtendedModifier { ExtendedModifier}
+ *        Identifier
+ *        ( Block | <b>;</b> )
  * </pre>
  * <p>
  * The ReceiverParameter is represented as: <code>Type [ SimpleName <b>.</b> ] <b>this</b></code><br>
@@ -51,6 +58,7 @@
  * parameters), or the first character of the identifier (constructor,
  * no modifiers). The source range extends through the last character of the
  * ";" token (if no body), or the last character of the block (if body).
+ * The compact constructor must be declared public. (jls-8.10.5)
  * </p>
  *
  * @since 2.0
@@ -89,6 +97,13 @@
 		new SimplePropertyDescriptor(MethodDeclaration.class, "constructor", boolean.class, MANDATORY); //$NON-NLS-1$
 
 	/**
+	 * The "compact constructor" structural property of record node type (type: {@link Boolean}).
+	 * @since 3.22
+	 */
+	public static final SimplePropertyDescriptor COMPACT_CONSTRUCTOR_PROPERTY =
+		new SimplePropertyDescriptor(MethodDeclaration.class, "compactConstructor", boolean.class, OPTIONAL); //$NON-NLS-1$
+
+	/**
 	 * The "name" structural property of this node type (child type: {@link SimpleName}).
 	 * @since 3.0
 	 */
@@ -200,6 +215,14 @@
 	 */
 	private static final List PROPERTY_DESCRIPTORS_8_0;
 
+	/**
+	 * A list of property descriptors (element type:
+	 * {@link StructuralPropertyDescriptor}),
+	 * or null if uninitialized.
+	 * @since 3.22
+	 */
+	private static final List PROPERTY_DESCRIPTORS_9_0;
+
 	static {
 		List propertyList = new ArrayList(10);
 		createPropertyList(MethodDeclaration.class, propertyList);
@@ -243,6 +266,23 @@
 		addProperty(THROWN_EXCEPTION_TYPES_PROPERTY, propertyList);
 		addProperty(BODY_PROPERTY, propertyList);
 		PROPERTY_DESCRIPTORS_8_0 = reapPropertyList(propertyList);	
+
+		propertyList = new ArrayList(14);
+		createPropertyList(MethodDeclaration.class, propertyList);
+		addProperty(JAVADOC_PROPERTY, propertyList);
+		addProperty(MODIFIERS2_PROPERTY, propertyList);
+		addProperty(CONSTRUCTOR_PROPERTY, propertyList);
+		addProperty(TYPE_PARAMETERS_PROPERTY, propertyList);
+		addProperty(RETURN_TYPE2_PROPERTY, propertyList);
+		addProperty(NAME_PROPERTY, propertyList);
+		addProperty(RECEIVER_TYPE_PROPERTY, propertyList);
+		addProperty(RECEIVER_QUALIFIER_PROPERTY, propertyList);
+		addProperty(PARAMETERS_PROPERTY, propertyList);
+		addProperty(EXTRA_DIMENSIONS2_PROPERTY, propertyList);
+		addProperty(THROWN_EXCEPTION_TYPES_PROPERTY, propertyList);
+		addProperty(BODY_PROPERTY, propertyList);
+		addProperty(COMPACT_CONSTRUCTOR_PROPERTY, propertyList);
+		PROPERTY_DESCRIPTORS_9_0 = reapPropertyList(propertyList);
 	}
 
 	/**
@@ -255,10 +295,28 @@
 	 * @since 3.0
 	 */
 	public static List propertyDescriptors(int apiLevel) {
+		return propertyDescriptors(apiLevel, false);
+	}
+
+	/**
+	 * Returns a list of structural property descriptors for this node type.
+	 * Clients must not modify the result.
+	 *
+	 * @param apiLevel the API level; one of the
+	 * <code>AST.JLS*</code> constants
+	 * @param previewEnabled the previewEnabled flag
+	 * @return a list of property descriptors (element type:
+	 * {@link StructuralPropertyDescriptor})
+	 * @noreference This method is not intended to be referenced by clients.
+	 * @since 3.22
+	 */
+	public static List propertyDescriptors(int apiLevel, boolean previewEnabled) {
 		if (apiLevel == AST.JLS2_INTERNAL) {
 			return PROPERTY_DESCRIPTORS_2_0;
 		} else if (apiLevel < AST.JLS8_INTERNAL) {
 			return PROPERTY_DESCRIPTORS_3_0;
+		} else if (DOMASTUtil.isRecordDeclarationSupported(apiLevel, previewEnabled)) {
+			return PROPERTY_DESCRIPTORS_9_0;
 		} else {
 			return PROPERTY_DESCRIPTORS_8_0;
 		}
@@ -270,6 +328,13 @@
 	 */
 	private boolean isConstructor = false;
 
+
+	/**
+	 * <code>true</code> for a compact constructor in a record, <code>false</code> for a method.
+	 * Defaults to method.
+	 */
+	private boolean isCompactConstructor = false;
+
 	/**
 	 * The method name; lazily initialized; defaults to an unspecified,
 	 * legal Java identifier.
@@ -401,6 +466,11 @@
 	}
 
 	@Override
+	final List internalStructuralPropertiesForType(int apiLevel, boolean previewEnabled) {
+		return propertyDescriptors(apiLevel, previewEnabled);
+	}
+
+	@Override
 	final int internalGetSetIntProperty(SimplePropertyDescriptor property, boolean get, int value) {
 		if (property == MODIFIERS_PROPERTY) {
 			if (get) {
@@ -431,6 +501,13 @@
 				setConstructor(value);
 				return false;
 			}
+		} else if (property == COMPACT_CONSTRUCTOR_PROPERTY) {
+			if (get) {
+				return isCompactConstructor();
+			} else {
+				setCompactConstructor(value);
+				return false;
+			}
 		}
 		// allow default implementation to flag the error
 		return super.internalGetSetBooleanProperty(property, get, value);
@@ -578,6 +655,9 @@
 		} else {
 			result.thrownExceptions().addAll(ASTNode.copySubtrees(target, thrownExceptions()));			
 		}
+		if (DOMASTUtil.isRecordDeclarationSupported(this.ast)) {
+			result.setCompactConstructor(isCompactConstructor());
+		}
 		result.setBody(
 			(Block) ASTNode.copySubtree(target, getBody()));
 		return result;
@@ -643,6 +723,40 @@
 	}
 
 	/**
+	 * Returns whether this declaration declares a constructor or a method.
+	 *
+	 * @return <code>true</code> if this is a compact constructor declaration in a record,
+	 *    and <code>false</code> if this is a method declaration
+	 * @since 3.22
+	 * @noreference This method is not intended to be referenced by clients.
+	 * @exception UnsupportedOperationException if this operation is not used in JLS14
+	 * @exception UnsupportedOperationException if this operation is used with previewEnabled flag as false
+	 */
+
+	public boolean isCompactConstructor() {
+		supportedOnlyIn14();
+		unsupportedWithoutPreviewError();
+		return this.isCompactConstructor;
+	}
+
+	/**
+	 * Sets whether this declaration declares a compact constructor in a record or a method.
+	 *
+	 * @param isCompactConstructor <code>true</code> for a constructor declaration,
+	 *    and <code>false</code> for a method declaration
+	 * @since 3.22
+	 * @noreference This method is not intended to be referenced by clients.
+	 * @exception UnsupportedOperationException if this operation is not used in JLS14
+	 * @exception UnsupportedOperationException if this operation is used with previewEnabled flag as false
+	 */
+
+	public void setCompactConstructor(boolean isCompactConstructor) {
+		preValueChange(COMPACT_CONSTRUCTOR_PROPERTY);
+		this.isCompactConstructor = isCompactConstructor;
+		postValueChange(COMPACT_CONSTRUCTOR_PROPERTY);
+	}
+
+	/**
 	 * Returns the live ordered list of type parameters of this method
 	 * declaration (added in JLS3 API). This list is non-empty for parameterized methods.
 	 *
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodReference.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodReference.java
index 72f8ee7..aa88b9b 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodReference.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodReference.java
@@ -18,7 +18,7 @@
 /**
  * Abstract base class of all AST node types that represent a method reference
  * expression (added in JLS8 API).
- * 
+ *
  * <pre>
  * MethodReference:
  *    CreationReference
@@ -29,7 +29,7 @@
  * <p>
  * A method reference that is represented by a simple or qualified name,
  * followed by <code>::</code>, followed by a simple name can be represented
- * as {@link ExpressionMethodReference} or as {@link TypeMethodReference}. 
+ * as {@link ExpressionMethodReference} or as {@link TypeMethodReference}.
  * The ASTParser currently prefers the first form.
  * </p>
  *
@@ -49,9 +49,9 @@
 	ASTNode.NodeList typeArguments;
 
 	/**
-	 * Creates and returns a structural property descriptor for the "typeArguments" 
+	 * Creates and returns a structural property descriptor for the "typeArguments"
 	 * property declared on the given concrete node type (element type: {@link Type}).
-	 * 
+	 *
 	 * @return the property descriptor
 	 */
 	static final ChildListPropertyDescriptor internalTypeArgumentsFactory(Class nodeClass) {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ModuleBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ModuleBinding.java
index f302f6e..329bcf8 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ModuleBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ModuleBinding.java
@@ -86,7 +86,7 @@
 	@Override
 	public String getName() {
 		if (this.name == null) {
-			char[] tmp = this.binding.moduleName;	
+			char[] tmp = this.binding.moduleName;
 			return tmp != null && tmp.length != 0 ? new String(tmp) : Util.EMPTY_STRING;
 		}
 		return this.name;
@@ -113,7 +113,7 @@
 		// TODO Auto-generated method stub
 		// TODO Java 9 no reference seen in jvms draft - only in sotm
 		// check on version change and after compiler ast implements isSynthetic return this.binding.isSynthetic();
-		
+
 		return false;
 	}
 
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameEnvironmentWithProgress.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameEnvironmentWithProgress.java
index 9b0e9a2..0a29d91 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameEnvironmentWithProgress.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameEnvironmentWithProgress.java
@@ -31,7 +31,7 @@
  */
 class NameEnvironmentWithProgress extends FileSystem implements INameEnvironmentWithProgress {
 	IProgressMonitor monitor;
-	
+
 	public NameEnvironmentWithProgress(Classpath[] paths, String[] initialFileNames, IProgressMonitor monitor) {
 		super(paths, initialFileNames, false);
 		setMonitor(monitor);
@@ -90,7 +90,7 @@
 		checkCanceled();
 		return super.isPackage(compoundName, packageName);
 	}
-	
+
 	@Override
 	public void setMonitor(IProgressMonitor monitor) {
 		this.monitor = monitor;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameQualifiedType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameQualifiedType.java
index 44c7f3a..6015bdf 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameQualifiedType.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NameQualifiedType.java
@@ -19,12 +19,12 @@
 
 /**
  * Node for a name-qualified type (added in JLS8 API).
- * 
+ *
  * <pre>
  * NameQualifiedType:
  *    Name <b>.</b> { Annotation } SimpleName
  * </pre>
- * 
+ *
  * <p>
  * The qualifier can resolve to a type or to a package.
  * </p>
@@ -36,7 +36,7 @@
  *
  * @see SimpleType
  * @see QualifiedType
- * 
+ *
  * @since 3.10
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
@@ -54,13 +54,13 @@
 	 */
 	public static final ChildListPropertyDescriptor ANNOTATIONS_PROPERTY =
 			internalAnnotationsPropertyFactory(NameQualifiedType.class);
-	
+
 	/**
 	 * The "name" structural property of this node type (child type: {@link SimpleName}).
 	 */
 	public static final ChildPropertyDescriptor NAME_PROPERTY =
 		new ChildPropertyDescriptor(NameQualifiedType.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$
-	
+
 	/**
 	 * A list of property descriptors (element type:
 	 * {@link StructuralPropertyDescriptor}),
@@ -91,7 +91,7 @@
 	}
 
 	/**
-	 * The qualifier node; lazily initialized; defaults to 
+	 * The qualifier node; lazily initialized; defaults to
 	 * an unspecified, but legal, simple name.
 	 */
 	private Name qualifier = null;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeFinder.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeFinder.java
index 3b15d60..f9e5137 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeFinder.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/NodeFinder.java
@@ -111,7 +111,7 @@
 	/**
 	 * Maps a selection to an ASTNode, where the selection is defined using a source range.
 	 * Calls <code>perform(root, range.getOffset(), range.getLength())</code>.
-	 * 
+	 *
 	 * @param root the root node from which the search starts
 	 * @param range the selection range
 	 * @return the innermost node that exactly matches the selection, or the first node that contains the selection
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/OpensDirective.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/OpensDirective.java
index bb69aae..d83fb08 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/OpensDirective.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/OpensDirective.java
@@ -23,7 +23,7 @@
  * </pre>
  *
  * @since 3.14
- * 
+ *
  * @noextend This class is not intended to be subclassed by clients.
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrimitiveType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrimitiveType.java
index 6450bf5..18ff64f 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrimitiveType.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/PrimitiveType.java
@@ -165,7 +165,7 @@
 	 */
 	public static final ChildListPropertyDescriptor ANNOTATIONS_PROPERTY =
 			internalAnnotationsPropertyFactory(PrimitiveType.class);
-	
+
 	/**
 	 * The "primitiveTypeCode" structural property of this node type (type: {@link PrimitiveType.Code}).
 	 * @since 3.0
@@ -191,7 +191,7 @@
 		createPropertyList(PrimitiveType.class, propertyList);
 		addProperty(PRIMITIVE_TYPE_CODE_PROPERTY, propertyList);
 		PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
-		
+
 		propertyList = new ArrayList(3);
 		createPropertyList(PrimitiveType.class, propertyList);
 		addProperty(ANNOTATIONS_PROPERTY, propertyList);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ProvidesDirective.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ProvidesDirective.java
index 8cd2551..02d993a 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ProvidesDirective.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ProvidesDirective.java
@@ -23,7 +23,7 @@
  * </pre>
  *
  * @since 3.14
- * 
+ *
  * @noextend This class is not intended to be subclassed by clients.
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/QualifiedType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/QualifiedType.java
index b24cffe..4d42ddc 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/QualifiedType.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/QualifiedType.java
@@ -19,7 +19,7 @@
 
 /**
  * Type node for a qualified type (added in JLS3 API).
- * 
+ *
  * <pre>
  * QualifiedType:
  *    Type <b>.</b> { Annotation } SimpleName
@@ -62,10 +62,10 @@
  * same rules.
  * </li>
  * </ul>
- * 
+ *
  * @see SimpleType
  * @see NameQualifiedType
- * 
+ *
  * @since 3.1
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
@@ -88,13 +88,13 @@
 	 */
 	public static final ChildListPropertyDescriptor ANNOTATIONS_PROPERTY =
 			internalAnnotationsPropertyFactory(QualifiedType.class);
-	
+
 	/**
 	 * The "name" structural property of this node type (child type: {@link SimpleName}).
 	 */
 	public static final ChildPropertyDescriptor NAME_PROPERTY =
 		new ChildPropertyDescriptor(QualifiedType.class, "name", SimpleName.class, MANDATORY, NO_CYCLE_RISK); //$NON-NLS-1$
-	
+
 	/**
 	 * A list of property descriptors (element type:
 	 * {@link StructuralPropertyDescriptor}),
@@ -115,7 +115,7 @@
 		addProperty(QUALIFIER_PROPERTY, propertyList);
 		addProperty(NAME_PROPERTY, propertyList);
 		PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
-		
+
 		propertyList = new ArrayList(4);
 		createPropertyList(QualifiedType.class, propertyList);
 		addProperty(QUALIFIER_PROPERTY, propertyList);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecordDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecordDeclaration.java
new file mode 100644
index 0000000..ca78834
--- /dev/null
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecordDeclaration.java
@@ -0,0 +1,510 @@
+/*******************************************************************************
+ * Copyright (c) 2019, 2020 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.core.dom;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Record declaration AST node type (added in JLS14 API).
+ *
+ * <pre>
+ * RecordDeclaration:
+ *     [ Javadoc ] { ExtendedModifier } <b>record</b> Identifier
+ *     		[ <b>&lt;</b> TypeParameter <b>&gt;</b> ]
+ *     		<b>(</b>
+ *          	[ FormalParameter { <b>,</b> FormalParameter } ]
+ *        	<b>)</b> { Dimension }
+ *     		[ <b>implements</b> Type { <b>,</b> Type } ]
+ *         	[ <b>;</b> { RecordBodyDeclaration | <b>;</b> } ]
+ * </pre>
+ * The {@link #bodyDeclarations()} list holds the class body declarations
+ * that appear after the semicolon.
+ * <p>
+ * When a Javadoc comment is present, the source
+ * range begins with the first character of the "/**" comment delimiter.
+ * When there is no Javadoc comment, the source range begins with the first
+ * character of the first modifier or annotation (if present), or the
+ * first character of the "record" keyword (if no
+ * modifiers or annotations). The source range extends through the last
+ * character of the "}" token following the body declarations.
+ * </p>
+ *
+ * @since 3.22
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ * @noreference This class is not intended to be referenced by clients as it is a part of Java preview feature.
+ */
+@SuppressWarnings({ "rawtypes", "unchecked" })
+public class RecordDeclaration extends AbstractTypeDeclaration {
+
+	/**
+	 * The "javadoc" structural property of this node type (child type: {@link Javadoc}).
+	 * @since 3.22
+	 */
+	public static final ChildPropertyDescriptor JAVADOC_PROPERTY =
+		internalJavadocPropertyFactory(RecordDeclaration.class);
+
+	/**
+	 * The "modifiers" structural property of this node type (element type: {@link IExtendedModifier}).
+	 * @since 3.22
+	 */
+	public static final ChildListPropertyDescriptor MODIFIERS2_PROPERTY =
+		internalModifiers2PropertyFactory(RecordDeclaration.class);
+
+	/**
+	 * The "name" structural property of this node type (child type: {@link SimpleName}).
+	 * @since 3.22
+	 */
+	public static final ChildPropertyDescriptor NAME_PROPERTY =
+		internalNamePropertyFactory(RecordDeclaration.class);
+
+
+	/**
+	 * The "superInterfaceTypes" structural property of this node type (element type: {@link Type}).
+	 * @since 3.22
+	 */
+	public static final ChildListPropertyDescriptor SUPER_INTERFACE_TYPES_PROPERTY =
+		new ChildListPropertyDescriptor(RecordDeclaration.class, "superInterfaceTypes", Type.class, NO_CYCLE_RISK); //$NON-NLS-1$
+
+	/**
+	 * The "typeParameters" structural property of this node type (element type: {@link TypeParameter}).
+	 * @since 3.22
+	 */
+	public static final ChildListPropertyDescriptor TYPE_PARAMETERS_PROPERTY =
+		new ChildListPropertyDescriptor(RecordDeclaration.class, "typeParameters", TypeParameter.class, NO_CYCLE_RISK); //$NON-NLS-1$
+
+	/**
+	 * The "recordComponents" structural property of this node type (element type: {@link SingleVariableDeclaration}).
+	 * @since 3.22
+	 */
+	public static final ChildListPropertyDescriptor RECORD_COMPONENTS_PROPERTY =
+		new ChildListPropertyDescriptor(RecordDeclaration.class, "recordComponents", SingleVariableDeclaration.class, NO_CYCLE_RISK); //$NON-NLS-1$
+
+	/**
+	 * The "bodyDeclarations" structural property of this node type (element type: {@link BodyDeclaration}).
+	 * @since 3.22
+	 */
+	public static final ChildListPropertyDescriptor BODY_DECLARATIONS_PROPERTY =
+		internalBodyDeclarationPropertyFactory(RecordDeclaration.class);
+
+
+	/**
+	 * A character index into the original restricted identifier source string,
+	 * or <code>-1</code> if no restricted identifier source position information is available
+	 * for this node; <code>-1</code> by default.
+	 */
+	private int restrictedIdentifierStartPosition = -1;
+
+	public void setRestrictedIdentifierStartPosition(int restrictedIdentifierStartPosition) {
+		if (restrictedIdentifierStartPosition < 0) {
+			throw new IllegalArgumentException();
+		}
+		// restrictedIdentifierStartPosition is not considered a structural property
+		// but we protect it nevertheless
+		checkModifiable();
+		this.restrictedIdentifierStartPosition= restrictedIdentifierStartPosition;
+	}
+
+	public int getRestrictedIdentifierStartPosition() {
+		return this.restrictedIdentifierStartPosition;
+	}
+
+	/**
+	 * A list of property descriptors (element type:
+	 * {@link StructuralPropertyDescriptor}),
+	 * or null if uninitialized.
+	 * @since 3.22
+	 */
+	private static final List PROPERTY_DESCRIPTORS;
+
+	static {
+
+		ArrayList propertyList = new ArrayList(8);
+		createPropertyList(RecordDeclaration.class, propertyList);
+		addProperty(JAVADOC_PROPERTY, propertyList);
+		addProperty(MODIFIERS2_PROPERTY, propertyList);
+		addProperty(NAME_PROPERTY, propertyList);
+		addProperty(TYPE_PARAMETERS_PROPERTY, propertyList);
+		addProperty(RECORD_COMPONENTS_PROPERTY, propertyList);
+		addProperty(SUPER_INTERFACE_TYPES_PROPERTY, propertyList);
+		addProperty(BODY_DECLARATIONS_PROPERTY, propertyList);
+
+		PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
+	}
+
+	/**
+	 * Returns a list of structural property descriptors for this node type.
+	 * Clients must not modify the result.
+	 *
+	 * @param apiLevel the API level; one of the
+	 * <code>AST.JLS*</code> constants
+
+	 * @return a list of property descriptors (element type:
+	 * {@link StructuralPropertyDescriptor})
+	 * @noreference This method is not intended to be referenced by clients.
+	 * @since 3.22
+	 */
+	public static List propertyDescriptors(int apiLevel) {
+		return propertyDescriptors(apiLevel, false);
+	}
+
+	/**
+	 * Returns a list of structural property descriptors for this node type.
+	 * Clients must not modify the result.
+	 *
+	 * @param apiLevel the API level; one of the
+	 * <code>AST.JLS*</code> constants
+	 * @param previewEnabled the previewEnabled flag
+	 * @return a list of property descriptors (element type:
+	 * {@link StructuralPropertyDescriptor})
+	 * @noreference This method is not intended to be referenced by clients.
+	 * @since 3.22
+	 */
+	public static List propertyDescriptors(int apiLevel, boolean previewEnabled) {
+		if (apiLevel == AST.JLS14_INTERNAL && previewEnabled) {
+			return PROPERTY_DESCRIPTORS;
+		}
+		return null;
+	}
+
+	/**
+	 * The type parameters (element type: {@link TypeParameter}).
+	 * defaults to an empty list
+	 * @since 3.22
+	 */
+	private ASTNode.NodeList typeParameters = new ASTNode.NodeList(TYPE_PARAMETERS_PROPERTY);
+
+
+	/**
+	 * The superinterface types (element type: {@link Type}).
+	 * defaults to an empty list
+	 * (see constructor).
+	 * @since 3.22
+	 */
+	private ASTNode.NodeList superInterfaceTypes =  new ASTNode.NodeList(SUPER_INTERFACE_TYPES_PROPERTY);
+
+	/**
+	 * The parameters (element type: {@link SingleVariableDeclaration}).
+	 * defaults to an empty list
+	 * (see constructor).
+	 * @since 3.22
+	 */
+	private ASTNode.NodeList recordComponents = new ASTNode.NodeList(RECORD_COMPONENTS_PROPERTY);
+
+
+	/**
+	 * Creates a new AST node for a type declaration owned by the given
+	 * AST. By default, the type declaration is for a class of an
+	 * unspecified, but legal, name; no modifiers; no javadoc;
+	 * no type parameters; no superinterfaces; and an empty list
+	 * of body declarations.
+	 * <p>
+	 * N.B. This constructor is package-private; all subclasses must be
+	 * declared in the same package; clients are unable to declare
+	 * additional subclasses.
+	 * </p>
+	 *
+	 * @param ast the AST that is to own this node
+	 * @exception UnsupportedOperationException if this operation is used other than JLS14
+	 * @exception UnsupportedOperationException if this expression is used with previewEnabled flag as false
+	 */
+	RecordDeclaration(AST ast) {
+		super(ast);
+		supportedOnlyIn14();
+		unsupportedWithoutPreviewError();
+	}
+
+	@Override
+	final List internalStructuralPropertiesForType(int apiLevel) {
+		return propertyDescriptors(apiLevel);
+	}
+
+	@Override
+	final List internalStructuralPropertiesForType(int apiLevel, boolean previewEnabled) {
+		return propertyDescriptors(apiLevel, previewEnabled);
+	}
+
+	@Override
+	final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) {
+		if (property == JAVADOC_PROPERTY) {
+			if (get) {
+				return getJavadoc();
+			} else {
+				setJavadoc((Javadoc) child);
+				return null;
+			}
+		}
+		if (property == NAME_PROPERTY) {
+			if (get) {
+				return getName();
+			} else {
+				setName((SimpleName) child);
+				return null;
+			}
+		}
+		// allow default implementation to flag the error
+		return super.internalGetSetChildProperty(property, get, child);
+	}
+
+	@Override
+	final List internalGetChildListProperty(ChildListPropertyDescriptor property) {
+		if (property == MODIFIERS2_PROPERTY) {
+			return modifiers();
+		}
+		if (property == TYPE_PARAMETERS_PROPERTY) {
+			return typeParameters();
+		}
+		if (property == SUPER_INTERFACE_TYPES_PROPERTY) {
+			return superInterfaceTypes();
+		}
+		if (property == RECORD_COMPONENTS_PROPERTY) {
+			return recordComponents();
+		}
+		if (property == BODY_DECLARATIONS_PROPERTY) {
+			return bodyDeclarations();
+		}
+		// allow default implementation to flag the error
+		return super.internalGetChildListProperty(property);
+	}
+
+	@Override
+	final ChildPropertyDescriptor internalJavadocProperty() {
+		return JAVADOC_PROPERTY;
+	}
+
+	@Override
+	final ChildListPropertyDescriptor internalModifiers2Property() {
+		return MODIFIERS2_PROPERTY;
+	}
+
+	@Override
+	final ChildPropertyDescriptor internalNameProperty() {
+		return NAME_PROPERTY;
+	}
+
+	@Override
+	final ChildListPropertyDescriptor internalBodyDeclarationsProperty() {
+		return BODY_DECLARATIONS_PROPERTY;
+	}
+
+	@Override
+	final int getNodeType0() {
+		return RECORD_DECLARATION;
+	}
+
+	@Override
+	ASTNode clone0(AST target) {
+		RecordDeclaration result = new RecordDeclaration(target);
+		result.restrictedIdentifierStartPosition = getRestrictedIdentifierStartPosition();
+		result.setSourceRange(getStartPosition(), getLength());
+		result.setJavadoc(
+			(Javadoc) ASTNode.copySubtree(target, getJavadoc()));
+		result.setName((SimpleName) getName().clone(target));
+		result.modifiers().addAll(ASTNode.copySubtrees(target, modifiers()));
+		result.typeParameters().addAll(
+				ASTNode.copySubtrees(target, typeParameters()));
+		result.superInterfaceTypes().addAll(
+				ASTNode.copySubtrees(target, superInterfaceTypes()));
+		result.recordComponents().addAll(
+				ASTNode.copySubtrees(target, recordComponents()));
+		result.bodyDeclarations().addAll(
+			ASTNode.copySubtrees(target, bodyDeclarations()));
+		return result;
+	}
+
+	@Override
+	final boolean subtreeMatch0(ASTMatcher matcher, Object other) {
+		// dispatch to correct overloaded match method
+		return matcher.match(this, other);
+	}
+
+	@Override
+	void accept0(ASTVisitor visitor) {
+		boolean visitChildren = visitor.visit(this);
+		if (visitChildren) {
+			// visit children in normal left to right reading order
+			acceptChild(visitor, getJavadoc());
+			acceptChildren(visitor, this.modifiers);
+			acceptChild(visitor, getName());
+			acceptChildren(visitor, this.typeParameters);
+			acceptChildren(visitor, this.superInterfaceTypes);
+			acceptChildren(visitor, this.recordComponents);
+			acceptChildren(visitor, this.bodyDeclarations);
+		}
+		visitor.endVisit(this);
+	}
+
+	/**
+	 * Returns the live ordered list of type parameters of this type
+	 * declaration (added in JLS3 API). This list is non-empty for parameterized types.
+	 *
+	 * @return the live list of type parameters
+	 *    (element type: {@link TypeParameter})
+	 * @since 3.22
+	 */
+	public List typeParameters() {
+		return this.typeParameters;
+	}
+
+
+	/**
+	 * Returns the live ordered list of superinterfaces of this type
+	 * declaration (added in JLS3 API). For a class declaration, these are the interfaces
+	 * that this class implements; for an interface declaration,
+	 * these are the interfaces that this interface extends.
+	 *
+	 * @return the live list of interface types
+	 *    (element type: {@link Type})
+	 * @since 3.22
+	 */
+	public List superInterfaceTypes() {
+		return this.superInterfaceTypes;
+	}
+
+	/**
+	 * Returns the live ordered list of recordComponents of record declaration.
+	 *
+	 * @return the live list of  recordComponents
+	 *    (element type: {@link SingleVariableDeclaration})
+	 * @since 3.22
+	 */
+	public List recordComponents() {
+		return this.recordComponents;
+	}
+
+	/**
+	 * Returns the ordered list of field declarations of this type
+	 * declaration. For a class declaration, these are the
+	 * field declarations; for an interface declaration, these are
+	 * the constant declarations.
+	 * <p>
+	 * This convenience method returns this node's body declarations
+	 * with non-fields filtered out. Unlike <code>bodyDeclarations</code>,
+	 * this method does not return a live result.
+	 * </p>
+	 *
+	 * @return the (possibly empty) list of field declarations
+	 */
+	public FieldDeclaration[] getFields() {
+		List bd = bodyDeclarations();
+		int fieldCount = 0;
+		for (Iterator it = bd.listIterator(); it.hasNext(); ) {
+			if (it.next() instanceof FieldDeclaration) {
+				fieldCount++;
+			}
+		}
+		FieldDeclaration[] fields = new FieldDeclaration[fieldCount];
+		int next = 0;
+		for (Iterator it = bd.listIterator(); it.hasNext(); ) {
+			Object decl = it.next();
+			if (decl instanceof FieldDeclaration) {
+				fields[next++] = (FieldDeclaration) decl;
+			}
+		}
+		return fields;
+	}
+
+	/**
+	 * Returns the ordered list of method declarations of this type
+	 * declaration.
+	 * <p>
+	 * This convenience method returns this node's body declarations
+	 * with non-methods filtered out. Unlike <code>bodyDeclarations</code>,
+	 * this method does not return a live result.
+	 * </p>
+	 *
+	 * @return the (possibly empty) list of method (and constructor)
+	 *    declarations
+	 */
+	public MethodDeclaration[] getMethods() {
+		List bd = bodyDeclarations();
+		int methodCount = 0;
+		for (Iterator it = bd.listIterator(); it.hasNext(); ) {
+			if (it.next() instanceof MethodDeclaration) {
+				methodCount++;
+			}
+		}
+		MethodDeclaration[] methods = new MethodDeclaration[methodCount];
+		int next = 0;
+		for (Iterator it = bd.listIterator(); it.hasNext(); ) {
+			Object decl = it.next();
+			if (decl instanceof MethodDeclaration) {
+				methods[next++] = (MethodDeclaration) decl;
+			}
+		}
+		return methods;
+	}
+
+	/**
+	 * Returns the ordered list of member type declarations of this type
+	 * declaration.
+	 * <p>
+	 * This convenience method returns this node's body declarations
+	 * with non-types filtered out. Unlike <code>bodyDeclarations</code>,
+	 * this method does not return a live result.
+	 * </p>
+	 *
+	 * @return the (possibly empty) list of member type declarations
+	 */
+	public RecordDeclaration[] getTypes() {
+		List bd = bodyDeclarations();
+		int typeCount = 0;
+		for (Iterator it = bd.listIterator(); it.hasNext(); ) {
+			if (it.next() instanceof RecordDeclaration) {
+				typeCount++;
+			}
+		}
+		RecordDeclaration[] memberTypes = new RecordDeclaration[typeCount];
+		int next = 0;
+		for (Iterator it = bd.listIterator(); it.hasNext(); ) {
+			Object decl = it.next();
+			if (decl instanceof RecordDeclaration) {
+				memberTypes[next++] = (RecordDeclaration) decl;
+			}
+		}
+		return memberTypes;
+	}
+
+	@Override
+	ITypeBinding internalResolveBinding() {
+		return this.ast.getBindingResolver().resolveType(this);
+	}
+
+	@Override
+	int memSize() {
+		return super.memSize() + 8 * 4;
+	}
+
+	@Override
+	int treeSize() {
+		return memSize()
+			+ (this.optionalDocComment == null ? 0 : getJavadoc().treeSize())
+			+ (this.modifiers == null ? 0 : this.modifiers.listSize())
+			+ (this.typeName == null ? 0 : getName().treeSize())
+			+ (this.typeParameters == null ? 0 : this.typeParameters.listSize())
+			+ (this.superInterfaceTypes == null ? 0 : this.superInterfaceTypes.listSize())
+			+ (this.recordComponents == null ? 0 : this.recordComponents.listSize())
+			+ this.bodyDeclarations.listSize();
+	}
+
+	@Override
+	SimplePropertyDescriptor internalModifiersProperty() {
+		// node type does not exist before JLS 14
+		return null;
+	}
+
+}
+
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredPackageBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredPackageBinding.java
index 26bb449..5ed3ec7 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredPackageBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredPackageBinding.java
@@ -37,7 +37,7 @@
 		this.binding = binding;
 		this.resolver = resolver;
 	}
-	
+
 	@Override
 	public IAnnotationBinding[] getAnnotations() {
 		return AnnotationBinding.NoAnnotations;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredTypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredTypeBinding.java
index cde2f51..11b472f 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredTypeBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/RecoveredTypeBinding.java
@@ -93,12 +93,12 @@
 	public ITypeBinding getGenericTypeOfWildcardType() {
 		return null;
 	}
-	
+
 	@Override
 	public int getRank() {
 		return -1;
 	}
-	
+
 	@Override
 	public ITypeBinding getComponentType() {
 		if (this.dimensions == 0) return null;
@@ -170,7 +170,7 @@
 		}
 		return null;
 	}
-	
+
 	@Override
 	public ITypeBinding getErasure() {
 		return this;
@@ -180,7 +180,7 @@
 	public IMethodBinding getFunctionalInterfaceMethod() {
 		return null;
 	}
-	
+
 	@Override
 	public ITypeBinding[] getInterfaces() {
 		return TypeBinding.NO_TYPE_BINDINGS;
@@ -401,6 +401,11 @@
 	}
 
 	@Override
+	public boolean isRecord() {
+		return false;
+	}
+
+	@Override
 	public boolean isFromSource() {
 		return false;
 	}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleType.java
index f60a736..fdb2ee2 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleType.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleType.java
@@ -33,10 +33,10 @@
  * In JLS8 and later, the SimpleType may have optional annotations.
  * If annotations are present, then the name must be a {@link SimpleName}.
  * Annotated qualified names are represented as {@link QualifiedType} or {@link NameQualifiedType}.
- * 
+ *
  * @see QualifiedType
  * @see NameQualifiedType
- * 
+ *
  * @since 2.0
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
@@ -49,7 +49,7 @@
 	 */
 	public static final ChildListPropertyDescriptor ANNOTATIONS_PROPERTY =
 			internalAnnotationsPropertyFactory(SimpleType.class);
-	
+
 	/**
 	 * The "name" structural property of this node type (child type: {@link Name}).
 	 * @since 3.0
@@ -76,7 +76,7 @@
 		createPropertyList(SimpleType.class, propertyList);
 		addProperty(NAME_PROPERTY, propertyList);
 		PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
-		
+
 		propertyList = new ArrayList(3);
 		createPropertyList(SimpleType.class, propertyList);
 		addProperty(ANNOTATIONS_PROPERTY, propertyList);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java
index 85a02df..bbf86d2 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SingleVariableDeclaration.java
@@ -206,7 +206,7 @@
 	 * The type annotations on the varargs token (element type: {@link Annotation}).
 	 * Null before JLS8. Added in JLS8; defaults to an empty list
 	 * (see constructor).
-	 * 
+	 *
 	 * @since 3.10
 	 */
 	private ASTNode.NodeList varargsAnnotations = null;
@@ -254,7 +254,7 @@
 	final ChildListPropertyDescriptor internalExtraDimensions2Property() {
 		return EXTRA_DIMENSIONS2_PROPERTY;
 	}
-	
+
 	@Override
 	final ChildPropertyDescriptor internalInitializerProperty() {
 		return INITIALIZER_PROPERTY;
@@ -603,7 +603,7 @@
 	 */
 	public List varargsAnnotations() {
 		if (this.varargsAnnotations == null) {
-			unsupportedIn2_3_4(); 
+			unsupportedIn2_3_4();
 		}
 		return this.varargsAnnotations;
 	}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperMethodReference.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperMethodReference.java
index bdafc03..0801231 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperMethodReference.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SuperMethodReference.java
@@ -18,14 +18,14 @@
 
 /**
  * Super method reference AST node type (added in JLS8 API).
- * 
+ *
  * <pre>
  * SuperMethodReference:
  *     [ ClassName <b>.</b> ] <b>super</b> <b>::</b>
  *         [ <b>&lt;</b> Type { <b>,</b> Type } <b>&gt;</b> ]
  *         Identifier
  * </pre>
- * 
+ *
  * @since 3.10
  * @noinstantiate This class is not intended to be instantiated by clients
  */
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchCase.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchCase.java
index 7fc7125..cfa1220 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchCase.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchCase.java
@@ -24,7 +24,7 @@
  * SwitchCase:
  * 		<b>case</b> Expression  <b>:</b>
  * 		<b>default</b> <b>:</b>
- * 
+ *
  * Switch case allows multiple expressions and '->' as part of Java 12 preview feature (JEP 325)
  *		<b>case</b> [ Expression { <b>,</b> Expression } ]  <b>{ : | ->}</b>
  *		<b>default</b> <b>{ : | ->}</b>
@@ -51,7 +51,7 @@
 	 */
 	public static final ChildListPropertyDescriptor EXPRESSIONS2_PROPERTY  =
 			new ChildListPropertyDescriptor(SwitchCase.class, "expression", Expression.class, CYCLE_RISK); //$NON-NLS-1$);
-	
+
 	/**
 	 * The "switchLabeledRule" structural property of this node type (type: {@link Boolean}).
 	 * @noreference This property is not intended to be referenced by clients as it is a part of Java preview feature.
@@ -59,14 +59,14 @@
 	 */
 	public static final SimplePropertyDescriptor SWITCH_LABELED_RULE_PROPERTY =
 		new SimplePropertyDescriptor(SwitchCase.class, "switchLabeledRule", boolean.class, MANDATORY); //$NON-NLS-1$
-	
+
 	/**
 	 * A list of property descriptors (element type:
 	 * {@link StructuralPropertyDescriptor}),
 	 * or null if uninitialized.
 	 */
 	private static final List PROPERTY_DESCRIPTORS;
-	
+
 	/**
 	 * A list of property descriptors (element type:
 	 * {@link StructuralPropertyDescriptor}),
@@ -79,7 +79,7 @@
 		createPropertyList(SwitchCase.class, propertyList);
 		addProperty(EXPRESSION_PROPERTY, propertyList);
 		PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
-		
+
 		propertyList = new ArrayList(2);
 		createPropertyList(SwitchCase.class, propertyList);
 		addProperty(EXPRESSIONS2_PROPERTY , propertyList);
@@ -98,23 +98,7 @@
 	 * @since 3.0
 	 */
 	public static List propertyDescriptors(int apiLevel) {
-		return propertyDescriptors(apiLevel, false);
-	}
-	
-	/**
-	 * Returns a list of structural property descriptors for this node type.
-	 * Clients must not modify the result.
-	 *
-	 * @param apiLevel the API level; one of the
-	 * <code>AST.JLS*</code> constants
-	 * @param previewEnabled the previewEnabled flag
-	 * @return a list of property descriptors (element type:
-	 * {@link StructuralPropertyDescriptor})
-	 * @noreference This method is not intended to be referenced by clients.
-	 * @since 3.19
-	 */
-	public static List propertyDescriptors(int apiLevel, boolean previewEnabled) {
-		if (apiLevel == AST.JLS13_INTERNAL && previewEnabled) {
+		if (apiLevel >= AST.JLS14_INTERNAL) {
 			return PROPERTY_DESCRIPTORS_13;
 		}
 		return PROPERTY_DESCRIPTORS;
@@ -126,15 +110,15 @@
 	 * @see #expressionInitialized
 	 */
 	private Expression optionalExpression = null;
-	
+
 	/**
 	 * <code>true</code> indicates "->" and <code>false</code> indicates ":".
 	 */
 	private boolean switchLabeledRule = false;
 
-	
+
 	/**
-	 * The expression list; <code>empty</code> for none; 
+	 * The expression list; <code>empty</code> for none;
 	 */
 	private ASTNode.NodeList expressions = null;
 
@@ -152,7 +136,7 @@
 	 */
 	SwitchCase(AST ast) {
 		super(ast);
-		if (ast.isPreviewEnabled()) {
+		if (ast.apiLevel >= AST.JLS14) {
 			this.expressions = new ASTNode.NodeList(EXPRESSIONS2_PROPERTY );
 		}
 	}
@@ -161,11 +145,6 @@
 	final List internalStructuralPropertiesForType(int apiLevel) {
 		return propertyDescriptors(apiLevel);
 	}
-	
-	@Override
-	final List internalStructuralPropertiesForType(int apiLevel, boolean isPreviewEnabled) {
-		return propertyDescriptors(apiLevel, isPreviewEnabled);
-	}
 
 	@Override
 	final boolean internalGetSetBooleanProperty(SimplePropertyDescriptor property, boolean get, boolean value) {
@@ -203,7 +182,7 @@
 		// allow default implementation to flag the error
 		return super.internalGetChildListProperty(property);
 	}
-	
+
 	@Override
 	final int getNodeType0() {
 		return SWITCH_CASE;
@@ -215,7 +194,7 @@
 		SwitchCase result = new SwitchCase(target);
 		result.setSourceRange(getStartPosition(), getLength());
 		result.copyLeadingComment(this);
-		if (this.ast.isPreviewEnabled()) {
+		if (this.ast.apiLevel >= AST.JLS14) {
 			result.expressions().addAll(
 				ASTNode.copySubtrees(target, expressions()));
 		} else {
@@ -235,7 +214,7 @@
 	void accept0(ASTVisitor visitor) {
 		boolean visitChildren = visitor.visit(this);
 		if (visitChildren) {
-			if (this.ast.isPreviewEnabled()) {
+			if (this.ast.apiLevel >= AST.JLS14) {
 				acceptChildren(visitor, this.expressions);
 			} else {
 				acceptChild(visitor, getExpression());
@@ -265,7 +244,7 @@
 		}
 		return this.optionalExpression;
 	}
-	
+
 	/**
 	 * Returns the list of expressions of this switch case, or
 	 * <code>empty</code> if there is none (the "default:" case).
@@ -273,16 +252,12 @@
 	 *
 	 *  @return the list of expression nodes
 	 *    (element type: {@link Expression})
-	 * @exception UnsupportedOperationException if this operation is used other than JLS13
-	 * @exception UnsupportedOperationException if this expression is used with previewEnabled flag as false
-	 * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
-	 * @nooverride This method is not intended to be re-implemented or extended by clients as it is a part of Java preview feature.
-	 * @since 3.18
+	 * @exception UnsupportedOperationException if this operation is used below JLS14
+	 * @since 3.22
 	 */
 	public List expressions() {
 		if (this.expressions == null) {
-			supportedOnlyIn13();
-			unsupportedWithoutPreviewError();
+			unsupportedBelow14();
 		}
 		return this.expressions;
 	}
@@ -308,40 +283,32 @@
 		this.expressionInitialized = true;
 		postReplaceChild(oldChild, expression, EXPRESSION_PROPERTY);
 	}
-	
+
 	/**
 	 * Sets the switchLabeledRule of this switch case as <code>true</code> or <code>false</code>.
 	 * <code>true</code> indicates "->" and <code>false</code> indicates ":".
 
 	 * @param switchLabeledRule <code>true</code> or <code>false</code>
-	 * @exception UnsupportedOperationException if this operation is used other than JLS13
-	 * @exception UnsupportedOperationException if this expression is used with previewEnabled flag as false
-	 * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
-	 * @nooverride This method is not intended to be re-implemented or extended by clients as it is a part of Java preview feature.
-	 * @since 3.18
+	 * @exception UnsupportedOperationException if this operation is used below JLS14
+	 * @since 3.22
 	 */
 	public void setSwitchLabeledRule(boolean switchLabeledRule) {
-		supportedOnlyIn13();
-		unsupportedWithoutPreviewError();
+		unsupportedBelow14();
 		preValueChange(SWITCH_LABELED_RULE_PROPERTY);
 		this.switchLabeledRule = switchLabeledRule;
 		postValueChange(SWITCH_LABELED_RULE_PROPERTY);
 	}
-	
+
 	/**
 	 * Gets the switchLabeledRule of this switch case as <code>true</code> or <code>false</code>.
 	 *<code>true</code> indicates "->" and <code>false</code> indicates ":".
 	 *
 	 * @return switchLabeledRule <code>true</code> or <code>false</code>
-	 * @exception UnsupportedOperationException if this operation is used other than JLS13
-	 * @exception UnsupportedOperationException if this expression is used with previewEnabled flag as false
-	 * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
-	 * @nooverride This method is not intended to be re-implemented or extended by clients as it is a part of Java preview feature.
-	 * @since 3.18
+	 * @exception UnsupportedOperationException if this operation is used below JLS14
+	 * @since 3.22
 	 */
 	public boolean isSwitchLabeledRule() {
-		supportedOnlyIn13();
-		unsupportedWithoutPreviewError();
+		unsupportedBelow14();
 		return this.switchLabeledRule;
 	}
 
@@ -356,7 +323,7 @@
 	 *    <code>false</code> if this is a non-default switch case
 	 */
 	public boolean isDefault()  {
-		if (this.ast.isPreviewEnabled()) {
+		if (this.ast.apiLevel >= AST.JLS14) {
 			return expressions().isEmpty();
 		}
 		return getExpression() == null;
@@ -373,6 +340,6 @@
 			memSize()
 			+ (this.optionalExpression == null ? 0 : this.optionalExpression.treeSize());
 	}
-	
+
 
 }
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchExpression.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchExpression.java
index a8ec301..dca6c0d 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchExpression.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SwitchExpression.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2019 IBM Corporation and others.
+ * Copyright (c) 2019, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -30,23 +30,21 @@
  * <code>SwitchCase</code> nodes are treated as a kind of
  * <code>Statement</code>.
  *
- * @since 3.18
- * @noinstantiate This class is not intended to be instantiated by clients.
- * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
+ * @since 3.22
  */
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class SwitchExpression extends Expression {
 
 	/**
 	 * The "expression" structural property of this node type (child type: {@link Expression}).
-	 * @since 3.16
+	 * @since 3.22
 	 */
 	public static final ChildPropertyDescriptor EXPRESSION_PROPERTY =
 		new ChildPropertyDescriptor(SwitchExpression.class, "expression", Expression.class, MANDATORY, CYCLE_RISK); //$NON-NLS-1$
 
 	/**
 	 * The "statements" structural property of this node type (element type: {@link Statement}).
-	 * @since 3.16
+	 * @since 3.22
 	 */
 	public static final ChildListPropertyDescriptor STATEMENTS_PROPERTY =
 		new ChildListPropertyDescriptor(SwitchExpression.class, "statements", Statement.class, CYCLE_RISK); //$NON-NLS-1$
@@ -74,29 +72,10 @@
 	 * <code>AST.JLS*</code> constants
 	 * @return a list of property descriptors (element type:
 	 * {@link StructuralPropertyDescriptor})
-	 * @since 3.16
+	 * @since 3.22
 	 */
 	public static List propertyDescriptors(int apiLevel) {
-		return propertyDescriptors(apiLevel, false);
-	}
-	
-		/**
-	 * Returns a list of structural property descriptors for this node type.
-	 * Clients must not modify the result.
-	 *
-	 * @param apiLevel the API level; one of the
-	 * <code>AST.JLS*</code> constants
-	 * @param previewEnabled previewEnabled flag
-	 * @return a list of property descriptors (element type:
-	 * {@link StructuralPropertyDescriptor})
-	 * @noreference This method is not intended to be referenced by clients.
-	 * @since 3.20
-	 */
-	public static List propertyDescriptors(int apiLevel, boolean previewEnabled) {
-		if (apiLevel == AST.JLS13_INTERNAL && previewEnabled) {
-			return PROPERTY_DESCRIPTORS;
-		}
-		return null;
+		return PROPERTY_DESCRIPTORS;
 	}
 
 	/**
@@ -122,24 +101,17 @@
 	 * </p>
 	 *
 	 * @param ast the AST that is to own this node
-	 * @exception UnsupportedOperationException if this operation is used other than JLS13
-	 * @exception UnsupportedOperationException if this expression is used with previewEnabled flag as false
+	 * @exception UnsupportedOperationException if this operation is used below JLS14
 	 */
 	SwitchExpression(AST ast) {
 		super(ast);
-		supportedOnlyIn13();
-		unsupportedWithoutPreviewError();
+		unsupportedBelow14();
 	}
 
 	@Override
 	final List internalStructuralPropertiesForType(int apiLevel) {
 		return propertyDescriptors(apiLevel);
 	}
-	
-	@Override
-	final List internalStructuralPropertiesForType(int apiLevel, boolean previewEnabled) {
-		return propertyDescriptors(apiLevel, previewEnabled);
-	}
 
 	@Override
 	final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) {
@@ -199,6 +171,7 @@
 	 * Returns the expression of this switch statement.
 	 *
 	 * @return the expression node
+	 * @since 3.22
 	 */
 	public Expression getExpression() {
 		if (this.expression == null) {
@@ -224,6 +197,7 @@
 	 * <li>the node already has a parent</li>
 	 * <li>a cycle in would be created</li>
 	 * </ul>
+	 * @since 3.22
 	 */
 	public void setExpression(Expression expression) {
 		if (expression == null) {
@@ -242,6 +216,7 @@
 	 *
 	 * @return the live list of statement nodes
 	 *    (element type: {@link Statement})
+	 * @since 3.22
 	 */
 	public List statements() {
 		return this.statements;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TagElement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TagElement.java
index 544569f..10aa5e7 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TagElement.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TagElement.java
@@ -112,7 +112,7 @@
 	 * Standard doc tag name (value {@value}).
 	 */
 	public static final String TAG_EXCEPTION = "@exception"; //$NON-NLS-1$
-	
+
 	/**
 	 * Standard doc tag name (value {@value}).
 	 * @since 3.18
@@ -124,7 +124,7 @@
 	 * @since 3.18
 	 */
 	public static final String TAG_INDEX = "@index"; //$NON-NLS-1$
-	
+
 	/**
 	 * Standard inline doc tag name (value {@value}).
 	 */
@@ -159,7 +159,7 @@
 	 * @since 3.18
 	 */
 	public static final String TAG_PROVIDES = "@provides"; //$NON-NLS-1$
-	
+
 	/**
 	 * Standard doc tag name (value {@value}).
 	 */
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TextBlock.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TextBlock.java
index 38ab6c9..77d11c8 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TextBlock.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TextBlock.java
@@ -26,7 +26,7 @@
 /**
  * TextBolck  AST node type.
  *
- * These are block of String literal nodes. 
+ * These are block of String literal nodes.
  *
  * @since 3.20
  * @noinstantiate This class is not intended to be instantiated by clients.
@@ -84,7 +84,7 @@
 	 * @since 3.20
 	 */
 	public static List propertyDescriptors(int apiLevel, boolean previewEnabled) {
-		if (apiLevel == AST.JLS13_INTERNAL && previewEnabled) {
+		if (apiLevel == AST.JLS14_INTERNAL && previewEnabled) {
 			return PROPERTY_DESCRIPTORS;
 		}
 		return null;
@@ -103,12 +103,12 @@
 	 * </p>
 	 *
 	 * @param ast the AST that is to own this node
-	 * @exception UnsupportedOperationException if this operation is used other than JLS13
+	 * @exception UnsupportedOperationException if this operation is used other than JLS14
 	 * @exception UnsupportedOperationException if this expression is used with previewEnabled flag as false
 	 */
 	TextBlock(AST ast) {
 		super(ast);
-		supportedOnlyIn13();
+		supportedOnlyIn14();
 		unsupportedWithoutPreviewError();
 	}
 
@@ -116,7 +116,7 @@
 	final List internalStructuralPropertiesForType(int apiLevel) {
 		return propertyDescriptors(apiLevel);
 	}
-	
+
 	@Override
 	final List internalStructuralPropertiesForType(int apiLevel, boolean previewEnabled) {
 		return propertyDescriptors(apiLevel, previewEnabled);
@@ -246,7 +246,7 @@
 		if (len < 7) {
 			throw new IllegalArgumentException();
 		}
-		
+
 		int start = -1;
 		loop: for (int i = 3; i < len; i++) {
 			char c = escaped[i];
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TryStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TryStatement.java
index a21679d..90d5535 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TryStatement.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TryStatement.java
@@ -30,9 +30,9 @@
  * <p>
  * Not all node arrangements will represent legal Java constructs. In particular,
  * at least one resource, catch clause, or finally block must be present.</p>
- * 
+ *
  * <p>A resource is either a {@link VariableDeclarationExpression} or (since JLS9) a {@link Name}.</p>
- * 
+ *
  * @since 2.0
  * @noinstantiate This class is not intended to be instantiated by clients.
  * @noextend This class is not intended to be subclassed by clients.
@@ -40,7 +40,7 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class TryStatement extends Statement {
 
-	
+
 	/**
 	 * The "resources" structural property of this node type (element type: {@link VariableDeclarationExpression}) (added in JLS4 API).
 	 * @deprecated In the JLS9 API, this property is replaced by {@link #RESOURCES2_PROPERTY}.
@@ -83,7 +83,7 @@
 	 * or null if uninitialized.
 	 */
 	private static final List PROPERTY_DESCRIPTORS;
-	
+
 	/**
 	 * A list of property descriptors (element type:
 	 * {@link StructuralPropertyDescriptor}),
@@ -360,7 +360,7 @@
 
 	/**
 	 * Returns the live ordered list of resources for this try statement (added in JLS4 API).
-	 * 
+	 *
 	 * <p>A resource is either a {@link VariableDeclarationExpression} or (since JLS9) a {@link Name}.</p>
 	 *
 	 * @return the live list of resources (element type: {@link Expression}).
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Type.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Type.java
index a5637be..85ea4ea 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Type.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Type.java
@@ -36,7 +36,7 @@
  *    ParameterizedType
  *    UnionType
  *    IntersectionType
- *    
+ *
  * {@link PrimitiveType}:
  *    { Annotation } <b>byte</b>
  *    { Annotation } <b>short</b>
@@ -68,7 +68,7 @@
  * @since 2.0
  */
 public abstract class Type extends ASTNode {
-	
+
 	/**
 	 * Creates a new AST node for a type owned by the given AST.
 	 * <p>
@@ -218,14 +218,14 @@
 	public final boolean isWildcardType() {
 		return (this instanceof WildcardType);
 	}
-	
+
 	/**
 	 * Returns whether this type can be annotated. All sub-classes of
 	 * {@link AnnotatableType} can be annotated.
 	 *
 	 * @return <code>true</code> if this type is an instance of {@link AnnotatableType}, and
 	 * <code>false</code> otherwise
-	 * 			
+	 *
 	 * @since 3.10
 	 */
 	public boolean isAnnotatable() {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
index fd364c1..3ac7e77 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeBinding.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -200,7 +200,7 @@
 		}
 		return null;
 	}
-	
+
 	@Override
 	public ITypeBinding getGenericTypeOfWildcardType() {
 		switch (this.binding.kind()) {
@@ -213,7 +213,7 @@
 		}
 		return null;
 	}
-	
+
 	@Override
 	public int getRank() {
 		switch (this.binding.kind()) {
@@ -225,7 +225,7 @@
 				return -1;
 		}
 	}
-	
+
 	@Override
 	public ITypeBinding getComponentType() {
 		if (!isArray()) {
@@ -474,12 +474,12 @@
 			return this.resolver.getTypeBinding(((ParameterizedTypeBinding)this.binding).genericType());
 		return this.resolver.getTypeBinding(this.binding.unannotated());
 	}
-	
+
 	@Override
 	public ITypeBinding getErasure() {
 		return this.resolver.getTypeBinding(this.binding.erasure());
 	}
-	
+
 	@Override
 	public IMethodBinding getFunctionalInterfaceMethod() {
 		Scope scope = this.resolver.scope();
@@ -1060,7 +1060,7 @@
 			org.eclipse.jdt.internal.compiler.lookup.TypeBinding expressionType = ((TypeBinding) type).binding;
 			// simulate capture in case checked binding did not properly get extracted from a reference
 			expressionType = expressionType.capture(scope, 0, 0);
-			return TypeBinding.EXPRESSION.checkCastTypesCompatibility(scope, this.binding, expressionType, null);
+			return TypeBinding.EXPRESSION.checkCastTypesCompatibility(scope, this.binding, expressionType, null, true);
 		} catch (AbortCompilation e) {
 			// don't surface internal exception to clients
 			// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=143013
@@ -1094,6 +1094,11 @@
 	}
 
 	@Override
+	public boolean isRecord() {
+		return this.binding.isRecord();
+	}
+
+	@Override
 	public boolean isEqualTo(IBinding other) {
 		if (other == this) {
 			// identical binding - equal (key or no key)
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeDeclaration.java
index 00bad84..b38f71b 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeDeclaration.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeDeclaration.java
@@ -1,3 +1,4 @@
+// AspectJ
 /*******************************************************************************
  * Copyright (c) 2000, 2013 IBM Corporation and others.
  *
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeMethodReference.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeMethodReference.java
index b58d621..32a0b96 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeMethodReference.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeMethodReference.java
@@ -20,7 +20,7 @@
  * Type method reference expression AST node type (added in JLS8 API).
  * <pre>
  * TypeMethodReference:
- *     Type <b>::</b> 
+ *     Type <b>::</b>
  *         [ <b>&lt;</b> Type { <b>,</b> Type } <b>&gt;</b> ]
  *         Identifier
  * </pre>
@@ -55,7 +55,7 @@
 	 * or null if uninitialized.
 	 */
 	private static final List PROPERTY_DESCRIPTORS_8_0;
-	
+
 	static {
 		List propertyList = new ArrayList(4);
 		createPropertyList(TypeMethodReference.class, propertyList);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeParameter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeParameter.java
index 19b450d..eb3b26b 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeParameter.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/TypeParameter.java
@@ -19,7 +19,7 @@
 
 /**
  * Type parameter declaration node (added in JLS3 API).
- * 
+ *
  * <pre>
  * TypeParameter:
  *    { ExtendedModifier } Identifier [ <b>extends</b> Type { <b>&amp;</b> Type } ]
@@ -37,7 +37,7 @@
 	 */
 	public static final ChildListPropertyDescriptor MODIFIERS_PROPERTY =
 			new ChildListPropertyDescriptor(TypeParameter.class, "modifiers", IExtendedModifier.class, CYCLE_RISK); //$NON-NLS-1$
-	
+
 	/**
 	 * The "name" structural property of this node type (child type: {@link SimpleName}).
 	 */
@@ -70,7 +70,7 @@
 		addProperty(NAME_PROPERTY, propertyList);
 		addProperty(TYPE_BOUNDS_PROPERTY, propertyList);
 		PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
-		
+
 		propertyList = new ArrayList(4);
 		createPropertyList(TypeParameter.class, propertyList);
 		addProperty(MODIFIERS_PROPERTY, propertyList);
@@ -119,7 +119,7 @@
 	 * (see constructor).
 	 */
 	private ASTNode.NodeList modifiers = null;
-	
+
 	/**
 	 * Creates a new unparented node for a parameterized type owned by the
 	 * given AST. By default, an unspecified, but legal, type variable name,
@@ -275,7 +275,7 @@
 	public List typeBounds() {
 		return this.typeBounds;
 	}
-	
+
 	/**
 	 * Returns the live ordered list of modifiers for this TypeParameter node (added in JLS8 API).
 	 *
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/UnionType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/UnionType.java
index 77de29c..5d365bb 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/UnionType.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/UnionType.java
@@ -74,7 +74,7 @@
 	/**
 	 * Creates a new unparented node for an union type owned by the given AST.
 	 * By default, it has no types.<p>
-	 * 
+	 *
 	 * N.B. This constructor is package-private.
 	 * </p>
 	 *
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclaration.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclaration.java
index 053ae77..df829cd 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclaration.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclaration.java
@@ -52,7 +52,7 @@
 	 * (element type: {@link Dimension}).
 	 * Null before JLS8. Added in JLS8; defaults to an empty list
 	 * (see constructor).
-	 * 
+	 *
 	 * @since 3.10
 	 */
 	ASTNode.NodeList extraDimensions = null;
@@ -83,7 +83,7 @@
 	static final SimplePropertyDescriptor internalExtraDimensionsPropertyFactory(Class nodeClass) {
 		return 	new SimplePropertyDescriptor(nodeClass, "extraDimensions", int.class, MANDATORY); //$NON-NLS-1$
 	}
-	
+
 	/**
 	 * Creates and returns a structural property descriptor for the
 	 * "extraDimensions2" property declared on the given concrete node type (element type: {@link Dimension}).
@@ -93,7 +93,7 @@
 	static final ChildListPropertyDescriptor internalExtraDimensions2PropertyFactory(Class nodeClass) {
 		return 	new ChildListPropertyDescriptor(nodeClass, "extraDimensions2", Dimension.class, CYCLE_RISK); //$NON-NLS-1$
 	}
-	
+
 	/**
 	 * Creates and returns a structural property descriptor for the
 	 * "initializer" property declared on the given concrete node type (child type: {@link Expression}).
@@ -124,7 +124,7 @@
 		return internalNameProperty();
 	}
 
-	
+
 	/**
 	 * Returns the structural property descriptor for the "extraDimensions" property
 	 * of this node (type: {@link Integer}) (below JLS8 only).
@@ -155,7 +155,7 @@
 	 * @since 3.10
 	 */
 	abstract ChildListPropertyDescriptor internalExtraDimensions2Property();
-	
+
 	/**
 	 * Returns the structural property descriptor for the "extraDimensions" property
 	 * of this node (element type: {@link Dimension}) (added in JLS8 API).
@@ -166,7 +166,7 @@
 	public final ChildListPropertyDescriptor getExtraDimensions2Property() {
 		return internalExtraDimensions2Property();
 	}
-	
+
 	/**
 	 * Returns structural property descriptor for the "initializer" property
 	 * of this node (child type: {@link Expression}).
@@ -288,7 +288,7 @@
 	 * @exception IllegalArgumentException if the number of dimensions is
 	 *    negative
 	 * @exception UnsupportedOperationException if this operation is used in
-	 * a JLS8 or later AST 
+	 * a JLS8 or later AST
 	 * @deprecated In the JLS8 API, this method is replaced by
 	 * {@link #extraDimensions()} which contains a list of {@link Dimension} nodes.
 	 * @since 2.1
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationFragment.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationFragment.java
index 909915c..b923cbe 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationFragment.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/VariableDeclarationFragment.java
@@ -143,7 +143,7 @@
 	final ChildListPropertyDescriptor internalExtraDimensions2Property() {
 		return EXTRA_DIMENSIONS2_PROPERTY;
 	}
-	
+
 	@Override
 	final ChildPropertyDescriptor internalInitializerProperty() {
 		return INITIALIZER_PROPERTY;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WildcardType.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WildcardType.java
index 7af7d1a..2627070 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WildcardType.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/WildcardType.java
@@ -41,7 +41,7 @@
 	 */
 	public static final ChildListPropertyDescriptor ANNOTATIONS_PROPERTY =
 			internalAnnotationsPropertyFactory(WildcardType.class);
-	
+
 	/**
 	 * The "bound" structural property of this node type (child type: {@link Type}).
 	 */
@@ -74,7 +74,7 @@
 		addProperty(BOUND_PROPERTY, propertyList);
 		addProperty(UPPER_BOUND_PROPERTY, propertyList);
 		PROPERTY_DESCRIPTORS = reapPropertyList(propertyList);
-		
+
 		propertyList = new ArrayList(4);
 		createPropertyList(WildcardType.class, propertyList);
 		addProperty(ANNOTATIONS_PROPERTY, propertyList);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/YieldStatement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/YieldStatement.java
index 4b1af17..9ab51ff 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/YieldStatement.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/YieldStatement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2019 IBM Corporation and others.
+ * Copyright (c) 2019, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -25,9 +25,7 @@
  *		<b>Yield</b> <b>{ Identifier/Expression }</b>
  * </pre>
  *
- * @since 3.20
- * @noinstantiate This class is not intended to be instantiated by clients.
- * @noreference This class is not intended to be referenced by clients as it is a part of Java preview feature.
+ * @since 3.22
  */
 @SuppressWarnings("rawtypes")
 public class YieldStatement extends Statement {
@@ -49,7 +47,7 @@
 	 * <code>true</code> indicates implicit and <code>false</code> indicates not implicit.
 	 */
 	private boolean isImplicit = false;
-	
+
 	static {
 		List properyList = new ArrayList(2);
 		createPropertyList(YieldStatement.class, properyList);
@@ -66,31 +64,13 @@
 
 	 * @return a list of property descriptors (element type:
 	 * {@link StructuralPropertyDescriptor})
+	 * @since 3.22
 	 */
 	public static List propertyDescriptors(int apiLevel) {
-		return propertyDescriptors(apiLevel, false);
+		return PROPERTY_DESCRIPTORS;
 	}
 
 	/**
-	 * Returns a list of structural property descriptors for this node type.
-	 * Clients must not modify the result.
-	 *
-	 * @param apiLevel the API level; one of the
-	 * <code>AST.JLS*</code> constants
-	 * @param previewEnabled the previewEnabled flag
-	 * @return a list of property descriptors (element type:
-	 * {@link StructuralPropertyDescriptor})
-	 * @noreference This method is not intended to be referenced by clients.
-	 * @since 3.20
-	 */
-	public static List propertyDescriptors(int apiLevel, boolean previewEnabled) {
-		if (apiLevel == AST.JLS13_INTERNAL && previewEnabled) {
-			return PROPERTY_DESCRIPTORS;
-		}
-		return null;
-	}
-	
-	/**
 	 * The expression
 	 */
 	private Expression expression = null;
@@ -103,13 +83,11 @@
 	 * </p>
 	 *
 	 * @param ast the AST that is to own this node
-	 * @exception UnsupportedOperationException if this operation is used other than JLS13
-	 * @exception UnsupportedOperationException if this expression is used with previewEnabled flag as false
+	 * @exception UnsupportedOperationException if this operation is used below JLS14
 	 */
 	YieldStatement(AST ast) {
 		super(ast);
-		supportedOnlyIn13();
-		unsupportedWithoutPreviewError();
+		unsupportedBelow14();
 	}
 
 	@Override
@@ -119,9 +97,9 @@
 
 	@Override
 	final List internalStructuralPropertiesForType(int apiLevel, boolean previewEnabled) {
-		return propertyDescriptors(apiLevel, previewEnabled);
+		return propertyDescriptors(apiLevel);
 	}
-	
+
 	@Override
 	final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) {
 		if (property == EXPRESSION_PROPERTY) {
@@ -164,22 +142,21 @@
 		if (visitChildren) {
 			if (this.ast.apiLevel >= AST.JLS13_INTERNAL) {
 				acceptChild(visitor, getExpression());
-			} 
+			}
 		}
 		visitor.endVisit(this);
 	}
-	
+
 	/**
 	 * Returns the expression of this Yield statement, or <code>null</code> if
 	 * there is none.
 	 *
 	 * @return the expression, or <code>null</code> if there is none
-	 * @exception UnsupportedOperationException if this operation is used other than JLS13
-	 * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
-	 * @nooverride This method is not intended to be re-implemented or extended by clients as it is a part of Java preview feature.
+	 * @exception UnsupportedOperationException if this operation is used below JLS14
+	 * @since 3.22
 	 */
 	public Expression getExpression() {
-		supportedOnlyIn13();
+		unsupportedBelow14();
 		return this.expression;
 	}
 
@@ -192,12 +169,11 @@
 	 * <li>the node belongs to a different AST</li>
 	 * <li>the node already has a parent</li>
 	 * </ul>
-	 * @exception UnsupportedOperationException if this operation is used other than JLS13
-	 * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
-	 * @nooverride This method is not intended to be re-implemented or extended by clients as it is a part of Java preview feature.
+	 * @exception UnsupportedOperationException if this operation is used below JLS14
+	 * @since 3.22
 	 */
 	public void setExpression(Expression expression) {
-		supportedOnlyIn13();
+		unsupportedBelow14();
 		ASTNode oldChild = this.expression;
 		preReplaceChild(oldChild, expression, EXPRESSION_PROPERTY);
 		this.expression = expression;
@@ -209,12 +185,11 @@
 	 *<code>true</code> indicates implicit and <code>false</code> indicates not implicit.
 	 *
 	 * @return isImplicit <code>true</code> or <code>false</code>
-	 * @exception UnsupportedOperationException if this operation is used other than JLS13
-	 * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
-	 * @nooverride This method is not intended to be re-implemented or extended by clients as it is a part of Java preview feature.
+	 * @exception UnsupportedOperationException if this operation is used below JLS14
+	 * @since 3.22
 	 */
 	public boolean isImplicit() {
-		supportedOnlyIn13();
+		unsupportedBelow14();
 		return this.isImplicit;
 	}
 
@@ -224,14 +199,14 @@
 	 * generated by compiler and is not expected to be set by client.
 
 	 * @param isImplicit <code>true</code> or <code>false</code>
-	 * @exception UnsupportedOperationException if this operation is used other than JLS13
+	 * @exception UnsupportedOperationException if this operation is used below JLS14
 	 */
 	void setImplicit(boolean isImplicit) {
-		supportedOnlyIn13();
+		unsupportedBelow14();
 		this.isImplicit = isImplicit;
 	}
 
-	
+
 	@Override
 	int memSize() {
 		return super.memSize() + 2 * 4;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java
index 06fdd67..3228a3e 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.java
@@ -1,3 +1,4 @@
+// AspectJ
 /*******************************************************************************
  * Copyright (c) 2004, 2014 IBM Corporation and others.
  *
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java
index 2814267..9378d3b 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java
@@ -107,7 +107,7 @@
 public final class ImportRewrite {
 	/**
 	 * Used to determine how a type will be used, so that unwanted annotations can be filtered,
-	 * which is in particular relevant for avoiding redundant null annotations in the scope of {@code @NonNullByDefault}. 
+	 * which is in particular relevant for avoiding redundant null annotations in the scope of {@code @NonNullByDefault}.
 	 * This enum is a superset of org.eclipse.jdt.annotation.DefaultLocation, and roughly corresponds
 	 * to the classification of type locations as introduced by JSR 308.
 	 *
@@ -116,49 +116,49 @@
 	public enum TypeLocation {
 		/**
 		 * see org.eclipse.jdt.annotation.DefaultLocation.PARAMETER
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		PARAMETER,
 
 		/**
 		 * see org.eclipse.jdt.annotation.DefaultLocation.RETURN_TYPE
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		RETURN_TYPE,
 
 		/**
 		 * see org.eclipse.jdt.annotation.DefaultLocation.FIELD
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		FIELD,
 
 		/**
 		 * see org.eclipse.jdt.annotation.DefaultLocation.TYPE_PARAMETER
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		TYPE_PARAMETER,
 
 		/**
 		 * see org.eclipse.jdt.annotation.DefaultLocation.TYPE_BOUND
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		TYPE_BOUND,
 
 		/**
 		 * see org.eclipse.jdt.annotation.DefaultLocation.TYPE_ARGUMENT
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		TYPE_ARGUMENT,
 
 		/**
 		 * see org.eclipse.jdt.annotation.DefaultLocation.ARRAY_CONTENTS
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		ARRAY_CONTENTS,
@@ -167,7 +167,7 @@
 		 * The special value {@link #LOCAL_VARIABLE} is used for local variables: their nullness is determines by flow analysis,
 		 * so top level nullness annotations are usually not needed for local variables (unless their type is a free
 		 * type variable). Does not correspond to a value in org.eclipse.jdt.annotation.DefaultLocation.
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		LOCAL_VARIABLE,
@@ -176,25 +176,25 @@
 		 * The special value {@link #CAST} is used for casts.
 		 * Casts are never affected by {@code @NonNullByDefault}
 		 * Does not correspond to a value in org.eclipse.jdt.annotation.DefaultLocation.
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		CAST,
-		
+
 		/**
 		 * The special value {@link #INSTANCEOF} is used for {@code instanceof} expressions.
 		 * Null annotations are not supported in this location.
 		 * Does not correspond to a value in org.eclipse.jdt.annotation.DefaultLocation.
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		INSTANCEOF,
 
 		/**
-		 * The special value {@link #NEW} is used for {@code new} expressions (object allocations). 
+		 * The special value {@link #NEW} is used for {@code new} expressions (object allocations).
 		 * Null annotations are not supported in this location.
 		 * Does not correspond to a value in org.eclipse.jdt.annotation.DefaultLocation.
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		NEW,
@@ -203,7 +203,7 @@
 		 * The special value {@link #RECEIVER} is used for the receiver type in a method declaration or method reference.
 		 * Null annotations are not supported in this location.
 		 * Does not correspond to a value in org.eclipse.jdt.annotation.DefaultLocation.
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		RECEIVER,
@@ -211,7 +211,7 @@
 		/**
 		 * The special value {@link #EXCEPTION} is used for exception types in catch and throws declarations, which are
 		 * implicitly non-null. Does not correspond to a value in org.eclipse.jdt.annotation.DefaultLocation.
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		EXCEPTION,
@@ -220,7 +220,7 @@
 		 * The special value {@link #OTHER} is used for locations where type annotations are illegal, like type literals
 		 * (X.class), annotations, or as scope for static field accesses. Does not correspond to a value in
 		 * org.eclipse.jdt.annotation.DefaultLocation.
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		OTHER,
@@ -228,7 +228,7 @@
 		/**
 		 * The special value {@link #UNKNOWN} is used for invocations that don't specify the intended type usage. Does not
 		 * correspond to a value in org.eclipse.jdt.annotation.DefaultLocation.
-		 * 
+		 *
 		 * @since 3.13
 		 */
 		UNKNOWN,
@@ -454,7 +454,7 @@
 		this.importOrder= CharOperation.NO_STRINGS;
 		this.importOnDemandThreshold= 99;
 		this.staticImportOnDemandThreshold= 99;
-		
+
 		this.importsKindMap = new HashMap();
 	}
 
@@ -532,10 +532,10 @@
 	 * Note: {@link #setUseContextToFilterImplicitImports(boolean)} can be used to filter implicit imports
 	 * when a context is used.
 	 * </p>
-	 * 
+	 *
 	 * @param filterImplicitImports
 	 *            if <code>true</code>, implicit imports will be filtered
-	 * 
+	 *
 	 * @see #setUseContextToFilterImplicitImports(boolean)
 	 */
 	public void setFilterImplicitImports(boolean filterImplicitImports) {
@@ -552,16 +552,16 @@
 	* whether an import can be filtered because the type is implicitly visible. Note that too many imports
 	* may be kept if this option is set and <code>addImport*(...)</code> methods are called without a context.
 	* </p>
-	* 
+	*
 	* @param useContextToFilterImplicitImports the given setting
-	* 
+	*
 	* @see #setFilterImplicitImports(boolean)
 	* @since 3.6
 	*/
 	public void setUseContextToFilterImplicitImports(boolean useContextToFilterImplicitImports) {
 		this.useContextToFilterImplicitImports = useContextToFilterImplicitImports;
 	}
-	
+
 	private static int compareImport(char prefix, String qualifier, String name, String curr) {
 		if (curr.charAt(0) != prefix || !curr.endsWith(name)) {
 			return ImportRewriteContext.RES_NAME_UNKNOWN;
@@ -620,14 +620,14 @@
 						|| mainTypeName.equals(Util.concatenateName(qualifier, name, '.'))) {
 					return ImportRewriteContext.RES_NAME_FOUND;
 				}
-				
+
 				if (this.astRoot != null) {
 					List<AbstractTypeDeclaration> types = this.astRoot.types();
 					int nTypes = types.size();
 					for (int i = 0; i < nTypes; i++) {
 						AbstractTypeDeclaration type = types.get(i);
 						SimpleName simpleName = type.getName();
-						if (simpleName.getIdentifier().equals(name)) { 
+						if (simpleName.getIdentifier().equals(name)) {
 							return qualifier.equals(packageName)
 									? ImportRewriteContext.RES_NAME_FOUND
 									: ImportRewriteContext.RES_NAME_CONFLICT;
@@ -672,7 +672,7 @@
 	 * to use the default context (only using the available imports)
 	 * @return an annotation node. The returned annotation contains unqualified type names where
 	 * an import could be added or was already known. Type names are fully qualified if an import conflict prevented an import.
-	 * 
+	 *
 	 * @since 3.10
 	 */
 	public Annotation addAnnotation(IAnnotationBinding annotation, AST ast, ImportRewriteContext context) {
@@ -959,7 +959,7 @@
 	 * in the code. The type binding can be an array binding, type variable or wildcard.
 	 * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type
 	 * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard
-	 * of wildcards are ignored. If type annotations or type arguments are present at any point, the import is added up to that point and 
+	 * of wildcards are ignored. If type annotations or type arguments are present at any point, the import is added up to that point and
 	 * the type is retained from that point with type annotations and type arguments.
 	 * 	<p>
  	 * No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead.
@@ -982,7 +982,7 @@
 	 * in the code. The type binding can be an array binding, type variable or wildcard.
 	 * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type
 	 * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard
-	 * of wildcards are ignored. If type annotations or type arguments are present at any point, the import is added up to that point and 
+	 * of wildcards are ignored. If type annotations or type arguments are present at any point, the import is added up to that point and
 	 * the type is retained from that point with type annotations and type arguments
 	 * 	<p>
  	 * No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead.
@@ -1007,7 +1007,7 @@
 	 * in the code. The type binding can be an array binding, type variable or wildcard.
 	 * If the binding is a generic type, the type parameters are ignored. For parameterized types, also the type
 	 * arguments are processed and imports added if necessary. Anonymous types inside type arguments are normalized to their base type, wildcard
-	 * of wildcards are ignored. If type annotations or type arguments are present at any point, the import is added up to that point and 
+	 * of wildcards are ignored. If type annotations or type arguments are present at any point, the import is added up to that point and
 	 * the type is retained from that point with type annotations and type arguments
 	 * 	<p>
  	 * No imports are added for types that are already known. If a import for a type is recorded to be removed, this record is discarded instead.
@@ -1025,7 +1025,7 @@
 	 * or else qualified names if an import conflict prevented an import.
 	 * @since 3.13
 	 */
-	public Type addImport(ITypeBinding binding, AST ast, ImportRewriteContext context, TypeLocation location) {	
+	public Type addImport(ITypeBinding binding, AST ast, ImportRewriteContext context, TypeLocation location) {
 		ITypeBinding bindingPoint = checkAnnotationAndGenerics(binding);
 		Type type = internalAddImport(bindingPoint == null ? binding : bindingPoint, ast, context, null, /* getBase */ true, bindingPoint != null && !bindingPoint.equals(binding) ? TypeLocation.OTHER : location);
 		if (bindingPoint != null && !bindingPoint.equals(binding)) {
@@ -1332,7 +1332,7 @@
 			String qualifiedName = addedImport.substring(1);
 			computer.addImport(isStatic, qualifiedName);
 		}
-	
+
 		for (String removedImport : this.removedImports) {
 			boolean isStatic = STATIC_PREFIX == removedImport.charAt(0);
 			String qualifiedName = removedImport.substring(1);
@@ -1519,7 +1519,7 @@
 
 		String qualifiedName= getRawQualifiedName(normalizedBinding);
 		String res = qualifiedName.length() > 0 ? internalAddImport(qualifiedName, context) : getRawName(normalizedBinding);
-	
+
 		if (annotsPresent) {
 			int dotIndex = res != null ? res.lastIndexOf('.') : -1;
 			if (dotIndex > 0) {
@@ -1556,7 +1556,7 @@
 	private Type internalAddImport(ITypeBinding binding, AST ast, ImportRewriteContext context, Type currentType, boolean getBase, TypeLocation location) {
 		Type type = null;
 		ITypeBinding normalizedBinding = null;
-		
+
 		if (binding.isPrimitive()) {
 			type = ast.newPrimitiveType(PrimitiveType.toCode(binding.getName()));
 			normalizedBinding= binding;
@@ -1588,7 +1588,7 @@
 		if (getBase) {
 			type = createBaseType(ast, context, normalizedBinding, location);
 		} else  {
-			type = currentType != null ? (Type) ast.newQualifiedType(currentType, ast.newSimpleName(getRawName(normalizedBinding))) : 
+			type = currentType != null ? (Type) ast.newQualifiedType(currentType, ast.newSimpleName(getRawName(normalizedBinding))) :
 				ast.newSimpleType(ast.newName(getRawName(normalizedBinding)));
 			type = annotateType(normalizedBinding, ast, context, type, location);
 		}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
index f179e40..f04b9d9 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/NaiveASTFlattener.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -18,6 +18,7 @@
 
 import org.eclipse.jdt.core.dom.*;
 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
+import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
 
 /**
  * Internal AST visitor for serializing an AST in a quick and dirty fashion.
@@ -49,7 +50,7 @@
 	 * @since 3.4
 	 */
 	private static final int JLS2 = AST.JLS2;
-	
+
 	/**
 	 * Internal synonym for {@link AST#JLS3}. Use to alleviate
 	 * deprecation warnings.
@@ -81,7 +82,7 @@
 	 * @since 3.14
 	 */
 	private static final int JLS9 = AST.JLS9;
-	
+
 	/**
 	 * The string buffer into which the serialized representation of the AST is
 	 * written.
@@ -251,7 +252,7 @@
 			this.buffer.append('>');
 		}
 	}
-	
+
 	private void visitTypeAnnotations(AnnotatableType node) {
 		if (node.getAST().apiLevel() >= JLS8) {
 			visitAnnotationsList(node.annotations());
@@ -265,7 +266,7 @@
 			this.buffer.append(' ');
 		}
 	}
-	
+
 	/**
 	 * Resets this printer so that it can be used again.
 	 */
@@ -595,7 +596,7 @@
 		this.buffer.append(";\n");//$NON-NLS-1$
 		return false;
 	}
-	
+
 	@Override
 	public boolean visit(CreationReference node) {
 		node.getType().accept(this);
@@ -859,7 +860,11 @@
 	public boolean visit(InstanceofExpression node) {
 		node.getLeftOperand().accept(this);
 		this.buffer.append(" instanceof ");//$NON-NLS-1$
-		node.getRightOperand().accept(this);
+		if (DOMASTUtil.isInstanceofExpressionPatternSupported(node.getAST()) && node.getPatternVariable()!= null) {
+			node.getPatternVariable().accept(this);
+		} else {
+			node.getRightOperand().accept(this);
+		}
 		return false;
 	}
 
@@ -969,7 +974,7 @@
 				this.buffer.append(">");//$NON-NLS-1$
 			}
 		}
-		if (!node.isConstructor()) {
+		if (!node.isConstructor()){
 			if (node.getAST().apiLevel() == JLS2) {
 				getReturnType(node).accept(this);
 			} else {
@@ -983,31 +988,33 @@
 			this.buffer.append(" ");//$NON-NLS-1$
 		}
 		node.getName().accept(this);
-		this.buffer.append("(");//$NON-NLS-1$
-		if (node.getAST().apiLevel() >= JLS8) {
-			Type receiverType = node.getReceiverType();
-			if (receiverType != null) {
-				receiverType.accept(this);
-				this.buffer.append(' ');
-				SimpleName qualifier = node.getReceiverQualifier();
-				if (qualifier != null) {
-					qualifier.accept(this);
-					this.buffer.append('.');
-				}
-				this.buffer.append("this"); //$NON-NLS-1$
-				if (node.parameters().size() > 0) {
-					this.buffer.append(',');
+		if (!(DOMASTUtil.isRecordDeclarationSupported(node.getAST()) && node.isCompactConstructor())) {
+			this.buffer.append("(");//$NON-NLS-1$
+			if (node.getAST().apiLevel() >= JLS8) {
+				Type receiverType = node.getReceiverType();
+				if (receiverType != null) {
+					receiverType.accept(this);
+					this.buffer.append(' ');
+					SimpleName qualifier = node.getReceiverQualifier();
+					if (qualifier != null) {
+						qualifier.accept(this);
+						this.buffer.append('.');
+					}
+					this.buffer.append("this"); //$NON-NLS-1$
+					if (node.parameters().size() > 0) {
+						this.buffer.append(',');
+					}
 				}
 			}
-		}
-		for (Iterator it = node.parameters().iterator(); it.hasNext(); ) {
-			SingleVariableDeclaration v = (SingleVariableDeclaration) it.next();
-			v.accept(this);
-			if (it.hasNext()) {
-				this.buffer.append(",");//$NON-NLS-1$
+			for (Iterator it = node.parameters().iterator(); it.hasNext(); ) {
+				SingleVariableDeclaration v = (SingleVariableDeclaration) it.next();
+				v.accept(this);
+				if (it.hasNext()) {
+					this.buffer.append(",");//$NON-NLS-1$
+				}
 			}
+			this.buffer.append(")");//$NON-NLS-1$
 		}
-		this.buffer.append(")");//$NON-NLS-1$
 		int size = node.getExtraDimensions();
 		if (node.getAST().apiLevel() >= JLS8) {
 			List dimensions = node.extraDimensions();
@@ -1028,11 +1035,11 @@
 					if (it.hasNext()) {
 						this.buffer.append(", ");//$NON-NLS-1$
 					}
-				}				
+				}
 				this.buffer.append(" ");//$NON-NLS-1$
-			} 
+			}
 		} else {
-			if (!node.thrownExceptionTypes().isEmpty()) {				
+			if (!node.thrownExceptionTypes().isEmpty()) {
 				this.buffer.append(" throws ");//$NON-NLS-1$
 				for (Iterator it = node.thrownExceptionTypes().iterator(); it.hasNext(); ) {
 					Type n = (Type) it.next();
@@ -1040,8 +1047,8 @@
 					if (it.hasNext()) {
 						this.buffer.append(", ");//$NON-NLS-1$
 					}
-				}	
-				this.buffer.append(" ");//$NON-NLS-1$				
+				}
+				this.buffer.append(" ");//$NON-NLS-1$
 			}
 		}
 		if (node.getBody() == null) {
@@ -1299,6 +1306,62 @@
 	}
 
 	@Override
+	public boolean visit(RecordDeclaration node) {
+		if (node.getJavadoc() != null) {
+			node.getJavadoc().accept(this);
+		}
+		printIndent();
+		printModifiers(node.modifiers());
+		this.buffer.append("record ");//$NON-NLS-1$
+		node.getName().accept(this);
+		this.buffer.append(" ");//$NON-NLS-1$
+
+		if (!node.typeParameters().isEmpty()) {
+			this.buffer.append("<");//$NON-NLS-1$
+			for (Iterator it = node.typeParameters().iterator(); it.hasNext(); ) {
+				TypeParameter t = (TypeParameter) it.next();
+				t.accept(this);
+				if (it.hasNext()) {
+					this.buffer.append(",");//$NON-NLS-1$
+				}
+			}
+			this.buffer.append(">");//$NON-NLS-1$
+		}
+		this.buffer.append(" ");//$NON-NLS-1$
+		this.buffer.append("(");//$NON-NLS-1$
+		for (Iterator it = node.recordComponents().iterator(); it.hasNext(); ) {
+			SingleVariableDeclaration v = (SingleVariableDeclaration) it.next();
+			v.accept(this);
+			if (it.hasNext()) {
+				this.buffer.append(",");//$NON-NLS-1$
+			}
+		}
+		this.buffer.append(")");//$NON-NLS-1$
+		if (!node.superInterfaceTypes().isEmpty()) {
+			this.buffer.append(" implements ");//$NON-NLS-1$
+			for (Iterator it = node.superInterfaceTypes().iterator(); it.hasNext(); ) {
+				Type t = (Type) it.next();
+				t.accept(this);
+				if (it.hasNext()) {
+					this.buffer.append(", ");//$NON-NLS-1$
+				}
+			}
+			this.buffer.append(" ");//$NON-NLS-1$
+		}
+		this.buffer.append("{");//$NON-NLS-1$
+		if (!node.bodyDeclarations().isEmpty()) {
+			this.buffer.append("\n");//$NON-NLS-1$
+			for (Iterator it = node.bodyDeclarations().iterator(); it.hasNext(); ) {
+				BodyDeclaration d = (BodyDeclaration) it.next();
+				d.accept(this);
+				// other body declarations include trailing punctuation
+			}
+		}
+		this.buffer.append("}\n");//$NON-NLS-1$
+		return false;
+	}
+
+	@Override
 	public boolean visit(RequiresDirective node) {
 		printIndent();
 		this.buffer.append("requires");//$NON-NLS-1$
@@ -1470,7 +1533,7 @@
 
 	/*
 	 * @see ASTVisitor#visit(SuperMethodReference)
-	 * 
+	 *
 	 * @since 3.10
 	 */
 	@Override
@@ -1487,7 +1550,7 @@
 
 	@Override
 	public boolean visit(SwitchCase node) {
-		if ((node.getAST().isPreviewEnabled())) {
+		if ((node.getAST().apiLevel() >= AST.JLS14)) {
 			if (node.isDefault()) {
 				this.buffer.append("default");//$NON-NLS-1$
 				this.buffer.append(node.isSwitchLabeledRule() ? " ->" : ":");//$NON-NLS-1$ //$NON-NLS-2$
@@ -1546,14 +1609,14 @@
 		this.indent--;
 		printIndent();
 		this.buffer.append("}\n");//$NON-NLS-1$
-			
+
 	}
 	@Override
 	public boolean visit(SwitchExpression node) {
 		visitSwitchNode(node);
 		return false;
 	}
-	
+
 	@Override
 	public boolean visit(SwitchStatement node) {
 		visitSwitchNode(node);
@@ -1617,7 +1680,7 @@
 		this.buffer.append(node.getEscapedValue());
 		return false;
 	}
-	
+
 	@Override
 	public boolean visit(TextElement node) {
 		this.buffer.append(node.getText());
@@ -1769,7 +1832,7 @@
 
 	/*
 	 * @see ASTVisitor#visit(TypeMethodReference)
-	 * 
+	 *
 	 * @since 3.10
 	 */
 	@Override
@@ -1909,10 +1972,10 @@
 		}
 		return false;
 	}
-	
+
 	@Override
 	public boolean visit(YieldStatement node) {
-		if ((node.getAST().isPreviewEnabled()) && node.isImplicit()  && node.getExpression() == null) {
+		if ((node.getAST().apiLevel() >= AST.JLS14) && node.isImplicit()  && node.getExpression() == null) {
 			return false;
 		}
 		printIndent();
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/SourceRangeVerifier.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/SourceRangeVerifier.java
index 8e29d89..148d3f7 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/SourceRangeVerifier.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/SourceRangeVerifier.java
@@ -19,16 +19,19 @@
 import org.eclipse.jdt.core.dom.ASTParser;
 import org.eclipse.jdt.core.dom.ASTVisitor;
 import org.eclipse.jdt.core.dom.ArrayCreation;
+import org.eclipse.jdt.core.dom.MethodDeclaration;
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
+import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
 
 @SuppressWarnings("rawtypes")
 public class SourceRangeVerifier extends ASTVisitor {
 
 	public static boolean DEBUG = false;
 	public static boolean DEBUG_THROW = false;
-	
-	private StringBuffer bugs; 
-	
+
+	private StringBuffer bugs;
+
 	/**
 	 * Verifies proper node nesting as specified in {@link ASTParser#setKind(int)}:
 	 * <p>
@@ -36,7 +39,7 @@
 	 * within the source range of its parent, and the source ranges of sibling
 	 * nodes never overlap.
 	 * </p>
-	 * 
+	 *
 	 * @param node
 	 * @return <code>null</code> if everything is OK; a list of errors otherwise
 	 */
@@ -49,11 +52,11 @@
 			return null;
 		return buffer.toString();
 	}
-	
+
 	@Override
 	public boolean preVisit2(ASTNode node) {
 		ASTNode previous = null;
-		
+
 		List properties = node.structuralPropertiesForType();
 		for (int i = 0; i < properties.size(); i++) {
 			StructuralPropertyDescriptor property = (StructuralPropertyDescriptor) properties.get(i);
@@ -86,19 +89,24 @@
 	private boolean checkChild(ASTNode parent, ASTNode previous, ASTNode child) {
 		if ((parent.getFlags() & (ASTNode.RECOVERED | ASTNode.MALFORMED)) != 0
 				|| (child.getFlags() & (ASTNode.RECOVERED | ASTNode.MALFORMED)) != 0)
-			return false; 
-		
+			return false;
+		if (DOMASTUtil.isRecordDeclarationSupported(child.getAST()) && child instanceof SingleVariableDeclaration) {
+			if (previous != null && previous instanceof MethodDeclaration && ((MethodDeclaration)previous).isCompactConstructor()) {
+				return true; // For compact constructors, do not validate for parameters
+			}
+		}
+
 		int parentStart = parent.getStartPosition();
 		int parentEnd = parentStart + parent.getLength();
-		
+
 		int childStart = child.getStartPosition();
 		int childEnd = childStart + child.getLength();
-		
+
 		if (previous != null) {
 			// Turn a blind eye on a known problem ... see https://bugs.eclipse.org/391894#c4
 			if (child.getLocationInParent() == ArrayCreation.DIMENSIONS_PROPERTY)
 				return false;
-			
+
 			int previousStart = previous.getStartPosition();
 			int previousEnd = previousStart + previous.getLength();
 			if (childStart < previousEnd) {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
index 31c2028..f4647f9 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
@@ -1,6 +1,6 @@
 // AspectJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -42,6 +42,7 @@
 import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore.CopyPlaceholderData;
 import org.eclipse.jdt.internal.core.dom.rewrite.NodeInfoStore.StringPlaceholderData;
 import org.eclipse.jdt.internal.core.dom.rewrite.RewriteEventStore.CopySourceInfo;
+import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
 import org.eclipse.text.edits.CopySourceEdit;
 import org.eclipse.text.edits.CopyTargetEdit;
 import org.eclipse.text.edits.DeleteEdit;
@@ -2274,6 +2275,41 @@
 	}
 
 	@Override
+	public boolean visit(RecordDeclaration node) {
+		if (!hasChildrenChanges(node)) {
+			return doVisitUnchangedChildren(node);
+		}
+		int pos= rewriteJavadoc(node, RecordDeclaration.JAVADOC_PROPERTY);
+
+		rewriteModifiers2(node, RecordDeclaration.MODIFIERS2_PROPERTY, pos);
+
+		// name
+		pos= rewriteRequiredNode(node, RecordDeclaration.NAME_PROPERTY);
+
+		pos= rewriteOptionalTypeParameters(node, RecordDeclaration.TYPE_PARAMETERS_PROPERTY, pos, Util.EMPTY_STRING, false, true);
+
+		pos= rewriteNodeList(node, RecordDeclaration.RECORD_COMPONENTS_PROPERTY, pos, Util.EMPTY_STRING, ", "); //$NON-NLS-1$
+
+		// extended interfaces
+		ChildListPropertyDescriptor superInterfaceProperty= RecordDeclaration.SUPER_INTERFACE_TYPES_PROPERTY;
+
+		RewriteEvent interfaceEvent= getEvent(node, superInterfaceProperty);
+		if (interfaceEvent == null || interfaceEvent.getChangeKind() == RewriteEvent.UNCHANGED) {
+			pos= doVisit(node, superInterfaceProperty, pos);
+		} else {
+			String keyword=  " implements "; //$NON-NLS-1$
+			pos= rewriteNodeList(node, superInterfaceProperty, pos, keyword, ", "); //$NON-NLS-1$
+		}
+
+		// type members
+		// startPos : find position after left brace of type, be aware that bracket might be missing
+		int startIndent= getIndent(node.getStartPosition()) + 1;
+		int startPos= getPosAfterLeftBrace(pos);
+		rewriteParagraphList(node, RecordDeclaration.BODY_DECLARATIONS_PROPERTY, startPos, startIndent, -1, 2);
+		return false;
+	}
+
+	@Override
 	public boolean visit(ReturnStatement node) {
 		try {
 			this.beforeRequiredSpaceIndex = getScanner().getTokenEndOffset(TerminalTokens.TokenNamereturn, node.getStartPosition());
@@ -3088,7 +3124,11 @@
 
 		rewriteRequiredNode(node, InstanceofExpression.LEFT_OPERAND_PROPERTY);
 		ensureSpaceAfterReplace(node, InstanceofExpression.LEFT_OPERAND_PROPERTY);
+		if (DOMASTUtil.isInstanceofExpressionPatternSupported(node.getAST()) && node.getPatternVariable()!= null) {
+			rewriteRequiredNode(node, InstanceofExpression.PATTERN_VARIABLE_PROPERTY);
+		} else {
 		rewriteRequiredNode(node, InstanceofExpression.RIGHT_OPERAND_PROPERTY);
+		}
 		return false;
 	}
 
@@ -3551,7 +3591,7 @@
 		}
 
 		// dont allow switching from case to default or back. New statements should be created.
-		if (node.getAST().isPreviewEnabled()) {
+		if (node.getAST().apiLevel() >= AST.JLS14) {
 			int pos = node.expressions().size() == 0 ? node.getStartPosition() :
 					rewriteNodeList(node, SwitchCase.EXPRESSIONS2_PROPERTY, node.getStartPosition(), Util.EMPTY_STRING, ", "); //$NON-NLS-1$
 			if (isChanged(node, SwitchCase.SWITCH_LABELED_RULE_PROPERTY)) {
@@ -3775,7 +3815,7 @@
 					insertIndent++;
 				}
 				ParagraphListRewriter listRewriter;
-				if ((node.getAST().isPreviewEnabled())) {
+				if ((node.getAST().apiLevel() >= AST.JLS14)) {
 					listRewriter= new SwitchListLabeledRuleRewriter(insertIndent);
 				} else {
 					listRewriter= new SwitchListRewriter(insertIndent);
@@ -4522,7 +4562,7 @@
 
 		try {
 			int offset= getScanner().getTokenEndOffset(TerminalTokens.TokenNamebreak, node.getStartPosition());
-			if ((node.getAST().isPreviewEnabled())) {
+			if ((node.getAST().apiLevel() >= AST.JLS14)) {
 				rewriteNode(node, YieldStatement.EXPRESSION_PROPERTY, offset, ASTRewriteFormatter.SPACE); // space between yield and label
 			}
 		} catch (CoreException e) {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
index c2f775a..5b8443a 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFlattener.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -18,6 +18,7 @@
 
 import org.eclipse.jdt.core.dom.*;
 import org.eclipse.jdt.internal.compiler.util.Util;
+import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
 
 @SuppressWarnings("rawtypes")
 public class ASTRewriteFlattener extends ASTVisitor {
@@ -36,7 +37,7 @@
 
 	/** @deprecated using deprecated code */
 	private static final ChildPropertyDescriptor INTERNAL_METHOD_RETURN_TYPE_PROPERTY = MethodDeclaration.RETURN_TYPE_PROPERTY;
-	
+
 	/** @deprecated using deprecated code */
 	private static final SimplePropertyDescriptor INTERNAL_METHOD_EXTRA_DIMENSIONS_PROPERTY = MethodDeclaration.EXTRA_DIMENSIONS_PROPERTY;
 
@@ -93,7 +94,7 @@
 
 	/** @deprecated using deprecated code */
 	private static final int JLS9_INTERNAL = AST.JLS9;
-	
+
 	public static String asString(ASTNode node, RewriteEventStore store) {
 		ASTRewriteFlattener flattener= new ASTRewriteFlattener(store);
 		node.accept(flattener);
@@ -622,7 +623,11 @@
 	public boolean visit(InstanceofExpression node) {
 		getChildNode(node, InstanceofExpression.LEFT_OPERAND_PROPERTY).accept(this);
 		this.result.append(" instanceof "); //$NON-NLS-1$
-		getChildNode(node, InstanceofExpression.RIGHT_OPERAND_PROPERTY).accept(this);
+		if (DOMASTUtil.isInstanceofExpressionPatternSupported(node.getAST()) && node.getPatternVariable()!= null) {
+			getChildNode(node, InstanceofExpression.PATTERN_VARIABLE_PROPERTY).accept(this);
+		} else {
+			getChildNode(node, InstanceofExpression.RIGHT_OPERAND_PROPERTY).accept(this);
+		}
 		return false;
 	}
 
@@ -698,32 +703,34 @@
 			this.result.append(' ');
 		}
 		getChildNode(node, MethodDeclaration.NAME_PROPERTY).accept(this);
-		this.result.append('(');
-		// receiver parameter
-		if (node.getAST().apiLevel() >= JLS8_INTERNAL) {
-			ASTNode receiverType = getChildNode(node, MethodDeclaration.RECEIVER_TYPE_PROPERTY);
-			if (receiverType != null) {
-				receiverType.accept(this);
-				this.result.append(' ');
-				ASTNode qualifier = getChildNode(node, MethodDeclaration.RECEIVER_QUALIFIER_PROPERTY);
-				if (qualifier != null) {
-					qualifier.accept(this);
-					this.result.append('.');
-				}
-				this.result.append("this"); //$NON-NLS-1$
-				if (getChildList(node, MethodDeclaration.PARAMETERS_PROPERTY).size() > 0) {
-					this.result.append(',');
+		if (!(DOMASTUtil.isRecordDeclarationSupported(node.getAST()) && getBooleanAttribute(node, MethodDeclaration.COMPACT_CONSTRUCTOR_PROPERTY))) {
+			this.result.append('(');
+			// receiver parameter
+			if (node.getAST().apiLevel() >= JLS8_INTERNAL) {
+				ASTNode receiverType = getChildNode(node, MethodDeclaration.RECEIVER_TYPE_PROPERTY);
+				if (receiverType != null) {
+					receiverType.accept(this);
+					this.result.append(' ');
+					ASTNode qualifier = getChildNode(node, MethodDeclaration.RECEIVER_QUALIFIER_PROPERTY);
+					if (qualifier != null) {
+						qualifier.accept(this);
+						this.result.append('.');
+					}
+					this.result.append("this"); //$NON-NLS-1$
+					if (getChildList(node, MethodDeclaration.PARAMETERS_PROPERTY).size() > 0) {
+						this.result.append(',');
+					}
 				}
 			}
+
+			visitList(node, MethodDeclaration.PARAMETERS_PROPERTY, String.valueOf(','));
+			this.result.append(')');
 		}
-	
-		visitList(node, MethodDeclaration.PARAMETERS_PROPERTY, String.valueOf(','));
-		this.result.append(')');
 		visitExtraDimensions(node, INTERNAL_METHOD_EXTRA_DIMENSIONS_PROPERTY, MethodDeclaration.EXTRA_DIMENSIONS2_PROPERTY);
 
-		ChildListPropertyDescriptor exceptionsProperty = node.getAST().apiLevel() <	JLS8_INTERNAL ? 
+		ChildListPropertyDescriptor exceptionsProperty = node.getAST().apiLevel() <	JLS8_INTERNAL ?
 				INTERNAL_METHOD_THROWN_EXCEPTIONS_PROPERTY : MethodDeclaration.THROWN_EXCEPTION_TYPES_PROPERTY;
-		visitList(node, exceptionsProperty, String.valueOf(','), " throws ", Util.EMPTY_STRING); //$NON-NLS-1$			
+		visitList(node, exceptionsProperty, String.valueOf(','), " throws ", Util.EMPTY_STRING); //$NON-NLS-1$
 		ASTNode body= getChildNode(node, MethodDeclaration.BODY_PROPERTY);
 		if (body == null) {
 			this.result.append(';');
@@ -846,6 +853,32 @@
 	}
 
 	@Override
+	public boolean visit(RecordDeclaration node) {
+		ASTNode javadoc= getChildNode(node, RecordDeclaration.JAVADOC_PROPERTY);
+		if (javadoc != null) {
+			javadoc.accept(this);
+		}
+		visitList(node, RecordDeclaration.MODIFIERS2_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' '));
+		this.result.append("record ");//$NON-NLS-1$
+		getChildNode(node, RecordDeclaration.NAME_PROPERTY).accept(this);
+		this.result.append(' ');
+
+		visitList(node, RecordDeclaration.TYPE_PARAMETERS_PROPERTY, String.valueOf(','), String.valueOf('<'), String.valueOf('>'));
+
+		this.result.append('(');
+		visitList(node, RecordDeclaration.RECORD_COMPONENTS_PROPERTY, String.valueOf(','));
+		this.result.append(')');
+
+		this.result.append(' ');
+		visitList(node, RecordDeclaration.SUPER_INTERFACE_TYPES_PROPERTY, String.valueOf(','), "implements ", Util.EMPTY_STRING); //$NON-NLS-1$
+
+		this.result.append('{');
+		visitList(node, RecordDeclaration.BODY_DECLARATIONS_PROPERTY, Util.EMPTY_STRING, String.valueOf(';'), Util.EMPTY_STRING);
+		this.result.append('}');
+		return false;
+	}
+
+	@Override
 	public boolean visit(RequiresDirective node) {
 		this.result.append("requires "); //$NON-NLS-1$
 		visitList(node, RequiresDirective.MODIFIERS_PROPERTY, String.valueOf(' '), Util.EMPTY_STRING, String.valueOf(' '));
@@ -962,7 +995,7 @@
 
 	@Override
 	public boolean visit(SwitchCase node) {
-		if ((node.getAST().isPreviewEnabled())) {
+		if ((node.getAST().apiLevel() >= AST.JLS14)) {
 			if (node.isDefault()) {
 				this.result.append("default");//$NON-NLS-1$
 				this.result.append(getBooleanAttribute(node, SwitchCase.SWITCH_LABELED_RULE_PROPERTY) ? " ->" : ":");//$NON-NLS-1$ //$NON-NLS-2$
@@ -973,7 +1006,7 @@
 						t.accept(this);
 						this.result.append(it.hasNext() ? ", " : ""); //$NON-NLS-1$ //$NON-NLS-2$
 				}
-				this.result.append(getBooleanAttribute(node, SwitchCase.SWITCH_LABELED_RULE_PROPERTY) ? " ->" : ":");//$NON-NLS-1$ //$NON-NLS-2$ 
+				this.result.append(getBooleanAttribute(node, SwitchCase.SWITCH_LABELED_RULE_PROPERTY) ? " ->" : ":");//$NON-NLS-1$ //$NON-NLS-2$
 			}
 		} else {
 			ASTNode expression= getChildNode(node, INTERNAL_SWITCH_EXPRESSION_PROPERTY);
@@ -993,7 +1026,7 @@
 		visitSwitchNode(node);
 		return false;
 	}
-	
+
 	private void visitSwitchNode(ASTNode node) {
 		this.result.append("switch ("); //$NON-NLS-1$
 		if (node instanceof SwitchExpression) {
@@ -1010,10 +1043,10 @@
 		else if (node instanceof SwitchStatement) {
 			visitList(node, SwitchStatement.STATEMENTS_PROPERTY, null);
 		}
-		
+
 		this.result.append('}');
 	}
-	
+
 	@Override
 	public boolean visit(SwitchStatement node) {
 		visitSwitchNode(node);
@@ -1266,7 +1299,7 @@
 		this.result.append(getAttribute(node, TextBlock.ESCAPED_VALUE_PROPERTY));
 		return false;
 	}
-	
+
 	@Override
 	public boolean visit(TextElement node) {
 		this.result.append(getAttribute(node, TextElement.TEXT_PROPERTY));
@@ -1494,13 +1527,13 @@
 		}
 		return false;
 	}
-	
+
 	@Override
 	public boolean visit(YieldStatement node) {
-		if (node.getAST().isPreviewEnabled() && node.isImplicit()  && node.getExpression() == null) {
+		if (node.getAST().apiLevel() >= AST.JLS14 && node.isImplicit()  && node.getExpression() == null) {
 			return false;
 		}
-		
+
 		this.result.append("yield"); //$NON-NLS-1$
 
 		ASTNode expression = getChildNode(node, YieldStatement.EXPRESSION_PROPERTY);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java
index f46bad8..a54ca64 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java
@@ -5,7 +5,7 @@
  * are made available under the terms of the Eclipse Public License 2.0
  * which accompanies this distribution, and is available at
  * https://www.eclipse.org/legal/epl-2.0/
- * 
+ *
  *
  * SPDX-License-Identifier: EPL-2.0
  *
@@ -129,14 +129,14 @@
 	public ASTRewriteFormatter(NodeInfoStore placeholders, RewriteEventStore eventStore, Map options, String lineDelimiter) {
 		this.placeholders= placeholders;
 		this.eventStore= eventStore;
-	
+
 		this.options= options == null ? JavaCore.getOptions() : (Map) new HashMap(options);
 		this.options.put(
 				DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_RESOURCES_IN_TRY,
 				DefaultCodeFormatterConstants.createAlignmentValue(true, DefaultCodeFormatterConstants.WRAP_NEXT_PER_LINE, DefaultCodeFormatterConstants.INDENT_DEFAULT));
 
 		this.lineDelimiter= lineDelimiter;
-	
+
 		this.tabWidth= IndentManipulation.getTabWidth(options);
 		this.indentWidth= IndentManipulation.getIndentWidth(options);
 	}
@@ -569,12 +569,12 @@
 	public final Prefix VARARGS= new FormattingPrefix("void foo(A ... a) { }", "A ." , CodeFormatter.K_CLASS_BODY_DECLARATIONS); //$NON-NLS-1$ //$NON-NLS-2$
 	public final Prefix TRY_RESOURCES = new FormattingPrefix("try (A a = new A(); B b = new B()) {}", "; B" , CodeFormatter.K_STATEMENTS); //$NON-NLS-1$ //$NON-NLS-2$
 	public final Prefix TRY_RESOURCES_PAREN = new FormattingPrefix("try (A a = new A(); B b = new B()) {}", "y (" , CodeFormatter.K_STATEMENTS); //$NON-NLS-1$ //$NON-NLS-2$
-	
+
 	public final BlockContext IF_BLOCK_WITH_ELSE= new BlockFormattingPrefixSuffix("if (true)", "else{}", 8); //$NON-NLS-1$ //$NON-NLS-2$
 	public final BlockContext IF_BLOCK_NO_ELSE= new BlockFormattingPrefix("if (true)", 8); //$NON-NLS-1$
 	public final BlockContext ELSE_AFTER_STATEMENT= new BlockFormattingPrefix("if (true) foo();else ", 15); //$NON-NLS-1$
 	public final BlockContext ELSE_AFTER_BLOCK= new BlockFormattingPrefix("if (true) {}else ", 11); //$NON-NLS-1$
-	
+
 	public final Prefix CASE_SEPARATION= new FormattingPrefix("case A, B", "A" , CodeFormatter.K_EXPRESSION); //$NON-NLS-1$ //$NON-NLS-2$
 
 	public final BlockContext FOR_BLOCK= new BlockFormattingPrefix("for (;;) ", 7); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEventStore.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEventStore.java
index f24ebaa..6e60bf2 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEventStore.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/RewriteEventStore.java
@@ -38,13 +38,13 @@
 	 * If enabled, then {@link ASTRewrite} and {@link ListRewrite}
 	 * throw an {@link IllegalArgumentException} if a rewrite operation tries to insert an
 	 * AST node in a place where nodes of this type are not allowed (node type not a subtype of
-	 * the structural property's type). 
+	 * the structural property's type).
 	 * </p>
 	 * <p>
 	 * Disabled by default, since this hasn't been enforced from the beginning, and there are clients
 	 * (e.g. in JDT UI refactorings) that rely on a bit of leeway here.
 	 * E.g. the qualifier of a QualifiedName cannot be a MethodInvocation expression or a SimpleType, but
-	 * that's sometimes the easiest solution for such a change, and ASTRewrite has no problems with it.  
+	 * that's sometimes the easiest solution for such a change, and ASTRewrite has no problems with it.
 	 * </p>
 	 */
 	public static boolean DEBUG = false;
@@ -528,10 +528,10 @@
 		}
 		return accessOriginalValue(parent, property);
 	}
-	
+
 	public List getChangedPropertieEvents(ASTNode parent) {
 		List changedPropertiesEvent = new ArrayList();
-		
+
 		List entriesList = (List) this.eventLookup.get(parent);
 		if (entriesList != null) {
 			for (int i= 0; i < entriesList.size(); i++) {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/util/DOMASTUtil.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/util/DOMASTUtil.java
new file mode 100644
index 0000000..e01136b
--- /dev/null
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/util/DOMASTUtil.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2019, 2020 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.core.dom.util;
+
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTNode;
+
+public class DOMASTUtil {
+
+	/**
+	 * Validates if the given <code>AST</code> supports the provided <code>nodeType</code>. This API checks for node
+	 * types supported from JLS 14 onwards and will return <code>true></code> for nodes added before JLS14.
+	 *
+	 * @param ast
+	 *            the AST to be evaluated
+	 * @param nodeType
+	 *            the node type constant indicating a node of type to be evaluated
+	 * @return <code>true</code> if the given <code>AST</code> supports the provided <code>nodeType</code> else
+	 *         <code>false</code>
+	 * @see ASTNode#getNodeType()
+	 * @since 3.22
+	 */
+	private static boolean isNodeTypeSupportedinAST(AST ast, int nodeType) {
+		return isNodeTypeSupportedinAST(ast.apiLevel(), ast.isPreviewEnabledSet(), nodeType);
+	}
+
+	/**
+	 * Validates if the given <code>apiLevel</code> and <code>previewEnabled</code> supports the provided
+	 * <code>nodeType</code>. This API checks for node types supported from JLS 14 onwards and will return
+	 * <code>true></code> for nodes added before JLS14.
+	 *
+	 * @param apiLevel
+	 *            the level to be checked
+	 * @param previewEnabled
+	 *            the preview feature to be considered
+	 * @param nodeType
+	 *            the node type constant indicating a node of type to be evaluated
+	 * @return <code>true</code> if the given <code>AST</code> supports the provided <code>nodeType</code> else
+	 *         <code>false</code>
+	 * @see ASTNode#getNodeType()
+	 * @since 3.22
+	 */
+	private static boolean isNodeTypeSupportedinAST(int apiLevel, boolean previewEnabled, int nodeType) {
+		switch (nodeType) {
+			case ASTNode.SWITCH_EXPRESSION:
+			case ASTNode.YIELD_STATEMENT:
+				return apiLevel >= AST.JLS14;
+			case ASTNode.TEXT_BLOCK:
+			case ASTNode.RECORD_DECLARATION:
+			case ASTNode.INSTANCEOF_EXPRESSION:
+				return isPreviewEnabled(apiLevel, previewEnabled);
+		}
+		return false;
+	}
+
+	private static boolean isPreviewEnabled(int apiLevel, boolean previewEnabled) {
+		return (apiLevel == AST.JLS14 && previewEnabled);
+	}
+
+	public static boolean isSwitchExpressionSupported(AST ast) {
+		return isNodeTypeSupportedinAST(ast, ASTNode.SWITCH_EXPRESSION);
+	}
+
+	public static boolean isYieldStatementSupported(AST ast) {
+		return isNodeTypeSupportedinAST(ast, ASTNode.YIELD_STATEMENT);
+	}
+
+	public static boolean isTextBlockSupported(AST ast) {
+		return isNodeTypeSupportedinAST(ast, ASTNode.TEXT_BLOCK);
+	}
+
+	public static boolean isRecordDeclarationSupported(AST ast) {
+		return isNodeTypeSupportedinAST(ast, ASTNode.RECORD_DECLARATION);
+	}
+
+	public static boolean isRecordDeclarationSupported(int apiLevel, boolean previewEnabled) {
+		return isNodeTypeSupportedinAST(apiLevel, previewEnabled, ASTNode.RECORD_DECLARATION);
+	}
+
+	public static boolean isInstanceofExpressionPatternSupported(AST ast) {
+		return isNodeTypeSupportedinAST(ast, ASTNode.INSTANCEOF_EXPRESSION);
+	}
+
+	public static boolean isInstanceofExpressionPatternSupported(int apiLevel, boolean previewEnabled) {
+		return isNodeTypeSupportedinAST(apiLevel, previewEnabled, ASTNode.INSTANCEOF_EXPRESSION);
+	}
+
+	@SuppressWarnings("deprecation")
+	public static void checkASTLevel(int level) {
+		switch (level) {
+	        case AST.JLS2 :
+	        case AST.JLS3 :
+	        case AST.JLS4 :
+	        case AST.JLS8 :
+	        case AST.JLS9 :
+	        case AST.JLS10 :
+	        case AST.JLS11 :
+	        case AST.JLS12 :
+	        case AST.JLS13 :
+	        case AST.JLS14 :
+	        	return;
+		}
+		throw new IllegalArgumentException();
+
+	}
+
+}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java
index 1536b4f..5c2de26 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetAllocationExpression.java
@@ -15,7 +15,7 @@
  *                          Bug 409245 - [1.8][compiler] Type annotations dropped when call is routed through a synthetic bridge method
  *                          Bug 409250 - [1.8][compiler] Various loose ends in 308 code generation
  *        Stephan Herrmann - Contribution for
- *							Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) 
+ *							Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec)
  *							Bug 424415 - [1.8][compiler] Eventual resolution of ReferenceExpression is not seen to be happening.
  *							Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280)
  *******************************************************************************/
@@ -225,11 +225,11 @@
 		}
 		this.resolvedType = this.type.resolvedType = scope.environment().createParameterizedType(((ParameterizedTypeBinding) this.resolvedType).genericType(), inferredTypes, ((ParameterizedTypeBinding) this.resolvedType).enclosingType());
  	}
-	
+
 	ReferenceBinding allocatedType = (ReferenceBinding) this.resolvedType;
 	this.binding = findConstructorBinding(scope, this, allocatedType, this.argumentTypes);
 
-	if (!this.binding.isValidBinding()) {	
+	if (!this.binding.isValidBinding()) {
 		if (this.binding instanceof ProblemMethodBinding
 			&& ((ProblemMethodBinding) this.binding).problemId() == NotVisible) {
 			if (this.evaluationContext.declaringTypeName != null) {
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java
index cbbc423..6b0757b 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetFieldReference.java
@@ -68,7 +68,7 @@
 				default :
 					codeStream.dup_x2();
 					break;
-			}			
+			}
 		}
 		codeStream.generateEmulatedWriteAccessForField(codegenBinding);
 	}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java
index 9a00586..f2b0ff3 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetMessageSend.java
@@ -83,7 +83,7 @@
 			this.receiver.generateCode(currentScope, codeStream, !isStatic);
 			if ((this.bits & NeedReceiverGenericCast) != 0) {
 				codeStream.checkcast(this.actualReceiverType);
-			}			
+			}
 			codeStream.recordPositionsFrom(pc, this.sourceStart);
 		}
 		// generate arguments
@@ -113,7 +113,7 @@
 			this.receiver.generateCode(currentScope, codeStream, !isStatic);
 			if ((this.bits & NeedReceiverGenericCast) != 0) {
 				codeStream.checkcast(this.actualReceiverType);
-			}			
+			}
 			codeStream.recordPositionsFrom(pc, this.sourceStart);
 		}
 		if (isStatic) {
@@ -200,7 +200,7 @@
 public TypeBinding resolveType(BlockScope scope) {
 	// Answer the signature return type
 	// Base type promotion
-	
+
 	if (this.constant != Constant.NotAConstant) {
 		this.constant = Constant.NotAConstant;
 		boolean receiverCast = false;
@@ -262,7 +262,7 @@
 		}
 	}
 	findMethodBinding(scope);
-		
+
 	if (!this.binding.isValidBinding()) {
 		if (this.binding instanceof ProblemMethodBinding
 			&& ((ProblemMethodBinding) this.binding).problemId() == ProblemReasons.NotVisible) {
@@ -323,7 +323,7 @@
 			this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType);
 			if (TypeBinding.notEquals(this.actualReceiverType, oldReceiverType) && TypeBinding.notEquals(this.receiver.postConversionType(scope), this.actualReceiverType)) { // record need for explicit cast at codegen since receiver could not handle it
 				this.bits |= NeedReceiverGenericCast;
-			}			
+			}
 		}
 	}
 	if (checkInvocationArguments(scope, this.receiver, this.actualReceiverType, this.binding, this.arguments, this.argumentTypes, this.argsContainCast, this)) {
@@ -348,12 +348,12 @@
 		this.resolvedType = this.actualReceiverType;
 	} else {
 		TypeBinding returnType = this.binding.returnType;
-		
+
 		if (returnType != null) {
 			if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) {
 				returnType = scope.environment().convertToRawType(returnType.erasure(), true);
 			}
-			returnType = returnType.capture(scope, this.sourceStart, this.sourceEnd);			
+			returnType = returnType.capture(scope, this.sourceStart, this.sourceEnd);
 		}
 		this.resolvedType = returnType;
 	}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java
index b8d630c..e483740 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetParser.java
@@ -74,7 +74,7 @@
 		}
 		alloc.type = getTypeReference(0);
 		checkForDiamond(alloc.type);
-		
+
 		//the default constructor with the correct number of argument
 		//will be created and added by the TC (see createsInternalConstructorWithBinding)
 		alloc.sourceStart = this.intStack[this.intPtr--];
@@ -414,20 +414,20 @@
 			&& this.scanner.startPosition <= this.codeSnippetEnd + 1 + this.lineSeparatorLength // 14838
 			&& isTopLevelType()) {
 
-	
+
 		MessageSend m = newMessageSendWithTypeArguments();
 		m.sourceEnd = this.rParenPos;
 		m.sourceStart =
 			(int) ((m.nameSourcePosition = this.identifierPositionStack[this.identifierPtr]) >>> 32);
 		m.selector = this.identifierStack[this.identifierPtr--];
 		this.identifierLengthPtr--;
-	
+
 		// handle type arguments
 		int length = this.genericsLengthStack[this.genericsLengthPtr--];
 		this.genericsPtr -= length;
 		System.arraycopy(this.genericsStack, this.genericsPtr + 1, m.typeArguments = new TypeReference[length], 0, length);
 		this.intPtr--;
-	
+
 		m.receiver = getUnspecifiedReference();
 		m.sourceStart = m.receiver.sourceStart;
 		pushOnExpressionStack(m);
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java
index 5a2bd8d..1df9f03 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetQualifiedNameReference.java
@@ -172,8 +172,8 @@
 				break;
 			default :
 				codeStream.dup_x2();
-			break;	
-		}		
+			break;
+		}
 	}
 	codeStream.generateEmulatedWriteAccessForField(lastFieldBinding);
 	if (valueRequired) {
@@ -233,7 +233,7 @@
 				break;
 			default :
 				codeStream.dup_x2();
-			break;	
+			break;
 		}
 	}
 	// current stack is:
@@ -257,8 +257,8 @@
 				break;
 			default :
 				codeStream.dup();
-			break;	
-		}		
+			break;
+		}
 	}
 	codeStream.generateEmulationForField(lastFieldBinding);
 	if ((TypeBinding.equalsEquals(lastFieldBinding.type, TypeBinding.LONG)) || (TypeBinding.equalsEquals(lastFieldBinding.type, TypeBinding.DOUBLE))) {
@@ -301,7 +301,7 @@
 	TypeBinding lastGenericCast;
 	TypeBinding lastReceiverType;
 	boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4;
-	
+
 	switch (this.bits & RestrictiveFlagMASK) {
 		case Binding.FIELD :
 			lastFieldBinding = ((FieldBinding) this.binding).original();
@@ -361,7 +361,7 @@
 			}
 			break;
 		default : // should not occur
-			return null;			
+			return null;
 	}
 	// all intermediate field accesses are read accesses
 	// only the last field binding is a write access
@@ -444,10 +444,10 @@
 				if (lastFieldBinding.isStatic()) {
 					codeStream.aconst_null();
 				}
-			}			
+			}
 		}
 	}
-	return lastFieldBinding;	
+	return lastFieldBinding;
 }
 
 
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java
index d829d09..1f74261 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetScope.java
@@ -13,7 +13,7 @@
  *     Jesper S Moller <jesper@selskabet.org> - Contributions for
  *								bug 378674 - "The method can be declared as static" is wrong
  *     Stephan Herrmann - Contribution for
- *								Bug 424167 - [1.8] Fully integrate type inference with overload resolution     
+ *								Bug 424167 - [1.8] Fully integrate type inference with overload resolution
  *******************************************************************************/
 package org.eclipse.jdt.internal.eval;
 
@@ -133,7 +133,7 @@
 	TypeBinding originalDeclaringClass = fieldBinding.declaringClass .original();
 	do {
 		if (type.isCapture()) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=285002
-			if (TypeBinding.equalsEquals(originalDeclaringClass, type.erasure().original())) return true;	
+			if (TypeBinding.equalsEquals(originalDeclaringClass, type.erasure().original())) return true;
 		} else {
 			if (TypeBinding.equalsEquals(originalDeclaringClass, type.original())) return true;
 		}
@@ -513,7 +513,7 @@
 					CharOperation.concatWith(CharOperation.subarray(compoundName, 0, currentIndex), '.'),
 					ProblemReasons.NonStaticReferenceInStaticContext);
 		}
-		// Since a qualified reference must be for a static member, it won't affect static-ness of the enclosing method, 
+		// Since a qualified reference must be for a static member, it won't affect static-ness of the enclosing method,
 		// so we don't have to call resetEnclosingMethodStaticFlag() in this case
 		return binding;
 	}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java
index e1ec3dd..6872a5b 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSingleNameReference.java
@@ -471,7 +471,7 @@
 						default:
 							codeStream.dup_x2();
 							break;
-					}					
+					}
 				}
 				// current stack is:
 				// value field receiver value
@@ -489,7 +489,7 @@
 					default:
 						codeStream.dup();
 						break;
-				}				
+				}
 			}
 			codeStream.store(localBinding, false);
 	}
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSkeleton.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSkeleton.java
index 6945bcd..06dc1f8 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSkeleton.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetSkeleton.java
@@ -90,7 +90,7 @@
 		}
 		@Override
 		public IBinaryTypeAnnotation[] getTypeAnnotations() {
-			return null; 
+			return null;
 		}
 		@Override
 		public char[] getSelector() {
@@ -143,7 +143,7 @@
 }
 @Override
 public IBinaryTypeAnnotation[] getTypeAnnotations() {
-	return null; 
+	return null;
 }
 @Override
 public char[] getEnclosingMethod() {
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetThisReference.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetThisReference.java
index 4d81717..469ece4 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetThisReference.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetThisReference.java
@@ -50,7 +50,7 @@
 		this.evaluationContext = evaluationContext;
 		this.isImplicit = isImplicit;
 	}
-	
+
 	@Override
 	public boolean checkAccess(BlockScope scope, ReferenceBinding thisType) {
 		// this/super cannot be used in constructor call
@@ -68,7 +68,7 @@
 		scope.tagAsAccessingEnclosingInstanceStateOf(thisType, false /* type variable access */);
 		return true;
 	}
-	
+
 	@Override
 	public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
 		int pc = codeStream.position;
@@ -78,7 +78,7 @@
 		}
 		codeStream.recordPositionsFrom(pc, this.sourceStart);
 	}
-	
+
 	/**
 	 * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
 	 */
@@ -86,7 +86,7 @@
 	public TypeBinding[] genericTypeArguments() {
 		return null;
 	}
-	
+
 	@Override
 	public InferenceContext18 freshInferenceContext(Scope scope) {
 		return null;
@@ -96,12 +96,12 @@
 	public boolean isSuperAccess(){
 		return false;
 	}
-	
+
 	@Override
 	public boolean isTypeAccess(){
 		return false;
 	}
-	
+
 	@Override
 	public StringBuffer printExpression(int indent, StringBuffer output){
 
@@ -113,7 +113,7 @@
 			output.append(declaringType);
 		return output.append(")this"); //$NON-NLS-1$
 	}
-	
+
 	@Override
 	public TypeBinding resolveType(BlockScope scope) {
 		// implicit this
@@ -133,17 +133,17 @@
 		}
 		return this.resolvedType = this.delegateThis.type;
 	}
-	
+
 	@Override
 	public void setActualReceiverType(ReferenceBinding receiverType) {
 		// ignored
 	}
-	
+
 	@Override
 	public void setDepth(int depth){
 		// ignored
 	}
-	
+
 	@Override
 	public void setFieldIndex(int index){
 		// ignored
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java
index aecdfc2..00be115 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/CodeSnippetToCuMapper.java
@@ -59,7 +59,7 @@
 	// Mapping of external local variables
 	char[][] localVarNames;
 	char[][] localVarTypeNames;
-	
+
 	long complianceVersion;
 
 /**
diff --git a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java
index 1240151..cbd41a8 100644
--- a/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java
+++ b/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java
@@ -105,7 +105,7 @@
  *
  *  @param owner
  *  	the owner of working copies that take precedence over their original compilation units
- *  
+ *
  *  @param monitor
  *  	the progress monitor used to report progress
  */
diff --git a/org.eclipse.jdt.core/forceQualifierUpdate.txt b/org.eclipse.jdt.core/forceQualifierUpdate.txt
index fa0a0ab..0e7f62e 100644
--- a/org.eclipse.jdt.core/forceQualifierUpdate.txt
+++ b/org.eclipse.jdt.core/forceQualifierUpdate.txt
@@ -6,3 +6,5 @@
 Several bundles changed and need to be touched
 Bug 418646 - org.eclipse.jdt.core does not provide an artifact with classifier 'antadapter'
 Bug 436266 - Use RC3 (plus) version of JDT compiler to build RC4
+Bug 551547 - The library org.eclipse.jdt.core.compiler.batch_*.jar should be signed
+Bug 549687 - Local ecj build has a SHA-256 digest error for org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.class
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/CodeFormatterApplication.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/CodeFormatterApplication.java
index 8c38c53..b1880d2 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/CodeFormatterApplication.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/CodeFormatterApplication.java
@@ -7,7 +7,7 @@
  *  https://www.eclipse.org/legal/epl-2.0/
  *
  *  SPDX-License-Identifier: EPL-2.0
- * 
+ *
  *  Contributors:
  *     Ben Konrath <ben@bagu.org> - initial implementation
  *     Red Hat Incorporated - improvements based on comments from JDT developers
@@ -40,9 +40,9 @@
 
 /**
  * Implements an Eclipse Application for org.eclipse.jdt.core.JavaCodeFormatter.
- * 
+ *
  * <p>On MacOS, when invoked using the Eclipse executable, the "user.dir" property is set to the folder
- * in which the eclipse.ini file is located. This makes it harder to use relative paths to point to the 
+ * in which the eclipse.ini file is located. This makes it harder to use relative paths to point to the
  * files to be formatted or the configuration file to use to set the code formatter's options.</p>
  *
  * <p>There are a couple improvements that could be made: 1. Make a list of all the
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
index 31f10d7..7f0a169 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
@@ -43,6 +43,8 @@
 	 * @see #FORMATTER_BRACE_POSITION_FOR_BLOCK
 	 * @see #FORMATTER_BRACE_POSITION_FOR_CONSTRUCTOR_DECLARATION
  	 * @see #FORMATTER_BRACE_POSITION_FOR_METHOD_DECLARATION
+ 	 * @see #FORMATTER_BRACE_POSITION_FOR_RECORD_CONSTRUCTOR
+ 	 * @see #FORMATTER_BRACE_POSITION_FOR_RECORD_DECLARATION
  	 * @see #FORMATTER_BRACE_POSITION_FOR_SWITCH
 	 * @see #FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION
 	 * @see #FORMATTER_BRACE_POSITION_FOR_LAMBDA_BODY
@@ -83,7 +85,7 @@
 	 * @since 3.15
 	 */
 	public static final String FORMATTER_ALIGN_VARIABLE_DECLARATIONS_ON_COLUMNS = JavaCore.PLUGIN_ID + ".formatter.align_variable_declarations_on_columns";	 //$NON-NLS-1$
-	
+
 	/**
 	 * <pre>
 	 * FORMATTER / Option to align assignment statements on column
@@ -96,7 +98,7 @@
 	 * @since 3.15
 	 */
 	public static final String FORMATTER_ALIGN_ASSIGNMENT_STATEMENTS_ON_COLUMNS = JavaCore.PLUGIN_ID + ".formatter.align_assignment_statements_on_columns";	 //$NON-NLS-1$
-	
+
 	/**
 	 * <pre>
 	 * FORMATTER / Option to use spaces when aligning members, independent of selected tabulation character
@@ -285,7 +287,7 @@
 	 *     - possible values:   values returned by <code>createAlignmentValue(boolean, int, int)</code> call
 	 *     - default:           createAlignmentValue(false, WRAP_COMPACT, INDENT_DEFAULT)
 	 * </pre>
-	 * 
+	 *
 	 * @see #createAlignmentValue(boolean, int, int)
 	 * @since 3.0
 	 * @deprecated Use new settings instead: {@link #FORMATTER_ALIGNMENT_FOR_MULTIPLICATIVE_OPERATOR},
@@ -443,6 +445,17 @@
 	public static final String FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_METHOD_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.alignment_for_parameters_in_method_declaration";	 //$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option for alignment of components in record declaration
+	 *     - option id:         "org.eclipse.jdt.core.formatter.alignment_for_record_components"
+	 *     - possible values:   values returned by <code>createAlignmentValue(boolean, int, int)</code> call
+	 *     - default:           createAlignmentValue(false, WRAP_COMPACT, INDENT_DEFAULT)
+	 * </pre>
+	 * @see #createAlignmentValue(boolean, int, int)
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_ALIGNMENT_FOR_RECORD_COMPONENTS = JavaCore.PLUGIN_ID + ".formatter.alignment_for_record_components";	 //$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option for alignment of resources in a try with resources statement
 	 *     - option id:         "org.eclipse.jdt.core.formatter.alignment_for_resources_in_try"
 	 *     - possible values:   values returned by <code>createAlignmentValue(boolean, int, int)</code> call
@@ -487,6 +500,17 @@
 	public static final String FORMATTER_ALIGNMENT_FOR_SUPERINTERFACES_IN_ENUM_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.alignment_for_superinterfaces_in_enum_declaration";	 //$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option for alignment of superinterfaces in record declaration
+	 *     - option id:         "org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration"
+	 *     - possible values:   values returned by <code>createAlignmentValue(boolean, int, int)</code> call
+	 *     - default:           createAlignmentValue(false, WRAP_COMPACT, INDENT_DEFAULT)
+	 * </pre>
+	 * @see #createAlignmentValue(boolean, int, int)
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_ALIGNMENT_FOR_SUPERINTERFACES_IN_RECORD_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.alignment_for_superinterfaces_in_record_declaration";	 //$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option for alignment of superinterfaces in type declaration
 	 *     - option id:         "org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration"
 	 *     - possible values:   values returned by <code>createAlignmentValue(boolean, int, int)</code> call
@@ -924,6 +948,34 @@
 	public static final String FORMATTER_BRACE_POSITION_FOR_METHOD_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.brace_position_for_method_declaration";	//$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to position the braces of a record constructor
+	 *     - option id:         "org.eclipse.jdt.core.formatter.brace_position_for_record_constructor"
+	 *     - possible values:   { END_OF_LINE, NEXT_LINE, NEXT_LINE_SHIFTED, NEXT_LINE_ON_WRAP }
+	 *     - default:           END_OF_LINE
+	 * </pre>
+	 * @see #END_OF_LINE
+	 * @see #NEXT_LINE
+	 * @see #NEXT_LINE_SHIFTED
+	 * @see #NEXT_LINE_ON_WRAP
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_BRACE_POSITION_FOR_RECORD_CONSTRUCTOR = JavaCore.PLUGIN_ID + ".formatter.brace_position_for_record_constructor";	//$NON-NLS-1$
+	/**
+	 * <pre>
+	 * FORMATTER / Option to position the braces of a record declaration
+	 *     - option id:         "org.eclipse.jdt.core.formatter.brace_position_for_record_declaration"
+	 *     - possible values:   { END_OF_LINE, NEXT_LINE, NEXT_LINE_SHIFTED, NEXT_LINE_ON_WRAP }
+	 *     - default:           END_OF_LINE
+	 * </pre>
+	 * @see #END_OF_LINE
+	 * @see #NEXT_LINE
+	 * @see #NEXT_LINE_SHIFTED
+	 * @see #NEXT_LINE_ON_WRAP
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_BRACE_POSITION_FOR_RECORD_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.brace_position_for_record_declaration";	//$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to position the braces of a switch statement
 	 *     - option id:         "org.eclipse.jdt.core.formatter.brace_position_for_switch"
 	 *     - possible values:   { END_OF_LINE, NEXT_LINE, NEXT_LINE_SHIFTED, NEXT_LINE_ON_WRAP }
@@ -1016,6 +1068,22 @@
 
 	/**
 	 * <pre>
+	 * FORMATTER / Option to position parentheses in record declarations
+	 *     - option id:         "org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration"
+	 *     - possible values:   { COMMON_LINES, SEPARATE_LINES_IF_NOT_EMPTY, SEPARATE_LINES_IF_WRAPPED, SEPARATE_LINES, PRESERVE_POSITIONS }
+	 *     - default:           COMMON_LINES
+	 * </pre>
+	 * @see #COMMON_LINES
+	 * @see #SEPARATE_LINES_IF_NOT_EMPTY
+	 * @see #SEPARATE_LINES_IF_WRAPPED
+	 * @see #SEPARATE_LINES
+	 * @see #PRESERVE_POSITIONS
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_PARENTHESES_POSITIONS_IN_RECORD_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.parentheses_positions_in_record_declaration";	//$NON-NLS-1$
+
+	/**
+	 * <pre>
 	 * FORMATTER / Option to position parentheses in 'if' and 'while' statements
 	 *     - option id:         "org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement"
 	 *     - possible values:   { COMMON_LINES, SEPARATE_LINES_IF_WRAPPED, SEPARATE_LINES, PRESERVE_POSITIONS }
@@ -1201,7 +1269,7 @@
 	 * {@link #FORMATTER_COMMENT_FORMAT_LINE_COMMENT} option has been set to
 	 * {@link #FALSE} or the formatter is created with the mode
 	 * {@link ToolFactory#M_FORMAT_NEW}.
-	 * 
+	 *
 	 * @see #TRUE
 	 * @see #FALSE
 	 * @see ToolFactory#createCodeFormatter(Map, int)
@@ -1322,14 +1390,14 @@
 	 *     - possible values:   { TRUE, FALSE }
 	 *     - default:           TRUE
 	 * </pre>
-	 * 
+	 *
 	 * Note that at most one of these options can be set to {@code TRUE}:
 	 * <ul>
 	 * <li>{@code FORMATTER_COMMENT_INDENT_ROOT_TAGS},
 	 * <li>{@code FORMATTER_COMMENT_ALIGN_TAGS_NAMES_DESCRIPTIONS},
 	 * <li>{@code FORMATTER_COMMENT_ALIGN_TAGS_DESCREIPTIONS_GROUPED}.
 	 * </ul>
-	 * 
+	 *
 	 * @see #TRUE
 	 * @see #FALSE
 	 * @see #FORMATTER_COMMENT_ALIGN_TAGS_NAMES_DESCRIPTIONS
@@ -1345,14 +1413,14 @@
 	 *     - possible values:   { TRUE, FALSE }
 	 *     - default:           TRUE
 	 * </pre>
-	 * 
+	 *
 	 * Note that at most one of these options can be set to {@code TRUE}:
 	 * <ul>
 	 * <li>{@code FORMATTER_COMMENT_INDENT_ROOT_TAGS},
 	 * <li>{@code FORMATTER_COMMENT_ALIGN_TAGS_NAMES_DESCRIPTIONS},
 	 * <li>{@code FORMATTER_COMMENT_ALIGN_TAGS_DESCREIPTIONS_GROUPED}.
 	 * </ul>
-	 * 
+	 *
 	 * @see #TRUE
 	 * @see #FALSE
 	 * @see #FORMATTER_COMMENT_INDENT_ROOT_TAGS
@@ -1368,14 +1436,14 @@
 	 *     - possible values:   { TRUE, FALSE }
 	 *     - default:           TRUE
 	 * </pre>
-	 * 
+	 *
 	 * Note that at most one of these options can be set to {@code TRUE}:
 	 * <ul>
 	 * <li>{@code FORMATTER_COMMENT_INDENT_ROOT_TAGS},
 	 * <li>{@code FORMATTER_COMMENT_ALIGN_TAGS_NAMES_DESCRIPTIONS},
 	 * <li>{@code FORMATTER_COMMENT_ALIGN_TAGS_DESCREIPTIONS_GROUPED}.
 	 * </ul>
-	 * 
+	 *
 	 * @see #TRUE
 	 * @see #FALSE
 	 * @see #FORMATTER_COMMENT_INDENT_ROOT_TAGS
@@ -1396,6 +1464,18 @@
 	 * @since 3.1
 	 */
 	public final static String FORMATTER_COMMENT_INSERT_EMPTY_LINE_BEFORE_ROOT_TAGS = "org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags"; //$NON-NLS-1$
+	/**
+	 * <pre>
+	 * FORMATTER / Option to insert an empty line between Javadoc tags of different type
+	 *     - option id:         "org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.20
+	 */
+	public final static String FORMATTER_COMMENT_INSERT_EMPTY_LINE_BETWEEN_DIFFERENT_TAGS = "org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags"; //$NON-NLS-1$
 
 	/**
 	 * <pre>
@@ -1507,14 +1587,14 @@
 	 *     - option id:         "org.eclipse.jdt.core.formatter.disabling_tag"
 	 *     - possible values:   String, with constraints mentioned below
 	 *     - default:           "@formatter:off"
-	 * 
+	 *
 	 * See the {@link #FORMATTER_ENABLING_TAG} option to re-enable it.
 	 * </pre>
-	 * 
+	 *
 	 * <p>
 	 * Note that:
 	 * <ol>
-	 * <li>This tag is used by the formatter only if the 
+	 * <li>This tag is used by the formatter only if the
 	 * {@link #FORMATTER_USE_ON_OFF_TAGS} option is set to {@link #TRUE}.</li>
 	 * <li>The tag name will be trimmed. Hence if it does contain white spaces
 	 * at the beginning or at the end, they will not be taken into account while
@@ -1634,11 +1714,11 @@
 	 *     - possible values:   String, with constraints mentioned below
 	 *     - default:           "@formatter:on"
 	 * </pre>
-	 * 
+	 *
 	 * <p>
 	 * Note that:
 	 * <ol>
-	 * <li>This tag is used by the formatter only if the 
+	 * <li>This tag is used by the formatter only if the
 	 * {@link #FORMATTER_USE_ON_OFF_TAGS} option is set to {@link #TRUE}.</li>
 	 * <li>The tag name will be trimmed. Hence if it does contain white spaces
 	 * at the beginning or at the end, they will not be taken into account while
@@ -1794,6 +1874,18 @@
 	public static final String FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_ENUM_DECLARATION_HEADER = JavaCore.PLUGIN_ID + ".formatter.indent_body_declarations_compare_to_enum_declaration_header";	//$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to indent body declarations compare to its enclosing record header
+	 *     - option id:         "org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header"
+	 *     - possible values:   { TRUE, FALSE }
+	 *     - default:           TRUE
+	 * </pre>
+	 * @see #TRUE
+	 * @see #FALSE
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_RECORD_HEADER = JavaCore.PLUGIN_ID + ".formatter.indent_body_declarations_compare_to_record_header";	//$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to indent body declarations compare to its enclosing type header
 	 *     - option id:         "org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header"
 	 *     - possible values:   { TRUE, FALSE }
@@ -1902,7 +1994,7 @@
 	 * @see #INDENT_BY_ONE
 	 * @see #INDENT_DEFAULT
 	 * @see #INDENT_ON_COLUMN
-	 * @since 3.19
+	 * @since 3.20
 	 */
 	public static final String FORMATTER_TEXT_BLOCK_INDENTATION = JavaCore.PLUGIN_ID + ".formatter.text_block_indentation"; //$NON-NLS-1$
 
@@ -2059,7 +2151,7 @@
 	 * @see JavaCore#DO_NOT_INSERT
 	 * @since 3.6
 	 */
-	public static final String FORMATTER_INSERT_NEW_LINE_AFTER_LABEL = JavaCore.PLUGIN_ID + ".formatter.insert_new_line_after_label";	//$NON-NLS-1$	
+	public static final String FORMATTER_INSERT_NEW_LINE_AFTER_LABEL = JavaCore.PLUGIN_ID + ".formatter.insert_new_line_after_label";	//$NON-NLS-1$
 
 	/**
 	 * <pre>
@@ -2722,6 +2814,18 @@
 	public static final String FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_PARAMETERIZED_TYPE_REFERENCE = JavaCore.PLUGIN_ID + ".formatter.insert_space_after_comma_in_parameterized_type_reference"; //$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to insert a space after comma in record components list
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_RECORD_COMPONENTS = JavaCore.PLUGIN_ID + ".formatter.insert_space_after_comma_in_record_components";	//$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to insert a space after the comma in superinterfaces names of a type header
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -2986,6 +3090,18 @@
 	public static final String FORMATTER_INSERT_SPACE_AFTER_OPENING_PAREN_IN_PARENTHESIZED_EXPRESSION = JavaCore.PLUGIN_ID + ".formatter.insert_space_after_opening_paren_in_parenthesized_expression"; //$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to insert a space after the opening parenthesis in a record declaration
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           DO_NOT_INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_INSERT_SPACE_AFTER_OPENING_PAREN_IN_RECORD_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.insert_space_after_opening_paren_in_record_declaration"; //$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to insert a space after the opening parenthesis in a switch statement
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -3094,7 +3210,7 @@
 	public static final String FORMATTER_INSERT_SPACE_AFTER_SEMICOLON_IN_FOR = JavaCore.PLUGIN_ID + ".formatter.insert_space_after_semicolon_in_for"; //$NON-NLS-1$
 	/**
 	 * <pre>
-	 * FORMATTER / Option to insert a space after semicolons following each resource declaration in a try with 
+	 * FORMATTER / Option to insert a space after semicolons following each resource declaration in a try with
 	 * resources statement
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -3119,6 +3235,18 @@
 	public static final String FORMATTER_INSERT_SPACE_AFTER_UNARY_OPERATOR = JavaCore.PLUGIN_ID + ".formatter.insert_space_after_unary_operator"; //$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to insert a space after 'not' operator
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_after_not_operator"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           DO_NOT_INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.20
+	 */
+	public static final String FORMATTER_INSERT_SPACE_AFTER_NOT_OPERATOR = JavaCore.PLUGIN_ID + ".formatter.insert_space_after_not_operator"; //$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to insert a space before and in wildcard
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -3471,6 +3599,18 @@
 	public static final String FORMATTER_INSERT_SPACE_BEFORE_CLOSING_PAREN_IN_PARENTHESIZED_EXPRESSION = JavaCore.PLUGIN_ID + ".formatter.insert_space_before_closing_paren_in_parenthesized_expression"; //$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to insert a space before the closing parenthesis in a record declaration
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           DO_NOT_INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_INSERT_SPACE_BEFORE_CLOSING_PAREN_IN_RECORD_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.insert_space_before_closing_paren_in_record_declaration";	//$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to insert a space before the closing parenthesis in a switch statement
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -3783,6 +3923,18 @@
 	public static final String FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_PARAMETERIZED_TYPE_REFERENCE = JavaCore.PLUGIN_ID + ".formatter.insert_space_before_comma_in_parameterized_type_reference";	//$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to insert a space before comma in record components list
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           DO_NOT_INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_RECORD_COMPONENTS = JavaCore.PLUGIN_ID + ".formatter.insert_space_before_comma_in_record_components";	//$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to insert a space before comma in the superinterfaces names in a type header
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -3987,6 +4139,30 @@
 	public static final String FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_METHOD_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.insert_space_before_opening_brace_in_method_declaration";	//$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to insert a space before the opening brace in a record constructor
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_RECORD_CONSTRUCTOR = JavaCore.PLUGIN_ID + ".formatter.insert_space_before_opening_brace_in_record_constructor";	//$NON-NLS-1$
+	/**
+	 * <pre>
+	 * FORMATTER / Option to insert a space before the opening brace in a record declaration
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_RECORD_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.insert_space_before_opening_brace_in_record_declaration";	//$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to insert a space before the opening brace in a switch statement
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -4167,6 +4343,18 @@
 	public static final String FORMATTER_INSERT_SPACE_BEFORE_OPENING_PAREN_IN_PARENTHESIZED_EXPRESSION = JavaCore.PLUGIN_ID + ".formatter.insert_space_before_opening_paren_in_parenthesized_expression"; //$NON-NLS-1$
 	/**
 	 * <pre>
+	 * FORMATTER / Option to insert a space before the opening parenthesis in a record declaration
+	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration"
+	 *     - possible values:   { INSERT, DO_NOT_INSERT }
+	 *     - default:           DO_NOT_INSERT
+	 * </pre>
+	 * @see JavaCore#INSERT
+	 * @see JavaCore#DO_NOT_INSERT
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_INSERT_SPACE_BEFORE_OPENING_PAREN_IN_RECORD_DECLARATION = JavaCore.PLUGIN_ID + ".formatter.insert_space_before_opening_paren_in_record_declaration"; //$NON-NLS-1$
+	/**
+	 * <pre>
 	 * FORMATTER / Option to insert a space before the opening parenthesis in a switch statement
 	 *     - option id:         "org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch"
 	 *     - possible values:   { INSERT, DO_NOT_INSERT }
@@ -4706,6 +4894,38 @@
 	 * @since 3.16
 	 */
 	public static final String FORMATTER_KEEP_ANNOTATION_DECLARATION_ON_ONE_LINE = JavaCore.PLUGIN_ID + ".formatter.keep_annotation_declaration_on_one_line"; //$NON-NLS-1$
+	/**
+	 * <pre>
+	 * FORMATTER / Option to control when a record declaration should be kept on one line
+	 *     - option id:         "org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line"
+	 *     - possible values:   { ONE_LINE_NEVER, ONE_LINE_IF_EMPTY, ONE_LINE_IF_SINGLE_ITEM,
+	 *                            ONE_LINE_ALWAYS, ONE_LINE_PRESERVE }
+	 *     - default:           ONE_LINE_NEVER
+	 * </pre>
+	 * @see #ONE_LINE_NEVER
+	 * @see #ONE_LINE_IF_EMPTY
+	 * @see #ONE_LINE_IF_SINGLE_ITEM
+	 * @see #ONE_LINE_ALWAYS
+	 * @see #ONE_LINE_PRESERVE
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_KEEP_RECORD_DECLARATION_ON_ONE_LINE = JavaCore.PLUGIN_ID + ".formatter.keep_record_declaration_on_one_line"; //$NON-NLS-1$
+	/**
+	 * <pre>
+	 * FORMATTER / Option to control when a record constructor should be kept on one line
+	 *     - option id:         "org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line"
+	 *     - possible values:   { ONE_LINE_NEVER, ONE_LINE_IF_EMPTY, ONE_LINE_IF_SINGLE_ITEM,
+	 *                            ONE_LINE_ALWAYS, ONE_LINE_PRESERVE }
+	 *     - default:           ONE_LINE_NEVER
+	 * </pre>
+	 * @see #ONE_LINE_NEVER
+	 * @see #ONE_LINE_IF_EMPTY
+	 * @see #ONE_LINE_IF_SINGLE_ITEM
+	 * @see #ONE_LINE_ALWAYS
+	 * @see #ONE_LINE_PRESERVE
+	 * @since 3.22
+	 */
+	public static final String FORMATTER_KEEP_RECORD_CONSTRUCTOR_ON_ONE_LINE = JavaCore.PLUGIN_ID + ".formatter.keep_record_constructor_on_one_line"; //$NON-NLS-1$
 
 	/**
 	 * <pre>
@@ -4763,7 +4983,7 @@
 	/**
 	 * <pre>
 	 * FORMATTER / Option to specify whether the formatter can join wrapped lines or not
-	 * 
+	 *
 	 * 		For example, the wrapped lines of method foo return statement in following test case:
 	 * 			class X {
 	 * 			String foo() {
@@ -4794,7 +5014,7 @@
 	/**
 	 * <pre>
 	 * FORMATTER / Option to specify whether the formatter can join text lines in comments or not
-	 * 
+	 *
 	 * 		For example, the following comment:
 	 * 			/**
 	 * 			 * The foo method.
@@ -4802,7 +5022,7 @@
 	 * 			 *&#0047;
 	 * 			public class X {
 	 * 			}
-	 * 
+	 *
 	 * 		will be unchanged by the formatter when this new preference is used,
 	 * 		even if the maximum line width would give it enough space to join the lines.
 	 *
@@ -5047,7 +5267,7 @@
 	 * then the preference needs to be set to {@link #FALSE} to retrieve the previous formatter behavior.</li>
 	 * <li>The new strategy currently only applies to nested method calls, but might be extended to other nested expressions in future versions</li>
 	 * </ol>
-	 * 
+	 *
 	 * @see #TRUE
 	 * @see #FALSE
 	 * @since 3.6
@@ -5079,7 +5299,7 @@
 	 * <pre>
 	 * FORMATTER / Indentation is not touched, it's preserved from original source.
 	 * </pre>
-	 * @since 3.19
+	 * @since 3.20
 	 */
 	public static final int INDENT_PRESERVE = 3;
 
@@ -5103,6 +5323,8 @@
 	 * @see #FORMATTER_BRACE_POSITION_FOR_BLOCK
 	 * @see #FORMATTER_BRACE_POSITION_FOR_CONSTRUCTOR_DECLARATION
  	 * @see #FORMATTER_BRACE_POSITION_FOR_METHOD_DECLARATION
+ 	 * @see #FORMATTER_BRACE_POSITION_FOR_RECORD_CONSTRUCTOR
+ 	 * @see #FORMATTER_BRACE_POSITION_FOR_RECORD_DECLARATION
  	 * @see #FORMATTER_BRACE_POSITION_FOR_SWITCH
 	 * @see #FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION
 	 * @see #FORMATTER_BRACE_POSITION_FOR_LAMBDA_BODY
@@ -5119,6 +5341,8 @@
 	 * @see #FORMATTER_BRACE_POSITION_FOR_BLOCK
 	 * @see #FORMATTER_BRACE_POSITION_FOR_CONSTRUCTOR_DECLARATION
  	 * @see #FORMATTER_BRACE_POSITION_FOR_METHOD_DECLARATION
+ 	 * @see #FORMATTER_BRACE_POSITION_FOR_RECORD_CONSTRUCTOR
+ 	 * @see #FORMATTER_BRACE_POSITION_FOR_RECORD_DECLARATION
  	 * @see #FORMATTER_BRACE_POSITION_FOR_SWITCH
 	 * @see #FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION
 	 * @see #FORMATTER_BRACE_POSITION_FOR_LAMBDA_BODY
@@ -5135,6 +5359,8 @@
 	 * @see #FORMATTER_BRACE_POSITION_FOR_BLOCK
 	 * @see #FORMATTER_BRACE_POSITION_FOR_CONSTRUCTOR_DECLARATION
  	 * @see #FORMATTER_BRACE_POSITION_FOR_METHOD_DECLARATION
+ 	 * @see #FORMATTER_BRACE_POSITION_FOR_RECORD_CONSTRUCTOR
+ 	 * @see #FORMATTER_BRACE_POSITION_FOR_RECORD_DECLARATION
  	 * @see #FORMATTER_BRACE_POSITION_FOR_SWITCH
 	 * @see #FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION
 	 * @see #FORMATTER_BRACE_POSITION_FOR_LAMBDA_BODY
@@ -5150,6 +5376,7 @@
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_DECLARATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_INVOCATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_ENUM_CONSTANT_DECLARATION
+	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_RECORD_DECLARATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_IF_WHILE_STATEMENT
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_FOR_STATEMENT
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_SWITCH_STATEMENT
@@ -5169,6 +5396,7 @@
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_DECLARATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_INVOCATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_ENUM_CONSTANT_DECLARATION
+	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_RECORD_DECLARATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_ANNOTATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_LAMBDA_DECLARATION
 	 * @since 3.12
@@ -5183,6 +5411,7 @@
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_DECLARATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_INVOCATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_ENUM_CONSTANT_DECLARATION
+	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_RECORD_DECLARATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_IF_WHILE_STATEMENT
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_FOR_STATEMENT
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_SWITCH_STATEMENT
@@ -5193,7 +5422,7 @@
 	 * @since 3.12
 	 */
 	public static final String SEPARATE_LINES_IF_WRAPPED = "separate_lines_if_wrapped";	//$NON-NLS-1$
-	
+
 	/**
 	 * <pre>
 	 * FORMATTER / Value to set parentheses location on separate lines from their contents,
@@ -5203,6 +5432,7 @@
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_DECLARATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_INVOCATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_ENUM_CONSTANT_DECLARATION
+	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_RECORD_DECLARATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_IF_WHILE_STATEMENT
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_FOR_STATEMENT
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_SWITCH_STATEMENT
@@ -5222,6 +5452,7 @@
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_DECLARATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_INVOCATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_ENUM_CONSTANT_DECLARATION
+	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_RECORD_DECLARATION
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_IF_WHILE_STATEMENT
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_FOR_STATEMENT
 	 * @see #FORMATTER_PARENTHESES_POSITIONS_IN_SWITCH_STATEMENT
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/IndentManipulation.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/IndentManipulation.java
index 004f627..791bc44 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/IndentManipulation.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/IndentManipulation.java
@@ -17,7 +17,6 @@
 import java.util.Arrays;
 import java.util.Map;
 
-import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
 import org.eclipse.jdt.internal.compiler.util.Util;
 import org.eclipse.jface.text.BadLocationException;
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java
index 85d047e..ac03d5f 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CommentsPreparator.java
@@ -33,7 +33,7 @@
 import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-
+import java.util.stream.Collectors;
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.ASTVisitor;
 import org.eclipse.jdt.core.dom.BlockComment;
@@ -109,7 +109,7 @@
 	private int noFormatTagOpenStart = -1;
 	private int formatCodeTagOpenEnd = -1;
 	private int lastFormatCodeClosingTagIndex = -1;
-	private Token firstTagToken;
+	private ArrayList<Integer> commonAttributeAnnotations = new ArrayList<Integer>();
 	private DefaultCodeFormatter commentCodeFormatter;
 
 	public CommentsPreparator(TokenManager tm, DefaultCodeFormatterOptions options, String sourceLevel) {
@@ -536,7 +536,7 @@
 		this.noFormatTagOpenStart = -1;
 		this.formatCodeTagOpenEnd = -1;
 		this.lastFormatCodeClosingTagIndex = -1;
-		this.firstTagToken = null;
+		this.commonAttributeAnnotations.clear();
 		this.ctm = null;
 
 		int commentIndex = this.tm.firstIndexIn(node, TokenNameCOMMENT_JAVADOC);
@@ -564,6 +564,7 @@
 		this.ctm = new TokenManager(commentToken.getInternalStructure(), this.tm);
 
 		handleJavadocTagAlignment(node);
+		handleJavadocBlankLines(node);
 
 		return true;
 	}
@@ -572,10 +573,6 @@
 	public void endVisit(Javadoc node) {
 		if (this.ctm == null)
 			return;
-		if (this.options.comment_insert_empty_line_before_root_tags && this.firstTagToken != null
-				&& this.ctm.indexOf(this.firstTagToken) > 1) {
-			this.firstTagToken.putLineBreaksBefore(2);
-		}
 		addSubstituteWraps();
 	}
 
@@ -599,10 +596,6 @@
 			Token startTokeen = this.ctm.get(startIndex);
 			if (startIndex > 1)
 				startTokeen.breakBefore();
-			int firstTagIndex;
-			if (this.firstTagToken == null || (firstTagIndex = this.ctm.indexOf(this.firstTagToken)) < 0
-					|| startIndex < firstTagIndex)
-				this.firstTagToken = startTokeen;
 
 			handleHtml(node);
 		}
@@ -648,7 +641,7 @@
 			}
 			javadocRootTags.add(tagTokens);
 		}
-		
+
 		if (this.options.comment_align_tags_names_descriptions) {
 			int maxTagNameLength = 0;
 			int maxParamNameLength = 0;
@@ -698,6 +691,35 @@
 		}
 	}
 
+	private void handleJavadocBlankLines(Javadoc node) {
+		List<TagElement> tagElements = node.tags();
+		List<Integer> tagIndexes = tagElements.stream()
+				.filter(t -> !t.isNested() && t.getTagName() != null && t.getTagName().length() > 1)
+				.map(t -> tokenStartingAt(t.getStartPosition()))
+				.collect(Collectors.toList());
+		tagIndexes.addAll(this.commonAttributeAnnotations);
+		Collections.sort(tagIndexes);
+
+		String previousName = null;
+		if (!tagIndexes.isEmpty()) {
+			int firstIndex = tagIndexes.get(0);
+			previousName = this.ctm.toString(firstIndex);
+			if (this.options.comment_insert_empty_line_before_root_tags && firstIndex > 1)
+				this.ctm.get(firstIndex).putLineBreaksBefore(2);
+		}
+		if (this.options.comment_insert_empty_line_between_different_tags) {
+			for (int i = 1; i < tagIndexes.size(); i++) {
+				Token tagToken = this.ctm.get(tagIndexes.get(i));
+				String thisName = this.tm.toString(tagToken);
+				boolean sameType = previousName.equals(thisName)
+						|| (isCommonsAttributeAnnotation(previousName) && isCommonsAttributeAnnotation(thisName));
+				if (!sameType)
+					tagToken.putLineBreaksBefore(2);
+				previousName = thisName;
+			}
+		}
+	}
+
 	private void alignJavadocTag(List<Token> tagTokens, int paramNameAlign, int descriptionAlign) {
 		Token paramName = tagTokens.get(1);
 		if (paramName != null) {
@@ -1066,11 +1088,12 @@
 						if (this.tm.charAt(tokenStart) == '@') {
 							outputToken.setWrapPolicy(WrapPolicy.DISABLE_WRAP);
 							if (commentToken.tokenType == TokenNameCOMMENT_BLOCK && lineBreaks == 1
-									&& structure.size() > 1)
+									&& structure.size() > 1) {
 								outputToken.putLineBreaksBefore(cleanBlankLines ? 1 : 2);
-							if (this.tm.charAt(tokenStart + 1) == '@' && lineBreaks > 0 && this.firstTagToken == null) {
-								// Commons Attributes annotation, see bug 237051
-								this.firstTagToken = outputToken;
+							}
+							if (lineBreaks > 0 && isCommonsAttributeAnnotation(this.tm.toString(outputToken))) {
+								outputToken.breakBefore();
+								this.commonAttributeAnnotations.add(structure.size());
 							}
 						}
 						structure.add(outputToken);
@@ -1103,6 +1126,10 @@
 		return true;
 	}
 
+	private boolean isCommonsAttributeAnnotation(String tokenContent) {
+		return tokenContent.startsWith("@@"); //$NON-NLS-1$
+	}
+
 	private void noSubstituteWrapping(int from, int to) {
 		int commentStart = this.ctm.get(0).originalStart;
 		assert commentStart <= from && from <= to && to <= this.ctm.get(this.ctm.size() - 1).originalEnd;
@@ -1157,7 +1184,7 @@
 		for (Token token : formattedTokens)
 			token.setAlign(token.getAlign() + openingToken.getAlign() + openingToken.getIndent());
 		fixJavadocTagAlign(openingToken, closingTagFirstIndex);
-		
+
 		// there are too few linebreaks at the start and end
 		Token start = formattedTokens.get(0);
 		start.putLineBreaksBefore(start.getLineBreaksBefore() + 1);
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 bfa9414..5afa975 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
@@ -127,14 +127,14 @@
 			this.workingOptions = new DefaultCodeFormatterOptions(options);
 			this.oldCommentFormatOption = getOldCommentFormatOption(options);
 			String compilerSource = options.get(CompilerOptions.OPTION_Source);
-			this.sourceLevel = compilerSource != null ? compilerSource : CompilerOptions.VERSION_13;
+			this.sourceLevel = compilerSource != null ? compilerSource : CompilerOptions.VERSION_14;
 			this.previewEnabled = JavaCore.ENABLED.equals(options.get(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES));
 		} else {
 			Map<String, String> settings = DefaultCodeFormatterConstants.getJavaConventionsSettings();
 			this.originalOptions = new DefaultCodeFormatterOptions(settings);
 			this.workingOptions = new DefaultCodeFormatterOptions(settings);
 			this.oldCommentFormatOption = DefaultCodeFormatterConstants.TRUE;
-			this.sourceLevel = CompilerOptions.VERSION_13;
+			this.sourceLevel = CompilerOptions.VERSION_14;
 		}
 		if (defaultCodeFormatterOptions != null) {
 			this.originalOptions.set(defaultCodeFormatterOptions.getMap());
@@ -325,7 +325,7 @@
 		for (int kindToTry : kindsToTry) {
 			ASTNode astNode = createParser(kindToTry).createAST(null);
 			if (!hasErrors(astNode)) {
-				if (kindToTry == K_MODULE_INFO) 
+				if (kindToTry == K_MODULE_INFO)
 					tokenizeSource(kindToTry); // run scanner again to get module specific tokens
 				return astNode;
 			}
@@ -334,7 +334,7 @@
 	}
 
 	private ASTParser createParser(int kind) {
-		ASTParser parser = ASTParser.newParser(AST.JLS13);
+		ASTParser parser = ASTParser.newParser(AST.JLS14);
 
 		if (kind == K_MODULE_INFO) {
 			parser.setSource(createDummyModuleInfoCompilationUnit());
@@ -416,7 +416,7 @@
 	private void prepareLineBreaks() {
 		LineBreaksPreparator breaksPreparator = new LineBreaksPreparator(this.tokenManager, this.workingOptions);
 		this.astRoot.accept(breaksPreparator);
-		breaksPreparator.finishUp();
+		breaksPreparator.finishUp(this.formatRegions);
 		this.astRoot.accept(new OneLineEnforcer(this.tokenManager, this.workingOptions));
 	}
 
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
index 1828844..0cb87ac 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatterOptions.java
@@ -147,9 +147,11 @@
 	public int alignment_for_parameterized_type_references;
 	public int alignment_for_parameters_in_constructor_declaration;
 	public int alignment_for_parameters_in_method_declaration;
+	public int alignment_for_record_components;
 	public int alignment_for_selector_in_method_invocation;
 	public int alignment_for_superclass_in_type_declaration;
 	public int alignment_for_superinterfaces_in_enum_declaration;
+	public int alignment_for_superinterfaces_in_record_declaration;
 	public int alignment_for_superinterfaces_in_type_declaration;
 	public int alignment_for_throws_clause_in_constructor_declaration;
 	public int alignment_for_throws_clause_in_method_declaration;
@@ -175,11 +177,14 @@
 	public String brace_position_for_lambda_body;
 	public String brace_position_for_method_declaration;
 	public String brace_position_for_type_declaration;
+	public String brace_position_for_record_constructor;
+	public String brace_position_for_record_declaration;
 	public String brace_position_for_switch;
 
 	public String parenthesis_positions_in_method_declaration;
 	public String parenthesis_positions_in_method_invocation;
 	public String parenthesis_positions_in_enum_constant_declaration;
+	public String parenthesis_positions_in_record_declaration;
 	public String parenthesis_positions_in_if_while_statement;
 	public String parenthesis_positions_in_for_statement;
 	public String parenthesis_positions_in_switch_statement;
@@ -229,6 +234,7 @@
 	public boolean comment_align_tags_names_descriptions;
 	public boolean comment_align_tags_descriptions_grouped;
 	public boolean comment_insert_empty_line_before_root_tags;
+	public boolean comment_insert_empty_line_between_different_tags;
 	public boolean comment_insert_new_line_for_parameter;
 	public boolean comment_preserve_white_space_between_code_and_line_comments;
 	public int comment_line_length;
@@ -245,6 +251,7 @@
 	public boolean indent_body_declarations_compare_to_annotation_declaration_header;
 	public boolean indent_body_declarations_compare_to_enum_constant_header;
 	public boolean indent_body_declarations_compare_to_enum_declaration_header;
+	public boolean indent_body_declarations_compare_to_record_header;
 	public boolean indent_body_declarations_compare_to_type_header;
 	public boolean indent_breaks_compare_to_cases;
 	public boolean indent_empty_lines;
@@ -279,6 +286,8 @@
 	public String keep_enum_declaration_on_one_line;
 	public String keep_enum_constant_declaration_on_one_line;
 	public String keep_annotation_declaration_on_one_line;
+	public String keep_record_declaration_on_one_line;
+	public String keep_record_constructor_on_one_line;
 	public boolean keep_simple_getter_setter_on_one_line;
 
 	public boolean insert_space_after_and_in_type_parameter;
@@ -320,12 +329,14 @@
 	public boolean insert_space_after_comma_in_multiple_field_declarations;
 	public boolean insert_space_after_comma_in_multiple_local_declarations;
 	public boolean insert_space_after_comma_in_parameterized_type_reference;
+	public boolean insert_space_after_comma_in_record_components;
 	public boolean insert_space_after_comma_in_superinterfaces;
 	public boolean insert_space_after_comma_in_switch_case_expressions;
 	public boolean insert_space_after_comma_in_type_arguments;
 	public boolean insert_space_after_comma_in_type_parameters;
 	public boolean insert_space_after_ellipsis;
 	public boolean insert_space_after_lambda_arrow;
+	public boolean insert_space_after_not_operator;
 	public boolean insert_space_after_opening_angle_bracket_in_parameterized_type_reference;
 	public boolean insert_space_after_opening_angle_bracket_in_type_arguments;
 	public boolean insert_space_after_opening_angle_bracket_in_type_parameters;
@@ -342,6 +353,7 @@
 	public boolean insert_space_after_opening_paren_in_method_declaration;
 	public boolean insert_space_after_opening_paren_in_method_invocation;
 	public boolean insert_space_after_opening_paren_in_parenthesized_expression;
+	public boolean insert_space_after_opening_paren_in_record_declaration;
 	public boolean insert_space_after_opening_paren_in_switch;
 	public boolean insert_space_after_opening_paren_in_synchronized;
 	public boolean insert_space_after_opening_paren_in_try;
@@ -381,6 +393,7 @@
 	public boolean insert_space_before_closing_paren_in_method_declaration;
 	public boolean insert_space_before_closing_paren_in_method_invocation;
 	public boolean insert_space_before_closing_paren_in_parenthesized_expression;
+	public boolean insert_space_before_closing_paren_in_record_declaration;
 	public boolean insert_space_before_closing_paren_in_switch;
 	public boolean insert_space_before_closing_paren_in_synchronized;
 	public boolean insert_space_before_closing_paren_in_try;
@@ -407,6 +420,7 @@
 	public boolean insert_space_before_comma_in_multiple_field_declarations;
 	public boolean insert_space_before_comma_in_multiple_local_declarations;
 	public boolean insert_space_before_comma_in_parameterized_type_reference;
+	public boolean insert_space_before_comma_in_record_components;
 	public boolean insert_space_before_comma_in_superinterfaces;
 	public boolean insert_space_before_comma_in_switch_case_expressions;
 	public boolean insert_space_before_comma_in_type_arguments;
@@ -427,6 +441,8 @@
 	public boolean insert_space_before_opening_brace_in_enum_constant;
 	public boolean insert_space_before_opening_brace_in_enum_declaration;
 	public boolean insert_space_before_opening_brace_in_method_declaration;
+	public boolean insert_space_before_opening_brace_in_record_constructor;
+	public boolean insert_space_before_opening_brace_in_record_declaration;
 	public boolean insert_space_before_opening_brace_in_type_declaration;
 	public boolean insert_space_before_opening_bracket_in_array_allocation_expression;
 	public boolean insert_space_before_opening_bracket_in_array_reference;
@@ -440,6 +456,7 @@
 	public boolean insert_space_before_opening_paren_in_if;
 	public boolean insert_space_before_opening_paren_in_method_invocation;
 	public boolean insert_space_before_opening_paren_in_method_declaration;
+	public boolean insert_space_before_opening_paren_in_record_declaration;
 	public boolean insert_space_before_opening_paren_in_switch;
 	public boolean insert_space_before_opening_paren_in_try;
 	public boolean insert_space_before_opening_brace_in_switch;
@@ -503,6 +520,20 @@
 			DefaultCodeFormatterConstants.ONE_LINE_ALWAYS,
 			DefaultCodeFormatterConstants.ONE_LINE_PRESERVE);
 
+	private final static List<String> BRACE_POSITION_VALUES = Arrays.asList(
+			DefaultCodeFormatterConstants.END_OF_LINE,
+			DefaultCodeFormatterConstants.NEXT_LINE,
+			DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED,
+			DefaultCodeFormatterConstants.NEXT_LINE_ON_WRAP);
+
+	private final static List<String> PARENTHESIS_POSITION_VALUES = Arrays.asList(
+			DefaultCodeFormatterConstants.COMMON_LINES,
+			DefaultCodeFormatterConstants.SEPARATE_LINES_IF_NOT_EMPTY,
+			DefaultCodeFormatterConstants.SEPARATE_LINES_IF_WRAPPED,
+			DefaultCodeFormatterConstants.SEPARATE_LINES,
+			DefaultCodeFormatterConstants.SEPARATE_LINES,
+			DefaultCodeFormatterConstants.PRESERVE_POSITIONS);
+
 	private DefaultCodeFormatterOptions() {
 		// cannot be instantiated
 	}
@@ -546,10 +577,12 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERIZED_TYPE_REFERENCES, getAlignment(this.alignment_for_parameterized_type_references));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_CONSTRUCTOR_DECLARATION, getAlignment(this.alignment_for_parameters_in_constructor_declaration));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERS_IN_METHOD_DECLARATION, getAlignment(this.alignment_for_parameters_in_method_declaration));
+		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_RECORD_COMPONENTS, getAlignment(this.alignment_for_record_components));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_RESOURCES_IN_TRY, getAlignment(this.alignment_for_resources_in_try));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SELECTOR_IN_METHOD_INVOCATION, getAlignment(this.alignment_for_selector_in_method_invocation));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SUPERCLASS_IN_TYPE_DECLARATION, getAlignment(this.alignment_for_superclass_in_type_declaration));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SUPERINTERFACES_IN_ENUM_DECLARATION, getAlignment(this.alignment_for_superinterfaces_in_enum_declaration));
+		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SUPERINTERFACES_IN_RECORD_DECLARATION, getAlignment(this.alignment_for_superinterfaces_in_record_declaration));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SUPERINTERFACES_IN_TYPE_DECLARATION, getAlignment(this.alignment_for_superinterfaces_in_type_declaration));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_THROWS_CLAUSE_IN_CONSTRUCTOR_DECLARATION, getAlignment(this.alignment_for_throws_clause_in_constructor_declaration));
 		options.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_THROWS_CLAUSE_IN_METHOD_DECLARATION, getAlignment(this.alignment_for_throws_clause_in_method_declaration));
@@ -572,10 +605,13 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_METHOD_DECLARATION, this.brace_position_for_method_declaration);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION, this.brace_position_for_type_declaration);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_LAMBDA_BODY, this.brace_position_for_lambda_body);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_RECORD_CONSTRUCTOR, this.brace_position_for_record_constructor);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_RECORD_DECLARATION, this.brace_position_for_record_declaration);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_SWITCH, this.brace_position_for_switch);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_DECLARATION, this.parenthesis_positions_in_method_declaration);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_PARENTHESES_POSITIONS_IN_METHOD_INVOCATION, this.parenthesis_positions_in_method_invocation);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_PARENTHESES_POSITIONS_IN_ENUM_CONSTANT_DECLARATION, this.parenthesis_positions_in_enum_constant_declaration);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_PARENTHESES_POSITIONS_IN_RECORD_DECLARATION, this.parenthesis_positions_in_record_declaration);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_PARENTHESES_POSITIONS_IN_IF_WHILE_STATEMENT, this.parenthesis_positions_in_if_while_statement);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_PARENTHESES_POSITIONS_IN_FOR_STATEMENT, this.parenthesis_positions_in_for_statement);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_PARENTHESES_POSITIONS_IN_SWITCH_STATEMENT, this.parenthesis_positions_in_switch_statement);
@@ -600,6 +636,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_ALIGN_TAGS_NAMES_DESCRIPTIONS, this.comment_align_tags_names_descriptions ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_ALIGN_TAGS_DESCREIPTIONS_GROUPED, this.comment_align_tags_descriptions_grouped ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_INSERT_EMPTY_LINE_BEFORE_ROOT_TAGS, this.comment_insert_empty_line_before_root_tags ? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_INSERT_EMPTY_LINE_BETWEEN_DIFFERENT_TAGS, this.comment_insert_empty_line_between_different_tags ? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_INSERT_NEW_LINE_FOR_PARAMETER, this.comment_insert_new_line_for_parameter ? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_PRESERVE_WHITE_SPACE_BETWEEN_CODE_AND_LINE_COMMENT, this.comment_preserve_white_space_between_code_and_line_comments ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_LINE_LENGTH, Integer.toString(this.comment_line_length));
@@ -631,6 +668,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_ANNOTATION_DECLARATION_HEADER, this.indent_body_declarations_compare_to_annotation_declaration_header ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_ENUM_CONSTANT_HEADER, this.indent_body_declarations_compare_to_enum_constant_header ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_ENUM_DECLARATION_HEADER, this.indent_body_declarations_compare_to_enum_declaration_header ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_RECORD_HEADER, this.indent_body_declarations_compare_to_record_header ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_TYPE_HEADER, this.indent_body_declarations_compare_to_type_header ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BREAKS_COMPARE_TO_CASES, this.indent_breaks_compare_to_cases ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_EMPTY_LINES, this.indent_empty_lines ? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
@@ -662,6 +700,8 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_ENUM_DECLARATION_ON_ONE_LINE, this.keep_enum_declaration_on_one_line);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_METHOD_BODY_ON_ONE_LINE, this.keep_method_body_on_one_line);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_TYPE_DECLARATION_ON_ONE_LINE, this.keep_type_declaration_on_one_line);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_RECORD_DECLARATION_ON_ONE_LINE, this.keep_record_declaration_on_one_line);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_RECORD_CONSTRUCTOR_ON_ONE_LINE, this.keep_record_constructor_on_one_line);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_KEEP_SIMPLE_GETTER_SETTER_ON_ONE_LINE, this.keep_simple_getter_setter_on_one_line? DefaultCodeFormatterConstants.TRUE : DefaultCodeFormatterConstants.FALSE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_LABEL, this.insert_new_line_after_label? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_AND_IN_TYPE_PARAMETER, this.insert_space_after_and_in_type_parameter? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
@@ -702,6 +742,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_MULTIPLE_FIELD_DECLARATIONS, this.insert_space_after_comma_in_multiple_field_declarations? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_MULTIPLE_LOCAL_DECLARATIONS, this.insert_space_after_comma_in_multiple_local_declarations? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_PARAMETERIZED_TYPE_REFERENCE, this.insert_space_after_comma_in_parameterized_type_reference? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_RECORD_COMPONENTS, this.insert_space_after_comma_in_record_components? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_SUPERINTERFACES, this.insert_space_after_comma_in_superinterfaces? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_SWITCH_CASE_EXPRESSIONS, this.insert_space_after_comma_in_switch_case_expressions ? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_TYPE_ARGUMENTS, this.insert_space_after_comma_in_type_arguments ? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
@@ -709,6 +750,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_BRACKET_IN_ARRAY_ALLOCATION_EXPRESSION, this.insert_space_after_opening_bracket_in_array_allocation_expression? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_ELLIPSIS, this.insert_space_after_ellipsis ? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_LAMBDA_ARROW, this.insert_space_after_lambda_arrow ? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_NOT_OPERATOR, this.insert_space_after_not_operator? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_ANGLE_BRACKET_IN_PARAMETERIZED_TYPE_REFERENCE, this.insert_space_after_opening_angle_bracket_in_parameterized_type_reference? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_ANGLE_BRACKET_IN_TYPE_ARGUMENTS, this.insert_space_after_opening_angle_bracket_in_type_arguments? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_ANGLE_BRACKET_IN_TYPE_PARAMETERS, this.insert_space_after_opening_angle_bracket_in_type_parameters? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
@@ -724,6 +766,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_PAREN_IN_METHOD_DECLARATION, this.insert_space_after_opening_paren_in_method_declaration? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_PAREN_IN_METHOD_INVOCATION, this.insert_space_after_opening_paren_in_method_invocation? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_PAREN_IN_PARENTHESIZED_EXPRESSION, this.insert_space_after_opening_paren_in_parenthesized_expression? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_PAREN_IN_RECORD_DECLARATION, this.insert_space_after_opening_paren_in_record_declaration? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_PAREN_IN_SWITCH, this.insert_space_after_opening_paren_in_switch? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_PAREN_IN_SYNCHRONIZED, this.insert_space_after_opening_paren_in_synchronized? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_PAREN_IN_TRY, this.insert_space_after_opening_paren_in_try? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
@@ -763,6 +806,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_PAREN_IN_METHOD_DECLARATION, this.insert_space_before_closing_paren_in_method_declaration? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_PAREN_IN_METHOD_INVOCATION, this.insert_space_before_closing_paren_in_method_invocation? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_PAREN_IN_PARENTHESIZED_EXPRESSION, this.insert_space_before_closing_paren_in_parenthesized_expression? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_PAREN_IN_RECORD_DECLARATION, this.insert_space_before_closing_paren_in_record_declaration? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_PAREN_IN_SWITCH, this.insert_space_before_closing_paren_in_switch? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_PAREN_IN_SYNCHRONIZED, this.insert_space_before_closing_paren_in_synchronized? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_PAREN_IN_TRY, this.insert_space_before_closing_paren_in_try? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
@@ -788,6 +832,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_METHOD_DECLARATION_THROWS, this.insert_space_before_comma_in_method_declaration_throws? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_MULTIPLE_FIELD_DECLARATIONS, this.insert_space_before_comma_in_multiple_field_declarations? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_MULTIPLE_LOCAL_DECLARATIONS, this.insert_space_before_comma_in_multiple_local_declarations? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_RECORD_COMPONENTS, this.insert_space_before_comma_in_record_components? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_SUPERINTERFACES, this.insert_space_before_comma_in_superinterfaces? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_SWITCH_CASE_EXPRESSIONS, this.insert_space_before_comma_in_switch_case_expressions? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_TYPE_ARGUMENTS, this.insert_space_before_comma_in_type_arguments ? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
@@ -806,6 +851,8 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_ENUM_CONSTANT, this.insert_space_before_opening_brace_in_enum_constant? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_ENUM_DECLARATION, this.insert_space_before_opening_brace_in_enum_declaration? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_METHOD_DECLARATION, this.insert_space_before_opening_brace_in_method_declaration? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_RECORD_CONSTRUCTOR, this.insert_space_before_opening_brace_in_record_constructor? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_RECORD_DECLARATION, this.insert_space_before_opening_brace_in_record_declaration? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_TYPE_DECLARATION, this.insert_space_before_opening_brace_in_type_declaration? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACKET_IN_ARRAY_ALLOCATION_EXPRESSION, this.insert_space_before_opening_bracket_in_array_allocation_expression ? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACKET_IN_ARRAY_REFERENCE, this.insert_space_before_opening_bracket_in_array_reference? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
@@ -819,6 +866,7 @@
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_PAREN_IN_IF, this.insert_space_before_opening_paren_in_if? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_PAREN_IN_METHOD_INVOCATION, this.insert_space_before_opening_paren_in_method_invocation? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_PAREN_IN_METHOD_DECLARATION, this.insert_space_before_opening_paren_in_method_declaration? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
+		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_PAREN_IN_RECORD_DECLARATION, this.insert_space_before_opening_paren_in_record_declaration? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_PAREN_IN_SWITCH, this.insert_space_before_opening_paren_in_switch? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_SWITCH, this.insert_space_before_opening_brace_in_switch? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_PAREN_IN_SYNCHRONIZED, this.insert_space_before_opening_paren_in_synchronized? JavaCore.INSERT : JavaCore.DO_NOT_INSERT);
@@ -1062,6 +1110,8 @@
 				this.alignment_for_parameters_in_method_declaration = Alignment.M_COMPACT_SPLIT;
 			}
 		}
+		setInt(settings, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_RECORD_COMPONENTS,
+				v -> this.alignment_for_record_components = v);
 		final Object alignmentForResourcesInTry = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_RESOURCES_IN_TRY);
 		if (alignmentForResourcesInTry != null) {
 			try {
@@ -1094,6 +1144,8 @@
 				this.alignment_for_superinterfaces_in_enum_declaration = Alignment.M_NEXT_SHIFTED_SPLIT;
 			}
 		}
+		setInt(settings, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SUPERINTERFACES_IN_RECORD_DECLARATION,
+				v -> this.alignment_for_superinterfaces_in_record_declaration = v);
 		final Object alignmentForSuperinterfacesInTypeDeclarationOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SUPERINTERFACES_IN_TYPE_DECLARATION);
 		if (alignmentForSuperinterfacesInTypeDeclarationOption != null) {
 			try {
@@ -1238,6 +1290,10 @@
 				this.brace_position_for_method_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 			}
 		}
+		setString(settings, DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_RECORD_CONSTRUCTOR, BRACE_POSITION_VALUES,
+				v -> this.brace_position_for_record_constructor = v);
+		setString(settings, DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_RECORD_DECLARATION, BRACE_POSITION_VALUES,
+				v -> this.brace_position_for_record_declaration = v);
 		final Object bracePositionForSwitchOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_SWITCH);
 		if (bracePositionForSwitchOption != null) {
 			try {
@@ -1267,6 +1323,8 @@
 		if (closingParenPositionInEnumConstantDeclaration != null) {
 			this.parenthesis_positions_in_enum_constant_declaration = toString(closingParenPositionInEnumConstantDeclaration, DefaultCodeFormatterConstants.COMMON_LINES);
 		}
+		setString(settings, DefaultCodeFormatterConstants.FORMATTER_PARENTHESES_POSITIONS_IN_RECORD_DECLARATION, PARENTHESIS_POSITION_VALUES,
+			v -> this.parenthesis_positions_in_record_declaration = v);
 		final Object closingParenPositionInIfWhileStatement = settings.get(DefaultCodeFormatterConstants.FORMATTER_PARENTHESES_POSITIONS_IN_IF_WHILE_STATEMENT);
 		if (closingParenPositionInIfWhileStatement != null) {
 			this.parenthesis_positions_in_if_while_statement = toString(closingParenPositionInIfWhileStatement, DefaultCodeFormatterConstants.COMMON_LINES);
@@ -1479,6 +1537,8 @@
 		if (commentInsertEmptyLineBeforeRootTagsOption != null) {
 			this.comment_insert_empty_line_before_root_tags = JavaCore.INSERT.equals(commentInsertEmptyLineBeforeRootTagsOption);
 		}
+		setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_COMMENT_INSERT_EMPTY_LINE_BETWEEN_DIFFERENT_TAGS, JavaCore.INSERT,
+				v -> this.comment_insert_empty_line_between_different_tags = v);
 		final Object commentInsertNewLineForParameterOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_COMMENT_INSERT_NEW_LINE_FOR_PARAMETER);
 		if (commentInsertNewLineForParameterOption != null) {
 			this.comment_insert_new_line_for_parameter = JavaCore.INSERT.equals(commentInsertNewLineForParameterOption);
@@ -1515,6 +1575,8 @@
 		if (indentStatementsCompareToBodyOption != null) {
 			this.indent_statements_compare_to_body = DefaultCodeFormatterConstants.TRUE.equals(indentStatementsCompareToBodyOption);
 		}
+		setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_RECORD_HEADER, DefaultCodeFormatterConstants.TRUE,
+			v -> this.indent_body_declarations_compare_to_record_header = v);
 		final Object indentBodyDeclarationsCompareToAnnotationDeclarationHeaderOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_ANNOTATION_DECLARATION_HEADER);
 		if (indentBodyDeclarationsCompareToAnnotationDeclarationHeaderOption != null) {
 			this.indent_body_declarations_compare_to_annotation_declaration_header = DefaultCodeFormatterConstants.TRUE.equals(indentBodyDeclarationsCompareToAnnotationDeclarationHeaderOption);
@@ -1589,7 +1651,7 @@
 		if (insertNewLineBeforeWhileInDoStatementOption != null) {
 			this.insert_new_line_before_while_in_do_statement = JavaCore.INSERT.equals(insertNewLineBeforeWhileInDoStatementOption);
 		}
-		
+
 		setString(settings, DefaultCodeFormatterConstants.FORMATTER_KEEP_ANNOTATION_DECLARATION_ON_ONE_LINE, KEEP_ON_ONE_LINE_VALUES,
 				v -> this.keep_annotation_declaration_on_one_line = v);
 		setString(settings, DefaultCodeFormatterConstants.FORMATTER_KEEP_ANONYMOUS_TYPE_DECLARATION_ON_ONE_LINE, KEEP_ON_ONE_LINE_VALUES,
@@ -1611,6 +1673,10 @@
 				v -> this.keep_method_body_on_one_line = v);
 		setString(settings, DefaultCodeFormatterConstants.FORMATTER_KEEP_TYPE_DECLARATION_ON_ONE_LINE, KEEP_ON_ONE_LINE_VALUES,
 				v -> this.keep_type_declaration_on_one_line = v);
+		setString(settings, DefaultCodeFormatterConstants.FORMATTER_KEEP_RECORD_DECLARATION_ON_ONE_LINE, KEEP_ON_ONE_LINE_VALUES,
+				v -> this.keep_record_declaration_on_one_line = v);
+		setString(settings, DefaultCodeFormatterConstants.FORMATTER_KEEP_RECORD_CONSTRUCTOR_ON_ONE_LINE, KEEP_ON_ONE_LINE_VALUES,
+				v -> this.keep_record_constructor_on_one_line = v);
 		setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_KEEP_SIMPLE_GETTER_SETTER_ON_ONE_LINE, DefaultCodeFormatterConstants.TRUE,
 				v -> this.keep_simple_getter_setter_on_one_line = v);
 
@@ -1752,6 +1818,8 @@
 		if (insertSpaceAfterCommaInParameterizedTypeReferenceOption != null) {
 			this.insert_space_after_comma_in_parameterized_type_reference = JavaCore.INSERT.equals(insertSpaceAfterCommaInParameterizedTypeReferenceOption);
 		}
+		setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_RECORD_COMPONENTS, JavaCore.INSERT,
+				v -> this.insert_space_after_comma_in_record_components = v);
 		final Object insertSpaceAfterCommaInSuperinterfacesOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_SUPERINTERFACES);
 		if (insertSpaceAfterCommaInSuperinterfacesOption != null) {
 			this.insert_space_after_comma_in_superinterfaces = JavaCore.INSERT.equals(insertSpaceAfterCommaInSuperinterfacesOption);
@@ -1774,6 +1842,8 @@
 		if (insertSpaceAfterLambdaArrowOption != null) {
 			this.insert_space_after_lambda_arrow = JavaCore.INSERT.equals(insertSpaceAfterLambdaArrowOption);
 		}
+		setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_NOT_OPERATOR, JavaCore.INSERT,
+				v -> this.insert_space_after_not_operator = v);
 		final Object insertSpaceAfterOpeningAngleBracketInParameterizedTypeReferenceOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_ANGLE_BRACKET_IN_PARAMETERIZED_TYPE_REFERENCE);
 		if (insertSpaceAfterOpeningAngleBracketInParameterizedTypeReferenceOption != null) {
 			this.insert_space_after_opening_angle_bracket_in_parameterized_type_reference = JavaCore.INSERT.equals(insertSpaceAfterOpeningAngleBracketInParameterizedTypeReferenceOption);
@@ -1838,6 +1908,8 @@
 		if (insertSpaceAfterOpeningParenInParenthesizedExpressionOption != null) {
 			this.insert_space_after_opening_paren_in_parenthesized_expression = JavaCore.INSERT.equals(insertSpaceAfterOpeningParenInParenthesizedExpressionOption);
 		}
+		setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_PAREN_IN_RECORD_DECLARATION, JavaCore.INSERT,
+			v -> this.insert_space_after_opening_paren_in_record_declaration = v);
 		final Object insertSpaceAfterOpeningParenInSwitchOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_OPENING_PAREN_IN_SWITCH);
 		if (insertSpaceAfterOpeningParenInSwitchOption != null) {
 			this.insert_space_after_opening_paren_in_switch = JavaCore.INSERT.equals(insertSpaceAfterOpeningParenInSwitchOption);
@@ -1976,6 +2048,8 @@
 		if (insertSpaceBeforeClosingParenInParenthesizedExpressionOption != null) {
 			this.insert_space_before_closing_paren_in_parenthesized_expression = JavaCore.INSERT.equals(insertSpaceBeforeClosingParenInParenthesizedExpressionOption);
 		}
+		setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_PAREN_IN_RECORD_DECLARATION, JavaCore.INSERT,
+			v -> this.insert_space_before_closing_paren_in_record_declaration = v);
 		final Object insertSpaceBeforeClosingParenInSwitchOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_CLOSING_PAREN_IN_SWITCH);
 		if (insertSpaceBeforeClosingParenInSwitchOption != null) {
 			this.insert_space_before_closing_paren_in_switch = JavaCore.INSERT.equals(insertSpaceBeforeClosingParenInSwitchOption);
@@ -2081,6 +2155,8 @@
 			this.insert_space_before_comma_in_parameterized_type_reference = JavaCore.INSERT.equals(insertSpaceBeforeCommaInParameterizedTypeReferenceOption);
 		}
 		final Object insertSpaceBeforeCommaInSuperinterfacesOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_SUPERINTERFACES);
+		setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_RECORD_COMPONENTS, JavaCore.INSERT,
+				v -> this.insert_space_before_comma_in_record_components = v);
 		if (insertSpaceBeforeCommaInSuperinterfacesOption != null) {
 			this.insert_space_before_comma_in_superinterfaces = JavaCore.INSERT.equals(insertSpaceBeforeCommaInSuperinterfacesOption);
 		}
@@ -2146,6 +2222,10 @@
 		if (insertSpaceBeforeOpeningBraceInMethodDeclarationOption != null) {
 			this.insert_space_before_opening_brace_in_method_declaration = JavaCore.INSERT.equals(insertSpaceBeforeOpeningBraceInMethodDeclarationOption);
 		}
+		setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_RECORD_CONSTRUCTOR, JavaCore.INSERT,
+				v -> this.insert_space_before_opening_brace_in_record_constructor = v);
+		setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_RECORD_DECLARATION, JavaCore.INSERT,
+			v -> this.insert_space_before_opening_brace_in_record_declaration = v);
 		final Object insertSpaceBeforeOpeningBraceInTypeDeclarationOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_TYPE_DECLARATION);
 		if (insertSpaceBeforeOpeningBraceInTypeDeclarationOption != null) {
 			this.insert_space_before_opening_brace_in_type_declaration = JavaCore.INSERT.equals(insertSpaceBeforeOpeningBraceInTypeDeclarationOption);
@@ -2198,6 +2278,8 @@
 		if (insertSpaceBeforeOpeningParenInMethodDeclarationOption != null) {
 			this.insert_space_before_opening_paren_in_method_declaration = JavaCore.INSERT.equals(insertSpaceBeforeOpeningParenInMethodDeclarationOption);
 		}
+		setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_PAREN_IN_RECORD_DECLARATION, JavaCore.INSERT,
+				v -> this.insert_space_before_opening_paren_in_record_declaration = v);
 		final Object insertSpaceBeforeOpeningParenInSwitchOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_PAREN_IN_SWITCH);
 		if (insertSpaceBeforeOpeningParenInSwitchOption != null) {
 			this.insert_space_before_opening_paren_in_switch = JavaCore.INSERT.equals(insertSpaceBeforeOpeningParenInSwitchOption);
@@ -2369,7 +2451,7 @@
 			// reverse values swapping performed by IndentationTabPage
 			if (!JavaCore.SPACE.equals(settings.get(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR)))
 				this.tab_size = tabSize;
-			if (!DefaultCodeFormatterConstants.MIXED.equals(settings.get(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR)))			
+			if (!DefaultCodeFormatterConstants.MIXED.equals(settings.get(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR)))
 				this.indentation_size = tabSize;
 		}
 		final Object useTabsOnlyForLeadingIndentationsOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_USE_TABS_ONLY_FOR_LEADING_INDENTATIONS);
@@ -2538,7 +2620,7 @@
 	 * so that the formatter recognizes those deprecated options when used with project specific formatter profiles.
 	 * (see <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=544776">Bug 544776</a>)
 	 * </p>
-	 * 
+	 *
 	 * @param settings the given map
 	 * @deprecated
 	 */
@@ -2558,17 +2640,17 @@
 				this.comment_clear_blank_lines_in_block_comment = DefaultCodeFormatterConstants.TRUE.equals(commentClearBlankLinesInBlockCommentOption);
 			}
 		}
-		
+
 		// New line after annotations
 		final Object insertNewLineAfterAnnotationOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_ANNOTATION);
-		
+
 		final Object insertNewLineAfterAnnotationOnMemberOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_ANNOTATION_ON_MEMBER);
 		final Object insertNewLineAfterAnnotationOnTypeOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_ANNOTATION_ON_TYPE);
 		final Object insertNewLineAfterAnnotationOnEnumConstantOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_ANNOTATION_ON_ENUM_CONSTANT);
 		final Object insertNewLineAfterAnnotationOnFieldOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_ANNOTATION_ON_FIELD);
 		final Object insertNewLineAfterAnnotationOnMethodOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_ANNOTATION_ON_METHOD);
 		final Object insertNewLineAfterAnnotationOnPackageOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_ANNOTATION_ON_PACKAGE);
-		
+
 		final Object insertNewLineAfterAnnotationOnParameterOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_ANNOTATION_ON_PARAMETER);
 		final Object insertNewLineAfterAnnotationOnLocalVariableOption = settings.get(DefaultCodeFormatterConstants.FORMATTER_INSERT_NEW_LINE_AFTER_ANNOTATION_ON_LOCAL_VARIABLE);
 
@@ -2585,7 +2667,7 @@
 				this.insert_new_line_after_annotation_on_field = insert;
 				this.insert_new_line_after_annotation_on_method = insert;
 				this.insert_new_line_after_annotation_on_package = insert;
-				
+
 				// and use the other 3.4 options if available
 				if (insertNewLineAfterAnnotationOnParameterOption != null) {
 					this.insert_new_line_after_annotation_on_parameter = JavaCore.INSERT.equals(insertNewLineAfterAnnotationOnParameterOption);
@@ -2787,6 +2869,10 @@
 			setInt(settings, DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_BEFORE_METHOD,
 					v -> this.blank_lines_before_abstract_method = v);
 		}
+		if (!settings.containsKey(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_NOT_OPERATOR)) {
+			setBoolean(settings, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_UNARY_OPERATOR, JavaCore.INSERT,
+					v -> this.insert_space_after_not_operator = v);
+		}
 	}
 
 	public void setDefaultSettings() {
@@ -2817,10 +2903,12 @@
 		this.alignment_for_parameterized_type_references = Alignment.M_NO_ALIGNMENT;
 		this.alignment_for_parameters_in_constructor_declaration = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_parameters_in_method_declaration = Alignment.M_COMPACT_SPLIT;
+		this.alignment_for_record_components = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_resources_in_try = Alignment.M_NEXT_PER_LINE_SPLIT;
 		this.alignment_for_selector_in_method_invocation = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_superclass_in_type_declaration = Alignment.M_NEXT_SHIFTED_SPLIT;
 		this.alignment_for_superinterfaces_in_enum_declaration = Alignment.M_NEXT_SHIFTED_SPLIT;
+		this.alignment_for_superinterfaces_in_record_declaration = Alignment.M_NEXT_SHIFTED_SPLIT;
 		this.alignment_for_superinterfaces_in_type_declaration = Alignment.M_NEXT_SHIFTED_SPLIT;
 		this.alignment_for_throws_clause_in_constructor_declaration = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_throws_clause_in_method_declaration = Alignment.M_COMPACT_SPLIT;
@@ -2843,10 +2931,13 @@
 		this.brace_position_for_lambda_body = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_method_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
+		this.brace_position_for_record_constructor = DefaultCodeFormatterConstants.END_OF_LINE;
+		this.brace_position_for_record_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_switch = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.parenthesis_positions_in_method_declaration = DefaultCodeFormatterConstants.COMMON_LINES;
 		this.parenthesis_positions_in_method_invocation = DefaultCodeFormatterConstants.COMMON_LINES;
 		this.parenthesis_positions_in_enum_constant_declaration = DefaultCodeFormatterConstants.COMMON_LINES;
+		this.parenthesis_positions_in_record_declaration = DefaultCodeFormatterConstants.COMMON_LINES;
 		this.parenthesis_positions_in_if_while_statement = DefaultCodeFormatterConstants.COMMON_LINES;
 		this.parenthesis_positions_in_for_statement = DefaultCodeFormatterConstants.COMMON_LINES;
 		this.parenthesis_positions_in_switch_statement = DefaultCodeFormatterConstants.COMMON_LINES;
@@ -2869,12 +2960,13 @@
 		this.comment_align_tags_names_descriptions = false;
 		this.comment_align_tags_descriptions_grouped = false;
 		this.comment_insert_empty_line_before_root_tags = true;
+		this.comment_insert_empty_line_between_different_tags = false;
 		this.comment_insert_new_line_for_parameter = true;
 		this.comment_new_lines_at_block_boundaries = true;
 		this.comment_new_lines_at_javadoc_boundaries = true;
 		this.comment_line_length = 80;
 		this.comment_count_line_length_from_starting_position = true;
-		this.comment_preserve_white_space_between_code_and_line_comments= false; 
+		this.comment_preserve_white_space_between_code_and_line_comments= false;
 		this.continuation_indentation = 2;
 		this.continuation_indentation_for_array_initializer = 2;
 		this.blank_lines_after_imports = 0;
@@ -2902,6 +2994,7 @@
 		this.indent_body_declarations_compare_to_annotation_declaration_header = true;
 		this.indent_body_declarations_compare_to_enum_constant_header = true;
 		this.indent_body_declarations_compare_to_enum_declaration_header = true;
+		this.indent_body_declarations_compare_to_record_header = true;
 		this.indent_body_declarations_compare_to_type_header = true;
 		this.indent_breaks_compare_to_cases = true;
 		this.indent_empty_lines = false;
@@ -2933,6 +3026,8 @@
 		this.keep_enum_declaration_on_one_line = DefaultCodeFormatterConstants.ONE_LINE_NEVER;
 		this.keep_method_body_on_one_line = DefaultCodeFormatterConstants.ONE_LINE_NEVER;
 		this.keep_type_declaration_on_one_line = DefaultCodeFormatterConstants.ONE_LINE_NEVER;
+		this.keep_record_declaration_on_one_line = DefaultCodeFormatterConstants.ONE_LINE_NEVER;
+		this.keep_record_constructor_on_one_line = DefaultCodeFormatterConstants.ONE_LINE_NEVER;
 		this.keep_simple_getter_setter_on_one_line = false;
 		this.insert_space_after_and_in_type_parameter = true;
 		this.insert_space_after_arrow_in_switch_case = true;
@@ -2972,12 +3067,14 @@
 		this.insert_space_after_comma_in_multiple_field_declarations = true;
 		this.insert_space_after_comma_in_multiple_local_declarations = true;
 		this.insert_space_after_comma_in_parameterized_type_reference = true;
+		this.insert_space_after_comma_in_record_components = true;
 		this.insert_space_after_comma_in_superinterfaces = true;
 		this.insert_space_after_comma_in_switch_case_expressions = true;
 		this.insert_space_after_comma_in_type_arguments = true;
 		this.insert_space_after_comma_in_type_parameters = true;
 		this.insert_space_after_ellipsis = true;
 		this.insert_space_after_lambda_arrow = true;
+		this.insert_space_after_not_operator = false;
 		this.insert_space_after_opening_angle_bracket_in_parameterized_type_reference = false;
 		this.insert_space_after_opening_angle_bracket_in_type_arguments = false;
 		this.insert_space_after_opening_angle_bracket_in_type_parameters = false;
@@ -2994,6 +3091,7 @@
 		this.insert_space_after_opening_paren_in_method_declaration = false;
 		this.insert_space_after_opening_paren_in_method_invocation = false;
 		this.insert_space_after_opening_paren_in_parenthesized_expression = false;
+		this.insert_space_after_opening_paren_in_record_declaration = false;
 		this.insert_space_after_opening_paren_in_switch = false;
 		this.insert_space_after_opening_paren_in_synchronized = false;
 		this.insert_space_after_opening_paren_in_try = false;
@@ -3033,6 +3131,7 @@
 		this.insert_space_before_closing_paren_in_method_declaration = false;
 		this.insert_space_before_closing_paren_in_method_invocation = false;
 		this.insert_space_before_closing_paren_in_parenthesized_expression = false;
+		this.insert_space_before_closing_paren_in_record_declaration = false;
 		this.insert_space_before_closing_paren_in_switch = false;
 		this.insert_space_before_closing_paren_in_synchronized = false;
 		this.insert_space_before_closing_paren_in_try = false;
@@ -3058,6 +3157,7 @@
 		this.insert_space_before_comma_in_multiple_field_declarations = false;
 		this.insert_space_before_comma_in_multiple_local_declarations = false;
 		this.insert_space_before_comma_in_parameterized_type_reference = false;
+		this.insert_space_before_comma_in_record_components = false;
 		this.insert_space_before_comma_in_superinterfaces = false;
 		this.insert_space_before_comma_in_switch_case_expressions = false;
 		this.insert_space_before_comma_in_type_arguments = false;
@@ -3077,6 +3177,8 @@
 		this.insert_space_before_opening_brace_in_enum_constant = true;
 		this.insert_space_before_opening_brace_in_enum_declaration = true;
 		this.insert_space_before_opening_brace_in_method_declaration = true;
+		this.insert_space_before_opening_brace_in_record_constructor = true;
+		this.insert_space_before_opening_brace_in_record_declaration = true;
 		this.insert_space_before_opening_brace_in_switch = true;
 		this.insert_space_before_opening_brace_in_type_declaration = true;
 		this.insert_space_before_opening_bracket_in_array_allocation_expression = false;
@@ -3091,6 +3193,7 @@
 		this.insert_space_before_opening_paren_in_if = true;
 		this.insert_space_before_opening_paren_in_method_invocation = false;
 		this.insert_space_before_opening_paren_in_method_declaration = false;
+		this.insert_space_before_opening_paren_in_record_declaration = false;
 		this.insert_space_before_opening_paren_in_switch = true;
 		this.insert_space_before_opening_paren_in_synchronized = true;
 		this.insert_space_before_opening_paren_in_try = true;
@@ -3182,10 +3285,12 @@
 		this.alignment_for_parameterized_type_references = Alignment.M_NO_ALIGNMENT;
 		this.alignment_for_parameters_in_constructor_declaration = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_parameters_in_method_declaration = Alignment.M_COMPACT_SPLIT;
+		this.alignment_for_record_components = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_resources_in_try = Alignment.M_NEXT_PER_LINE_SPLIT;
 		this.alignment_for_selector_in_method_invocation = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_superclass_in_type_declaration = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_superinterfaces_in_enum_declaration = Alignment.M_COMPACT_SPLIT;
+		this.alignment_for_superinterfaces_in_record_declaration = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_superinterfaces_in_type_declaration = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_throws_clause_in_constructor_declaration = Alignment.M_COMPACT_SPLIT;
 		this.alignment_for_throws_clause_in_method_declaration = Alignment.M_COMPACT_SPLIT;
@@ -3208,10 +3313,13 @@
 		this.brace_position_for_lambda_body = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_method_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_type_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
+		this.brace_position_for_record_constructor = DefaultCodeFormatterConstants.END_OF_LINE;
+		this.brace_position_for_record_declaration = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.brace_position_for_switch = DefaultCodeFormatterConstants.END_OF_LINE;
 		this.parenthesis_positions_in_method_declaration = DefaultCodeFormatterConstants.COMMON_LINES;
 		this.parenthesis_positions_in_method_invocation = DefaultCodeFormatterConstants.COMMON_LINES;
 		this.parenthesis_positions_in_enum_constant_declaration = DefaultCodeFormatterConstants.COMMON_LINES;
+		this.parenthesis_positions_in_record_declaration = DefaultCodeFormatterConstants.COMMON_LINES;
 		this.parenthesis_positions_in_if_while_statement = DefaultCodeFormatterConstants.COMMON_LINES;
 		this.parenthesis_positions_in_for_statement = DefaultCodeFormatterConstants.COMMON_LINES;
 		this.parenthesis_positions_in_switch_statement = DefaultCodeFormatterConstants.COMMON_LINES;
@@ -3234,17 +3342,19 @@
 		this.comment_align_tags_names_descriptions = false;
 		this.comment_align_tags_descriptions_grouped = true;
 		this.comment_insert_empty_line_before_root_tags = true;
+		this.comment_insert_empty_line_between_different_tags = false;
 		this.comment_insert_new_line_for_parameter = false;
 		this.comment_new_lines_at_block_boundaries = true;
 		this.comment_new_lines_at_javadoc_boundaries = true;
 		this.comment_line_length = 80;
 		this.comment_count_line_length_from_starting_position = true;
-		this.comment_preserve_white_space_between_code_and_line_comments= false; 
+		this.comment_preserve_white_space_between_code_and_line_comments= false;
 		this.continuation_indentation = 2;
 		this.continuation_indentation_for_array_initializer = 2;
 		this.blank_lines_after_imports = 1;
 		this.blank_lines_after_package = 1;
 		this.blank_lines_before_field = 0;
+		this.blank_lines_before_first_class_body_declaration = 0;
 		this.blank_lines_after_last_class_body_declaration = 0;
 		this.blank_lines_before_imports = 1;
 		this.blank_lines_before_member_type = 1;
@@ -3266,6 +3376,7 @@
 		this.indent_body_declarations_compare_to_annotation_declaration_header = true;
 		this.indent_body_declarations_compare_to_enum_constant_header = true;
 		this.indent_body_declarations_compare_to_enum_declaration_header = true;
+		this.indent_body_declarations_compare_to_record_header = true;
 		this.indent_body_declarations_compare_to_type_header = true;
 		this.indent_breaks_compare_to_cases = true;
 		this.indent_empty_lines = false;
@@ -3297,6 +3408,9 @@
 		this.keep_enum_declaration_on_one_line = DefaultCodeFormatterConstants.ONE_LINE_NEVER;
 		this.keep_method_body_on_one_line = DefaultCodeFormatterConstants.ONE_LINE_NEVER;
 		this.keep_type_declaration_on_one_line = DefaultCodeFormatterConstants.ONE_LINE_NEVER;
+		this.keep_record_declaration_on_one_line = DefaultCodeFormatterConstants.ONE_LINE_NEVER;
+		this.keep_record_constructor_on_one_line = DefaultCodeFormatterConstants.ONE_LINE_NEVER;
+		this.keep_simple_getter_setter_on_one_line = false;
 		this.insert_space_after_and_in_type_parameter = true;
 		this.insert_space_after_arrow_in_switch_case = true;
 		this.insert_space_after_arrow_in_switch_default = true;
@@ -3335,12 +3449,14 @@
 		this.insert_space_after_comma_in_multiple_field_declarations = true;
 		this.insert_space_after_comma_in_multiple_local_declarations = true;
 		this.insert_space_after_comma_in_parameterized_type_reference = true;
+		this.insert_space_after_comma_in_record_components = true;
 		this.insert_space_after_comma_in_superinterfaces = true;
 		this.insert_space_after_comma_in_switch_case_expressions = true;
 		this.insert_space_after_comma_in_type_arguments = true;
 		this.insert_space_after_comma_in_type_parameters = true;
 		this.insert_space_after_ellipsis = true;
 		this.insert_space_after_lambda_arrow = true;
+		this.insert_space_after_not_operator = false;
 		this.insert_space_after_opening_angle_bracket_in_parameterized_type_reference = false;
 		this.insert_space_after_opening_angle_bracket_in_type_arguments = false;
 		this.insert_space_after_opening_angle_bracket_in_type_parameters = false;
@@ -3357,6 +3473,7 @@
 		this.insert_space_after_opening_paren_in_method_declaration = false;
 		this.insert_space_after_opening_paren_in_method_invocation = false;
 		this.insert_space_after_opening_paren_in_parenthesized_expression = false;
+		this.insert_space_after_opening_paren_in_record_declaration = false;
 		this.insert_space_after_opening_paren_in_switch = false;
 		this.insert_space_after_opening_paren_in_synchronized = false;
 		this.insert_space_after_opening_paren_in_try = false;
@@ -3396,6 +3513,7 @@
 		this.insert_space_before_closing_paren_in_method_declaration = false;
 		this.insert_space_before_closing_paren_in_method_invocation = false;
 		this.insert_space_before_closing_paren_in_parenthesized_expression = false;
+		this.insert_space_before_closing_paren_in_record_declaration = false;
 		this.insert_space_before_closing_paren_in_switch = false;
 		this.insert_space_before_closing_paren_in_synchronized = false;
 		this.insert_space_before_closing_paren_in_try = false;
@@ -3421,6 +3539,7 @@
 		this.insert_space_before_comma_in_multiple_field_declarations = false;
 		this.insert_space_before_comma_in_multiple_local_declarations = false;
 		this.insert_space_before_comma_in_parameterized_type_reference = false;
+		this.insert_space_before_comma_in_record_components = false;
 		this.insert_space_before_comma_in_superinterfaces = false;
 		this.insert_space_before_comma_in_switch_case_expressions = false;
 		this.insert_space_before_comma_in_type_arguments = false;
@@ -3440,6 +3559,8 @@
 		this.insert_space_before_opening_brace_in_enum_constant = true;
 		this.insert_space_before_opening_brace_in_enum_declaration = true;
 		this.insert_space_before_opening_brace_in_method_declaration = true;
+		this.insert_space_before_opening_brace_in_record_constructor = true;
+		this.insert_space_before_opening_brace_in_record_declaration = true;
 		this.insert_space_before_opening_brace_in_switch = true;
 		this.insert_space_before_opening_brace_in_type_declaration = true;
 		this.insert_space_before_opening_bracket_in_array_allocation_expression = false;
@@ -3454,6 +3575,7 @@
 		this.insert_space_before_opening_paren_in_if = true;
 		this.insert_space_before_opening_paren_in_method_invocation = false;
 		this.insert_space_before_opening_paren_in_method_declaration = false;
+		this.insert_space_before_opening_paren_in_record_declaration = false;
 		this.insert_space_before_opening_paren_in_switch = true;
 		this.insert_space_before_opening_paren_in_synchronized = true;
 		this.insert_space_before_opening_paren_in_try = true;
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java
index 01ea65c..9add4c0 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/LineBreaksPreparator.java
@@ -31,6 +31,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.ASTVisitor;
 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
@@ -64,6 +65,7 @@
 import org.eclipse.jdt.core.dom.ModuleDirective;
 import org.eclipse.jdt.core.dom.NormalAnnotation;
 import org.eclipse.jdt.core.dom.PackageDeclaration;
+import org.eclipse.jdt.core.dom.RecordDeclaration;
 import org.eclipse.jdt.core.dom.ReturnStatement;
 import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
@@ -83,6 +85,7 @@
 import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions.Alignment;
 import org.eclipse.jdt.internal.formatter.Token.WrapMode;
 import org.eclipse.jdt.internal.formatter.Token.WrapPolicy;
+import org.eclipse.jface.text.IRegion;
 
 public class LineBreaksPreparator extends ASTVisitor {
 	final private TokenManager tm;
@@ -151,8 +154,8 @@
 	public boolean visit(TypeDeclaration node) {
 		handleBodyDeclarations(node.bodyDeclarations());
 
-		if (node.getName().getStartPosition() == -1)
-			return true; // this is a fake type created by parsing in class body mode
+		if (this.tm.isFake(node))
+			return true;
 
 		breakLineBefore(node);
 
@@ -187,9 +190,11 @@
 			previous = bodyDeclaration;
 		}
 		if (previous != null) {
-			Token lastToken = this.tm.lastTokenIn(previous.getParent(), -1);
-			if (lastToken.tokenType == TokenNameRBRACE) // otherwise it's a fake type
+			ASTNode parent = previous.getParent();
+			if (!(parent instanceof TypeDeclaration && this.tm.isFake((TypeDeclaration) parent))) {
+				Token lastToken = this.tm.lastTokenIn(parent, -1);
 				putBlankLinesBefore(lastToken, this.options.blank_lines_after_last_class_body_declaration);
+			}
 		}
 	}
 
@@ -271,13 +276,22 @@
 	}
 
 	@Override
+	public boolean visit(RecordDeclaration node) {
+		handleBracedCode(node, node.getName(), this.options.brace_position_for_record_declaration,
+				this.options.indent_body_declarations_compare_to_record_header);
+		handleBodyDeclarations(node.bodyDeclarations());
+		return true;
+	}
+
+	@Override
 	public boolean visit(MethodDeclaration node) {
 		this.declarationModifierVisited = false;
 		if (node.getBody() == null)
 			return true;
 
-		String bracePosition = node.isConstructor() ? this.options.brace_position_for_constructor_declaration
-				: this.options.brace_position_for_method_declaration;
+		String bracePosition = node.isCompactConstructor() ? this.options.brace_position_for_record_constructor
+				: node.isConstructor() ? this.options.brace_position_for_constructor_declaration
+						: this.options.brace_position_for_method_declaration;
 		handleBracedCode(node.getBody(), null, bracePosition, this.options.indent_statements_compare_to_body,
 				this.options.blank_lines_at_beginning_of_method_body, this.options.blank_lines_at_end_of_method_body);
 
@@ -393,7 +407,7 @@
 
 	private void doSwitchStatementsLineBreaks(List<Statement> statements) {
 		boolean arrowMode = statements.stream()
-				.anyMatch(s -> s instanceof SwitchCase && ((SwitchCase) s).isSwitchLabeledRule());
+				.anyMatch(s -> s instanceof SwitchCase && s.getAST().apiLevel() >= AST.JLS14 &&((SwitchCase) s).isSwitchLabeledRule());
 		Statement previous = null;
 		for (Statement statement : statements) {
 			boolean skip = statement instanceof Block // will add break in visit(Block) if necessary
@@ -739,7 +753,7 @@
 	private void handleBracedCode(ASTNode node, ASTNode nodeBeforeOpenBrace, String bracePosition, boolean indentBody) {
 		handleBracedCode(node, nodeBeforeOpenBrace, bracePosition, indentBody, 0, 0);
 	}
-	
+
 	private void handleBracedCode(ASTNode node, ASTNode nodeBeforeOpenBrace, String bracePosition, boolean indentBody,
 			int blankLinesAfterOpeningBrace, int blankLinesBeforeClosingBrace) {
 		int openBraceIndex = nodeBeforeOpenBrace == null
@@ -794,13 +808,37 @@
 			this.tm.get(lastIndex + 1).unindent();
 	}
 
-	public void finishUp() {
+	public void finishUp(List<IRegion> regions) {
 		// the visits only noted where indents increase and decrease,
-		// now prepare actual indent values
-		int currentIndent = this.options.initial_indentation_level;
+		// now prepare actual indent values, preserving indents outside formatting regions
+		int currentIndent = this.options.initial_indentation_level * this.options.indentation_size;
+		Token previous = null;
 		for (Token token : this.tm) {
-			currentIndent += token.getIndent();
-			token.setIndent(currentIndent * this.options.indentation_size);
+			if (isFixedLineStart(token, previous, regions)) {
+				currentIndent = this.tm.findSourcePositionInLine(token.originalStart);
+			} else {
+				currentIndent = Math.max(currentIndent + token.getIndent() * this.options.indentation_size, 0);
+			}
+			token.setIndent(currentIndent);
+			previous = token;
 		}
 	}
+
+	private boolean isFixedLineStart(Token token, Token previous, List<IRegion> regions) {
+		if (previous == null && this.options.initial_indentation_level >0)
+			return false; // must be handling ast rewrite
+		if (previous != null && this.tm.countLineBreaksBetween(previous, token) == 0)
+			return false;
+		if (token.getLineBreaksBefore() == 0 && (previous == null || previous.getLineBreaksAfter() == 0))
+			return false;
+		int lineStart = token.originalStart;
+		char c;
+		while (lineStart > 0 && (c = this.tm.charAt(lineStart - 1)) != '\r' && c != '\n')
+			lineStart--;
+		for (IRegion r : regions) {
+			if (token.originalStart >= r.getOffset() && lineStart <= r.getOffset() + r.getLength())
+				return false;
+		}
+		return true;
+	}
 }
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/OneLineEnforcer.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/OneLineEnforcer.java
index 9b2671a..b5cbff8 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/OneLineEnforcer.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/OneLineEnforcer.java
@@ -10,7 +10,7 @@
  *
  * Contributors:
  *     Mateusz Matela <mateusz.matela@gmail.com> - Initial API and implementation
- *     
+ *
  *******************************************************************************/
 package org.eclipse.jdt.internal.formatter;
 
@@ -40,6 +40,7 @@
 import org.eclipse.jdt.core.dom.MethodDeclaration;
 import org.eclipse.jdt.core.dom.ModuleDeclaration;
 import org.eclipse.jdt.core.dom.PrimitiveType;
+import org.eclipse.jdt.core.dom.RecordDeclaration;
 import org.eclipse.jdt.core.dom.ReturnStatement;
 import org.eclipse.jdt.core.dom.Statement;
 import org.eclipse.jdt.core.dom.ThrowStatement;
@@ -86,6 +87,12 @@
 	}
 
 	@Override
+	public void endVisit(RecordDeclaration node) {
+		tryKeepOnOneLine(node, node.getName(), node.bodyDeclarations(),
+				this.options.keep_record_declaration_on_one_line);
+	}
+
+	@Override
 	public void endVisit(AnonymousClassDeclaration node) {
 		if (node.getParent() instanceof EnumConstantDeclaration) {
 			tryKeepOnOneLine(node, null, node.bodyDeclarations(),
@@ -104,9 +111,10 @@
 			return; // this is a fake block created by parsing in statements mode
 		String oneLineOption;
 		if (parent instanceof MethodDeclaration) {
-			oneLineOption = this.options.keep_method_body_on_one_line;
+			MethodDeclaration method = (MethodDeclaration) parent;
+			oneLineOption = method.isCompactConstructor() ? this.options.keep_record_constructor_on_one_line
+					: this.options.keep_method_body_on_one_line;
 			if (this.options.keep_simple_getter_setter_on_one_line) {
-				MethodDeclaration method = (MethodDeclaration) parent;
 				String name = method.getName().getIdentifier();
 				Type returnType = method.getReturnType2();
 				boolean returnsVoid = returnType instanceof PrimitiveType
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java
index da62bba..fe715a3 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/SpacePreparator.java
@@ -79,6 +79,7 @@
 import org.eclipse.jdt.core.dom.PostfixExpression;
 import org.eclipse.jdt.core.dom.PrefixExpression;
 import org.eclipse.jdt.core.dom.ProvidesDirective;
+import org.eclipse.jdt.core.dom.RecordDeclaration;
 import org.eclipse.jdt.core.dom.ReturnStatement;
 import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
@@ -172,8 +173,8 @@
 
 	@Override
 	public boolean visit(TypeDeclaration node) {
-		if (node.getName().getStartPosition() == -1)
-			return true; // this is a fake type created by parsing in class body mode
+		if (this.tm.isFake(node))
+			return true;
 
 		handleToken(node.getName(), TokenNameIdentifier, true, false);
 
@@ -218,7 +219,7 @@
 			int from = this.tm.firstIndexIn(node.getName(), TokenNameIdentifier) + 1;
 			AnonymousClassDeclaration classDeclaration = node.getAnonymousClassDeclaration();
 			int to = classDeclaration != null ? this.tm.firstIndexBefore(classDeclaration, -1)
-					: this.tm.lastIndexIn(node, -1); 
+					: this.tm.lastIndexIn(node, -1);
 			for (int i = from; i <= to; i++) {
 				if (this.tm.get(i).tokenType == TokenNameLPAREN) {
 					openingParen = this.tm.get(i);
@@ -245,63 +246,102 @@
 	}
 
 	@Override
+	public boolean visit(RecordDeclaration node) {
+		handleToken(node.getName(), TokenNameIdentifier, true, false);
+
+		List<TypeParameter> typeParameters = node.typeParameters();
+		handleTypeParameters(typeParameters);
+
+		handleToken(node.getName(), TokenNameLBRACE,
+				this.options.insert_space_before_opening_brace_in_record_declaration, false);
+		List<Type> superInterfaces = node.superInterfaceTypes();
+		if (!superInterfaces.isEmpty()) {
+			handleTokenBefore(superInterfaces.get(0), TokenNameimplements, true, true);
+			handleCommas(superInterfaces, this.options.insert_space_before_comma_in_superinterfaces,
+					this.options.insert_space_after_comma_in_superinterfaces);
+		}
+
+		List<SingleVariableDeclaration> components = node.recordComponents();
+		if (handleEmptyParens(node, this.options.insert_space_between_empty_parens_in_constructor_declaration)) {
+			handleToken(node, TokenNameLPAREN,
+					this.options.insert_space_before_opening_paren_in_record_declaration, false);
+		} else {
+			handleToken(node, TokenNameLPAREN,
+					this.options.insert_space_before_opening_paren_in_record_declaration,
+					this.options.insert_space_after_opening_paren_in_record_declaration);
+
+			if (this.options.insert_space_before_closing_paren_in_record_declaration) {
+				ASTNode nodeBeforeBrace = components.isEmpty() ? node.getName() : components.get(components.size() - 1);
+				handleTokenAfter(nodeBeforeBrace, TokenNameRPAREN, true, false);
+			}
+		}
+		handleCommas(components, this.options.insert_space_before_comma_in_record_components,
+				this.options.insert_space_after_comma_in_record_components);
+		return true;
+	}
+
+	@Override
 	public boolean visit(MethodDeclaration node) {
 		handleToken(node.getName(), TokenNameIdentifier, true, false);
 
-		boolean spaceBeforeOpenParen = node.isConstructor()
-				? this.options.insert_space_before_opening_paren_in_constructor_declaration
-				: this.options.insert_space_before_opening_paren_in_method_declaration;
-		boolean spaceAfterOpenParen = node.isConstructor()
-				? this.options.insert_space_after_opening_paren_in_constructor_declaration
-				: this.options.insert_space_after_opening_paren_in_method_declaration;
-		boolean spaceBetweenEmptyParens = node.isConstructor()
-				? this.options.insert_space_between_empty_parens_in_constructor_declaration
-				: this.options.insert_space_between_empty_parens_in_method_declaration;
-		if (handleEmptyParens(node.getName(), spaceBetweenEmptyParens)) {
-			handleToken(node.getName(), TokenNameLPAREN, spaceBeforeOpenParen, false);
-		} else {
-			handleToken(node.getName(), TokenNameLPAREN, spaceBeforeOpenParen, spaceAfterOpenParen);
+		List<SingleVariableDeclaration> params = node.parameters();
+		if (!node.isCompactConstructor()) {
+			boolean beforeOpenParen = node.isConstructor()
+					? this.options.insert_space_before_opening_paren_in_constructor_declaration
+					: this.options.insert_space_before_opening_paren_in_method_declaration;
+			boolean afterOpenParen = node.isConstructor()
+					? this.options.insert_space_after_opening_paren_in_constructor_declaration
+					: this.options.insert_space_after_opening_paren_in_method_declaration;
+			boolean betweenEmptyParens = node.isConstructor()
+					? this.options.insert_space_between_empty_parens_in_constructor_declaration
+					: this.options.insert_space_between_empty_parens_in_method_declaration;
+			if (handleEmptyParens(node.getName(), betweenEmptyParens)) {
+				handleToken(node.getName(), TokenNameLPAREN, beforeOpenParen, false);
+			} else {
+				handleToken(node.getName(), TokenNameLPAREN, beforeOpenParen, afterOpenParen);
 
-			boolean spaceBeforeCloseParen = node.isConstructor()
-					? this.options.insert_space_before_closing_paren_in_constructor_declaration
-					: this.options.insert_space_before_closing_paren_in_method_declaration;
-			if (spaceBeforeCloseParen) {
-				List<SingleVariableDeclaration> params = node.parameters();
-				ASTNode beforeBrace = params.isEmpty() ? node.getName() : params.get(params.size() - 1);
-				handleTokenAfter(beforeBrace, TokenNameRPAREN, true, false);
+				boolean beforeCloseParen = node.isConstructor()
+						? this.options.insert_space_before_closing_paren_in_constructor_declaration
+						: this.options.insert_space_before_closing_paren_in_method_declaration;
+				if (beforeCloseParen) {
+					ASTNode nodeBeforeBrace = params.isEmpty() ? node.getName() : params.get(params.size() - 1);
+					handleTokenAfter(nodeBeforeBrace, TokenNameRPAREN, true, false);
+				}
 			}
+
+			boolean beforeComma = node.isConstructor()
+					? this.options.insert_space_before_comma_in_constructor_declaration_parameters
+					: this.options.insert_space_before_comma_in_method_declaration_parameters;
+			boolean afterComma = node.isConstructor()
+					? this.options.insert_space_after_comma_in_constructor_declaration_parameters
+					: this.options.insert_space_after_comma_in_method_declaration_parameters;
+			if (node.getReceiverType() != null) {
+				params = new ArrayList<>(params);
+				params.add(0, null); // space for explicit receiver, null OK - first value not read in handleCommas
+			}
+			handleCommas(params, beforeComma, afterComma);
 		}
 
-		if ((node.isConstructor() ? this.options.insert_space_before_opening_brace_in_constructor_declaration
-				: this.options.insert_space_before_opening_brace_in_method_declaration) && node.getBody() != null)
+		boolean beforeOpeningBrace = node.isCompactConstructor()
+				? this.options.insert_space_before_opening_brace_in_record_constructor
+				: node.isConstructor() ? this.options.insert_space_before_opening_brace_in_constructor_declaration
+						: this.options.insert_space_before_opening_brace_in_method_declaration;
+		if (beforeOpeningBrace && node.getBody() != null)
 			this.tm.firstTokenIn(node.getBody(), TokenNameLBRACE).spaceBefore();
 
 		if (node.getReceiverType() != null)
 			this.tm.lastTokenIn(node.getReceiverType(), -1).spaceAfter();
 
-		boolean beforeComma = node.isConstructor()
-				? this.options.insert_space_before_comma_in_constructor_declaration_parameters
-				: this.options.insert_space_before_comma_in_method_declaration_parameters;
-		boolean afterComma = node.isConstructor()
-				? this.options.insert_space_after_comma_in_constructor_declaration_parameters
-				: this.options.insert_space_after_comma_in_method_declaration_parameters;
-		List<SingleVariableDeclaration> params = node.parameters();
-		if (node.getReceiverType() != null) {
-			params = new ArrayList<>(params);
-			params.add(0, null); // space for explicit receiver, null OK - first value not read in handleCommas 
-		}
-		handleCommas(params, beforeComma, afterComma);
-
 		List<Type> thrownExceptionTypes = node.thrownExceptionTypes();
 		if (!thrownExceptionTypes.isEmpty()) {
-			this.tm.firstTokenBefore(thrownExceptionTypes.get(0), TokenNamethrows).spaceBefore();
+			handleTokenBefore(thrownExceptionTypes.get(0), TokenNamethrows, true, false);
 
-			beforeComma = node.isConstructor()
+			boolean beforeComma = node.isConstructor()
 					? this.options.insert_space_before_comma_in_constructor_declaration_throws
-					: this.options.insert_space_before_comma_in_method_declaration_throws;
-			afterComma = node.isConstructor()
+							: this.options.insert_space_before_comma_in_method_declaration_throws;
+			boolean afterComma = node.isConstructor()
 					? this.options.insert_space_after_comma_in_constructor_declaration_throws
-					: this.options.insert_space_after_comma_in_method_declaration_throws;
+							: this.options.insert_space_after_comma_in_method_declaration_throws;
 			handleCommas(thrownExceptionTypes, beforeComma, afterComma);
 		}
 
@@ -397,7 +437,7 @@
 
 	@Override
 	public boolean visit(SwitchCase node) {
-		if (node.getAST().apiLevel() == AST.JLS13 && node.isSwitchLabeledRule()) {
+		if (node.getAST().apiLevel() > AST.JLS13 && node.isSwitchLabeledRule()) {
 			handleToken(this.tm.lastTokenIn(node, TokenNameARROW),
 					node.isDefault() ? this.options.insert_space_before_arrow_in_switch_default
 							: this.options.insert_space_before_arrow_in_switch_case,
@@ -411,7 +451,7 @@
 		}
 		if (!node.isDefault()) {
 			handleToken(node, TokenNamecase, false, true);
-			if (node.getAST().apiLevel() == AST.JLS13) {
+			if (node.getAST().apiLevel() > AST.JLS13) {
 				handleCommas(node.expressions(), this.options.insert_space_before_comma_in_switch_case_expressions,
 					this.options.insert_space_after_comma_in_switch_case_expressions);
 			}
@@ -811,8 +851,13 @@
 			handleOperator(operator.toString(), node.getOperand(),
 					this.options.insert_space_before_prefix_operator,
 					this.options.insert_space_after_prefix_operator);
+		} else if (operator.equals(PrefixExpression.Operator.NOT)) {
+			handleOperator(operator.toString(), node.getOperand(),
+					this.options.insert_space_before_unary_operator,
+					this.options.insert_space_after_not_operator);
 		} else {
-			handleOperator(operator.toString(), node.getOperand(), this.options.insert_space_before_unary_operator,
+			handleOperator(operator.toString(), node.getOperand(),
+					this.options.insert_space_before_unary_operator,
 					this.options.insert_space_after_unary_operator);
 		}
 		return true;
@@ -1061,7 +1106,7 @@
 		handleModuleStatementCommas(node.modules());
 		return true;
 	}
-	
+
 	@Override
 	public boolean visit(OpensDirective node) {
 		handleModuleStatementCommas(node.modules());
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java
index 071f282..7328e97 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/TokenManager.java
@@ -29,6 +29,7 @@
 import org.eclipse.jdt.core.dom.Expression;
 import org.eclipse.jdt.core.dom.InfixExpression;
 import org.eclipse.jdt.core.dom.StringLiteral;
+import org.eclipse.jdt.core.dom.TypeDeclaration;
 import org.eclipse.jdt.core.dom.InfixExpression.Operator;
 import org.eclipse.jdt.internal.formatter.Token.WrapMode;
 import org.eclipse.jdt.internal.formatter.linewrap.CommentWrapExecutor;
@@ -331,7 +332,7 @@
 	/**
 	 * Calculates the length of a source code fragment.
 	 * @param originalStart the first position of the source code fragment
-	 * @param originalEnd the last position of the source code fragment 
+	 * @param originalEnd the last position of the source code fragment
 	 * @param startPosition position in line of the first character (affects tabs calculation)
 	 * @return length, considering tabs and escaping characters as HTML entities
 	 */
@@ -412,6 +413,11 @@
 		return false;
 	}
 
+	public boolean isFake(TypeDeclaration node) {
+		// might be a fake type created by parsing in class body mode
+		return node.getName().getStartPosition() == -1;
+	}
+
 	public void addNLSAlignIndex(int index, int align) {
 		if (this.tokenIndexToNLSAlign == null)
 			this.tokenIndexToNLSAlign = new HashMap<Integer, Integer>();
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
index 2fb28a1..276da6c 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapExecutor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014, 2019 Mateusz Matela and others.
+ * Copyright (c) 2014, 2020 Mateusz Matela and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -26,15 +26,16 @@
 import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
-
+import java.util.function.Predicate;
 import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
 import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions;
 import org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions.Alignment;
 import org.eclipse.jdt.internal.formatter.Token;
-import org.eclipse.jdt.internal.formatter.TokenManager;
-import org.eclipse.jdt.internal.formatter.TokenTraverser;
 import org.eclipse.jdt.internal.formatter.Token.WrapMode;
 import org.eclipse.jdt.internal.formatter.Token.WrapPolicy;
+import org.eclipse.jdt.internal.formatter.TokenManager;
+import org.eclipse.jdt.internal.formatter.TokenTraverser;
+import org.eclipse.jface.text.IRegion;
 
 public class WrapExecutor {
 
@@ -148,7 +149,7 @@
 			if (token.hasNLSTag())
 				this.isNLSTagInLine = true;
 
-			if (token.isWrappable()) {
+			if (token.isWrappable() && isWrapInsideFormatRegion(index)) {
 				WrapPolicy wrapPolicy = token.getWrapPolicy();
 				if (wrapPolicy.wrapMode == WrapMode.TOP_PRIORITY && getLineBreaksBefore() == 0
 						&& index > this.currentTopPriorityGroupEnd) {
@@ -202,7 +203,7 @@
 				this.isNextLineWrapped = true;
 				if (this.firstPotentialWrap < 0)
 					this.firstPotentialWrap = index + 1;
-				return false; 
+				return false;
 			}
 
 			boolean isLineEnd = getLineBreaksAfter() > 0 || getNext() == null || (getNext().isNextLineOnWrap()
@@ -227,6 +228,7 @@
 
 	private class WrapsApplier extends TokenTraverser {
 
+		private final TokenManager tm2 = WrapExecutor.this.tm;
 		private ArrayDeque<Token> stack = new ArrayDeque<>();
 		private int initialIndent;
 		private int currentIndent;
@@ -242,22 +244,57 @@
 				newLine(token, index);
 			} else if ((this.nextWrap != null && index == this.nextWrap.wrapTokenIndex)
 					|| checkForceWrap(token, index, this.currentIndent)
-					|| (token.isNextLineOnWrap() && WrapExecutor.this.tm
-							.get(WrapExecutor.this.tm.findFirstTokenInLine(index)).isWrappable())) {
+					|| (token.isNextLineOnWrap() && this.tm2.get(this.tm2.findFirstTokenInLine(index)).isWrappable())) {
 				token.breakBefore();
 				newLine(token, index);
 			} else {
+				checkOnColumnAlign(token, index);
 				setIndent(token, this.currentIndent);
 			}
 			return true;
 		}
 
+		private void checkOnColumnAlign(Token token, int index) {
+			// if some further tokens in a group are wrapped on column,
+			// the first one should be aligned on column even if it's not wrapped
+			WrapPolicy wrapPolicy = token.getWrapPolicy();
+			if (wrapPolicy == null || !wrapPolicy.indentOnColumn || !wrapPolicy.isFirstInGroup)
+				return;
+			int positionInLine = this.tm2.getPositionInLine(index);
+			if (this.tm2.toIndent(positionInLine, true) == positionInLine)
+				return;
+
+			Predicate<Token> aligner = t -> {
+				WrapPolicy wp = t.getWrapPolicy();
+				if (wp != null && wp.indentOnColumn && wp.wrapParentIndex == wrapPolicy.wrapParentIndex) {
+					this.currentIndent = this.tm2.toIndent(positionInLine, true);
+					token.setAlign(this.currentIndent);
+					this.stack.push(token);
+					return true;
+				}
+				return false;
+			};
+
+			// check all future wraps
+			WrapInfo furtherWrap = this.nextWrap;
+			while (furtherWrap != null) {
+				if (aligner.test(this.tm2.get(furtherWrap.wrapTokenIndex)))
+					return;
+				furtherWrap = WrapExecutor.this.wrapSearchResults.get(furtherWrap).nextWrap;
+			}
+			// check all tokens that are already wrapped
+			for (int i = index; i <= wrapPolicy.groupEndIndex; i++) {
+				Token t = this.tm2.get(i);
+				if (t.getLineBreaksBefore() > 0 && aligner.test(t))
+					return;
+			}
+		}
+
 		private void newLine(Token token, int index) {
 			while (!this.stack.isEmpty() && index > this.stack.peek().getWrapPolicy().groupEndIndex)
 				this.stack.pop();
 			if (token.getWrapPolicy() != null) {
 				setIndent(token, getWrapIndent(token));
-				handleOnColumnIndent(index, token.getWrapPolicy());
 				this.stack.push(token);
 			} else if (this.stack.isEmpty()) {
 				this.initialIndent = token.getIndent();
@@ -372,12 +409,14 @@
 
 	final TokenManager tm;
 	final DefaultCodeFormatterOptions options;
+	final List<IRegion> regions;
 
 	private final WrapInfo wrapInfoTemp = new WrapInfo();
 
-	public WrapExecutor(TokenManager tokenManager, DefaultCodeFormatterOptions options) {
+	public WrapExecutor(TokenManager tokenManager, DefaultCodeFormatterOptions options, List<IRegion> regions) {
 		this.tm = tokenManager;
 		this.options = options;
+		this.regions = regions;
 		this.lineAnalyzer = new LineAnalyzer(tokenManager, options);
 	}
 
@@ -426,7 +465,7 @@
 				token.setWrapped(false);
 				this.wrapSearchStack.pop();
 				this.wrapSearchResults.put(item, wrapResult);
-				assert wrapResult.nextWrap == null || this.wrapSearchResults.get(wrapResult.nextWrap) != null; 
+				assert wrapResult.nextWrap == null || this.wrapSearchResults.get(wrapResult.nextWrap) != null;
 				if (item.wrapTokenIndex == startTokenIndex && item.indent == indent)
 					break;
 			} else {
@@ -444,7 +483,7 @@
 
 	/**
 	 * The main algorithm that looks for optimal places to wrap.
-	 * Calls itself recursively to get results for wrapped sub-lines.  
+	 * Calls itself recursively to get results for wrapped sub-lines.
 	 */
 	private WrapResult findWraps(int wrapTokenIndex, int indent) {
 		final int lastIndex = this.lineAnalyzer.analyzeLine(wrapTokenIndex, indent);
@@ -482,7 +521,7 @@
 			if (this.lineAnalyzer.minStructureDepth < currentDepth)
 				depthLimit = currentDepth;
 		}
-		// optimization: turns out there's no point checking multiple wraps with the same policy 
+		// optimization: turns out there's no point checking multiple wraps with the same policy
 		LinkedHashSet<WrapPolicy> policiesTried = new LinkedHashSet<>();
 
 		for (int i = lastIndex; firstPotentialWrap >= 0 && i >= firstPotentialWrap; i--) {
@@ -506,7 +545,8 @@
 			if (!token.isWrappable()
 					|| (activeTopPriorityWrap >= 0 && i != activeTopPriorityWrap)
 					|| policiesTried.contains(wrapPolicy)
-					|| wrapPolicy.structureDepth >= depthLimit)
+					|| wrapPolicy.structureDepth >= depthLimit
+					|| !isWrapInsideFormatRegion(i))
 				continue;
 			policiesTried.add(wrapPolicy);
 
@@ -638,21 +678,11 @@
 		return result;
 	}
 
-	void handleOnColumnIndent(int tokenIndex, WrapPolicy wrapPolicy) {
-		if (wrapPolicy != null && wrapPolicy.indentOnColumn && !wrapPolicy.isFirstInGroup
-				&& this.options.tab_char == DefaultCodeFormatterOptions.TAB
-				&& !this.options.use_tabs_only_for_leading_indentations) {
-			// special case: first wrap in a group should be aligned on column even if it's not wrapped
-			for (int i = tokenIndex - 1; i >= 0; i--) {
-				Token token = this.tm.get(i);
-				WrapPolicy wrapPolicy2 = token.getWrapPolicy();
-				if (wrapPolicy2 != null && wrapPolicy2.isFirstInGroup
-						&& wrapPolicy2.wrapParentIndex == wrapPolicy.wrapParentIndex) {
-					token.setAlign(getWrapIndent(token));
-					break;
-				}
-			}
-		}
+	boolean isWrapInsideFormatRegion(int tokenIndex) {
+		int pos1 = this.tm.get(tokenIndex - 1).originalEnd;
+		int pos2 = this.tm.get(tokenIndex).originalStart;
+		return this.regions.stream().anyMatch(r -> (pos1 >= r.getOffset() && pos1 < r.getOffset() + r.getLength())
+				|| (pos2 >= r.getOffset() && pos2 < r.getOffset() + r.getLength()));
 	}
 
 	int getWrapIndent(Token token) {
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
index b07e6ba..83ef7dc 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/linewrap/WrapPreparator.java
@@ -85,6 +85,7 @@
 import org.eclipse.jdt.core.dom.ParameterizedType;
 import org.eclipse.jdt.core.dom.ProvidesDirective;
 import org.eclipse.jdt.core.dom.QualifiedName;
+import org.eclipse.jdt.core.dom.RecordDeclaration;
 import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
 import org.eclipse.jdt.core.dom.Statement;
@@ -322,11 +323,37 @@
 	}
 
 	@Override
-	public boolean visit(MethodDeclaration node) {
+	public boolean visit(RecordDeclaration node) {
 		int lParen = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN);
-		int rParen = node.getBody() == null ? this.tm.lastIndexIn(node, TokenNameRPAREN)
-				: this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN);
-		handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_declaration);
+		List<SingleVariableDeclaration> components = node.recordComponents();
+		int rParen = this.tm.firstIndexAfter(
+				components.isEmpty() ? node.getName() : components.get(components.size() - 1), TokenNameRPAREN);
+		handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_record_declaration);
+
+		if (!components.isEmpty()) {
+			int wrappingOption = this.options.alignment_for_record_components;
+			this.wrapGroupEnd = this.tm.lastIndexIn(components.get(components.size() - 1), -1);
+			handleArguments(components, wrappingOption);
+		}
+
+		List<Type> superInterfaceTypes = node.superInterfaceTypes();
+		if (!superInterfaceTypes.isEmpty()) {
+			this.wrapParentIndex = this.tm.lastIndexIn(node.getName(), -1);
+			this.wrapIndexes.add(this.tm.firstIndexBefore(superInterfaceTypes.get(0), TokenNameimplements));
+			prepareElementsList(superInterfaceTypes, TokenNameCOMMA, -1);
+			handleWrap(this.options.alignment_for_superinterfaces_in_record_declaration, PREFERRED);
+		}
+		return true;
+	}
+
+	@Override
+	public boolean visit(MethodDeclaration node) {
+		if (!node.isCompactConstructor()) {
+			int lParen = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN);
+			int rParen = node.getBody() == null ? this.tm.lastIndexIn(node, TokenNameRPAREN)
+					: this.tm.firstIndexBefore(node.getBody(), TokenNameRPAREN);
+			handleParenthesesPositions(lParen, rParen, this.options.parenthesis_positions_in_method_declaration);
+		}
 
 		List<SingleVariableDeclaration> parameters = node.parameters();
 		Type receiverType = node.getReceiverType();
@@ -346,7 +373,7 @@
 					? this.options.alignment_for_throws_clause_in_constructor_declaration
 					: this.options.alignment_for_throws_clause_in_method_declaration;
 			if ((wrappingOption & Alignment.M_INDENT_ON_COLUMN) == 0)
-				this.wrapParentIndex = lParen;
+				this.wrapParentIndex = this.tm.firstIndexAfter(node.getName(), TokenNameLPAREN);
 			prepareElementsList(exceptionTypes, TokenNameCOMMA, TokenNameRPAREN);
 			// instead of the first exception type, wrap the "throws" token
 			this.wrapIndexes.set(0, this.tm.firstIndexBefore(exceptionTypes.get(0), TokenNamethrows));
@@ -1275,7 +1302,7 @@
 			wrapMode = WrapMode.FORCE;
 		} else if (isAlreadyWrapped) {
 			wrapMode = WrapMode.DISABLED; // to avoid triggering top priority wrapping
-		} else if (isTopPriority) { 
+		} else if (isTopPriority) {
 			wrapMode = WrapMode.TOP_PRIORITY;
 		}
 		extraIndent *= this.options.indentation_size;
@@ -1286,7 +1313,7 @@
 	public void finishUp(ASTNode astRoot, List<IRegion> regions) {
 		preserveExistingLineBreaks();
 		applyBreaksOutsideRegions(regions);
-		new WrapExecutor(this.tm, this.options).executeWraps();
+		new WrapExecutor(this.tm, this.options, regions).executeWraps();
 		this.aligner.alignComments();
 		wrapComments();
 		fixEnumConstantIndents(astRoot);
diff --git a/org.eclipse.jdt.core/grammar/java.g b/org.eclipse.jdt.core/grammar/java.g
index 1db76f7..2e7cd82 100644
--- a/org.eclipse.jdt.core/grammar/java.g
+++ b/org.eclipse.jdt.core/grammar/java.g
@@ -125,6 +125,7 @@
 	AT308DOTDOTDOT
 	BeginCaseExpr
 	RestrictedIdentifierYield
+	RestrictedIdentifierrecord
 
 --    BodyMarker
 
@@ -634,6 +635,7 @@
 Header -> ClassHeader
 Header -> InterfaceHeader
 Header -> EnumHeader
+Header -> RecordHeaderPart
 Header -> AnnotationTypeDeclarationHeader
 Header -> StaticInitializer
 Header -> RecoveryMethodHeader
@@ -724,6 +726,8 @@
 -----------------------------------------------
 TypeDeclaration -> EnumDeclaration
 TypeDeclaration -> AnnotationTypeDeclaration
+-- 14 preview feature
+TypeDeclaration -> RecordDeclaration
 /:$readableName TypeDeclaration:/
 
 --18.7 Only in the LALR(1) Grammar
@@ -858,6 +862,7 @@
 -- 1.5 feature
 ClassMemberDeclarationNoAroundMethod -> EnumDeclaration
 ClassMemberDeclarationNoAroundMethod -> AnnotationTypeDeclaration
+ClassMemberDeclarationNoAroundMethod -> RecordDeclaration
 /:$readableName ClassMemberDeclaration:/
 
 -- Empty declarations are not valid Java ClassMemberDeclarations.
@@ -1409,6 +1414,8 @@
 -- 1.5 feature
 ClassMemberDeclaration -> EnumDeclaration
 ClassMemberDeclaration -> AnnotationTypeDeclaration
+-- 14 preview feature
+ClassMemberDeclaration -> RecordDeclaration
 /:$readableName ClassMemberDeclaration:/
 
 -- Empty declarations are not valid Java ClassMemberDeclarations.
@@ -1755,8 +1762,147 @@
 InterfaceMemberDeclaration -> InterfaceDeclaration
 InterfaceMemberDeclaration -> EnumDeclaration
 InterfaceMemberDeclaration -> AnnotationTypeDeclaration
+InterfaceMemberDeclaration -> RecordDeclaration
 /:$readableName InterfaceMemberDeclaration:/
 
+-----------------------------------------------
+-- 14 preview feature : record type
+-----------------------------------------------
+
+RecordDeclaration ::= RecordHeaderPart RecordBody
+/.$putCase consumeRecordDeclaration(); $break ./
+/:$readableName RecordDeclaration:/
+/:$compliance 14:/
+
+RecordHeaderPart ::= RecordHeaderName RecordHeader ClassHeaderImplementsopt 
+/.$putCase consumeRecordHeaderPart(); $break ./
+/:$readableName RecordHeaderPart:/
+/:$compliance 14:/
+
+RecordHeaderName ::= RecordHeaderName1 TypeParameters
+/.$putCase consumeRecordHeaderNameWithTypeParameters(); $break ./
+/:$compliance 14:/
+
+RecordHeaderName -> RecordHeaderName1 
+/:$readableName RecordHeaderName:/
+/:$compliance 14:/
+
+RecordHeaderName1 ::= Modifiersopt RestrictedIdentifierrecord JavaIdentifier -- AspectJ extension, was 'Identifier'
+/.$putCase consumeRecordHeaderName1(); $break ./
+/:$readableName RecordHeaderName:/
+/:$compliance 14:/
+
+RecordComponentHeaderRightParen ::= ')'
+/.$putCase consumeRecordComponentHeaderRightParen(); $break ./
+/:$readableName ):/
+/:$recovery_template ):/
+/:$compliance 14:/
+
+RecordHeader ::= '(' RecordComponentsopt RecordComponentHeaderRightParen
+/.$putCase consumeRecordHeader(); $break ./
+/:$readableName RecordHeader:/
+/:$compliance 14:/
+
+RecordComponentsopt ::= $empty
+/.$putCase consumeRecordComponentsopt(); $break ./
+RecordComponentsopt -> RecordComponents
+/:$readableName RecordComponentsopt:/
+/:$compliance 14:/
+
+RecordComponents -> RecordComponent
+RecordComponents ::= RecordComponents ',' RecordComponent
+/.$putCase consumeRecordComponents(); $break ./
+/:$readableName RecordComponents:/
+/:$compliance 14:/
+
+RecordComponent -> VariableArityRecordComponent
+RecordComponent ::= Modifiersopt Type VariableDeclaratorId
+/.$putCase consumeRecordComponent(false); $break ./
+/:$readableName RecordComponent:/
+/:$compliance 14:/
+
+VariableArityRecordComponent ::= Modifiersopt Type PushZeroTypeAnnotations '...' VariableDeclaratorId
+/.$putCase consumeRecordComponent(true); $break ./
+/:$readableName VariableArityRecordComponent:/
+/:$compliance 14:/
+
+VariableArityRecordComponent ::= Modifiersopt Type @308... TypeAnnotations '...' VariableDeclaratorId
+/.$putCase consumeRecordComponent(true); $break ./
+/:$readableName VariableArityRecordComponent:/
+/:$compliance 14:/
+/:$recovery_template JavaIdentifier JavaIdentifier:/  -- AspectJ extension, was Identifier Identifier
+
+RecordBody ::= '{' RecordBodyDeclarationopt '}'
+/.$putCase consumeRecordBody(); $break ./
+/:$readableName RecordBody:/
+/:$compliance 14:/
+
+RecordBodyDeclarationopt ::= $empty
+/.$putCase consumeEmptyRecordBodyDeclaration(); $break ./
+RecordBodyDeclarationopt -> RecordBodyDeclarations
+/:$readableName RecordBodyDeclarationopt:/
+/:$compliance 14:/
+
+RecordBodyDeclarations ::= RecordBodyDeclaration
+RecordBodyDeclarations ::= RecordBodyDeclarations RecordBodyDeclaration
+/.$putCase consumeRecordBodyDeclarations(); $break ./
+/:$readableName RecordBodyDeclarations:/
+/:$compliance 14:/
+
+RecordBodyDeclaration ::=  ClassBodyDeclaration
+/.$putCase consumeRecordBodyDeclaration(); $break ./
+RecordBodyDeclaration ::=  CompactConstructorDeclaration
+/.$putCase consumeRecordBodyDeclaration(); $break ./
+/:$readableName RecordBodyDeclaration:/
+/:$compliance 14:/
+
+CompactConstructorDeclaration ::= CompactConstructorHeader MethodBody
+/.$putCase consumeCompactConstructorDeclaration(); $break ./
+/:$readableName CompactConstructorDeclaration:/
+/:$compliance 14:/
+
+CompactConstructorHeader ::= CompactConstructorHeaderName MethodHeaderThrowsClauseopt
+/.$putCase consumeCompactConstructorHeader(); $break ./
+/:$readableName CompactConstructorDeclaration:/
+/:$compliance 14:/
+
+CompactConstructorHeaderName ::= Modifiersopt JavaIdentifier -- AspectJ was 'Identifier'
+/.$putCase consumeCompactConstructorHeaderName(); $break ./
+CompactConstructorHeaderName ::= Modifiersopt TypeParameters JavaIdentifier -- AspectJ was 'Identifier'
+/.$putCase consumeCompactConstructorHeaderNameWithTypeParameters(); $break ./
+/:$readableName CompactConstructorHeaderName:/
+/:$compliance 14:/
+
+-----------------------------------------------
+-- 14 preview feature : end of record type
+-----------------------------------------------
+
+-----------------------------------------------
+-- 14 preview feature : instanceof pattern matching
+-----------------------------------------------
+
+
+InstanceofExpression -> RelationalExpression
+InstanceofExpression ::= InstanceofExpression 'instanceof' TypeOrPattern
+/.$putCase consumeInstanceOfExpression(); $break ./
+/:$readableName Expression:/
+
+TypeOrPattern -> Type
+TypeOrPattern -> Pattern
+Pattern -> TypeTestPattern
+TypeTestPattern ::= Type Identifier
+/.$putCase consumeTypeTestPattern(); $break ./
+/:$readableName TypeTestPattern:/
+
+--InstanceofExpression ::= InstanceofExpression 'instanceof' Type Identifier
+--/.$putCase consumeInstanceOfExpressionPattern(); $break ./
+--/:$readableName Expression:/
+--/:$compliance 14:/
+
+-----------------------------------------------
+-- 14 preview feature : end of instanceof pattern matching
+-----------------------------------------------
+
 ConstantDeclaration -> FieldDeclaration
 /:$readableName ConstantDeclaration:/
 
@@ -1804,6 +1950,7 @@
 BlockStatement -> Statement
 --1.1 feature
 BlockStatement -> ClassDeclaration
+BlockStatement -> RecordDeclaration
 BlockStatement ::= InterfaceDeclaration
 /.$putCase consumeInvalidInterfaceDeclaration(); $break ./
 /:$readableName BlockStatement:/
diff --git a/org.eclipse.jdt.core/lib/java14api.jar b/org.eclipse.jdt.core/lib/java14api.jar
new file mode 100644
index 0000000..fcf9985
--- /dev/null
+++ b/org.eclipse.jdt.core/lib/java14api.jar
Binary files differ
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BindingKey.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BindingKey.java
index 3f9094d..11d5782 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BindingKey.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/BindingKey.java
@@ -204,11 +204,11 @@
 	 * @param genericTypeKey the binding key of the generic type
 	 * @param boundKind one of {@link Signature#C_STAR}, {@link Signature#C_SUPER}, or {@link Signature#C_EXTENDS}
 	 * @param boundTypeKey the binding key of the bounding type.
-	 * @param rank the relative position of this wild card type in the parameterization of the generic type. 
+	 * @param rank the relative position of this wild card type in the parameterization of the generic type.
 	 * @return a new wildcard type binding key
 	 * @since 3.5
 	 */
-	
+
 	public static String createWildcardTypeBindingKey(String genericTypeKey, char boundKind, String boundTypeKey, int rank) {
 		// Note this implementation is heavily dependent on WildcardBinding#computeUniqueKey()
 		String wildCardKey;
@@ -231,11 +231,11 @@
 	/**
 	 * Returns the binding key of the declaring type of the element represented by this binding key. If the binding key
 	 * does not represent a member or if the member doesn't have a declaring type, returns <code>null</code>.
-	 * 
+	 *
 	 * <p>
 	 * Note that only binding keys for references to methods and fields
 	 * are fully supported. The binding keys for declarations will not have type parameters.
-	 * 
+	 *
 	 * @return the type binding key or <code>null</code>
 	 * @since 3.7.1
 	 */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionContext.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionContext.java
index 89f1264..11b441e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionContext.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionContext.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2012 IBM Corporation and others.
+ * Copyright (c) 2005, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -55,7 +55,7 @@
 	 * @since 3.4
 	 */
 	public static final int TL_STATEMENT_START = 2;
-	
+
 	/**
 	 * The completed token is the first token of a constructor
 	 * invocation expression.<br>
@@ -75,6 +75,19 @@
 	public static final int TL_CONSTRUCTOR_START = 4;
 
 	/**
+	 * The completed token is part of an import statement<br>
+	 * e.g.
+	 * <pre>
+	 * import java.util| // completion occurs at |
+	 * </pre>
+	 *
+	 * @see #getTokenLocation()
+	 *
+	 * @since 3.21
+	 */
+	public static final int TL_IN_IMPORT = 8;
+
+	/**
 	 * The completion token is unknown.
 	 * @since 3.2
 	 */
@@ -157,7 +170,7 @@
 	public char[][] getExpectedTypesSignatures() {
 		return null; // default overridden by concrete implementation
 	}
-	
+
 	/**
 	 * Return keys of expected types of a potential completion proposal at the completion position.
 	 *
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java
index f013e76..4dd896d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionProposal.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -771,7 +771,7 @@
 	 * @since 3.4
 	 */
 	public static final int FIELD_REF_WITH_CASTED_RECEIVER = 25;
-	
+
 	/**
 	 * Completion is a reference to a constructor.
 	 * This kind of completion might occur in a context like
@@ -803,11 +803,11 @@
 	 *
 	 * @see #getKind()
 	 * @see CompletionRequestor#setAllowsRequiredProposals(int, int, boolean)
-	 * 
+	 *
 	 * @since 3.5
 	 */
 	public static final int CONSTRUCTOR_INVOCATION = 26;
-	
+
 	/**
 	 * Completion is a reference of a constructor of an anonymous class.
 	 * This kind of completion might occur in a context like
@@ -843,7 +843,7 @@
 	 *
 	 * @see #getKind()
 	 * @see CompletionRequestor#setAllowsRequiredProposals(int, int, boolean)
-	 * 
+	 *
 	 * @since 3.5
 	 */
 	public static final int ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION = 27;
@@ -1065,7 +1065,7 @@
 	 * @param completion the completion string
 	 */
 	public void setCompletion(char[] completion) {
-		// default overridden by concrete implementation		
+		// default overridden by concrete implementation
 	}
 
 	/**
@@ -1180,9 +1180,9 @@
 	 * 	<li><code>METHOD_DECLARATION</code> - type signature
 	 * of the type that declares the method that is being
 	 * implemented or overridden</li>
-	 * 	<li><code>MODULE_DECLARATION</code> - 
+	 * 	<li><code>MODULE_DECLARATION</code> -
 	 * possible name of the module that is being declared</li>
-	 * 	<li><code>MODULE_REF</code> - 
+	 * 	<li><code>MODULE_REF</code> -
 	 * name of the module that is referenced</li>
 	 * 	<li><code>PACKAGE_REF</code> - dot-based package
 	 * name of the package that is referenced</li>
@@ -1785,17 +1785,17 @@
 		// default overridden by concrete implementation
 	}
 
-	/** 
+	/**
 	 * Returns whether it is safe to use the '<>' (diamond) operator in place of explicitly specifying
 	 * type arguments for this proposal.
-	 * 
+	 *
 	 * <p>
 	 * This is only relevant for source level 1.7 or greater.
 	 * </p>
-	 * 
+	 *
 	 * @param coreContext the completion context associated with the proposal
 	 * @since 3.7.1
-	 * @return <code>true</code> if it is safe to use the diamond operator for the constructor invocation, 
+	 * @return <code>true</code> if it is safe to use the diamond operator for the constructor invocation,
 	 * <code>false</code> otherwise. Also returns <code>false</code> for source levels below 1.7
 	 */
 	public boolean canUseDiamond(CompletionContext coreContext) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestor.java
index fb29721..1c97185 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CompletionRequestor.java
@@ -363,7 +363,7 @@
 
 	/**
 	 * If this returns true, exclude test sources and dependencies.
-	 * 
+	 *
 	 * @return <code>true</code> if this requestor does not want to get any completions from test code.
 	 * @see IClasspathAttribute#TEST
 	 * @since 3.14
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CorrectionEngine.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CorrectionEngine.java
index 4628df1..3d97ca1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CorrectionEngine.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/CorrectionEngine.java
@@ -242,7 +242,7 @@
 			Map<String,String> currentProjectOptions = this.compilationUnit.getJavaProject().getOptions(true);
 			long sourceLevel = CompilerOptions.versionToJdkLevel(currentProjectOptions.get(JavaCore.COMPILER_SOURCE));
 			long complianceLevel = CompilerOptions.versionToJdkLevel(currentProjectOptions.get(JavaCore.COMPILER_COMPLIANCE));
-			
+
 			Scanner scanner =
 				new Scanner(
 					false /*comment*/,
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java
index dd4ea08..4950c1b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Flags.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -174,15 +174,26 @@
 	 * @since 3.10
 	 */
 	public static final int AccAnnotationDefault = ClassFileConstants.AccAnnotationDefault;
-	
+
 	/**
 	 * Module declaration property flag.
 	 * Used to flag a compilation unit or a class file that contains a module declaration.
-	 * 
+	 *
 	 * @since 3.14
 	 */
 	public static final int AccModule = ClassFileConstants.AccModule;
-	
+
+	/**
+	 * Record property flag.
+	 * <p>
+	 * Note that this flag's value is internal and is not defined in the
+	 * Virtual Machine specification.
+	 * </p>
+	 * @since 3.22
+	 * @noreference This field is not intended to be referenced by clients as it is a part of Java preview feature.
+	 */
+	public static final int  AccRecord = ExtraCompilerModifiers.AccRecord;
+
 	/**
 	 * Not instantiable.
 	 */
@@ -380,6 +391,19 @@
 	}
 
 	/**
+	  * Returns whether the given integer has the <code>AccRecord</code>
+	 * bit set.
+	 *
+	 * @param flags the flags
+	 * @return <code>true</code> if the <code>AccRecord</code> flag is included
+	 * @see #AccRecord
+	 * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
+	 */
+	public static boolean isRecord(int flags) {
+		return (flags & AccRecord) != 0;
+	}
+
+	/**
 	 * Returns whether the given integer has the <code>AccAnnotation</code>
 	 * bit set.
 	 *
@@ -416,7 +440,7 @@
 	public static boolean isAnnnotationDefault(int flags) {
 		return (flags & AccAnnotationDefault) != 0;
 	}
-	
+
 	/**
 	 * Returns whether the given integer has the <code>AccModule</code>
 	 * bit set.
@@ -424,7 +448,7 @@
 	 * @return <code>true</code> if the <code>AccModule</code> flag is included
 	 * @see #AccModule
 	 * @since 3.14
-	 */	
+	 */
 	public static boolean isModule(int flags) {
 		return (flags & AccModule) != 0;
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IAccessRule.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IAccessRule.java
index 2025092..850cd4b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IAccessRule.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IAccessRule.java
@@ -56,10 +56,10 @@
  * </p>
  *
  * @since 3.1
- * 
+ *
  * @see JavaCore#newAccessRule(IPath, int)
  * @see IClasspathEntry#getExclusionPatterns()
- * 
+ *
  * @noimplement This interface is not intended to be implemented by clients.
  */
 public interface IAccessRule {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java
index 84cd2bd..6189c61 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathAttribute.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for
@@ -57,26 +57,26 @@
 
 	/**
 	 * Constant for the name of the javadoc location attribute.
-	 * 
+	 *
 	 * <p>The value for this attribute has to be the string representation of a URL.</p>
 	 *
 	 * @since 3.1
 	 */
 	String JAVADOC_LOCATION_ATTRIBUTE_NAME = "javadoc_location"; //$NON-NLS-1$
-	
+
 	/**
 	 * Constant for the name of the index location attribute.
-	 * 
+	 *
 	 * <p>The value for this attribute has to be the string representation of a URL.
 	 * It should point to an existing index file in a folder or a jar. The URL can also be of platform protocol.</p>
-	 * 
+	 *
 	 * @since 3.8
 	 */
 	String INDEX_LOCATION_ATTRIBUTE_NAME = "index_location"; //$NON-NLS-1$
 
 	/**
 	 * Constant for the name of the encoding to be used for source attachments.
-	 * 
+	 *
 	 * <p>The value of this attribute has to be a string representation of a valid encoding. The encoding
 	 * for a source attachment is determined in the following order: </p>
 	 *
@@ -131,7 +131,7 @@
 
 	/**
 	 * Constant for the name of the add-exports attribute.
-	 * 
+	 *
 	 * <p>The value of this attribute must adhere to the syntax of <code>javac's</code>
 	 * {@code --add-exports} command line option: {@code <source-module>/<package>=<target-module>(,<target-module>)*}.
 	 * Multiple such options are packed as a ':' separated list into a single classpath attribute.
@@ -139,14 +139,14 @@
 	 *
 	 * <p>Classpath entries with this attribute should also have a {@link #MODULE} attribute
 	 * with value <code>"true"</code>.</p>
-	 * 
+	 *
 	 * @since 3.14
 	 */
 	String ADD_EXPORTS = "add-exports"; //$NON-NLS-1$
 
 	/**
 	 * Constant for the name of the add-opens attribute.
-	 * 
+	 *
 	 * <p>The value of this attribute must adhere to the syntax of <code>javac's</code>
 	 * {@code --add-opens} command line option: {@code <source-module>/<package>=<target-module>(,<target-module>)*}.
 	 * Multiple such options are packed as a ':' separated list into a single classpath attribute.
@@ -154,19 +154,19 @@
 	 *
 	 * <p>Classpath entries with this attribute should also have a {@link #MODULE} attribute
 	 * with value <code>"true"</code>.</p>
-	 * 
+	 *
 	 * @since 3.18
 	 */
 	String ADD_OPENS = "add-opens"; //$NON-NLS-1$
 
 	/**
 	 * Constant for the name of the add-reads attribute.
-	 * 
+	 *
 	 * <p>The value of this attribute must adhere to the syntax of <code>javac's</code>
 	 * {@code --add-reads} command line option: {@code <source-module>=<target-module>}.
 	 * Multiple such options are packed as a ':' separated list into a single classpath attribute.
 	 * The given reads edge will be added at compile time.</p>
-	 * 
+	 *
 	 * @since 3.14
 	 */
 	String ADD_READS = "add-reads"; //$NON-NLS-1$
@@ -207,12 +207,12 @@
 
 	/**
 	 * Constant for the name of the limit-modules attribute.
-	 * 
+	 *
 	 * <p>The value of this attribute must be a comma-separated list of names of modules
 	 * defined in the classpath entry, to which this attribute is attached.
 	 * The set of modules observable through this entry will be limited to
 	 * the transitive closure of modules in this list.</p>
-	 * 
+	 *
 	 * <p>This attribute is supported for classpath entries of kind
 	 * {@link IClasspathEntry#CPE_CONTAINER}.
 	 * A classpath entry having this attribute must also have the
@@ -226,29 +226,29 @@
 	 * Constant of the name of the module-main-class attribute.
 	 * The classpath entry holding this attribute must refer to a source folder
 	 * containing the implementation of a module.
-	 * 
+	 *
 	 * <p>The value of this attribute must be the name of a class defined in this module.
 	 * It will be used for generating the <code>ModuleMainClass</code> attribute
 	 * in <code>module-info.class</code>.</p>
-	 * 
+	 *
 	 * @since 3.14
 	 */
 	String MODULE_MAIN_CLASS = "module-main-class"; //$NON-NLS-1$
 
 	/**
-	 * Constant for the name of the external annotation path attribute. 
-	 * 
+	 * Constant for the name of the external annotation path attribute.
+	 *
 	 * <p>The value for this attribute has to be the string representation of a path.
 	 * It should point to an existing directory where external annotations can be
 	 * found to support annotation based null analysis involving 3rd party libraries.</p>
-	 * 
+	 *
 	 * @since 3.11
 	 */
 	String EXTERNAL_ANNOTATION_PATH = "annotationpath"; //$NON-NLS-1$
 
 	/**
 	 * Constant for the name of the test attribute.
-	 * 
+	 *
 	 * <p>
 	 * The possible values for this attribute are <code>"true"</code> or <code>"false"</code>. When not present,
 	 * <code>"false"</code> is assumed. If the value of this attribute is <code>"true"</code>, and the classpath entry
@@ -259,20 +259,20 @@
 	 * not have the test attribute set to to "true". During the compilation of test sources, all code is visible as if
 	 * this attribute didn't exist at all.
 	 * </p>
-	 * 
+	 *
 	 * @since 3.14
 	 */
 	String TEST = "test"; //$NON-NLS-1$
 
 	/**
 	 * Constant for the name of the without_test_code attribute.
-	 * 
+	 *
 	 * <p>
 	 * The possible values for this attribute are <code>"true"</code> or <code>"false"</code>. When not present,
 	 * <code>"false"</code> is assumed. If the value of this attribute is <code>"true"</code>, and the classpath entry
 	 * is a project, any test code reachable via that classpath entry will not be visible even to test sources.
 	 * </p>
-	 * 
+	 *
 	 * @since 3.14
 	 */
 	String WITHOUT_TEST_CODE = "without_test_code"; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java
index ba3afda..1bfd257 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathContainer.java
@@ -30,7 +30,7 @@
  * <li> project entries (<code>CPE_PROJECT</code>) </li>
  * </ul>
  * In particular, a classpath container can neither reference further classpath containers or classpath variables.
- * <p> 
+ * <p>
  * A library entry can reference other libraries through the Class-Path section of the JAR's MANIFEST.MF file. If the
  * container wants such referenced entries to be part of the classpath, the container must explicitly add them to the
  * array returned from {@link #getClasspathEntries()}.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
index ad735bc..cc13438 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IClasspathEntry.java
@@ -417,23 +417,23 @@
 	 */
 	IPath getSourceAttachmentRootPath();
 
-	
+
 	/**
-	 * Returns the classpath entry that is making a reference to this classpath entry. For entry kinds 
-	 * {@link #CPE_LIBRARY}, the return value is the entry that is representing the JAR that includes 
-	 * <code>this</code> in the MANIFEST.MF file's Class-Path section. For entry kinds other than 
-	 * {@link #CPE_LIBRARY}, this returns <code>null</code>. For those entries that are on the raw classpath already, 
-	 * this returns <code>null</code>.  
+	 * Returns the classpath entry that is making a reference to this classpath entry. For entry kinds
+	 * {@link #CPE_LIBRARY}, the return value is the entry that is representing the JAR that includes
+	 * <code>this</code> in the MANIFEST.MF file's Class-Path section. For entry kinds other than
+	 * {@link #CPE_LIBRARY}, this returns <code>null</code>. For those entries that are on the raw classpath already,
+	 * this returns <code>null</code>.
 	 * <p>
 	 * It is possible that multiple library entries refer to the same entry
-	 * via the MANIFEST.MF file. In those cases, this method returns the first classpath entry 
-	 * that appears in the raw classpath. However, this does not mean that the other referencing 
-	 * entries do not relate to their referenced entries. 
-	 * See {@link JavaCore#getReferencedClasspathEntries(IClasspathEntry, IJavaProject)} for 
+	 * via the MANIFEST.MF file. In those cases, this method returns the first classpath entry
+	 * that appears in the raw classpath. However, this does not mean that the other referencing
+	 * entries do not relate to their referenced entries.
+	 * See {@link JavaCore#getReferencedClasspathEntries(IClasspathEntry, IJavaProject)} for
 	 * more details.
 	 * </p>
-	 * 
-	 * @return the classpath entry that is referencing this entry or <code>null</code> if 
+	 *
+	 * @return the classpath entry that is referencing this entry or <code>null</code> if
 	 * 		not applicable.
 	 * @since 3.6
 	 */
@@ -475,7 +475,7 @@
 	/**
 	 * This is a convience method, that returns <code>true</code> if the extra attributes contain an attribute whose name
 	 * is {@link IClasspathAttribute#TEST} and whose value is 'true'.
-	 * 
+	 *
 	 * @see #getExtraAttributes()
 	 * @see IClasspathAttribute#TEST
 	 * @return <code>true</code>, if if the extra attributes contain a attribute whose name is
@@ -493,7 +493,7 @@
 	/**
 	 * This is a convience method, that returns <code>true</code> if the extra attributes contain an attribute whose name
 	 * is {@link IClasspathAttribute#WITHOUT_TEST_CODE} and whose value is 'true'.
-	 * 
+	 *
 	 * @see #getExtraAttributes()
 	 * @see IClasspathAttribute#WITHOUT_TEST_CODE
 	 * @return <code>true</code>, if if the extra attributes contain a attribute whose name is
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java
index 0e0a5f5..28792ca 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java
@@ -87,7 +87,7 @@
  	 */
 	void codeComplete(int offset, CompletionRequestor requestor)
 		throws JavaModelException;
-	
+
 	/**
 	 * Performs code completion at the given offset position in this compilation unit,
 	 * reporting results to the given completion requestor. The <code>offset</code>
@@ -99,7 +99,7 @@
 	 * can be very long to compute are proposed. To avoid that the code assist operation
 	 * take too much time a {@link IProgressMonitor} which automatically cancel the code
 	 * assist operation when a specified amount of time is reached could be used.
-	 * 
+	 *
 	 * <pre>
 	 * new IProgressMonitor() {
 	 *     private final static int TIMEOUT = 500; //ms
@@ -188,7 +188,7 @@
 	 */
 	void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner)
 		throws JavaModelException;
-	
+
 	/**
 	 * Performs code completion at the given offset position in this compilation unit,
 	 * reporting results to the given completion requestor. The <code>offset</code>
@@ -207,7 +207,7 @@
 	 * can be very long to compute are proposed. To avoid that the code assist operation
 	 * take too much time a {@link IProgressMonitor} which automatically cancel the code
 	 * assist operation when a specified amount of time is reached could be used.
-	 * 
+	 *
 	 * <pre>
 	 * new IProgressMonitor() {
 	 *     private final static int TIMEOUT = 500; //ms
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java
index 62addd9..0507a4d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICompilationUnit.java
@@ -421,7 +421,7 @@
  * Returns <code>null</code> if this <code>ICompilationUnit</code> is the primary
  * working copy, or this <code>ICompilationUnit</code> is not a working copy,
  * otherwise the <code>WorkingCopyOwner</code>
- * 
+ *
  * @return <code>null</code> if this <code>ICompilationUnit</code> is the primary
  * working copy, or this <code>ICompilationUnit</code> is not a working copy,
  * otherwise the <code>WorkingCopyOwner</code>
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java
index a877f00..0e46339 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IElementChangedListener.java
@@ -19,7 +19,7 @@
  * <p>
  * This interface may be implemented by clients.
  * </p>
- * 
+ *
  * @see JavaCore#addElementChangedListener(IElementChangedListener)
  */
 public interface IElementChangedListener {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java
index 6e6a320..9348af1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java
@@ -70,7 +70,7 @@
 	 * <p>If the argument contains a '#', the character is doubled.<br>
 	 * {"foo#test", "bar" } is encoded as "2:foo##test#bar"
 	 * </p>
-	 * 
+	 *
 	 * @since 2.0
 	 * @see CorrectionEngine#getProblemArguments(IMarker)
 	 */
@@ -117,12 +117,12 @@
 	 * @since 2.0
 	 */
 	String CLASSPATH_FILE_FORMAT = "classpathFileFormat"; //$NON-NLS-1$
-	
+
 	/**
-	 * Output overlapping another source attribute (value <code>"outputOverlappingSource"</code>). 
-	 * Used only on buildpath problem markers. The value of this attribute is 
+	 * Output overlapping another source attribute (value <code>"outputOverlappingSource"</code>).
+	 * Used only on buildpath problem markers. The value of this attribute is
 	 * either "true" or "false".
-	 * 
+	 *
 	 * @since 3.6.4
 	 */
 	String OUTPUT_OVERLAPPING_SOURCE = "outputOverlappingSource"; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java
index 1604a57..46669ac 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java
@@ -132,12 +132,12 @@
 
 	/**
 	 * Status constant indicating that a destination provided for a copy/move/rename operation
-	 * is invalid. The destination for a package fragment must be a package fragment root; the 
-	 * destination for a compilation unit must be a package fragment; the destination for 
-	 * a package declaration or import declaration must be a compilation unit; the 
-	 * destination for a type must be a type or compilation unit; the destination for any 
+	 * is invalid. The destination for a package fragment must be a package fragment root; the
+	 * destination for a compilation unit must be a package fragment; the destination for
+	 * a package declaration or import declaration must be a compilation unit; the
+	 * destination for a type must be a type or compilation unit; the destination for any
 	 * type member (other than a type) must be a type. <br>
-	 * 
+	 *
 	 * The destination element can be retrieved using <code>getElements</code> on the status object.
 	 */
 	public static final int INVALID_DESTINATION = 978;
@@ -339,13 +339,13 @@
 	 * @since 3.4
 	 */
 	public static final int BAD_TEXT_EDIT_LOCATION = 1011;
-	
+
 	/**
 	 * <p>Status constant indicating that the attached javadoc content cannot be retrieved due to timeout
 	 * @since 3.7
 	 */
 	public static final int CANNOT_RETRIEVE_ATTACHED_JAVADOC_TIMEOUT = 1012;
-	
+
 	/**
 	 * <p>Status constant indicating that the default or specific output folder is overlapping
 	 * with another source location. </p>
@@ -359,9 +359,9 @@
 	 * @see org.eclipse.jdt.core.IClasspathAttribute#EXTERNAL_ANNOTATION_PATH
 	 */
 	public static final int CP_INVALID_EXTERNAL_ANNOTATION_PATH = 1014;
-	
+
 	/**
-	 * Status constant indicating that a source folder marked to contain test sources has no separate output location, but the project also contains main sources. 
+	 * Status constant indicating that a source folder marked to contain test sources has no separate output location, but the project also contains main sources.
 	 * preference settings.
 	 * @see IClasspathAttribute#TEST
 	 * @since 3.14
@@ -380,7 +380,7 @@
 	 * Status constant indicating that the project has only main source folders but depends on a project that has only
 	 * test source folders.
 	 * </p>
-	 * 
+	 *
 	 * @since 3.16
 	 */
 	public static final int MAIN_ONLY_PROJECT_DEPENDS_ON_TEST_ONLY_PROJECT = 1017;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java
index 0938c2f..07f4d3d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaProject.java
@@ -54,7 +54,7 @@
  * The children of a Java project are the package fragment roots that are
  * defined by the classpath and contained in this project (in other words, it
  * does not include package fragment roots for other projects). The children
- * (i.e. the package fragment roots) appear in the order they are defined by 
+ * (i.e. the package fragment roots) appear in the order they are defined by
  * the classpath.
  * <p>
  * An instance of one of these handles can be created via
@@ -69,11 +69,11 @@
 
 	/**
 	 * Path of the file containing the project's classpath relative to the project's root.
-	 * 
+	 *
 	 * <p>The file is a child of the project folder.</p>
 	 * <p>The format of this file is unspecified and it is not meant to be modified.
 	 * Its contents is modified by using the <code>IJavaProject#setRawClasspath(..)</code> methods.</p>
-	 * 
+	 *
 	 * @see #setRawClasspath(IClasspathEntry[], IProgressMonitor)
 	 * @see #setRawClasspath(IClasspathEntry[], boolean, IProgressMonitor)
 	 * @see #setRawClasspath(IClasspathEntry[], IPath, IProgressMonitor)
@@ -235,7 +235,7 @@
 	 * <p>
 	 * The result does not include package fragment roots in other projects
 	 * referenced on this project's classpath.
-	 * 
+	 *
 	 * @param entry the given entry
 	 * @return the existing package fragment roots identified by the given entry
 	 * @see IClasspathContainer
@@ -251,7 +251,7 @@
 	 * <p>
 	 * This API can be used to bypass any filter and get really all roots to which the given entry is resolved.
 	 * </p>
-	 * 
+	 *
 	 * @param entry a classpath entry of this Java project
 	 * @return the unfiltered array of package fragment roots to which the classpath entry resolves
 	 * @see #findPackageFragmentRoots(IClasspathEntry)
@@ -431,7 +431,7 @@
 	 * If the returned module descriptor is part of a compilation unit, its owner is the given owner.
 	 * @param moduleName the given module name
 	 * @param owner the owner of the returned module descriptor's compilation unit
-	 * 
+	 *
 	 * @exception JavaModelException if this project does not exist or if an
 	 *		exception occurs while accessing its corresponding resource
 	 * @return the first module found following this project's module path
@@ -554,7 +554,7 @@
 	 * Returns all of the  package fragment roots contained in this
 	 * project, identified on this project's resolved classpath. The result
 	 * does not include package fragment roots in other projects referenced
-	 * on this project's classpath. The package fragment roots appear in the 
+	 * on this project's classpath. The package fragment roots appear in the
 	 * order they are defined by the classpath.
 	 *
 	 * <p>NOTE: This is equivalent to <code>getChildren()</code>.
@@ -578,7 +578,7 @@
 	 * <p>
 	 * The result does not include package fragment roots in other projects
 	 * referenced on this project's classpath.
-	 * 
+	 *
 	 * @param entry the given entry
 	 * @return the existing package fragment roots identified by the given entry
 	 * @see IClasspathContainer
@@ -610,16 +610,16 @@
 	IProject getProject();
 
 	/**
-	 * Returns the {@link IModuleDescription} this project represents or 
-	 * null if the Java project doesn't represent any named module. A Java 
-	 * project is said to represent a module if any of its source package 
-	 * fragment roots (see {@link IPackageFragmentRoot#K_SOURCE}) contains a 
+	 * Returns the {@link IModuleDescription} this project represents or
+	 * null if the Java project doesn't represent any named module. A Java
+	 * project is said to represent a module if any of its source package
+	 * fragment roots (see {@link IPackageFragmentRoot#K_SOURCE}) contains a
 	 * valid Java module descriptor, or if one of its classpath entries
 	 * has a valid {@link IClasspathAttribute#PATCH_MODULE} attribute
 	 * affecting the current project.
 	 * In the latter case the corresponding module description of the
 	 * location referenced by that classpath entry is returned.
-	 * 
+	 *
 	 * @return the {@link IModuleDescription} this project represents.
 	 * @exception JavaModelException if this element does not exist or if an
 	 *		exception occurs while accessing its corresponding resource
@@ -628,13 +628,13 @@
 	IModuleDescription getModuleDescription() throws JavaModelException;
 
 	/**
-	 * Returns the <code>IModuleDescription</code> owned by this project or 
-	 * null if the Java project doesn't own a valid Java module descriptor. 
+	 * Returns the <code>IModuleDescription</code> owned by this project or
+	 * null if the Java project doesn't own a valid Java module descriptor.
 	 * This method considers only module descriptions contained in any of the
 	 * project's source package fragment roots (see {@link IPackageFragmentRoot#K_SOURCE}).
 	 * In particular any {@link IClasspathAttribute#PATCH_MODULE} attribute
 	 * is not considered.
-	 * 
+	 *
 	 * @return the {@link IModuleDescription} this project owns.
 	 * @exception JavaModelException if this element does not exist or if an
 	 *		exception occurs while accessing its corresponding resource
@@ -701,8 +701,8 @@
 	 * Because of this, hanging on resolved classpath is not recommended.
 	 * </p>
 	 * <p>
-	 * Note that if the resolution creates duplicate entries 
-	 * (i.e. {@link IClasspathEntry entries} which are {@link Object#equals(Object)}), 
+	 * Note that if the resolution creates duplicate entries
+	 * (i.e. {@link IClasspathEntry entries} which are {@link Object#equals(Object)}),
 	 * only the first one is added to the resolved classpath.
 	 * </p>
 	 *
@@ -1095,23 +1095,23 @@
 	void setRawClasspath(IClasspathEntry[] entries, boolean canModifyResources, IProgressMonitor monitor) throws JavaModelException;
 
 	/**
-	 * Works similar to {@link #setRawClasspath(IClasspathEntry[], IPath, IProgressMonitor)} and 
+	 * Works similar to {@link #setRawClasspath(IClasspathEntry[], IPath, IProgressMonitor)} and
 	 * additionally allows persisting the given array of referenced entries for this project.
-	 * The referenced entries and their attributes are stored in the .classpath file of this 
-	 * project. For details on referenced entries, see 
+	 * The referenced entries and their attributes are stored in the .classpath file of this
+	 * project. For details on referenced entries, see
 	 * {@link JavaCore#getReferencedClasspathEntries(IClasspathEntry, IJavaProject)}
 	 * and {@link IClasspathEntry#getReferencingEntry()}.
 	 * <p>
-	 * Since the referenced entries are stored in the .classpath file, clients can store additional 
+	 * Since the referenced entries are stored in the .classpath file, clients can store additional
 	 * information that belong to these entries and retrieve them across sessions, though the referenced
 	 * entries themselves may not be present in the raw classpath. By passing a <code>null</code>
 	 * referencedEntries, clients can choose not to modify the already persisted referenced entries,
 	 * which is fully equivalent to {@link #setRawClasspath(IClasspathEntry[], IPath, IProgressMonitor)}.
-	 * If an empty array is passed as referencedEntries, the already persisted referenced entries, 
-	 * if any, will be cleared. 
+	 * If an empty array is passed as referencedEntries, the already persisted referenced entries,
+	 * if any, will be cleared.
 	 * </p> <p>
-	 * If there are duplicates of a referenced entry or if any of the <code>referencedEntries</code> 
-	 * is already present in the raw classpath(<code>entries</code>) those referenced entries will 
+	 * If there are duplicates of a referenced entry or if any of the <code>referencedEntries</code>
+	 * is already present in the raw classpath(<code>entries</code>) those referenced entries will
 	 * be excluded and not be persisted.
 	 *</p>
 	 * @param entries a list of classpath entries
@@ -1132,8 +1132,8 @@
 			IProgressMonitor monitor) throws JavaModelException;
 
 	/**
-	 * Returns the list of referenced classpath entries stored in the .classpath file of <code>this</code> 
-	 * java project. Clients can store the referenced classpath entries using 
+	 * Returns the list of referenced classpath entries stored in the .classpath file of <code>this</code>
+	 * java project. Clients can store the referenced classpath entries using
 	 * {@link #setRawClasspath(IClasspathEntry[], IClasspathEntry[], IPath, IProgressMonitor)}
 	 * If the client has not stored any referenced entries for this project, an empty array is returned.
 	 *
@@ -1143,7 +1143,7 @@
 	 * @since 3.6
 	 */
 	IClasspathEntry[] getReferencedClasspathEntries() throws JavaModelException;
-	
+
 	/**
 	 * Sets the classpath of this project using a list of classpath entries. In particular such a classpath may contain
 	 * classpath variable entries. Classpath variable entries can be resolved individually ({@link JavaCore#getClasspathVariable(String)}),
@@ -1231,7 +1231,7 @@
 	/**
 	 * Returns the classpath entry that refers to the given path or <code>null</code> if there is no reference to the
 	 * path.
-	 * 
+	 *
 	 * @param path
 	 *            IPath
 	 * @return the classpath entry or <code>null</code>.
@@ -1246,7 +1246,7 @@
 	 * test-only dependencies that should not be mentioned in the module-info.java). When executing test code that was
 	 * compiled like this, corresponding "--add-reads" options need to be passed to the java runtime. This method
 	 * returns the list of modules on the project's classpath for which this is the case.
-	 * 
+	 *
 	 * @return the set of module names
 	 * @throws JavaModelException
 	 *             when access to the classpath or module description of the given project fails.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ILocalVariable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ILocalVariable.java
index 4fefad4..4bd8da8 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ILocalVariable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ILocalVariable.java
@@ -57,10 +57,10 @@
 	 * @see Signature
 	 */
 	String getTypeSignature();
-	
+
 	/**
 	 * Returns <code>true</code> if this local variable is a method parameter, <code>false</code> otherwise.
-	 * 
+	 *
 	 * @return <code>true</code> if this local variable is a method parameter, <code>false</code> otherwise
 	 * @since 3.7
 	 */
@@ -69,7 +69,7 @@
 	/**
 	 * Returns the modifier flags for this local variable. The flags can be examined using class
 	 * {@link Flags}.
-	 * 
+	 *
 	 * <p>Note that only flags as indicated in the source are returned.</p>
 	 *
 	 * @return the modifier flags for this local variable
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java
index d0f7804..e2a41e7 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IMethod.java
@@ -111,7 +111,7 @@
  * <p>For binary types, associated source is used to retrieve the {@link ILocalVariable#getNameRange() name range},
  * {@link ILocalVariable#getSourceRange() source range} and the {@link ILocalVariable#getFlags() flags}.</p>
  * <p>These local variables can be used to retrieve the {@link ILocalVariable#getAnnotations() parameter annotations}.</p>
- * 
+ *
  * @return the parameters of this method
  * @throws JavaModelException if this element does not exist or if an
  *      exception occurs while accessing its corresponding resource.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModularClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModularClassFile.java
index d67fe82..6a1ed95 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModularClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModularClassFile.java
@@ -24,7 +24,7 @@
 	 * Returns the module description contained in this type root.
 	 * An error-free {@link IModularClassFile} should always have a module.
 	 *
-	 * @throws JavaModelException 
+	 * @throws JavaModelException
 	 * @return the module description contained in the type root.
 	 */
 	@Override
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModuleDescription.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModuleDescription.java
index bf5eed5..9d077fa 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModuleDescription.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IModuleDescription.java
@@ -36,7 +36,7 @@
 	 * @since 3.14
 	 */
 	String[] getRequiredModuleNames() throws JavaModelException;
-	
+
 	/**
 	 * Get provided service names for this module.
 	 *
@@ -45,7 +45,7 @@
 	 * @since 3.18
 	 */
 	String[] getProvidedServiceNames() throws JavaModelException;
-	
+
 	/**
 	 * Get used service names for this module.
 	 *
@@ -76,7 +76,7 @@
 	String[] getOpenedPackageNames(IModuleDescription targetModule) throws JavaModelException;
 
 	/**
-	 * 
+	 *
 	 * @return true if automatic module, else false
 	 * @since 3.14
 	 */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java
index 40f9d65..ab5a6aa 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOpenable.java
@@ -118,10 +118,10 @@
 boolean isConsistent() throws JavaModelException;
 /**
  * Returns whether this openable is open. This is a handle-only method.
- * 
+ *
  * <p>Note: This method doesn't tell whether an {@link IJavaProject}'s {@link IJavaProject#getProject() getProject()} is open.
  * It is <b>not</b> equivalent to {@link IProject#isOpen()}!</p>
- * 
+ *
  * <p>Note: Although {@link #isOpen} is exposed in the API, clients
  * rarely have a need to rely on this internal state of the Java model.</p>
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOrdinaryClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOrdinaryClassFile.java
index cc1d5ca..9e3153a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOrdinaryClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IOrdinaryClassFile.java
@@ -15,7 +15,7 @@
 
 /**
  * Ordinary form of a {@link IClassFile} which holds exactly one <code>IType</code>.
- * 
+ *
  * @since 3.14
  * @noimplement This interface is not intended to be implemented by clients.
  */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java
index 5920844..d28c2e8 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragment.java
@@ -105,7 +105,7 @@
 	 * Returns the class file for <code>"module-info.class"</code> in this package.
 	 * This is a handle-only method.  The class file may or may not be present.
 	 * If the class file is present, then it is guaranteed to contain an {@link IModuleDescription}.
-	 * 
+	 *
 	 * @since 3.14
 	 * @return the class file representing "module-info.class" in this package.
 	 */
@@ -117,7 +117,7 @@
 	 * <p>Note: it is possible that a package fragment contains only
 	 * compilation units (in other words, its kind is <code>K_SOURCE</code>), in
 	 * which case this method returns an empty collection.</p>
-	 * 
+	 *
 	 * <p>Note: the returned list may contain ordinary class files as well as
 	 * a modular class file (for "module-info.class").</p>
 	 *
@@ -127,11 +127,11 @@
 	 * @since 3.14
 	 */
 	IClassFile[] getAllClassFiles() throws JavaModelException;
-	
+
 	/**
 	 * Returns all of the ordinary class files in this package fragment.
-	 * 
-	 * <p>Note: this list never includes a modular class file 
+	 *
+	 * <p>Note: this list never includes a modular class file
 	 * (see {@link #getModularClassFile()}).</p>
 	 *
 	 * <p>Note: it is possible that a package fragment contains only
@@ -153,7 +153,7 @@
 	 * <p>Note: it is possible that a package fragment contains only
 	 * compilation units (in other words, its kind is <code>K_SOURCE</code>), in
 	 * which case this method returns an empty collection.</p>
-	 * 
+	 *
 	 * @exception JavaModelException if this element does not exist or if an
 	 *		exception occurs while accessing its corresponding resource.
 	 * @return all of the ordinary class files in this package fragment
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java
index 20b09a0..9a9d080 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IPackageFragmentRoot.java
@@ -314,15 +314,15 @@
 	 * @since 2.0
 	 */
 	IClasspathEntry getRawClasspathEntry() throws JavaModelException;
-	
+
 	/**
 	 * Returns the first resolved classpath entry that corresponds to this package fragment root.
 	 * A resolved classpath entry is said to correspond to a root if the path of the resolved
 	 * entry is equal to the root's path.
-	 * 
+	 *
 	 * @return the first resolved classpath entry that corresponds to this package fragment root
 	 * @throws JavaModelException if this element does not exist or if an
-	 *		exception occurs while accessing its corresponding resource. 
+	 *		exception occurs while accessing its corresponding resource.
 	 * @since 3.6
 	 */
 	IClasspathEntry getResolvedClasspathEntry() throws JavaModelException;
@@ -454,7 +454,7 @@
 	 * Returns the <code>IModuleDescription</code> that this package fragment root contains.
 	 * Returns <code>null</code> if the root doesn't contain any named module or if the project compiler compliance is 1.8 or lower.
 	 * If present the module descriptor is found as a child of the package fragment representing the default package.
-	 * 
+	 *
 	 * Note that only one of the source package fragment roots in a Java Project can legally
 	 * contain a module descriptor.
 	 *
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java
index 8a642ca..3e8acf6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceRange.java
@@ -20,7 +20,7 @@
  * <p>Clients may use the method {@link org.eclipse.jdt.core.SourceRange#isAvailable(ISourceRange)}
  * in order to find out if a source range is available. This method returns <code>false</code>
  * when the source range offset is equals to <code>-1</code>.</p>
- * 
+ *
  * <p>Clients may use the default implementation provided by {@link SourceRange}.</p>
  *
  * @see SourceRange
@@ -39,11 +39,11 @@
 /**
  * Returns the 0-based index of the first character of the source code for this element,
  * relative to the source buffer in which this element is contained. However, if the element
- * has no associated source code, an implementation may return -1. 
+ * has no associated source code, an implementation may return -1.
  *
  * @return the 0-based index of the first character of the source code for this element,
  * relative to the source buffer in which this element is contained. However, if the element
- * has no associated source code, an implementation may return -1. 
+ * has no associated source code, an implementation may return -1.
  */
 int getOffset();
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java
index 0387ceb..4edc4b8 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ISourceReference.java
@@ -78,13 +78,13 @@
 
 /**
  * Returns the name range associated with this element.
- * 
+ *
  * <p>If the element is an {@link IMember}, it returns
  * the source range of this member's simple name,
  * or <code>null</code> if this member does not have a name
  * (for example, an initializer), or if this member does not have
  * associated source code (for example, a binary type).</p>
- * 
+ *
  * <p>If this element is an {@link IImportDeclaration}, the source range
  * of this import declaration's name, or <code>null</code> if this import
  * declaration does not have associated source code (for example, a binary type).
@@ -93,17 +93,17 @@
  * </p>
  *
  * <p>If this element is an {@link IPackageDeclaration}, the source range of
- * this package declaration's name, or <code>null</code> if this package 
+ * this package declaration's name, or <code>null</code> if this package
  * declaration does not have associated source code (for example, a binary type).</p>
  *
  * <p>If this element is an {@link IAnnotation}, the source range of
  * this annotation's name, or <code>null</code> if this annotation does not have
  * associated source code (for example, in a binary type).</p>
- * 
- * <p>If this element is an {@link ITypeParameter}, the source range of this 
+ *
+ * <p>If this element is an {@link ITypeParameter}, the source range of this
  * type parameter's name, or <code>null</code> if this type parameter does not have
  * associated source code (for example, in a binary type).</p>
- * 
+ *
  * <p>If this element is an {@link ITypeRoot} or {@link IImportContainer}, it
  * returns null.</p>
  *
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java
index 630f40c..e511ae1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -25,9 +25,9 @@
  * types are subkinds of classes and interfaces, respectively.
  * <p>
  * Note that the element name of an anonymous source type and lambda expressions
- * is always empty. Types representing lambda expressions are pseudo-elements 
- * and not included in the children of their parent. Lambda expressions are created 
- * as the result of a <code>ICodeAssist.codeSelect(...)</code>. For more information 
+ * is always empty. Types representing lambda expressions are pseudo-elements
+ * and not included in the children of their parent. Lambda expressions are created
+ * as the result of a <code>ICodeAssist.codeSelect(...)</code>. For more information
  * on such pseudo-elements, see <code>ILocalVariable</code>.
  * </p><p>
  * If a binary type cannot be parsed, its structure remains unknown.
@@ -166,7 +166,7 @@
 		boolean isStatic,
 		CompletionRequestor requestor)
 		throws JavaModelException;
-	
+
 	/**
 	 * Do code completion inside a code snippet in the context of the current type.
 	 *
@@ -178,7 +178,7 @@
 	 * can be very long to compute are proposed. To avoid that the code assist operation
 	 * take too much time a {@link IProgressMonitor} which automatically cancel the code
 	 * assist operation when a specified amount of time is reached could be used.
-	 * 
+	 *
 	 * <pre>
 	 * new IProgressMonitor() {
 	 *     private final static int TIMEOUT = 500; //ms
@@ -269,7 +269,7 @@
 		CompletionRequestor requestor,
 		WorkingCopyOwner owner)
 		throws JavaModelException;
-	
+
 	/**
 	 * Do code completion inside a code snippet in the context of the current type.
 	 * It considers types in the working copies with the given owner first. In other words,
@@ -288,7 +288,7 @@
 	 * can be very long to compute are proposed. To avoid that the code assist operation
 	 * take too much time a {@link IProgressMonitor} which automatically cancel the code
 	 * assist operation when a specified amount of time is reached could be used.
-	 * 
+	 *
 	 * <pre>
 	 * new IProgressMonitor() {
 	 *     private final static int TIMEOUT = 500; //ms
@@ -490,7 +490,7 @@
 	 * <p>
 	 * The results are listed in the order in which they appear in the source or class file.
 	 * </p>
-	 * 
+	 *
 	 * @return the children for the given category.
 	 * @exception JavaModelException if this element does not exist or if an
 	 *      exception occurs while accessing its corresponding resource.
@@ -501,7 +501,7 @@
 	/**
 	 * Returns the simple name of this type, unqualified by package or enclosing type.
 	 * This is a handle-only method.
-	 * 
+	 *
 	 * Note that the element name of an anonymous source type and lambda expressions
 	 * is always empty.
 	 *
@@ -521,7 +521,7 @@
 	IField getField(String name);
 
 	/**
-	 * Returns the fields declared by this type in the order in which they appear 
+	 * Returns the fields declared by this type in the order in which they appear
 	 * in the source or class file. For binary types, this includes synthetic fields.
 	 *
 	 * @exception JavaModelException if this element does not exist or if an
@@ -601,9 +601,9 @@
 	IInitializer getInitializer(int occurrenceCount);
 
 	/**
-	 * Returns the initializers declared by this type. For binary types this is an 
-	 * empty collection. For source types, the results are listed in the order in 
-	 * which they appear in the source. 
+	 * Returns the initializers declared by this type. For binary types this is an
+	 * empty collection. For source types, the results are listed in the order in
+	 * which they appear in the source.
 	 *
 	 * @exception JavaModelException if this element does not exist or if an
 	 *		exception occurs while accessing its corresponding resource.
@@ -636,7 +636,7 @@
 	 * The type signatures may be either unresolved (for source types)
 	 * or resolved (for binary types), and either basic (for basic types)
 	 * or rich (for parameterized types). See {@link Signature} for details.
-	 * Note that the parameter type signatures for binary methods are expected 
+	 * Note that the parameter type signatures for binary methods are expected
 	 * to be dot-based.
 	 * </p>
 	 *
@@ -651,7 +651,7 @@
 	 * For binary types, this may include the special <code>&lt;clinit&gt;</code> method
 	 * and synthetic methods.
 	 * <p>
-	 * The results are listed in the order in which they appear in the source or class file. 
+	 * The results are listed in the order in which they appear in the source or class file.
 	 * </p>
 	 *
 	 * @exception JavaModelException if this element does not exist or if an
@@ -901,6 +901,20 @@
 	boolean isEnum() throws JavaModelException;
 
 	/**
+	 * Returns whether this type represents a record class.
+	 * <p>
+	 * Note that a record class can neither be an enumeration, an interface, nor an annotation type.
+	 * </p>
+	 *
+	 * @exception JavaModelException if this element does not exist or if an
+	 *		exception occurs while accessing its corresponding resource.
+	 * @return true if this type represents a record class,
+	 * false otherwise
+	 * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
+	 */
+	boolean isRecord() throws JavaModelException;
+
+	/**
 	 * Returns whether this type represents an interface.
 	 * <p>
 	 * Note that an interface can also be an annotation type, but it can neither be a class nor an enumeration class.
@@ -927,10 +941,10 @@
 	boolean isAnnotation() throws JavaModelException;
 
 	/**
-	 * Returns whether this type represents a local type. For an anonymous type, 
+	 * Returns whether this type represents a local type. For an anonymous type,
 	 * this method returns true.
 	 * <p>
-	 * Note: This deviates from JLS3 14.3, which states that anonymous types are 
+	 * Note: This deviates from JLS3 14.3, which states that anonymous types are
 	 * not local types since they do not have a name.
 	 * </p>
 	 *
@@ -1226,7 +1240,7 @@
 	 * @since 3.0
 	 */
 	String[][] resolveType(String typeName, WorkingCopyOwner owner) throws JavaModelException;
-	
+
 	/**
 	 * Returns whether this type represents a lambda expression.
 	 *
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeParameter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeParameter.java
index 7aa9382..68b544b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeParameter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeParameter.java
@@ -45,12 +45,12 @@
 	String[] getBounds() throws JavaModelException;
 
 	/**
-	 * Returns the signatures for this type parameter's bounds. The type parameter may have 
-	 * been declared as part of a type or a method. The signatures represent only the individual 
-	 * bounds and do not include the type variable name or the <code>extends</code> keyword.  
-	 * The signatures may be either unresolved (for source types) or resolved (for binary types). 
+	 * Returns the signatures for this type parameter's bounds. The type parameter may have
+	 * been declared as part of a type or a method. The signatures represent only the individual
+	 * bounds and do not include the type variable name or the <code>extends</code> keyword.
+	 * The signatures may be either unresolved (for source types) or resolved (for binary types).
 	 * See {@link Signature} for details.
-	 * 
+	 *
 	 * @return the signatures for the bounds of this formal type parameter
 	 * @throws JavaModelException
 	 *             if this element does not exist or if an exception occurs while accessing its corresponding resource.
@@ -58,7 +58,7 @@
 	 * @since 3.6
 	 */
 	String[] getBoundsSignatures() throws JavaModelException;
-	
+
 	/**
 	 * Returns the declaring member of this type parameter. This can be either an <code>IType</code>
 	 * or an <code>IMethod</code>.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeRoot.java
index 1556b17..4e18644 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ITypeRoot.java
@@ -41,7 +41,7 @@
  * in this type root.
  * <p>Only subtype {@link IModularClassFile} promises to return non-null.</p>
  *
- * @throws JavaModelException 
+ * @throws JavaModelException
  * @since 3.14
  * @return the module description contained in the type root or null.
  */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java
index 10703a8..2f943c6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java
@@ -385,9 +385,9 @@
 
 	/**
 	 * Validate the given Java type name, either simple or qualified, for the given source and compliance levels.
-	 * 
+	 *
 	 * <p>For example, <code>"java.lang.Object"</code>, or <code>"Object"</code>.</p>
-	 * 
+	 *
 	 * <p>The source level and compliance level values should be taken from the constant defined inside
 	 * {@link JavaCore} class. The constants are named <code>JavaCore#VERSION_1_x</code>, x being set
 	 * between '1' and '8'.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
index 13812ee..b8959e2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
@@ -1,6 +1,6 @@
 // AspectJ
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -2073,6 +2073,22 @@
 	public static final String COMPILER_PB_NONNULL_TYPEVAR_FROM_LEGACY_INVOCATION = JavaCore.PLUGIN_ID+".compiler.problem.nonnullTypeVariableFromLegacyInvocation"; //$NON-NLS-1$
 
 	/**
+	 * Compiler option ID: Reporting Unsafe Conversion To Unannotated Type Argument.
+	 * <p>When enabled, the compiler will issue an error, warning or info when a value of a parameterized type
+	 * with annotated type arguments is assigned to a variable / bound to a method argument, where the corresponding
+	 * type argument is unannotated.</p>
+	 * <p>This situation is problematic because it will enable using the less-annotated type to manipulate the given
+	 * objects in ways that may violate contracts of the more-annotated type.</p>
+	 * <dl>
+	 * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated"</code></dd>
+	 * <dt>Possible values:</dt><dd><code>{ "error", "warning", "info", "ignore" }</code></dd>
+	 * <dt>Default:</dt><dd><code>"info"</code></dd>
+	 * </dl>
+	 * @since 3.21
+	 * @category CompilerOptionID
+	 */
+	public static final String COMPILER_PB_ANNOTATED_TYPE_ARGUMENT_TO_UNANNOTATED = JavaCore.PLUGIN_ID+".compiler.problem.annotatedTypeArgumentToUnannotated"; //$NON-NLS-1$
+	/**
 	 * Compiler option ID: Setting Source Compatibility Mode.
 	 * <p>Specify whether which source level compatibility is used. From 1.4 on, <code>'assert'</code> is a keyword
 	 *    reserved for assertion support. Also note, than when toggling to 1.4 mode, the target VM
@@ -2765,6 +2781,19 @@
 	 */
 	public static final String CODEASSIST_SUBSTRING_MATCH = PLUGIN_ID + ".codeComplete.substringMatch"; //$NON-NLS-1$
 	/**
+	 * Code assist option ID: Activate Subword Code Completion.
+	 * <p>When enabled, completion shows proposals in which the pattern can
+	 *    be found as a subword in a case-insensitive way.</p>
+	 * <dl>
+	 * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.codeComplete.subwordMatch"</code></dd>
+	 * <dt>Possible values:</dt><dd><code>{ "enabled", "disabled" }</code></dd>
+	 * <dt>Default:</dt><dd><code>"enabled"</code></dd>
+	 * </dl>
+	 * @since 3.21
+	 * @category CodeAssistOptionID
+	 */
+	public static final String CODEASSIST_SUBWORD_MATCH = PLUGIN_ID + ".codeComplete.subwordMatch"; //$NON-NLS-1$
+	/**
 	 * Code assist option ID: Automatic Qualification of Implicit Members.
 	 * <p>When active, completion automatically qualifies completion on implicit
 	 *    field references and message expressions.</p>
@@ -3088,12 +3117,18 @@
 	public static final String VERSION_13 = "13"; //$NON-NLS-1$
 	/**
 	 * Configurable option value: {@value}.
+	 * @since 3.22
+	 * @category OptionValue
+	 */
+	public static final String VERSION_14 = "14"; //$NON-NLS-1$
+	/**
+	 * Configurable option value: {@value}.
 	 * @since 3.4
 	 * @category OptionValue
 	 */
 	public static final String VERSION_CLDC_1_1 = "cldc1.1"; //$NON-NLS-1$
 	private static List<String> allVersions = Collections.unmodifiableList(Arrays.asList(VERSION_CLDC_1_1, VERSION_1_1, VERSION_1_2, VERSION_1_3, VERSION_1_4, VERSION_1_5,
-			VERSION_1_6, VERSION_1_7, VERSION_1_8, VERSION_9, VERSION_10, VERSION_11, VERSION_12, VERSION_13));
+			VERSION_1_6, VERSION_1_7, VERSION_1_8, VERSION_9, VERSION_10, VERSION_11, VERSION_12, VERSION_13, VERSION_14));
 
 	/**
 	 * Returns all {@link JavaCore}{@code #VERSION_*} levels in the order of their 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/NamingConventions.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/NamingConventions.java
index f2be556..9d2bf6b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/NamingConventions.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/NamingConventions.java
@@ -29,16 +29,16 @@
  * <ul>
  * <li> {@link JavaCore#CODEASSIST_FIELD_PREFIXES} : Define the Prefixes for Field Name.</li>
  * <li> {@link JavaCore#CODEASSIST_FIELD_SUFFIXES} : Define the Suffixes for Field Name.</li>
- * 
+ *
  * <li> {@link JavaCore#CODEASSIST_STATIC_FIELD_PREFIXES} : Define the Prefixes for Static Field Name.</li>
  * <li> {@link JavaCore#CODEASSIST_STATIC_FIELD_SUFFIXES} : Define the Suffixes for Static Field Name.</li>
- * 
+ *
  * <li> {@link JavaCore#CODEASSIST_STATIC_FINAL_FIELD_PREFIXES} : Define the Prefixes for Static Final Field Name.</li>
  * <li> {@link JavaCore#CODEASSIST_STATIC_FINAL_FIELD_SUFFIXES} : Define the Suffixes for Static Final Field Name.</li>
- * 
+ *
  * <li> {@link JavaCore#CODEASSIST_LOCAL_PREFIXES} : Define the Prefixes for Local Variable Name.</li>
  * <li> {@link JavaCore#CODEASSIST_LOCAL_SUFFIXES} : Define the Suffixes for Local Variable Name.</li>
- * 
+ *
  * <li> {@link JavaCore#CODEASSIST_ARGUMENT_PREFIXES} : Define the Prefixes for Argument Name.</li>
  * <li> {@link JavaCore#CODEASSIST_ARGUMENT_SUFFIXES} : Define the Suffixes for Argument Name.</li>
  * </ul>
@@ -244,51 +244,51 @@
 
 	/**
 	 * Variable kind which represents a static field.
-	 * 
+	 *
 	 * @since 3.5
 	 */
 	public static final int VK_STATIC_FIELD = InternalNamingConventions.VK_STATIC_FIELD;
 	/**
 	 * Variable kind which represents an instance field.
-	 * 
+	 *
 	 * @since 3.5
 	 */
 	public static final int VK_INSTANCE_FIELD = InternalNamingConventions.VK_INSTANCE_FIELD;
 	/**
 	 * Variable kind which represents a static final field.
-	 * 
+	 *
 	 * @since 3.5
 	 */
 	public static final int VK_STATIC_FINAL_FIELD = InternalNamingConventions.VK_STATIC_FINAL_FIELD;
 	/**
 	 * Variable kind which represents an argument.
-	 * 
+	 *
 	 * @since 3.5
 	 */
 	public static final int VK_PARAMETER = InternalNamingConventions.VK_PARAMETER;
 	/**
 	 * Variable kind which represents a local variable.
-	 * 
+	 *
 	 * @since 3.5
 	 */
 	public static final int VK_LOCAL = InternalNamingConventions.VK_LOCAL;
-	
+
 	/**
 	 * The base name associated to this base name kind is a simple name.
 	 * When this base name is used the whole name is considered.
-	 * 
+	 *
 	 * @see #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)
-	 * 
+	 *
 	 * @since 3.5
 	 */
 	public static final int BK_NAME = InternalNamingConventions.BK_SIMPLE_NAME;
-	
+
 	/**
 	 * The base name associated to this base name kind is a simple type name.
 	 * When this base name is used all the words of the name are considered.
-	 * 
+	 *
 	 * @see #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)
-	 * 
+	 *
 	 * @since 3.5
 	 */
 	public static final int BK_TYPE_NAME = InternalNamingConventions.BK_SIMPLE_TYPE_NAME;
@@ -336,7 +336,7 @@
 	 * @return char[] the name without prefix and suffix.
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
+	 *
 	 * @deprecated Use {@link #getBaseName(int, String, IJavaProject)} instead with {@link #VK_PARAMETER} as variable kind.
 	 */
 	public static char[] removePrefixAndSuffixForArgumentName(IJavaProject javaProject, char[] argumentName) {
@@ -365,7 +365,7 @@
 	 * @return char[] the name without prefix and suffix.
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
+	 *
 	 * @deprecated Use {@link #getBaseName(int, String, IJavaProject)} instead with {@link #VK_PARAMETER} as variable kind.
 	 */
 	public static String removePrefixAndSuffixForArgumentName(IJavaProject javaProject, String argumentName) {
@@ -397,7 +397,7 @@
 	 * @see Flags
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
+	 *
 	 * @deprecated Use {@link #getBaseName(int, String, IJavaProject)} instead
 	 * with {@link #VK_INSTANCE_FIELD} or {@link #VK_STATIC_FIELD} as variable kind.
 	 */
@@ -434,7 +434,7 @@
 	 * @see Flags
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
+	 *
 	 * @deprecated Use {@link #getBaseName(int, String, IJavaProject)} instead
 	 * with {@link #VK_INSTANCE_FIELD} or {@link #VK_STATIC_FIELD} as variable kind.
 	 */
@@ -464,7 +464,7 @@
 	 * @return char[] the name without prefix and suffix.
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
+	 *
 	 * @deprecated Use {@link #getBaseName(int, String, IJavaProject)} instead with {@link #VK_LOCAL} as variable kind.
 	 */
 	public static char[] removePrefixAndSuffixForLocalVariableName(IJavaProject javaProject, char[] localName) {
@@ -493,13 +493,13 @@
 	 * @return char[] the name without prefix and suffix.
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
+	 *
 	 * @deprecated Use {@link #getBaseName(int, String, IJavaProject)} instead with {@link #VK_LOCAL} as variable kind.
 	 */
 	public static String removePrefixAndSuffixForLocalVariableName(IJavaProject javaProject, String localName) {
 		return String.valueOf(removePrefixAndSuffixForLocalVariableName(javaProject, localName.toCharArray()));
 	}
-	
+
 	/**
 	 * Returns a base name which could be used to generate the given variable name with {@link #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)}.
 	 * <p>
@@ -522,12 +522,12 @@
 	 * If the variable is a {@link #VK_LOCAL}, the variable name is <code>preVariableNamesuf</code>, a possible prefix is <code>pre</code> and a possible suffix is <code>suf</code>
 	 * then the base name will be <code>variableName</code>.<br>
 	 * </p>
-	 * 
+	 *
 	 * @param variableKind specifies what type the variable is: {@link #VK_LOCAL}, {@link #VK_PARAMETER}, {@link #VK_STATIC_FIELD},
 	 * {@link #VK_INSTANCE_FIELD} or {@link #VK_STATIC_FINAL_FIELD}.
 	 * @param variableName a variable name
 	 * @param javaProject project which contains the variable or <code>null</code> to take into account only workspace settings.
-	 * 
+	 *
 	 * @see #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)
 	 * @since 3.5
 	 */
@@ -537,7 +537,7 @@
 			IJavaProject javaProject) {
 		return String.valueOf(InternalNamingConventions.getBaseName(variableKind, javaProject, variableName.toCharArray(), true));
 	}
-	
+
 	private static int getFieldVariableKind(int modifiers) {
 		if (Flags.isStatic(modifiers)) {
 			if (Flags.isFinal(modifiers)) {
@@ -585,15 +585,15 @@
 	 * @return char[][] an array of names.
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
+	 *
 	 * @deprecated Use {@link #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)} instead with {@link #VK_PARAMETER} as variable kind.
 	 */
 	public static char[][] suggestArgumentNames(IJavaProject javaProject, char[] packageName, char[] qualifiedTypeName, int dim, char[][] excludedNames) {
 		if(qualifiedTypeName == null || qualifiedTypeName.length == 0)
 			return CharOperation.NO_CHAR_CHAR;
-		
+
 		char[] typeName = CharOperation.lastSegment(qualifiedTypeName, '.');
-		
+
  		NamingRequestor requestor = new NamingRequestor();
 		InternalNamingConventions.suggestVariableNames(
 				VK_PARAMETER,
@@ -605,7 +605,7 @@
 				excludedNames,
 				true,
 				requestor);
- 
+
  		return requestor.getResults();
 	}
 
@@ -636,7 +636,7 @@
 	 * @return char[][] an array of names.
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
+	 *
 	 * @deprecated Use {@link #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)} instead with {@link #VK_PARAMETER} as variable kind.
 	 */
 	public static String[] suggestArgumentNames(IJavaProject javaProject, String packageName, String qualifiedTypeName, int dim, String[] excludedNames) {
@@ -680,16 +680,16 @@
 	 * @see Flags
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
-	 * @deprecated Use {@link #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)} instead 
+	 *
+	 * @deprecated Use {@link #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)} instead
 	 * with {@link #VK_INSTANCE_FIELD} or  {@link #VK_STATIC_FIELD} as variable kind.
 	 */
 	public static char[][] suggestFieldNames(IJavaProject javaProject, char[] packageName, char[] qualifiedTypeName, int dim, int modifiers, char[][] excludedNames) {
 		if(qualifiedTypeName == null || qualifiedTypeName.length == 0)
 			return CharOperation.NO_CHAR_CHAR;
-		
+
 		char[] typeName = CharOperation.lastSegment(qualifiedTypeName, '.');
-		
+
  		NamingRequestor requestor = new NamingRequestor();
 		InternalNamingConventions.suggestVariableNames(
 				Flags.isStatic(modifiers) ? VK_STATIC_FIELD : VK_INSTANCE_FIELD,
@@ -701,7 +701,7 @@
 				excludedNames,
 				true,
 				requestor);
- 
+
  		return requestor.getResults();
 	}
 
@@ -736,8 +736,8 @@
 	 * @see Flags
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
-	 * @deprecated Use {@link #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)} instead 
+	 *
+	 * @deprecated Use {@link #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)} instead
 	 * with {@link #VK_INSTANCE_FIELD} or  {@link #VK_STATIC_FIELD} as variable kind.
 	 */
 	public static String[] suggestFieldNames(IJavaProject javaProject, String packageName, String qualifiedTypeName, int dim, int modifiers, String[] excludedNames) {
@@ -750,7 +750,7 @@
 				modifiers,
 				convertStringToChars(excludedNames)));
 	}
-	
+
 	/**
 	 * Suggest name for a getter method. The name is computed from field's name
 	 * and possible prefixes or suffixes are removed.
@@ -869,15 +869,15 @@
 	 * @return char[][] an array of names.
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
+	 *
 	 * @deprecated Use {@link #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)} instead with {@link #VK_LOCAL} as variable kind.
 	 */
 	public static char[][] suggestLocalVariableNames(IJavaProject javaProject, char[] packageName, char[] qualifiedTypeName, int dim, char[][] excludedNames) {
 		if(qualifiedTypeName == null || qualifiedTypeName.length == 0)
 			return CharOperation.NO_CHAR_CHAR;
-		
+
 		char[] typeName = CharOperation.lastSegment(qualifiedTypeName, '.');
-		
+
 		NamingRequestor requestor = new NamingRequestor();
 		InternalNamingConventions.suggestVariableNames(
 				VK_LOCAL,
@@ -889,7 +889,7 @@
 				excludedNames,
 				true,
 				requestor);
- 
+
 		return requestor.getResults();
 
 	}
@@ -920,7 +920,7 @@
 	 * @return char[][] an array of names.
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
+	 *
 	 * @deprecated Use {@link #suggestVariableNames(int, int, String, IJavaProject, int, String[], boolean)} instead with {@link #VK_LOCAL} as variable kind.
 	 */
 	public static String[] suggestLocalVariableNames(IJavaProject javaProject, String packageName, String qualifiedTypeName, int dim, String[] excludedNames) {
@@ -950,7 +950,7 @@
 		}
 		return newName;
 	}
-	
+
 	/**
 	 * Suggest name for a setter method. The name is computed from field's name
 	 * and possible prefixes or suffixes are removed.
@@ -1045,7 +1045,7 @@
 				isBoolean,
 				convertStringToChars(excludedNames)));
 	}
-	
+
 	/**
 	 * Suggests names for a variable. The name is computed from a base name and possible prefixes or suffixes are added.
 	 *
@@ -1116,7 +1116,7 @@
 	 * @return String[] an array of names.
 	 * @see JavaCore#setOptions(java.util.Hashtable)
 	 * @see JavaCore#getDefaultOptions()
-	 * 
+	 *
 	 * @since 3.5
 	 */
 	public static String[] suggestVariableNames(
@@ -1127,7 +1127,7 @@
 			int dim,
 			String[] excluded,
 			boolean evaluateDefault) {
-		
+
 		NamingRequestor requestor = new NamingRequestor();
 		InternalNamingConventions.suggestVariableNames(
 			variableKind,
@@ -1142,7 +1142,7 @@
 
 		return convertCharsToString(requestor.getResults());
 	}
-	
+
 	private NamingConventions() {
 		// Not instantiable
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
index 62d0110..e889038 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
@@ -145,7 +145,7 @@
  * </p>
  * <p>Note: An empty signature is considered to be syntactically incorrect. So most methods will throw
  * an IllegalArgumentException if an empty signature is provided.</p>
- * 
+ *
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
 @SuppressWarnings({"rawtypes", "unchecked"})
@@ -407,7 +407,7 @@
 	 * Value is <code>"Z"</code>.
 	 */
 	public static final String SIG_BOOLEAN 		= "Z"; //$NON-NLS-1$
-	
+
 	/**
 	 * String constant for the signature of the primitive type byte.
 	 * Value is <code>"B"</code>.
@@ -1102,7 +1102,7 @@
 
 /**
  * Creates a new intersection type signature from the given type signatures.
- * 
+ *
  * <p>The encoded type signature is dot-based.</p>
  *
  * @param typeSignatures the given type signatures
@@ -1122,7 +1122,7 @@
 }
 /**
  * Creates a new union type signature from the given type signatures.
- * 
+ *
  * <p>The encoded type signature is dot-based.</p>
  *
  * @param typeSignatures the given type signatures
@@ -1143,7 +1143,7 @@
 
 /**
  * Creates a new intersection type signature from the given type signatures.
- * 
+ *
  * <p>The encoded type signature is dot-based.</p>
  *
  * @param typeSignatures the given type signatures
@@ -1160,7 +1160,7 @@
 }
 /**
  * Creates a new union type signature from the given type signatures.
- * 
+ *
  * <p>The encoded type signature is dot-based.</p>
  *
  * @param typeSignatures the given type signatures
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/SourceRange.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/SourceRange.java
index 9cbad97..1547a09 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/SourceRange.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/SourceRange.java
@@ -42,7 +42,7 @@
 
 	/**
 	 * Instantiate a new source range using the given offset and the given length.
-	 * 
+	 *
 	 * @param offset the given offset
 	 * @param length the given length
 	 */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java
index 9479cd8..2ed3678 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ToolFactory.java
@@ -582,7 +582,7 @@
 	 * @return a scanner
 	 * @see org.eclipse.jdt.core.compiler.IScanner
 	 *
-	 * @since 3.14
+	 * @since 3.20
 	 */
 	@SuppressWarnings("javadoc") // references deprecated TokenNameIdentifier
 	public static IScanner createScanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean recordLineSeparator, String sourceLevel, String complianceLevel, boolean enablePreview) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/WorkingCopyOwner.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/WorkingCopyOwner.java
index ba7a912..035906c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/WorkingCopyOwner.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/WorkingCopyOwner.java
@@ -92,16 +92,16 @@
 	public IProblemRequestor getProblemRequestor(ICompilationUnit workingCopy) {
 		return null;
 	}
-	
+
 	/**
 	 * Returns the source of the compilation unit that defines the given type in
 	 * the given package, or <code>null</code> if the type is unknown to this
 	 * owner.
-	 * <p>This method is called before the normal lookup (i.e. before looking 
-	 * at the project's classpath and before looking at the working copies of this 
+	 * <p>This method is called before the normal lookup (i.e. before looking
+	 * at the project's classpath and before looking at the working copies of this
 	 * owner.)</p>
-	 * <p>This allows to provide types that are not normally available, or to hide 
-	 * types that would normally be available by returning an empty source for 
+	 * <p>This allows to provide types that are not normally available, or to hide
+	 * types that would normally be available by returning an empty source for
 	 * the given type and package.</p>
 	 * <p>Example of use:
 	 * <pre>
@@ -128,7 +128,7 @@
 	 * // Working copy on X.java with the following contents:
 	 * //    public class X extends to.be.Generated {
 	 * //    }
-	 * ICompilationUnit workingCopy = ... 
+	 * ICompilationUnit workingCopy = ...
 	 * ASTParser parser = ASTParser.newParser(AST.JLS3);
 	 * parser.setSource(workingCopy);
 	 * parser.setResolveBindings(true);
@@ -136,7 +136,7 @@
 	 * CompilationUnit cu = (CompilationUnit) parser.createAST(null);
 	 * assert cu.getProblems().length == 0;
 	 * </pre>
-	 * 
+	 *
 	 * @param typeName the simple name of the type to lookup
 	 * @param packageName the dot-separated name of the package of type
 	 * @return the source of the compilation unit that defines the given type in
@@ -147,16 +147,16 @@
 	public String findSource(String typeName, String packageName) {
 		return null;
 	}
-	
+
 	/**
 	 * Returns whether the given package segments represent a package.
-	 * <p>This method is called before the normal lookup (i.e. before looking 
-	 * at the project's classpath and before looking at the working copies of this 
+	 * <p>This method is called before the normal lookup (i.e. before looking
+	 * at the project's classpath and before looking at the working copies of this
 	 * owner.)</p>
 	 * <p>This allows to provide packages that are not normally available.</p>
-	 * <p>If <code>false</code> is returned, then normal lookup is used on 
+	 * <p>If <code>false</code> is returned, then normal lookup is used on
 	 * this package.</p>
-	 * 
+	 *
 	 * @param pkg the segments of a package to lookup
 	 * @return whether the given package segments represent a package.
 	 * @see #findSource(String, String)
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java
index f996bc5..3f4e703 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/CompilationParticipant.java
@@ -125,7 +125,7 @@
  * <p>
  * Default is to return <code>false</code>.
  * </p>
- * 
+ *
  * @return whether this participant is interested in Annotations
  */
 public boolean isAnnotationProcessor() {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/IScanner.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/IScanner.java
index a2dda6c..b4449b6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/IScanner.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/IScanner.java
@@ -14,8 +14,6 @@
 
 package org.eclipse.jdt.core.compiler;
 
-import org.eclipse.jdt.core.compiler.InvalidInputException;
-
  /**
   * <p>
   * <strong>Caveat:</strong> With the introduction of "restricted keywords" in Java 9
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/ITerminalSymbols.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/ITerminalSymbols.java
index 2e60816..0f8ac5b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/ITerminalSymbols.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/compiler/ITerminalSymbols.java
@@ -30,11 +30,11 @@
 	int TokenNameCOMMENT_JAVADOC = 1003;
 
 	/**
-	 * @deprecated With the introduction of "restricted keywords" in Java 9, classification of tokens 
+	 * @deprecated With the introduction of "restricted keywords" in Java 9, classification of tokens
 	 * 	 by a scanner is inherently unreliable. Any token classified as an identifier could still
 	 *   be a "restricted keyword". Future versions of Java will introduce more words that have
 	 *   special syntactical meaning in specific contexts.
-	 *   For reliably detecting an identifier the only real solution is to use a parser instead 
+	 *   For reliably detecting an identifier the only real solution is to use a parser instead
 	 *   (see also the caveat at the top of the	interface documentation of {@link IScanner}).
 	 */
 	@Deprecated
@@ -189,6 +189,5 @@
 	 * @since 3.10
 	 */
 	int TokenNameCOLON_COLON = 406;
-	
-	
+
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java
index 4f14cd5..a1a4137 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java
@@ -178,7 +178,7 @@
 		int position,
 		CompletionRequestor requestor)
 		throws JavaModelException;
-	
+
 	/**
 	 * Performs a code completion at the given position in the given code snippet,
 	 * reporting results to the given completion requestor.
@@ -189,7 +189,7 @@
 	 * can be very long to compute are proposed. To avoid that the code assist operation
 	 * take too much time a {@link IProgressMonitor} which automatically cancel the code
 	 * assist operation when a specified amount of time is reached could be used.
-	 * 
+	 *
 	 * <pre>
 	 * new IProgressMonitor() {
 	 *     private final static int TIMEOUT = 500; //ms
@@ -224,7 +224,7 @@
 		CompletionRequestor requestor,
 		IProgressMonitor monitor)
 		throws JavaModelException;
-	
+
 	/**
 	 * Performs a code completion at the given position in the given code snippet,
 	 * reporting results to the given completion requestor.
@@ -258,7 +258,7 @@
 		CompletionRequestor requestor,
 		WorkingCopyOwner owner)
 		throws JavaModelException;
-	
+
 	/**
 	 * Performs a code completion at the given position in the given code snippet,
 	 * reporting results to the given completion requestor.
@@ -276,7 +276,7 @@
 	 * can be very long to compute are proposed. To avoid that the code assist operation
 	 * take too much time a {@link IProgressMonitor} which automatically cancel the code
 	 * assist operation when a specified amount of time is reached could be used.
-	 * 
+	 *
 	 * <pre>
 	 * new IProgressMonitor() {
 	 *     private final static int TIMEOUT = 500; //ms
@@ -313,7 +313,7 @@
 		WorkingCopyOwner owner,
 		IProgressMonitor monitor)
 		throws JavaModelException;
-	
+
 	/**
 	 * Resolves and returns a collection of Java elements corresponding to the source
 	 * code at the given positions in the given code snippet.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/provisional/JavaModelAccess.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/provisional/JavaModelAccess.java
index 0bdc298..97a83a1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/provisional/JavaModelAccess.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/provisional/JavaModelAccess.java
@@ -23,7 +23,7 @@
 
 /**
  * Provisional API for use by JDT/UI or JDT/Debug, which may possibly be removed in a future version.
- * See <a href="https://bugs.eclipse.org/522391">Bug 522391</a>. 
+ * See <a href="https://bugs.eclipse.org/522391">Bug 522391</a>.
  */
 public class JavaModelAccess {
 	/**
@@ -38,14 +38,14 @@
 	}
 
 	/**
-	 * Returns the <code>IModuleDescription</code> that the given java element contains 
+	 * Returns the <code>IModuleDescription</code> that the given java element contains
 	 * when regarded as an automatic module. The element must be an <code>IPackageFragmentRoot</code>
 	 * or an <code>IJavaProject</code>.
-	 * 
+	 *
 	 * <p>The returned module descriptor has a name (<code>getElementName()</code>) following
 	 * the specification of <code>java.lang.module.ModuleFinder.of(Path...)</code>, but it
 	 * contains no other useful information.</p>
-	 * 
+	 *
 	 * @return the <code>IModuleDescription</code> representing this java element as an automatic module,
 	 * 		never <code>null</code>.
 	 * @throws JavaModelException
@@ -67,7 +67,7 @@
 	/**
 	 * Answer whether the given module is a system module.
 	 * <p><em>This provisional API may likely be changed into a direct method {@code IModuleDescription.isSystemModule()}.</em></p>
-	 * 
+	 *
 	 * @param module the module being queried about
 	 * @return {@code true} iff the module is defined in the system library (also known as JRE).
 	 * @since 3.18
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/CompilationUnitSorter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/CompilationUnitSorter.java
index c4a9429..576f0ab 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/CompilationUnitSorter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/CompilationUnitSorter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -24,6 +24,7 @@
 import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.internal.core.SortElementsOperation;
+import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil;
 import org.eclipse.text.edits.TextEdit;
 import org.eclipse.text.edits.TextEditGroup;
 
@@ -50,17 +51,7 @@
      * @deprecated marking deprecated as it is using deprecated code
      */
     private static void checkASTLevel(int level) {
-        switch (level) {
-        case AST.JLS2 :
-        case AST.JLS3 :
-        case AST.JLS4 :
-        case AST.JLS8 :
-        case AST.JLS9 :
-        case AST.JLS10 :
-            break;
-        default :
-            throw new IllegalArgumentException();
-        }
+        DOMASTUtil.checkASTLevel(level);
     }
 
 	/**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java
index 67dba5d..f4d6ad6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ExternalAnnotationUtil.java
@@ -47,7 +47,7 @@
 /**
  * Utilities for accessing and manipulating text files that externally define annotations for a given Java type.
  * Files are assumed to be in ".eea format", a textual representation of annotated signatures of members of a given type.
- * 
+ *
  * @since 3.11
  * @noinstantiate This class is not intended to be instantiated by clients.
  */
@@ -198,18 +198,18 @@
 	 * the containing jar file and finally the sought annotation file.
 	 */
 	public static IFile getAnnotationFile(IJavaProject project, ITypeBinding type, IProgressMonitor monitor) throws CoreException {
-	
+
 		IType targetType = project.findType(type.getErasure().getQualifiedName());
 		if (!targetType.exists())
 			return null;
 
 		String binaryTypeName = targetType.getFullyQualifiedName('$').replace('.', '/');
-		
+
 		IPackageFragmentRoot packageRoot = (IPackageFragmentRoot) targetType.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 		IClasspathEntry entry = packageRoot.getResolvedClasspathEntry();
 		IPath annotationPath = ClasspathEntry.getExternalAnnotationPath(entry, project.getProject(), false);
-	
-		if (annotationPath == null) 
+
+		if (annotationPath == null)
 			return null;
 
 		IWorkspaceRoot workspaceRoot = project.getProject().getWorkspace().getRoot();
@@ -219,7 +219,7 @@
 			if (annotationZip.exists())
 				return null;
 		}
-		
+
 		annotationPath = annotationPath.append(binaryTypeName).addFileExtension(ExternalAnnotationProvider.ANNOTATION_FILE_EXTENSION);
 		return workspaceRoot.getFile(annotationPath);
 	}
@@ -516,7 +516,7 @@
 	}
 
 	/**
-	 * Insert that given annotation at the given position into the given signature. 
+	 * Insert that given annotation at the given position into the given signature.
 	 * @param mergeStrategy if set to {@link MergeStrategy#ADD_ANNOTATIONS}, refuse to
 	 *   overwrite any existing annotation in the specified location.
 	 */
@@ -543,7 +543,7 @@
 		if (mergeStrategy == MergeStrategy.REPLACE_SIGNATURE) {
 			buf.append(newType);
 			return false;
-		}			
+		}
 		try {
 			SignatureWrapper oWrap = new SignatureWrapper(oldType, true, true); // may already contain annotations
 			SignatureWrapper nWrap = new SignatureWrapper(newType, true, true); // may already contain annotations
@@ -572,7 +572,7 @@
 					|| match(buf, oWrap, nWrap, '-', false))
 			{
 				return true; // annotation allowed after this (not included in oldType / newType)
-			} else {			
+			} else {
 				buf.append(oldType);
 			}
 		} catch (ArrayIndexOutOfBoundsException aioobe) { // from several locations inside match() or mergeAnnotation().
@@ -589,7 +589,7 @@
 		if (mergeStrategy == MergeStrategy.REPLACE_SIGNATURE) {
 			buf.append(newType);
 			return false;
-		}			
+		}
 		try {
 			SignatureWrapper oWrap = new SignatureWrapper(oldType, true, true); // may already contain annotations
 			SignatureWrapper nWrap = new SignatureWrapper(newType, true, true); // may already contain annotations
@@ -648,7 +648,7 @@
 		if (match1 != match2) {
 			StringBuilder msg = new StringBuilder("Mismatching type structures ") //$NON-NLS-1$
 									.append(sig1.signature).append(" vs ").append(sig2.signature); //$NON-NLS-1$
-			throw new IllegalArgumentException(msg.toString()); 
+			throw new IllegalArgumentException(msg.toString());
 		}
 		if (match1) {
 			buf.append(expected);
@@ -664,7 +664,7 @@
 
 	/**
 	 * If a current char of 'oldS' and/or 'newS' represents a null annotation, insert it into 'buf' guided by 'mergeStrategy'.
-	 * If the new char is NO_ANNOTATION and strategy is OVERWRITE_ANNOTATIONS, silently skip over any null annotations in 'oldS'. 
+	 * If the new char is NO_ANNOTATION and strategy is OVERWRITE_ANNOTATIONS, silently skip over any null annotations in 'oldS'.
 	 */
 	private static void mergeAnnotation(StringBuffer buf, SignatureWrapper oldS, SignatureWrapper newS, MergeStrategy mergeStrategy) {
 		 // if atEnd use a char that's different from NULLABLE, NONNULL and NO_ANNOTATION:
@@ -692,8 +692,8 @@
 						switch (oldAnn) { case NULLABLE: case NONNULL: oldS.start++; } // just skip
 						break;
 					default:
-						switch (oldAnn) { 
-							case NULLABLE: case NONNULL: 
+						switch (oldAnn) {
+							case NULLABLE: case NONNULL:
 								oldS.start++;
 								buf.append(oldAnn); // keep
 						}
@@ -715,7 +715,7 @@
 									String nextLines, BufferedReader tailReader, IProgressMonitor monitor)
 			throws CoreException, IOException
 	{
-		head.append(' ').append(annotatedSignature).append('\n'); 
+		head.append(' ').append(annotatedSignature).append('\n');
 		if (nextLines != null)
 			head.append(nextLines).append('\n');
 		String line;
@@ -727,7 +727,7 @@
 
 	private static void createNewFile(IFile file, String newContent, IProgressMonitor monitor) throws CoreException {
 		ensureExists(file.getParent(), monitor);
-		
+
 		try {
 			file.create(new ByteArrayInputStream(newContent.getBytes("UTF-8")), false, monitor); //$NON-NLS-1$
 		} catch (UnsupportedEncodingException e) {
@@ -789,7 +789,7 @@
 	/**
 	 * Apply the specified changes on the given type.
 	 * This method can be used as a dry run without modifying an annotation file.
-	 * 
+	 *
 	 * @param originalSignature the original type signature, may be annotated already
 	 * @param annotatedType a type signature with additional annotations (incl. {@link #NO_ANNOTATION}).
 	 * @param mergeStrategy controls how old and new signatures should be merged
@@ -816,7 +816,7 @@
 	/**
 	 * Apply the specified changes on the return type of the given signature.
 	 * This method can be used as a dry run without modifying an annotation file.
-	 * 
+	 *
 	 * @param originalSignature the original full signature, may be annotated already
 	 * @param annotatedType a type signature with additional annotations (incl. {@link #NO_ANNOTATION}).
 	 * @param mergeStrategy controls how old and new signatures should be merged
@@ -841,12 +841,12 @@
 		result[3] = ""; //$NON-NLS-1$
 		return result;
 	}
-	
+
 
 	/**
 	 * Apply the specified changes on a parameter within the given signature.
 	 * This method can be used as a dry run without modifying an annotation file.
-	 * 
+	 *
 	 * @param originalSignature the original full signature, may be annotated already
 	 * @param annotatedType a type signature with additional annotations (incl. {@link #NO_ANNOTATION}).
 	 * @param paramIdx the index of a parameter to annotate
@@ -868,7 +868,7 @@
 			wrapper.start = wrapper.skipAngleContents(wrapper.computeEnd()) + 1;
 		int start = wrapper.start;
 		int end = wrapper.skipAngleContents(wrapper.computeEnd());
-		result[0] = originalSignature.substring(0, start);				
+		result[0] = originalSignature.substring(0, start);
 		buf = new StringBuffer();
 		result[1] = originalSignature.substring(start, end+1);
 		updateType(buf, result[1].toCharArray(), annotatedType.toCharArray(), mergeStrategy);
@@ -880,7 +880,7 @@
 	/**
 	 * Apply the specified changes on a type parameter within the given signature.
 	 * This method can be used as a dry run without modifying an annotation file.
-	 * 
+	 *
 	 * @param originalSignature the original full signature, may be annotated already
 	 * @param annotatedType a type signature with additional annotations (incl. {@link #NO_ANNOTATION}).
 	 * @param rank the index of a type parameter to annotate
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java
index 7a43348..c3f2dda 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java
@@ -147,7 +147,7 @@
 	 * @since 3.2
 	 */
 	char[] STACK_MAP = "StackMap".toCharArray(); //$NON-NLS-1$
-	
+
  	/**
 	 * "RuntimeVisibleTypeAnnotations" attribute (added in jsr 308).
 	 * @since 3.10
@@ -190,10 +190,10 @@
 	 * @since 3.14
 	 */
 	char[] MODULE_MAIN_CLASS = "ModuleMainClass".toCharArray(); //$NON-NLS-1$
-	
+
 	/**
 	 * "NestHost" attribute (JVMS 11).
-	 * @since 3.16 
+	 * @since 3.16
 	 */
 	char[] NEST_HOST = "NestHost".toCharArray(); //$NON-NLS-1$
 
@@ -202,5 +202,11 @@
 	 * @since 3.16
 	 */
 	char[] NEST_MEMBERS = "NestMembers".toCharArray(); //$NON-NLS-1$
+	/**
+	 * "Record" attribute (JVMS 14 - preview).
+	 * @since 3.22
+	 */
+	char[] RECORD = "Record".toCharArray(); //$NON-NLS-1$
+
 
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileReader.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileReader.java
index fd98502..f72dafb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileReader.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IClassFileReader.java
@@ -127,6 +127,16 @@
 	}
 
 	/**
+	 * Answer back the record attribute of this .class file, null if none.
+	 *
+	 * @return the nest record of this .class file, null if none
+	 * @since 3.22
+	 */
+	default IRecordAttribute getRecordAttribute() {
+		return null;
+	}
+
+	/**
 	 * Answer back the array of method infos of this .class file,
 	 * an empty array if none.
 	 *
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IComponentInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IComponentInfo.java
new file mode 100644
index 0000000..a88b8ff
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IComponentInfo.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2019 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
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.jdt.core.util;
+
+/**
+ * Description of a component info as described in the JVM
+ * specifications.
+ *
+ * This interface may be implemented by clients.
+ *
+ * @since 3.22
+ */
+public interface IComponentInfo {
+
+
+	/**
+	 * Answer back the name of this component info. The name is returned as
+	 * specified in the JVM specifications.
+	 *
+	 * @return the name of this component info. The name is returned as
+	 * specified in the JVM specifications
+	 */
+	char[] getName();
+
+	/**
+	 * Answer back the name index of this component info.
+	 *
+	 * @return the name index of this component info
+	 */
+	int getNameIndex();
+
+	/**
+	 * Answer back the descriptor of this component info. The descriptor is returned as
+	 * specified in the JVM specifications.
+	 *
+	 * @return the descriptor of this component info. The descriptor is returned as
+	 * specified in the JVM specifications
+	 */
+	char[] getDescriptor();
+
+	/**
+	 * Answer back the descriptor index of this component info.
+	 *
+	 * @return the descriptor index of this component info
+	 */
+	int getDescriptorIndex();
+
+	/**
+	 * Answer back the attribute number of the component info.
+	 *
+	 * @return the attribute number of the component info
+	 */
+	int getAttributeCount();
+
+
+	/**
+	 * Answer back the collection of all attributes of the component info. It
+	 * includes SyntheticAttribute, ConstantValueAttributes, etc.
+	 * Returns an empty collection if none.
+	 *
+	 * @return the collection of all attributes of the component info.
+	 * Returns an empty collection if none
+	 */
+	IClassFileAttribute[] getAttributes();
+
+	/**
+	 * Answer back the total size
+	 * @return the size of the component info
+	 */
+	public int sizeInBytes();
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java
index fe6cf26..cb62f32 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java
@@ -48,7 +48,7 @@
 	 * proposed new name in JVMLS11
 	 * @since 3.16
 	 */
-	int CONSTANT_DynamicCallSite = CONSTANT_InvokeDynamic; 
+	int CONSTANT_DynamicCallSite = CONSTANT_InvokeDynamic;
 
 	/**
 	 * @since 3.14
@@ -60,7 +60,7 @@
 	int CONSTANT_Package = 20;
 	/**
 	 * For the proposed section of JVMLS11 4.4.13 The CONSTANT_Dynamic_info Structure
-	 * @since 3.16 
+	 * @since 3.16
 	 */
 	int CONSTANT_Dynamic = 17;
 
@@ -89,7 +89,7 @@
 	int CONSTANT_InvokeDynamic_SIZE = 5;
 
 	/**
-	 * @since 3.16 
+	 * @since 3.16
 	 */
 	int CONSTANT_Dynamic_SIZE = 5;
 	/**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry.java
index c1529c8..2209488 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry.java
@@ -205,7 +205,7 @@
 	 * CONSTANT_InterfaceMethodref type entry. This value is set only when decoding the
 	 * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, CONSTANT_MethodType
 	 * or CONSTANT_InvokeDynamic entry.
-	 * 
+	 *
 	 * Returns null otherwise.
 	 *
 	 * @return the method descriptor value for a CONSTANT_Methodref,
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry2.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry2.java
index 88c6570..814ba70 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry2.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry2.java
@@ -50,7 +50,7 @@
 	 * @see IConstantPoolConstant#CONSTANT_MethodHandle
 	 */
 	int getReferenceIndex();
-	
+
 	/**
 	 * Returns the bootstrap method attribute index. This value is set only when decoding a InvokeDynamic entry.
 	 * The value is unspecified otherwise.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExtendedAnnotation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExtendedAnnotation.java
index 871158f..18c7cef 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExtendedAnnotation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExtendedAnnotation.java
@@ -31,10 +31,10 @@
 	 * @return the target type
 	 */
 	int getTargetType();
-	
+
 	/**
 	 * Answer back the offset.
-	 * 
+	 *
 	 * For a target_type value equals to:
 	 * <table border="1">
 	 * <tr>
@@ -56,73 +56,73 @@
 	 * may have been discarded by the compiler if it were a no-op.</td>
 	 * </tr>
 	 * </table>
-	 * 
-	 * 
+	 *
+	 *
 	 * @return the offset
 	 */
 	int getOffset();
-	
+
 	/**
 	 * Answer back the exception table index when the target_type is EXCEPTION_PARAMETER.
-	 * 
+	 *
 	 * @return the exception table index
 	 */
 	int getExceptionTableIndex();
-	
+
 	/**
 	 * Answer back the local variable reference info table length of this entry as specified in
 	 * the JVM specifications.
-	 * 
+	 *
 	 * <p>This is defined only for annotations related to a local variable.</p>
 	 *
 	 * @return the local variable reference info table length of this entry as specified in
 	 * the JVM specifications
 	 */
 	int getLocalVariableRefenceInfoLength();
-	
+
 	/**
 	 * Answer back the local variable reference info table of this entry as specified in
 	 * the JVM specifications. Answer an empty array if none.
-	 * 
+	 *
 	 * <p>This is defined only for annotations related to a local variable.</p>
 	 *
 	 * @return the local variable reference info table of this entry as specified in
 	 * the JVM specifications. Answer an empty array if none
 	 */
 	ILocalVariableReferenceInfo[] getLocalVariableTable();
-	
+
 	/**
 	 * Answer back the method parameter index.
-	 * 
+	 *
 	 * <p>The index is 0-based.</p>
-	 * 
+	 *
 	 * @return the method parameter index
 	 */
 	int getParameterIndex();
 
 	/**
 	 * Answer back the index of the type parameter of the class or method
-	 * 
+	 *
 	 * <p>The index is 0-based.</p>
-	 * 
+	 *
 	 * @return the index of the type parameter of the class or method
 	 */
 	int getTypeParameterIndex();
 
 	/**
 	 * Answer back the index of the bound of the type parameter of the method or class
-	 * 
+	 *
 	 * <p>The index is 0-based.</p>
-	 * 
+	 *
 	 * @return the index of the bound of the type parameter of the method or class
 	 */
 	int getTypeParameterBoundIndex();
 
 	/**
 	 * Answer back the index in the given different situations.
-	 * 
+	 *
 	 * <p>The index is 0-based.</p>
-	 * 
+	 *
 	 * <table border="1">
 	 * <tr>
 	 * <th>target_type</th>
@@ -130,13 +130,13 @@
 	 * </tr>
 	 * <tr>
 	 * <td>0x10 (CLASS_EXTENDS)</td>
-	 * <td>the index of the type in the clause: <code>-1 (65535)</code> is used if the annotation is on 
+	 * <td>the index of the type in the clause: <code>-1 (65535)</code> is used if the annotation is on
 	 * the superclass type, and the value <code>i</code> is used if the annotation is on the <code>i</code>th
 	 * superinterface type (counting from zero).</td>
 	 * </tr>
 	 * <tr>
 	 * <td>0x17 (THROWS)</td>
-	 * <td>the index of the exception type in the clause: the value <code>i</code> denotes an annotation of the 
+	 * <td>the index of the exception type in the clause: the value <code>i</code> denotes an annotation of the
 	 * <code>i</code>th exception type (counting from zero).</td>
 	 * </tr>
 	 * <tr>
@@ -148,14 +148,14 @@
 	 * @return the index in the given different situations
 	 */
 	int getAnnotationTypeIndex();
-	
+
 	/**
 	 * Answer back the locations of the annotated type as described in the JVM specifications.
-	 * 
+	 *
 	 * <p>This is used for parameterized and array types.</p>
 	 *
 	 * @return the locations of the annotated type
 	 */
 	int[][] getTypePath();
-	
+
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExtendedAnnotationConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExtendedAnnotationConstants.java
index b23f8f8..ebeeaa9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExtendedAnnotationConstants.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IExtendedAnnotationConstants.java
@@ -26,7 +26,7 @@
  * @noextend This interface is not intended to be extended by clients.
  */
 public interface IExtendedAnnotationConstants {
-	
+
 	int CLASS_TYPE_PARAMETER = AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER;
 	int METHOD_TYPE_PARAMETER = AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER;
 
@@ -51,7 +51,7 @@
 	int METHOD_INVOCATION_TYPE_ARGUMENT = AnnotationTargetTypeConstants.METHOD_INVOCATION_TYPE_ARGUMENT;
 	int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = AnnotationTargetTypeConstants.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT;
 	int METHOD_REFERENCE_TYPE_ARGUMENT = AnnotationTargetTypeConstants.METHOD_REFERENCE_TYPE_ARGUMENT;
-	
+
 	// Type path entry kinds
 	int TYPE_PATH_DEEPER_IN_ARRAY = 0;
 	int TYPE_PATH_DEEPER_IN_INNER_TYPE = 1;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IMethodParametersAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IMethodParametersAttribute.java
index f016b2c..c3a0dcd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IMethodParametersAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IMethodParametersAttribute.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     Jesper Steen Moeller - initial API and implementation
  *******************************************************************************/
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestHostAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestHostAttribute.java
index a37e97f..3db4618 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestHostAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestHostAttribute.java
@@ -13,7 +13,7 @@
 /**
  * Description of a nest host attribute as described in the JVM
  * specifications.
- * @since 3.16 
+ * @since 3.16
  */
 public interface INestHostAttribute {
 	/**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestMemberAttributeEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestMemberAttributeEntry.java
index d89df66..797c7b7 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestMemberAttributeEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestMemberAttributeEntry.java
@@ -13,7 +13,7 @@
 /**
  * Description of a nest host attribute as described in the JVM
  * specifications.
- * @since 3.16 
+ * @since 3.16
  */
 public interface INestMemberAttributeEntry {
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestMembersAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestMembersAttribute.java
index 2032b7c..77011dd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestMembersAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/INestMembersAttribute.java
@@ -14,7 +14,7 @@
  * Description of nest members attribute as described in the JVM
  * specifications.
  *
- * @since 3.16 
+ * @since 3.16
  */
 public interface INestMembersAttribute extends IClassFileAttribute {
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRecordAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRecordAttribute.java
new file mode 100644
index 0000000..8b02fcd
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IRecordAttribute.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2019, 2020 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
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.util;
+
+/**
+ * Description of record components attribute as described in the JVM
+ * specifications.
+ *
+ * @since 3.22
+ */
+public interface IRecordAttribute extends IClassFileAttribute {
+
+	/**
+	 * Answer back the number of components as specified in
+	 * the JVM specifications.
+	 *
+	 * @return the number of components as specified in
+	 * the JVM specifications
+	 */
+	int getNumberOfComponents();
+
+	/**
+	 * Answer back the array of record component infos as specified in
+	 * the JVM specifications, or an empty array if none.
+	 *
+	 * @return the array of record component infos as specified in
+	 * the JVM specifications, or an empty array if none
+	 */
+	IComponentInfo[] getComponentInfos();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java
index a0add07..213f330 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/DocumentElementParser.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -527,7 +527,7 @@
 
 	declaration.type = extendedTypeDimension != 0 ? augmentTypeWithAdditionalDimensions(type, extendedTypeDimension, annotationsOnExtendedDimensions, false) : type;
 	declaration.bits |= (type.bits & ASTNode.HasTypeAnnotations);
-	
+
 	this.variablesCounter[this.nestedType]++;
 	this.nestedMethod[this.nestedType]++;
 	pushOnAstStack(declaration);
@@ -753,15 +753,15 @@
 				varArgsAnnotations = new Annotation[length],
 				0,
 				length);
-		} 
+		}
 	}
 	int firstDimensions = this.intStack[this.intPtr--];
 	TypeReference type = getTypeReference(firstDimensions);
 
 	if (isVarArgs || extendedDimensions != 0) {
 		if (isVarArgs) {
-			type = augmentTypeWithAdditionalDimensions(type, 1, varArgsAnnotations != null ? new Annotation[][] { varArgsAnnotations } : null, true);	
-		} 
+			type = augmentTypeWithAdditionalDimensions(type, 1, varArgsAnnotations != null ? new Annotation[][] { varArgsAnnotations } : null, true);
+		}
 		if (extendedDimensions != 0) { // combination illegal.
 			type = augmentTypeWithAdditionalDimensions(type, extendedDimensions, annotationsOnExtendedDimensions, false);
 		}
@@ -777,8 +777,8 @@
 	Argument arg;
 	if (isReceiver) {
 		arg = new Receiver(
-				parameterName, 
-				namePositions, 
+				parameterName,
+				namePositions,
 				type,
 				qualifyingNameReference,
 				this.intStack[this.intPtr + 1] & ~ClassFileConstants.AccDeprecated);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ExtraFlags.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ExtraFlags.java
index 11b8214..7c41d65 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ExtraFlags.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ExtraFlags.java
@@ -24,21 +24,21 @@
 	public final static int HasNonPrivateStaticMemberTypes = 0x0001;
 	public final static int IsMemberType = 0x0002;
 	public final static int IsLocalType = 0x0004;
-	
+
 	//internal flags
 	public final static int ParameterTypesStoredAsSignature = 0x0010;
-	
+
 	public static int getExtraFlags(ClassFileReader reader) {
 		int extraFlags = 0;
-		
+
 		if (reader.isNestedType()) {
 			extraFlags |= ExtraFlags.IsMemberType;
 		}
-		
+
 		if (reader.isLocal()) {
 			extraFlags |= ExtraFlags.IsLocalType;
 		}
-		
+
 		IBinaryNestedType[] memberTypes = reader.getMemberTypes();
 		int memberTypeCounter = memberTypes == null ? 0 : memberTypes.length;
 		if (memberTypeCounter > 0) {
@@ -50,23 +50,23 @@
 					break done;
 				}
 			}
-			
+
 		}
-		
+
 		return extraFlags;
 	}
-	
+
 	public static int getExtraFlags(IType type) throws JavaModelException {
 		int extraFlags = 0;
-		
+
 		if (type.isMember()) {
 			extraFlags |= ExtraFlags.IsMemberType;
 		}
-		
+
 		if (type.isLocal()) {
 			extraFlags |= ExtraFlags.IsLocalType;
 		}
-		
+
 		IType[] memberTypes = type.getTypes();
 		int memberTypeCounter = memberTypes == null ? 0 : memberTypes.length;
 		if (memberTypeCounter > 0) {
@@ -79,13 +79,13 @@
 				}
 			}
 		}
-		
+
 		return extraFlags;
 	}
-	
+
 	public static int getExtraFlags(TypeDeclaration typeDeclaration) {
 		int extraFlags = 0;
-		
+
 		if (typeDeclaration.enclosingType != null) {
 			extraFlags |= ExtraFlags.IsMemberType;
 		}
@@ -101,7 +101,7 @@
 				}
 			}
 		}
-		
+
 		return extraFlags;
 	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java
index e89dce5..b6f071a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/ISourceElementRequestor.java
@@ -31,7 +31,7 @@
  *
  * The structural investigation includes: - package statement - import
  * statements - top-level types: package member, member types (member types of
- * member types...) - fields - methods. From Java 9 onwards it includes the 
+ * member types...) - fields - methods. From Java 9 onwards it includes the
  * module name in a module declaration
  *
  * If reference information is requested, then all source constructs are
@@ -233,7 +233,7 @@
 	void exitMethod(int declarationEnd, Expression defaultValue);
 
 	void exitType(int declarationEnd);
-	
+
 	default void enterModule(ModuleInfo info) {
 		// do nothing
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementNotifier.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementNotifier.java
index 3143632..a30c053 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementNotifier.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementNotifier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2017 IBM Corporation and others.
+ * Copyright (c) 2008, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -278,11 +278,11 @@
 	char[][] argumentNames = null;
 	boolean isVarArgs = false;
 	Argument[] arguments = methodDeclaration.arguments;
-	ParameterInfo[] parameterInfos = null; 
+	ParameterInfo[] parameterInfos = null;
 	ISourceElementRequestor.MethodInfo methodInfo = new ISourceElementRequestor.MethodInfo();
 	methodInfo.typeAnnotated = ((methodDeclaration.bits & ASTNode.HasTypeAnnotations) != 0);
 
-	if (arguments != null) {
+	if (arguments != null && arguments.length > 0) {
 		Object[][] argumentInfos = getArgumentInfos(arguments);
 		parameterInfos = (ParameterInfo[]) argumentInfos[0];
 		argumentTypes = (char[][]) argumentInfos[1][0];
@@ -452,7 +452,7 @@
 				nodes[index++] = types[i];
 			}
 		}
-		
+
 		if (parsedUnit.moduleDeclaration != null)
 			nodes[index++] = parsedUnit.moduleDeclaration;
 
@@ -675,7 +675,6 @@
 			typeInfo.annotations = typeDeclaration.annotations;
 			typeInfo.extraFlags = ExtraFlags.getExtraFlags(typeDeclaration);
 			typeInfo.node = typeDeclaration;
-			this.requestor.enterType(typeInfo);
 			switch (kind) {
 				case TypeDeclaration.CLASS_DECL :
 					if (superclassName != null)
@@ -690,7 +689,12 @@
 				case TypeDeclaration.ANNOTATION_TYPE_DECL :
 					implicitSuperclassName = TypeConstants.CharArray_JAVA_LANG_ANNOTATION_ANNOTATION;
 					break;
+				case TypeDeclaration.RECORD_DECL :
+ 					implicitSuperclassName = TypeConstants.CharArray_JAVA_LANG_RECORD;
+ 					typeInfo.modifiers |= ExtraCompilerModifiers.AccRecord;
+ 					break;
 			}
+			this.requestor.enterType(typeInfo);
 		}
 		if (this.nestedTypeIndex == this.typeNames.length) {
 			// need a resize
@@ -777,7 +781,7 @@
 				}
 			}
 			exps[i] = exp;
-		}					
+		}
 		modInfo.exports = exps;
 	}
 	if (mod.servicesCount > 0) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementParser.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementParser.java
index 5af01a9..17ec28e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementParser.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/SourceElementParser.java
@@ -334,6 +334,20 @@
 		rememberCategories();
 	}
 }
+
+@Override
+protected void consumeCompactConstructorHeaderName() {
+	long selectorSourcePositions = this.identifierPositionStack[this.identifierPtr];
+	int selectorSourceEnd = (int) selectorSourcePositions;
+	int currentAstPtr = this.astPtr;
+	super.consumeCompactConstructorHeaderName();
+	if (this.astPtr > currentAstPtr) { // if ast node was pushed on the ast stack
+		this.sourceEnds.put(this.astStack[this.astPtr], selectorSourceEnd);
+		rememberCategories();
+	}
+}
+
+
 @Override
 protected void consumeConstructorHeaderNameWithTypeParameters() {
 	long selectorSourcePositions = this.identifierPositionStack[this.identifierPtr];
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java
index d1f929e..7feb5c0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -131,7 +131,7 @@
 		org.eclipse.jdt.core.ICompilationUnit cuHandle = topLevelTypeInfo.getHandle().getCompilationUnit();
 		this.cu = (ICompilationUnit) cuHandle;
 		final CompilationUnitElementInfo compilationUnitElementInfo = (CompilationUnitElementInfo) ((JavaElement) this.cu).getElementInfo();
-		if (this.has1_5Compliance && 
+		if (this.has1_5Compliance &&
 				(compilationUnitElementInfo.annotationNumber >= CompilationUnitElementInfo.ANNOTATION_THRESHOLD_FOR_DIET_PARSE ||
 				(compilationUnitElementInfo.hasFunctionalTypes && (this.flags & LOCAL_TYPE) != 0))) {
 			// If more than 10 annotations, diet parse as this is faster, but not if
@@ -195,7 +195,7 @@
 		ModuleDescriptionInfo moduleInfo = (ModuleDescriptionInfo) module;
 		org.eclipse.jdt.core.ICompilationUnit cuHandle = moduleInfo.getHandle().getCompilationUnit();
 		this.cu = (ICompilationUnit) cuHandle;
-		// always parse, because (a) dietParse is always sufficient, (b) we don't yet have the necessary conversion methods for module directives 
+		// always parse, because (a) dietParse is always sufficient, (b) we don't yet have the necessary conversion methods for module directives
 		return new Parser(this.problemReporter, true).dietParse(this.cu, compilationResult);
 	}
 
@@ -475,8 +475,13 @@
 		SourceTypeElementInfo typeInfo = (SourceTypeElementInfo) typeHandle.getElementInfo();
 		if (typeInfo.isAnonymousMember())
 			throw new AnonymousMemberFound();
-		/* create type declaration - can be member type */
+		/* create type/record declaration - can be member type */
 		TypeDeclaration type = new TypeDeclaration(compilationResult);
+		if ((TypeDeclaration.kind(typeInfo.getModifiers()) == TypeDeclaration.RECORD_DECL)) {
+			// The first choice constructor that takes CompilationResult as arg is not setting all the fields
+			// Hence, use the one that does
+			type = new RecordDeclaration(type);
+		}
 		if (typeInfo.getEnclosingType() == null) {
 			if (typeHandle.isAnonymous()) {
 				type.name = CharOperation.NO_CHAR;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/TypeConverter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/TypeConverter.java
index 30203e2..bcca8dc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/TypeConverter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/TypeConverter.java
@@ -434,11 +434,11 @@
 				case '<' :
 					/* We need to convert and preserve 1.5 specific constructs either if compliance is 1.5 or above,
 					   or the caller has explicitly requested generics to be included. The parameter includeGenericsAnyway
-					   should be used by the caller to signal that in the calling context generics information must be 
+					   should be used by the caller to signal that in the calling context generics information must be
 					   internalized even when the requesting project is 1.4. But in all cases, we must skip over them to
 					   see if there are any applicable type fragments after the type parameters: i.e we just aren't done
-					   having seen a '<' in 1.4 mode. 
-					   
+					   having seen a '<' in 1.4 mode.
+
 					   Because of the way type signatures are encoded, TypeConverter.decodeType(String, int, int, int) is immune
 					   to this problem. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=325633
 					 */
@@ -469,7 +469,7 @@
 
 	/*
 	 * Method should be inlined.
-	 * 
+	 *
 	 * Only extracted to work around https://bugs.eclipse.org/471835 :
 	 * Random crashes in PhaseIdealLoop::build_loop_late_post when C2 JIT tries to compile TypeConverter::decodeType
 	 */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractClassFile.java
index 6a3ec80..b3457dc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractClassFile.java
@@ -62,10 +62,10 @@
 		if (perWorkingCopyInfo == null) {
 			// close cu and its children
 			close();
-	
+
 			BecomeWorkingCopyOperation operation = new BecomeWorkingCopyOperation(workingCopy, problemRequestor);
 			operation.runOperation(monitor);
-	
+
 			return workingCopy;
 		}
 		return perWorkingCopyInfo.workingCopy;
@@ -109,7 +109,7 @@
 	}
 	@Override
 	public abstract void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException;
-	
+
 	/**
 	 * @see ICodeAssist#codeSelect(int, int)
 	 */
@@ -119,7 +119,7 @@
 	}
 	@Override
 	public abstract IJavaElement[] codeSelect(int offset, int length, WorkingCopyOwner owner) throws JavaModelException;
-	
+
 	/**
 	 * Returns a new element info for this element.
 	 */
@@ -133,7 +133,7 @@
 		AbstractClassFile other = (AbstractClassFile) o;
 		return this.name.equals(other.name) && this.parent.equals(other.parent);
 	}
-	
+
 	/**
 	 * Finds the deepest <code>IJavaElement</code> in the hierarchy of
 	 * <code>elt</elt>'s children (including <code>elt</code> itself)
@@ -160,7 +160,7 @@
 		}
 		return elt;
 	}
-	
+
 	@Override
 	public byte[] getBytes() throws JavaModelException {
 		JavaElement pkg = (JavaElement) getParent();
@@ -213,7 +213,7 @@
 			throw new OperationCanceledException();
 		return contents;
 	}
-	
+
 	@Override
 	public IBuffer getBuffer() throws JavaModelException {
 		IStatus status = validateClassFile();
@@ -235,7 +235,7 @@
 	public ITypeRoot getTypeRoot() {
 		return this;
 	}
-	
+
 	/**
 	 * A class file has a corresponding resource unless it is contained
 	 * in a jar.
@@ -260,7 +260,7 @@
 		} else {
 			int index = this.name.indexOf('$');
 			int prefixLength = index < 0 ? this.name.length() : index;
-	
+
 			IType type = null;
 			int start = -1;
 			int end = Integer.MAX_VALUE;
@@ -269,14 +269,14 @@
 				if (children[i] instanceof IOrdinaryClassFile) {
 					IOrdinaryClassFile classFile = (IOrdinaryClassFile) children[i];
 					String childName = classFile.getElementName();
-		
+
 					int childIndex = childName.indexOf('$');
 					int childPrefixLength = childIndex < 0 ? childName.indexOf('.') : childIndex;
 					if (prefixLength == childPrefixLength && this.name.regionMatches(0, childName, 0, prefixLength)) {
-		
+
 						// ensure this class file's buffer is open so that source ranges are computed
 						classFile.getBuffer();
-		
+
 						SourceRange range = mapper.getSourceRange(classFile.getType());
 						if (range == SourceMapper.UNKNOWN_RANGE) continue;
 						int newStart = range.getOffset();
@@ -320,7 +320,7 @@
 			return getParent().getPath().append(getElementName());
 		}
 	}
-	
+
 	/*
 	 * @see IJavaElement
 	 */
@@ -391,7 +391,7 @@
 		IJavaProject project = getJavaProject();
 		return JavaConventions.validateClassFileName(getElementName(), project.getOption(JavaCore.COMPILER_SOURCE, true), project.getOption(JavaCore.COMPILER_COMPLIANCE, true));
 	}
-	
+
 
 	/**
 	 * @see ICodeAssist#codeComplete(int, ICodeCompletionRequestor)
@@ -467,7 +467,7 @@
 				}
 			});
 	}
-	
+
 	@Override
 	protected IStatus validateExistence(IResource underlyingResource) {
 		// check whether the class file can be opened
@@ -484,7 +484,7 @@
 		}
 		return JavaModelStatus.VERIFIED_OK;
 	}
-	
+
 	@Override
 	public ISourceRange getNameRange() {
 		return null;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractModule.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractModule.java
index b95f900..16daf4f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractModule.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/AbstractModule.java
@@ -28,14 +28,14 @@
 import org.eclipse.jdt.internal.compiler.env.IModule.IService;
 
 public interface AbstractModule extends IModuleDescription {
-	
+
 	/**
 	 * Handle for an automatic module.
 	 *
 	 * <p>Note, that by definition this is mostly a fake, only {@link #getElementName()} provides a useful value.</p>
 	 */
 	static class AutoModule extends NamedMember implements AbstractModule {
-	
+
 		private boolean nameFromManifest;
 
 		public AutoModule(JavaElement parent, String name, boolean nameFromManifest) {
@@ -75,7 +75,7 @@
 			buffer.append(this.name);
 		}
 	}
-	
+
 	// "forward declaration" for a method from JavaElement:
 	abstract Object getElementInfo() throws JavaModelException;
 
@@ -123,7 +123,7 @@
 	default IService[] getProvidedServices() throws JavaModelException {
 		return getModuleInfo().provides();
 	}
-	@Override 
+	@Override
 	default String[] getProvidedServiceNames() throws JavaModelException {
 		ArrayList<String> results = new ArrayList<>();
 		IService[] services = getProvidedServices();
@@ -131,12 +131,12 @@
 			results.add(new String(service.name()));
 		}
 		return results.toArray(new String[0]);
-		
+
 	}
 	default char[][] getUsedServices() throws JavaModelException {
 		return getModuleInfo().uses();
 	}
-	@Override 
+	@Override
 	default String[] getUsedServiceNames() throws JavaModelException {
 		ArrayList<String> results = new ArrayList<>();
 		char[][] services = getUsedServices();
@@ -144,7 +144,7 @@
 			char[] service = services[i];
 			results.add(new String(service));
 		}
-		return results.toArray(new String[0]);	
+		return results.toArray(new String[0]);
 	}
 	default IPackageExport[] getOpenedPackages() throws JavaModelException {
 		return getModuleInfo().opens();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java
index 91b0699..ed2c849 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMember.java
@@ -32,7 +32,7 @@
  */
 @SuppressWarnings({ "rawtypes", "unchecked" })
 public abstract class BinaryMember extends NamedMember {
-		
+
 /*
  * Constructs a binary member.
  */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java
index b283307..a8bfec9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryMethod.java
@@ -48,7 +48,7 @@
 	 */
 	protected String[] parameterTypes;
 	protected String [] erasedParamaterTypes; // lazily initialized via call to getErasedParameterTypes
-	
+
 	/**
 	 * The parameter names for the method.
 	 */
@@ -313,7 +313,7 @@
 				projectInfo.javadocCache.put(declaringType, BinaryType.EMPTY_JAVADOC);
 			}
 		}
-		
+
 		String methodDoc = null;
 		if (javadocContents == null) {
 			long timeOut = 50; // default value
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryModule.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryModule.java
index e2bb12e..5b96a39 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryModule.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryModule.java
@@ -32,7 +32,7 @@
 public class BinaryModule extends BinaryMember implements AbstractModule {
 
 	private IBinaryModule info;
-	
+
 	/** For creating a pure handle from its memento. */
 	public BinaryModule(JavaElement parent, String name) {
 		super(parent, name);
@@ -46,7 +46,7 @@
 	public IModule getModuleInfo() throws JavaModelException {
 		if (this.info == null) {
 			ModularClassFile classFile = (ModularClassFile) this.parent;
-			this.info = classFile.getBinaryModuleInfo();			
+			this.info = classFile.getBinaryModuleInfo();
 		}
 		return this.info;
 	}
@@ -108,7 +108,7 @@
 		synchronized (projectInfo.javadocCache) {
 			cachedJavadoc = (JavadocContents) projectInfo.javadocCache.get(this);
 		}
-		
+
 		if (cachedJavadoc != null && cachedJavadoc != BinaryType.EMPTY_JAVADOC) {
 			return cachedJavadoc;
 		}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
index 09a065a..e88f5af 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -704,6 +704,16 @@
 	return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.ENUM_DECL;
 }
 
+/**
+ * @see IType#isRecord()
+ * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
+ */
+@Override
+public boolean isRecord() throws JavaModelException {
+	IBinaryType info = (IBinaryType) getElementInfo();
+	return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.RECORD_DECL;
+}
+
 @Override
 public boolean isInterface() throws JavaModelException {
 	IBinaryType info = (IBinaryType) getElementInfo();
@@ -952,7 +962,9 @@
 		toStringName(buffer);
 	} else {
 		try {
-			if (isAnnotation()) {
+			if (isRecord()) {
+				buffer.append("record "); //$NON-NLS-1$
+			} else if (isAnnotation()) {
 				buffer.append("@interface "); //$NON-NLS-1$
 			} else if (isEnum()) {
 				buffer.append("enum "); //$NON-NLS-1$
@@ -986,7 +998,7 @@
 	synchronized (projectInfo.javadocCache) {
 		cachedJavadoc = (JavadocContents) projectInfo.javadocCache.get(this);
 	}
-	
+
 	if (cachedJavadoc != null && cachedJavadoc != EMPTY_JAVADOC) {
 		return cachedJavadoc;
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableNameEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableNameEnvironment.java
index 3b55a7a..fa12a48 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableNameEnvironment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CancelableNameEnvironment.java
@@ -67,7 +67,7 @@
 		checkCanceled();
 		super.findTypes(prefix, findMembers, camelCaseMatch, searchFor, storage, progressMonitor);
 	}
-	
+
 	@Override
 	public void setMonitor(IProgressMonitor monitor) {
 		this.monitor = monitor;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
index 914f6eb..91c7a7a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
@@ -82,7 +82,7 @@
 		info.setChildren(JavaElement.NO_ELEMENTS);
 		return false;
 	}
-	
+
 	// Make the type
 	IType type = getType();
 	info.setChildren(new IJavaElement[] {type});
@@ -234,7 +234,7 @@
 	} else {
 		result = BinaryTypeFactory.readType(descriptor, null);
 	}
-		
+
 	if (result == null) {
 		return null;
 	}
@@ -258,7 +258,7 @@
 			IProject project = javaProject.getProject();
 			IPath externalAnnotationPath = ClasspathEntry.getExternalAnnotationPath(entry, project, false); // unresolved for use in ExternalAnnotationTracker
 			if (externalAnnotationPath != null) {
-				result = setupExternalAnnotationProvider(project, externalAnnotationPath, result, 
+				result = setupExternalAnnotationProvider(project, externalAnnotationPath, result,
 						entryName.substring(0, entryName.length() - SuffixConstants.SUFFIX_CLASS.length));
 			} else if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
 				result = new ExternalAnnotationDecorator(result, true);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java
index 3990140..d7f8600 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFileInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -158,6 +158,9 @@
 	if ((tagBits & TagBits.AnnotationForModule) != 0) {
 		values.add(elementType + new String(TypeConstants.UPPER_MODULE));
 	}
+	if ((tagBits & TagBits.AnnotationForRecordComponent) != 0) {
+		values.add(elementType + new String(TypeConstants.UPPER_RECORD_COMPONENT));
+	}
 	final Object value;
 	if (values.size() == 0) {
 		if ((tagBits & TagBits.AnnotationTarget) != 0)
@@ -200,7 +203,7 @@
 		retention = new String(CharOperation.concatWith(TypeConstants.JAVA_LANG_ANNOTATION_RETENTIONPOLICY, '.')) + '.' + new String(TypeConstants.UPPER_CLASS);
 	}
 	final String value = retention;
-	return 
+	return
 		new IMemberValuePair[] {
 			new IMemberValuePair() {
 				@Override
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
index dc3de37..629c80b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Terry Parker <tparker@google.com> - DeltaProcessor misses state changes in archive files, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=357425
@@ -31,6 +31,7 @@
 import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -38,6 +39,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.zip.CRC32;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
@@ -88,9 +90,9 @@
  */
 @SuppressWarnings({ "rawtypes", "unchecked" })
 public class ClasspathEntry implements IClasspathEntry {
-	
+
 	public static class AssertionFailedException extends RuntimeException {
-		
+
 		private static final long serialVersionUID = -171699380721189572L;
 
 		public AssertionFailedException(String message) {
@@ -122,6 +124,9 @@
 	public static final String TAG_DISCOURAGED = "discouraged"; //$NON-NLS-1$
 	public static final String TAG_IGNORE_IF_BETTER = "ignoreifbetter"; //$NON-NLS-1$
 
+	// common index location for all workspaces
+	private static String SHARED_INDEX_LOCATION = System.getProperty("jdt.core.sharedIndexLocation"); //$NON-NLS-1$
+
 	/**
 	 * Describes the kind of classpath entry - one of
 	 * CPE_PROJECT, CPE_LIBRARY, CPE_SOURCE, CPE_VARIABLE or CPE_CONTAINER
@@ -221,7 +226,7 @@
 	 * a non-<code>null</code> value.
 	 */
 	public IPath sourceAttachmentRootPath;
-	
+
 	/**
 	 * See {@link IClasspathEntry#getReferencingEntry()}
 	 */
@@ -236,7 +241,7 @@
 	 * A constant indicating an output location.
 	 */
 	public static final int K_OUTPUT = 10;
-	
+
 	public static final String DOT_DOT = ".."; //$NON-NLS-1$
 
 	/**
@@ -263,13 +268,13 @@
 			boolean combineAccessRules,
 			IClasspathAttribute[] extraAttributes) {
 
-		this(	contentKind, 
-				entryKind, 
-				path, 
-				inclusionPatterns, 
-				exclusionPatterns, 
-				sourceAttachmentPath, 
-				sourceAttachmentRootPath, 
+		this(	contentKind,
+				entryKind,
+				path,
+				inclusionPatterns,
+				exclusionPatterns,
+				sourceAttachmentPath,
+				sourceAttachmentRootPath,
 				specificOutputLocation,
 				null,
 				isExported,
@@ -277,7 +282,7 @@
 				combineAccessRules,
 				extraAttributes);
 	}
-	
+
 	/**
 	 * Creates a class path entry of the specified kind with the given path.
 	 */
@@ -302,7 +307,7 @@
 		this.inclusionPatterns = inclusionPatterns;
 		this.exclusionPatterns = exclusionPatterns;
 		this.referencingEntry = referencingEntry;
-		
+
 		int length;
 		if (accessRules != null && (length = accessRules.length) > 0) {
 			AccessRule[] rules = new AccessRule[length];
@@ -389,7 +394,7 @@
 		return this;
 	}
 
-	
+
 	public ClasspathEntry withExtraAttributeRemoved(String attrName) {
 		IClasspathAttribute[] changedAttributes = Arrays.stream(this.getExtraAttributes())
 				.filter(a -> !a.getName().equals(attrName)).toArray(IClasspathAttribute[]::new);
@@ -409,7 +414,7 @@
 				changedAttributes);
 	}
 
-	
+
 	private IAccessRule[] combine(IAccessRule[] referringRules, IAccessRule[] rules, boolean combine) {
 		if (!combine) return rules;
 		if (rules == null || rules.length == 0) return referringRules;
@@ -651,9 +656,9 @@
 		boolean hasRestrictions = getAccessRuleSet() != null; // access rule set is null if no access rules
 		ArrayList unknownChildren = unknownXmlElements != null ? unknownXmlElements.children : null;
 		boolean hasUnknownChildren = unknownChildren != null;
-		
+
 		/* close tag if no extra attributes, no restriction and no unknown children */
-		String tagName = isReferencedEntry ? TAG_REFERENCED_ENTRY : TAG_CLASSPATHENTRY; 
+		String tagName = isReferencedEntry ? TAG_REFERENCED_ENTRY : TAG_CLASSPATHENTRY;
 		writer.printTag(
 			tagName,
 			parameters,
@@ -848,10 +853,10 @@
 				String projSegment = path.segment(0);
 				if (projSegment != null && projSegment.equals(project.getElementName())) { // this project
 					entry = JavaCore.newSourceEntry(
-												path, 
-												inclusionPatterns, 
-												exclusionPatterns, 
-												outputLocation, 
+												path,
+												inclusionPatterns,
+												exclusionPatterns,
+												outputLocation,
 												extraAttributes);
 				} else {
 					if (path.segmentCount() == 1) {
@@ -865,10 +870,10 @@
 					} else {
 						// an invalid source folder
 						entry = JavaCore.newSourceEntry(
-												path, 
-												inclusionPatterns, 
-												exclusionPatterns, 
-												outputLocation, 
+												path,
+												inclusionPatterns,
+												exclusionPatterns,
+												outputLocation,
 												extraAttributes);
 					}
 				}
@@ -918,7 +923,7 @@
 
 		return entry;
 	}
-	
+
 	/*
 	 * Returns whether the given path as a ".." segment
 	 */
@@ -970,7 +975,7 @@
 			return NO_PATHS;
 		return (IPath[]) result.toArray(new IPath[result.size()]);
 	}
-	
+
 	private static void resolvedChainedLibraries(IPath jarPath, HashSet visited, ArrayList result) {
 		if (visited.contains( jarPath))
 			return;
@@ -1055,7 +1060,7 @@
 		List calledFileNames = null;
 		try {
 			char[] manifestContents = getManifestContents(jarPath);
-			if (manifestContents == null) 
+			if (manifestContents == null)
 				return null;
 			// non-null implies regular file
 			ManifestAnalyzer analyzer = new ManifestAnalyzer();
@@ -1346,7 +1351,7 @@
 	 * </ol>
 	 * In case of ambiguity, workspace lookup has higher priority than filesystem lookup
 	 * (in fact filesystem paths are never validated).
-	 * 
+	 *
 	 * @param entry classpath entry to work on
 	 * @param project project whose classpath we are analysing
 	 * @param resolve if true, any workspace-relative paths will be resolved to filesystem paths.
@@ -1430,7 +1435,7 @@
 		}
 		return new JavaModelStatus(IJavaModelStatusConstants.CP_INVALID_EXTERNAL_ANNOTATION_PATH,
 				javaProject,
-				Messages.bind(Messages.classpath_invalidExternalAnnotationPath, 
+				Messages.bind(Messages.classpath_invalidExternalAnnotationPath,
 						new String[] { annotationPath.toString(), project.getName(), this.path.toString()}));
 	}
 
@@ -1491,7 +1496,7 @@
 		}
 		return null;
 	}
-	
+
 	/**
 	 * Returns the kind of a <code>PackageFragmentRoot</code> from its <code>String</code> form.
 	 */
@@ -1658,7 +1663,7 @@
 		}
 		return buffer.toString();
 	}
-	
+
 	public ClasspathEntry resolvedDotDot(IPath reference) {
 		IPath resolvedPath = resolveDotDot(reference, this.path);
 		if (resolvedPath == this.path)
@@ -1678,7 +1683,7 @@
 							this.combineAccessRules,
 							this.extraAttributes);
 	}
-	
+
 	/*
 	 * Read the Class-Path clause of the manifest of the jar pointed by this entry, and return
 	 * the corresponding library entries.
@@ -1708,7 +1713,7 @@
 		}
 		return result;
 	}
-	
+
 	/**
 	 * Answers an ID which is used to distinguish entries during package
 	 * fragment root computations
@@ -1749,7 +1754,7 @@
 
 		return JavaCore.getResolvedClasspathEntry(this);
 	}
-	
+
 	/**
 	 * This function computes the URL of the index location for this classpath entry. It returns null if the URL is
 	 * invalid.
@@ -1757,6 +1762,18 @@
 	public URL getLibraryIndexLocation() {
 		switch(getEntryKind()) {
 			case IClasspathEntry.CPE_LIBRARY :
+				if (SHARED_INDEX_LOCATION != null) {
+					try {
+						String pathString = getPath().toPortableString();
+						CRC32 checksumCalculator = new CRC32();
+						checksumCalculator.update(pathString.getBytes());
+						String fileName = Long.toString(checksumCalculator.getValue()) + ".index"; //$NON-NLS-1$
+						return new URL("file", null, Paths.get(SHARED_INDEX_LOCATION, fileName).toString()); //$NON-NLS-1$
+					} catch (MalformedURLException e1) {
+						Util.log(e1); // should not happen if protocol known (eg. 'file')
+					}
+				}
+				break;
 			case IClasspathEntry.CPE_VARIABLE :
 				break;
 			default :
@@ -1948,7 +1965,7 @@
 			IPath customOutput;
 			if ((customOutput = resolvedEntry.getOutputLocation()) != null) {
 				if(mainOutputLocations.contains(customOutput)) {
-					return new JavaModelStatus(IJavaModelStatusConstants.TEST_OUTPUT_FOLDER_MUST_BE_SEPARATE_FROM_MAIN_OUTPUT_FOLDERS, javaProject, resolvedEntry.getPath());				
+					return new JavaModelStatus(IJavaModelStatusConstants.TEST_OUTPUT_FOLDER_MUST_BE_SEPARATE_FROM_MAIN_OUTPUT_FOLDERS, javaProject, resolvedEntry.getPath());
 				}
 			} else {
 				if(sourceEntryCount > testSourcesFolders.size()) {
@@ -2081,18 +2098,18 @@
 							// Bug 287164 : Report errors of overlapping output locations only if the user sets the corresponding preference.
 							// The check is required for backward compatibility with bug-fix 36465.
 							String option = javaProject.getOption(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, true);
-							if (otherEntry.getPath().equals(output) 
+							if (otherEntry.getPath().equals(output)
 									&& !JavaCore.IGNORE.equals(option)) {
 								boolean opStartsWithProject = projectName.equals(otherEntry.getPath().segment(0));
 								String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() : otherEntry.getPath().makeRelative().toString();
 								if (JavaCore.ERROR.equals(option)) {
-									return new JavaModelStatus(IStatus.ERROR, IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, 
+									return new JavaModelStatus(IStatus.ERROR, IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE,
 											Messages.bind(Messages.classpath_cannotUseDistinctSourceFolderAsOutput, new String[] {
 											entryPathMsg, otherPathMsg, projectName }));
 								}
 								if (cachedStatus == null) {
 									// Note that the isOK() is being overridden to return true. This is an exceptional scenario
-									cachedStatus = new JavaModelStatus(IStatus.OK, IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, 
+									cachedStatus = new JavaModelStatus(IStatus.OK, IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE,
 										Messages.bind(Messages.classpath_cannotUseDistinctSourceFolderAsOutput, new String[] {
 										entryPathMsg, otherPathMsg, projectName })){
 										@Override
@@ -2149,9 +2166,9 @@
 				}
 			}
 		}
-		
+
 		// NOTE: The above code that checks for IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, can be configured to return
-		// a WARNING status and hence should be at the end of this validation method. Any other code that might return a more severe ERROR should be 
+		// a WARNING status and hence should be at the end of this validation method. Any other code that might return a more severe ERROR should be
 		// inserted before the mentioned code.
 		if (cachedStatus != null) return cachedStatus;
 
@@ -2177,7 +2194,7 @@
 		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=171136 and https://bugs.eclipse.org/bugs/show_bug.cgi?id=300136
 		// Ignore class path errors from optional entries.
 		int statusCode = status.getCode();
-		if ( (statusCode == IJavaModelStatusConstants.INVALID_CLASSPATH || 
+		if ( (statusCode == IJavaModelStatusConstants.INVALID_CLASSPATH ||
 				statusCode == IJavaModelStatusConstants.CP_CONTAINER_PATH_UNBOUND ||
 				statusCode == IJavaModelStatusConstants.CP_VARIABLE_PATH_UNBOUND ||
 				statusCode == IJavaModelStatusConstants.INVALID_PATH) &&
@@ -2185,7 +2202,7 @@
 			return JavaModelStatus.VERIFIED_OK;
 		return status;
 	}
-	
+
 	private static IJavaModelStatus validateClasspathEntry(IJavaProject project, IClasspathEntry entry, IClasspathContainer entryContainer, boolean checkSourceAttachment, boolean referredByContainer){
 
 		IPath path = entry.getPath();
@@ -2289,11 +2306,11 @@
 			// library entry check
 			case IClasspathEntry.CPE_LIBRARY :
 				path = ClasspathEntry.resolveDotDot(project.getProject().getLocation(), path);
-				
+
 				// do not validate entries from Class-Path: in manifest
 				// (these entries are considered optional since the user cannot act on them)
 				// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=252392
-				
+
 				String containerInfo = null;
 				if (entryContainer != null) {
 					if (entryContainer instanceof UserLibraryClasspathContainer) {
@@ -2324,11 +2341,11 @@
 							long prereqProjectTargetJDK = CompilerOptions.versionToJdkLevel(prereqProject.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true));
 							if (prereqProjectTargetJDK > projectTargetJDK) {
 								return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL,
-										project, path, 
+										project, path,
 										Messages.bind(Messages.classpath_incompatibleLibraryJDKLevel,
 												new String[] {
 													project.getElementName(),
-													CompilerOptions.versionFromJdkLevel(projectTargetJDK), 
+													CompilerOptions.versionFromJdkLevel(projectTargetJDK),
 													path.makeRelative().toString(),
 													CompilerOptions.versionFromJdkLevel(prereqProjectTargetJDK)}));
 							}
@@ -2390,7 +2407,7 @@
 			}
 			Object target = JavaModel.getTarget(path, true);
 			if (target == null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=248661
-				IPath workspaceLocation = workspaceRoot.getLocation(); 
+				IPath workspaceLocation = workspaceRoot.getLocation();
 				if (workspaceLocation.isPrefixOf(path)) {
 					target = JavaModel.getTarget(path.makeRelativeTo(workspaceLocation).makeAbsolute(), true);
 				}
@@ -2411,11 +2428,11 @@
 											CompilerOptions.versionFromJdkLevel(libraryJDK)}));
 					} else {
 						return new JavaModelStatus(IJavaModelStatusConstants.INCOMPATIBLE_JDK_LEVEL,
-								project, path, 
+								project, path,
 								Messages.bind(Messages.classpath_incompatibleLibraryJDKLevel,
 										new String[] {
 											project.getElementName(),
-											CompilerOptions.versionFromJdkLevel(projectTargetJDK), 
+											CompilerOptions.versionFromJdkLevel(projectTargetJDK),
 											path.makeRelative().toString(),
 											CompilerOptions.versionFromJdkLevel(libraryJDK)}));
 					}
@@ -2440,7 +2457,7 @@
 						// https://bugs.eclipse.org/bugs/show_bug.cgi?id=229042
 						// Validate the contents of the archive
 						IJavaModelStatus status = validateLibraryContents(path, project, entryPathMsg);
-						if (status != JavaModelStatus.VERIFIED_OK) 
+						if (status != JavaModelStatus.VERIFIED_OK)
 							return status;
 						break;
 					case IResource.FOLDER :	// internal binary folder
@@ -2476,7 +2493,7 @@
 					// Validate the contents of the archive
 					if(file.isFile()) {
 						IJavaModelStatus status = validateLibraryContents(path, project, entryPathMsg);
-						if (status != JavaModelStatus.VERIFIED_OK) 
+						if (status != JavaModelStatus.VERIFIED_OK)
 							return status;
 					}
 				}
@@ -2486,12 +2503,12 @@
 					if (container != null) {
 						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibraryInContainer, new String[] {path.toOSString(), container}));
 					} else {
-						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {path.toOSString(), project.getElementName()}));	
+						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {path.toOSString(), project.getElementName()}));
 					}
 				} else {
-					if (entryPathMsg == null) 
+					if (entryPathMsg == null)
 						entryPathMsg = 	project.getElementName().equals(path.segment(0)) ? path.removeFirstSegments(1).makeRelative().toString() : path.toString();
-					if (container!= null) {	
+					if (container!= null) {
 						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibraryInContainer, new String[] {entryPathMsg, container}));
 					} else {
 						return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_unboundLibrary, new String[] {entryPathMsg, project.getElementName()}));
@@ -2499,7 +2516,7 @@
 				}
 			}
 		} else {
-			if (entryPathMsg == null) 
+			if (entryPathMsg == null)
 				entryPathMsg = 	project.getElementName().equals(path.segment(0)) ? path.removeFirstSegments(1).makeRelative().toString() : path.toString();
 				if (container != null) {
 					return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_illegalLibraryPathInContainer, new String[] {entryPathMsg, container}));
@@ -2523,4 +2540,15 @@
 		}
 		return JavaModelStatus.VERIFIED_OK;
 	}
+
+	/*
+	 * For testing shared index location in JavaIndexTests only
+	 */
+	public static void setSharedIndexLocation(String value, Class<?> clazz) throws IllegalArgumentException{
+		if (clazz != null && "org.eclipse.jdt.core.tests.model.JavaIndexTests".equals(clazz.getName())) { //$NON-NLS-1$
+			SHARED_INDEX_LOCATION = value;
+		} else {
+			throw new IllegalArgumentException("Cannot set index location for specified test class"); //$NON-NLS-1$
+		}
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java
index 14a914f..ae7b047 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java
@@ -64,9 +64,9 @@
 		if (!status.isOK())
 			this.project.createClasspathProblemMarker(status);
 
-		// update overlapping output problem markers 
+		// update overlapping output problem markers
 		this.project.flushClasspathProblemMarkers(false/*cycle*/, false/*format*/, true/*overlapping*/);
-		
+
 		// update resolved classpath problems
 		this.project.flushClasspathProblemMarkers(false/*cycle*/, false/*format*/, false/*overlapping*/);
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
index 4c6e552..e30ae7a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java
@@ -1179,7 +1179,7 @@
 			? this.owner.createBuffer(this)
 			: BufferManager.createBuffer(this);
 	if (buffer == null) return null;
-	
+
 	ICompilationUnit original = null;
 	boolean mustSetToOriginalContent = false;
 	if (isWorkingCopy) {
@@ -1214,12 +1214,12 @@
 					buffer.setContents(Util.getResourceContentsAsCharArray(file));
 				}
 			}
-	
+
 			// add buffer to buffer cache
 			// note this may cause existing buffers to be removed from the buffer cache, but only primary compilation unit's buffer
 			// can be closed, thus no call to a client's IBuffer#close() can be done in this synchronized block.
 			bufManager.addBuffer(buffer);
-	
+
 			// listen to buffer changes
 			buffer.addBufferChangedListener(this);
 		}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java
index 6c8b15c..c2b6ec8 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitElementInfo.java
@@ -17,7 +17,7 @@
 import org.eclipse.jdt.core.SourceRange;
 
 public class CompilationUnitElementInfo extends OpenableElementInfo {
-	
+
 	/**
 	 * Count that will be used by SourceTypeConverter to decide whether or not to diet parse.
 	 */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java
index 753ff18..5a5243f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -106,15 +106,15 @@
 
 		CompilationResult result =
 			new CompilationResult(sourceTypes[0].getFileName(), 1, 1, this.options.maxProblemsPerUnit);
-		
+
 		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=305259, build the compilation unit in its own sand box.
 		final long savedComplianceLevel = this.options.complianceLevel;
 		final long savedSourceLevel = this.options.sourceLevel;
-		
+
 		LookupEnvironment environment = packageBinding.environment;
 		if (environment == null)
 			environment = this.lookupEnvironment;
-		
+
 		try {
 			IJavaProject project = ((SourceTypeElementInfo) sourceTypes[0]).getHandle().getJavaProject();
 			this.options.complianceLevel = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_COMPLIANCE, true));
@@ -152,14 +152,14 @@
 		}
 		CompilationResult result =
 				new CompilationResult(TypeConstants.MODULE_INFO_FILE_NAME, 1, 1, this.options.maxProblemsPerUnit);
-			
+
 		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=305259, build the compilation unit in its own sand box.
 		final long savedComplianceLevel = this.options.complianceLevel;
 		final long savedSourceLevel = this.options.sourceLevel;
-		
+
 		if (environment == null)
 			environment = this.lookupEnvironment;
-		
+
 		try {
 			IJavaProject project = handle.getJavaProject();
 			this.options.complianceLevel = CompilerOptions.versionToJdkLevel(project.getOption(JavaCore.COMPILER_COMPLIANCE, true));
@@ -232,7 +232,7 @@
 	}
 
 	/*
-	 * Can return null if the process was aborted or canceled 
+	 * Can return null if the process was aborted or canceled
 	 */
 	public static CompilationUnitDeclaration process(
 			CompilationUnit unitElement,
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java
index 1e1b978..fb5570b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitStructureRequestor.java
@@ -55,7 +55,7 @@
  */
 @SuppressWarnings({ "rawtypes", "unchecked" })
 public class CompilationUnitStructureRequestor extends ReferenceInfoAdapter implements ISourceElementRequestor {
-	
+
 	/**
 	 * The handle to the compilation unit being parsed
 	 */
@@ -375,7 +375,7 @@
 		Assert.isTrue(false); // Should not happen
 	}
 	resolveDuplicates(handle);
-	
+
 	addToChildren(parentInfo, handle);
 
 	this.infoStack.push(new int[] {declarationSourceStart, modifiers});
@@ -412,7 +412,7 @@
 
 	this.infoStack.push(methodInfo);
 	this.handleStack.push(handle);
-	
+
 	addToChildren(parentInfo, handle);
 	parentInfo.childrenCategories.put(handle, methodInfo.categories);
 }
@@ -479,7 +479,7 @@
 		localVarInfo.setSourceRangeEnd(argument.declarationSourceStart);
 		localVarInfo.setNameSourceStart(argument.sourceStart);
 		localVarInfo.setNameSourceEnd(argument.sourceEnd);
-		
+
 		String paramTypeSig = JavaModelManager.getJavaModelManager().intern(Signature.createTypeSignature(methodInfo.parameterTypes[i], false));
 		result[i] = new LocalVariable(
 				methodHandle,
@@ -490,7 +490,7 @@
 				argument.sourceEnd,
 				paramTypeSig,
 				argument.annotations,
-				argument.modifiers, 
+				argument.modifiers,
 				true);
 		this.newElements.put(result[i], localVarInfo);
 		this.infoStack.push(localVarInfo);
@@ -513,7 +513,7 @@
 	Object parentInfo = this.infoStack.peek();
 	JavaElement parentHandle= (JavaElement) this.handleStack.peek();
 	JavaElement handle = createModuleHandle(parentHandle, info);
-	
+
 	this.infoStack.push(info);
 	this.handleStack.push(handle);
 
@@ -601,7 +601,7 @@
 			Map.Entry entry = (Map.Entry) iterator.next();
 			info.addCategories((IJavaElement) entry.getKey(), (char[][]) entry.getValue());
 		}
-		
+
 	}
 	if (typeInfo.typeAnnotated) {
 		this.unitInfo.annotationNumber = CompilationUnitElementInfo.ANNOTATION_THRESHOLD_FOR_DIET_PARSE;
@@ -691,7 +691,7 @@
 	info.setSourceRangeEnd(declarationSourceEnd);
 	this.handleStack.pop();
 	this.infoStack.pop();
-	
+
 	// remember initializer source if field is a constant
 	if (initializationStart != -1) {
 		int flags = info.flags;
@@ -719,14 +719,14 @@
 	JavaElement handle = (JavaElement) this.handleStack.peek();
 	int[] initializerInfo = (int[]) this.infoStack.peek();
 	IJavaElement[] elements = getChildren(initializerInfo);
-	
+
 	InitializerElementInfo info = elements.length == 0 ? new InitializerElementInfo() : new InitializerWithChildrenInfo(elements);
 	info.setSourceRangeStart(initializerInfo[0]);
 	info.setFlags(initializerInfo[1]);
 	info.setSourceRangeEnd(declarationEnd);
 
 	this.newElements.put(handle, info);
-	
+
 	this.handleStack.pop();
 	this.infoStack.pop();
 }
@@ -737,10 +737,10 @@
 public void exitMethod(int declarationEnd, Expression defaultValue) {
 	SourceMethod handle = (SourceMethod) this.handleStack.peek();
 	MethodInfo methodInfo = (MethodInfo) this.infoStack.peek();
-	
+
 	SourceMethodElementInfo info = createMethodInfo(methodInfo, handle);
 	info.setSourceRangeEnd(declarationEnd);
-	
+
 	// remember default value of annotation method
 	if (info.isAnnotationMethod() && defaultValue != null) {
 		SourceAnnotationMethodInfo annotationMethodInfo = (SourceAnnotationMethodInfo) info;
@@ -751,7 +751,7 @@
 		defaultMemberValuePair.value = getMemberValue(defaultMemberValuePair, defaultValue);
 		annotationMethodInfo.defaultValue = defaultMemberValuePair;
 	}
-	
+
 	this.handleStack.pop();
 	this.infoStack.pop();
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java
index c0a44f1..5cea5b6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CopyResourceElementsOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -90,7 +90,7 @@
 		initializeASTParser();
 	}
 	private void initializeASTParser() {
-		this.parser = ASTParser.newParser(AST.JLS13);
+		this.parser = ASTParser.newParser(AST.JLS14);
 	}
 	/**
 	 * Returns the children of <code>source</code> which are affected by this operation.
@@ -279,7 +279,7 @@
 	 */
 	protected void prepareDeltas(IJavaElement sourceElement, IJavaElement destinationElement, boolean isMove, boolean overWriteCU) {
 		if (Util.isExcluded(sourceElement) || Util.isExcluded(destinationElement)) return;
-		
+
 		IJavaProject destProject = destinationElement.getJavaProject();
 		if (isMove) {
 			IJavaProject sourceProject = sourceElement.getJavaProject();
@@ -374,7 +374,7 @@
 			// register the correct change deltas
 			boolean contentChanged = this.force && destFile.exists();
 			prepareDeltas(source, destCU, isMove(), contentChanged);
-			
+
 			if (newCUName != null) {
 				//the main type has been renamed
 				String oldName = Util.getNameWithoutJavaLikeExtension(source.getElementName());
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalAnnotationTracker.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalAnnotationTracker.java
index 1723b42..bec2449 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalAnnotationTracker.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalAnnotationTracker.java
@@ -48,9 +48,9 @@
 	 */
 	static class DirectoryNode {
 
-		DirectoryNode parent;		
+		DirectoryNode parent;
 		IPath path;
-		
+
 		/** Key is a full workspace path. */
 		Map<IPath,DirectoryNode> children;
 		/**
@@ -59,7 +59,7 @@
 		 */
 		Map<IPath, ClassFile> classFiles;
 		IPackageFragmentRoot modelRoot; // TODO: for handling zipped annotations
-		
+
 		public DirectoryNode(DirectoryNode parent, IPath path) {
 			this.parent = parent;
 			this.path = path;
@@ -123,13 +123,13 @@
 
 	private static ExternalAnnotationTracker singleton;
 	private ExternalAnnotationTracker() { }
-	
+
 	/** Start listening. */
 	static void start(IWorkspace workspace) {
 		singleton = new ExternalAnnotationTracker();
 		workspace.addResourceChangeListener(singleton);
 	}
-	
+
 	/** Stop listening & clean up. */
 	static void shutdown(IWorkspace workspace) {
 		if (singleton != null) {
@@ -146,7 +146,7 @@
 	 * @param relativeAnnotationPath path corresponding to the qualified name of the main type of the class file.
 	 *  The path is relative to 'annotationBase'.
 	 *  When appending the file extension for annotation files it points to the annotation file
-	 *  that would correspond to the given class file. The annotation file may or may not yet exist. 
+	 *  that would correspond to the given class file. The annotation file may or may not yet exist.
 	 * @param classFile the ClassFile to register.
 	 */
 	public static void registerClassFile(IPath annotationBase, IPath relativeAnnotationPath, ClassFile classFile) {
@@ -239,6 +239,6 @@
 			} else {
 				traverseForClassFiles(classFiles, delta, baseDepth);
 			}
-		}		
+		}
 	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INameEnvironmentWithProgress.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INameEnvironmentWithProgress.java
index fa03c70..b758f65 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INameEnvironmentWithProgress.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/INameEnvironmentWithProgress.java
@@ -21,18 +21,18 @@
  * can use to look up types, compilation units, and packages in the
  * current environment.  The name environment is passed to the compiler
  * on creation.
- * 
+ *
  * This name environment can be canceled using the monitor passed as an argument to
  * {@link #setMonitor(IProgressMonitor)}.
- * 
+ *
  * @since 3.6
  */
 public interface INameEnvironmentWithProgress extends INameEnvironmentExtension {
 
 	/**
 	 * Set the monitor for the given name environment. In order to be able to cancel this name environment calls,
-	 * a non-null monitor should be given. 
-	 * 
+	 * a non-null monitor should be given.
+	 *
 	 * @param monitor the given monitor
 	 */
 	void setMonitor(IProgressMonitor monitor);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainerInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainerInfo.java
index 86246b1..fd57b36 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainerInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ImportContainerInfo.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerWithChildrenInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerWithChildrenInfo.java
index 925783d..e168e50 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerWithChildrenInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InitializerWithChildrenInfo.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -18,7 +18,7 @@
 public class InitializerWithChildrenInfo extends InitializerElementInfo {
 
 	protected IJavaElement[] children;
-	
+
 	public InitializerWithChildrenInfo(IJavaElement[] children) {
 		this.children = children;
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InternalNamingConventions.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InternalNamingConventions.java
index 36b3f1d..05b707d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InternalNamingConventions.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/InternalNamingConventions.java
@@ -93,11 +93,11 @@
 
 	private static char[][] computeNonBaseTypeNames(char[] sourceName, boolean isConstantField, boolean onlyLongest){
 		int length = sourceName.length;
-		
+
 		if (length == 0) {
 			return CharOperation.NO_CHAR_CHAR;
 		}
-		
+
 		if (length == 1) {
 			if (isConstantField) {
 				return generateConstantName(new char[][]{CharOperation.toLowerCase(sourceName)}, 0, onlyLongest);
@@ -105,31 +105,31 @@
 				return generateNonConstantName(new char[][]{CharOperation.toLowerCase(sourceName)}, 0, onlyLongest);
 			}
 		}
-		
+
 		char[][] nameParts = new char[length][];
 		int namePartsPtr = -1;
-		
+
 		int endIndex = length;
 		char c = sourceName[length - 1];
-		
+
 		final int IS_LOWER_CASE = 1;
 		final int IS_UPPER_CASE = 2;
 		final int IS_UNDERSCORE = 3;
 		final int IS_OTHER = 4;
-		
+
 		int previousCharKind =
 			ScannerHelper.isLowerCase(c) ? IS_LOWER_CASE :
 				ScannerHelper.isUpperCase(c) ? IS_UPPER_CASE :
 					c == '_' ? IS_UNDERSCORE : IS_OTHER;
-		
+
 		for(int i = length - 1 ; i >= 0 ; i--){
 			c = sourceName[i];
-			
+
 			int charKind =
 				ScannerHelper.isLowerCase(c) ? IS_LOWER_CASE :
 					ScannerHelper.isUpperCase(c) ? IS_UPPER_CASE :
 						c == '_' ? IS_UNDERSCORE : IS_OTHER;
-			
+
 			switch (charKind) {
 				case IS_LOWER_CASE:
 					if (previousCharKind == IS_UPPER_CASE) {
@@ -157,7 +157,7 @@
 					switch (previousCharKind) {
 						case IS_UNDERSCORE:
 							// https://bugs.eclipse.org/bugs/show_bug.cgi?id=283539
-							// Process consecutive underscores only for constant types 
+							// Process consecutive underscores only for constant types
 							if (isConstantField) {
 								if (i > 0) {
 									char pc = sourceName[i - 1];
@@ -198,15 +198,15 @@
 		if (namePartsPtr == -1) {
 			return new char[][] { sourceName };
 		}
-		
+
 		if (isConstantField) {
 			return generateConstantName(nameParts, namePartsPtr, onlyLongest);
 		} else {
 			return generateNonConstantName(nameParts, namePartsPtr, onlyLongest);
 		}
 	}
-	
-	
+
+
 
 	private static char[] excludeNames(
 		char[] suffixName,
@@ -229,7 +229,7 @@
 		}
 		return suffixName;
 	}
-	
+
 	private static char[][] generateNonConstantName(char[][] nameParts, int namePartsPtr, boolean onlyLongest) {
 		char[][] names;
 		if (onlyLongest) {
@@ -237,28 +237,28 @@
 		} else {
 			names = new char[namePartsPtr + 1][];
 		}
-		
+
 		char[] namePart = nameParts[0];
-		
+
 		char[] name = CharOperation.toLowerCase(namePart);
-		
+
 		if (!onlyLongest) {
 			names[namePartsPtr] = name;
 		}
-		
+
 		char[] nameSuffix = namePart;
-		
+
 		for (int i = 1; i <= namePartsPtr; i++) {
 			namePart = nameParts[i];
-			
+
 			name = CharOperation.concat(CharOperation.toLowerCase(namePart), nameSuffix);
 			// https://bugs.eclipse.org/bugs/show_bug.cgi?id=283539
 			// Only the first word is converted to lower case and the rest of them are not changed for non-constants
-			
+
 			if (!onlyLongest) {
 				names[namePartsPtr - i] = name;
 			}
-			
+
 			nameSuffix = CharOperation.concat(namePart, nameSuffix);
 		}
 		if (onlyLongest) {
@@ -274,17 +274,17 @@
 		} else {
 			names = new char[namePartsPtr + 1][];
 		}
-		
+
 		char[] namePart = CharOperation.toUpperCase(nameParts[0]);
 		int namePartLength = namePart.length;
 		System.arraycopy(namePart, 0, namePart, 0, namePartLength);
-		
+
 		char[] name = namePart;
-		
+
 		if (!onlyLongest) {
 			names[namePartsPtr] = name;
 		}
-		
+
 		for (int i = 1; i <= namePartsPtr; i++) {
 			namePart = CharOperation.toUpperCase(nameParts[i]);
 			namePartLength = namePart.length;
@@ -293,7 +293,7 @@
 			} else {
 				name = CharOperation.concat(namePart, name);
 			}
-			
+
 			if (!onlyLongest) {
 				names[namePartsPtr - i] = name;
 			}
@@ -303,20 +303,20 @@
 		}
 		return names;
 	}
-	
+
 	public static char[] getBaseName(
 			int variableKind,
 			IJavaProject javaProject,
 			char[] name,
 			boolean updateFirstCharacter) {
-		
+
 		AssistOptions assistOptions;
 		if (javaProject != null) {
 			assistOptions = new AssistOptions(javaProject.getOptions(true));
 		} else {
 			assistOptions = new AssistOptions(JavaCore.getOptions());
 		}
-		
+
 		char[][] prefixes = null;
 		char[][] suffixes = null;
 		switch (variableKind) {
@@ -341,20 +341,20 @@
 				suffixes = assistOptions.argumentSuffixes;
 				break;
 		}
-		
-		
+
+
 		return getBaseName(name, prefixes, suffixes, variableKind == VK_STATIC_FINAL_FIELD, updateFirstCharacter);
 	}
 
 	private static char[] getBaseName(char[] name, char[][] prefixes, char[][] suffixes, boolean isConstant, boolean updateFirstCharacter) {
 		char[] nameWithoutPrefixAndSiffix = removeVariablePrefixAndSuffix(name, prefixes, suffixes, updateFirstCharacter);
-		
+
 		char[] baseName;
 		if (isConstant) {
 			int length = nameWithoutPrefixAndSiffix.length;
 			baseName = new char[length];
 			int baseNamePtr = -1;
-			
+
 			boolean previousIsUnderscore = false;
 			for (int i = 0; i < length; i++) {
 				char c = nameWithoutPrefixAndSiffix[i];
@@ -373,10 +373,10 @@
 		} else {
 			baseName = nameWithoutPrefixAndSiffix;
 		}
-		
+
 		return baseName;
 	}
-	
+
 	public static char[] removeVariablePrefixAndSuffix(
 			int variableKind,
 			IJavaProject javaProject,
@@ -387,7 +387,7 @@
 		} else {
 			assistOptions = new AssistOptions(JavaCore.getOptions());
 		}
-		
+
 		char[][] prefixes = null;
 		char[][] suffixes = null;
 		switch (variableKind) {
@@ -412,10 +412,10 @@
 				suffixes = assistOptions.argumentSuffixes;
 				break;
 		}
-		
+
 		return InternalNamingConventions.removeVariablePrefixAndSuffix(name, prefixes, suffixes, true);
 	}
-	
+
 	private static char[] removeVariablePrefixAndSuffix(char[] name, char[][] prefixes, char[][] suffixes, boolean updateFirstCharacter) {
 		// remove longer prefix
 		char[] withoutPrefixName = name;
@@ -528,13 +528,13 @@
 
 		return withoutPrefixName;
 	}
-	
+
 	public static final int VK_STATIC_FIELD = 1;
 	public static final int VK_INSTANCE_FIELD = 2;
 	public static final int VK_STATIC_FINAL_FIELD = 3;
 	public static final int VK_PARAMETER = 4;
 	public static final int VK_LOCAL = 5;
-	
+
 	public static final int BK_SIMPLE_NAME = 1;
 	public static final int BK_SIMPLE_TYPE_NAME = 2;
 
@@ -548,10 +548,10 @@
 			char[][] excluded,
 			boolean evaluateDefault,
 			INamingRequestor requestor) {
-		
+
 		if(baseName == null || baseName.length == 0)
 			return;
-		
+
 		Map<String, String> options;
 		if (javaProject != null) {
 			options = javaProject.getOptions(true);
@@ -560,9 +560,9 @@
 		}
 		CompilerOptions compilerOptions = new CompilerOptions(options);
 		AssistOptions assistOptions = new AssistOptions(options);
-		
+
 		boolean isConstantField = false;
-		
+
 		char[][] prefixes = null;
 		char[][] suffixes = null;
 		switch (variableKind) {
@@ -588,7 +588,7 @@
 				suffixes = assistOptions.argumentSuffixes;
 				break;
 		}
-		
+
 		if(prefixes == null || prefixes.length == 0) {
 			prefixes = new char[1][0];
 		} else {
@@ -604,7 +604,7 @@
 			System.arraycopy(suffixes, 0, suffixes = new char[length+1][], 0, length);
 			suffixes[length] = CharOperation.NO_CHAR;
 		}
-		
+
 		if(internalPrefix == null) {
 			internalPrefix = CharOperation.NO_CHAR;
 		} else {
@@ -612,11 +612,11 @@
 		}
 
 		char[][] tempNames = null;
-		
+
 		Scanner nameScanner = getNameScanner(compilerOptions);
 		if (baseNameKind == BK_SIMPLE_TYPE_NAME) {
 			boolean isBaseType = false;
-			
+
 			try{
 				nameScanner.setSource(baseName);
 				switch (nameScanner.getNextToken()) {
@@ -637,7 +637,7 @@
 			if (isBaseType) {
 				// compute variable name from base type
 				if (internalPrefix.length > 0) return;
-	
+
 				tempNames = computeBaseTypeNames(baseName, isConstantField, excluded);
 			} else {
 				// compute variable name for non base type
@@ -652,11 +652,11 @@
 
 		for (int i = 0; i < tempNames.length; i++) {
 			char[] tempName = tempNames[i];
-			
+
 			// add English plural form is necessary
 			if(dim > 0) {
 				int length = tempName.length;
-				
+
 				if (isConstantField) {
 					if (tempName[length-1] == 'S'){
 						if(tempName.length > 1 && tempName[length-2] == 'S') {
@@ -725,13 +725,13 @@
 					}
 				}
 			}
-			
+
 			char[] unprefixedName = tempName;
-			
+
 			int matchingIndex = -1;
 			if (!isConstantField) {
 				unprefixedName[0] = ScannerHelper.toUpperCase(unprefixedName[0]);
-				
+
 				done : for (int j = 0; j <= internalPrefix.length; j++) {
 					if(j == internalPrefix.length ||
 							CharOperation.prefixEquals(CharOperation.subarray(internalPrefix, j, -1), unprefixedName, j != 0 /*do not check case when there is no prefix*/)) {
@@ -749,7 +749,7 @@
 							matchingIndex = j;
 							break done;
 						}
-						
+
 					}
 				}
 			}
@@ -765,7 +765,7 @@
 						tempName = CharOperation.concat(CharOperation.subarray(CharOperation.toUpperCase(internalPrefix), 0, matchingIndex), unprefixedName);
 					}
 				}
-				
+
 				for (int k = 0; k < prefixes.length; k++) {
 					if (!isConstantField) {
 						if(prefixes[k].length > 0
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JModPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JModPackageFragmentRoot.java
index 6370b87..b4a753a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JModPackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JModPackageFragmentRoot.java
@@ -24,7 +24,7 @@
  *
  * <p>NOTE: The only visible entries from a Jmod package fragment root
  * are .class files. The sub folder "classes" where the .class files are nested under
- * is hidden from clients. THe package fragments appear to be directly under the 
+ * is hidden from clients. THe package fragments appear to be directly under the
  * package fragment roots.
  * <p>NOTE: A JMod package fragment root may or may not have an associated resource.
  *
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
index 16561c9..1d0928e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRoot.java
@@ -14,6 +14,7 @@
 package org.eclipse.jdt.internal.core;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -91,7 +92,7 @@
 		super(resource, project);
 		this.jarPath = externalJarPath;
 		if (attributes == null) {
-			// attributes could either be 
+			// attributes could either be
 			// (1) provided by the caller (particularly when creating from memento),
 			// (2) retrieved from the corresponding classpath entry (if a resolved classpath is available).
 			// These two cases should cover all normal scenarios, else extraAttributes will be null.
@@ -129,7 +130,7 @@
 			if (JavaIndex.isEnabled()) {
 				JavaIndex index = JavaIndex.getIndex();
 				try (IReader reader = index.getNd().acquireReadLock()) {
-					IPath resourcePath = JavaIndex.getLocationForElement(this); 
+					IPath resourcePath = JavaIndex.getLocationForElement(this);
 					if (!resourcePath.isEmpty()) {
 						NdResourceFile resourceFile = index.getResourceFile(resourcePath.toString().toCharArray());
 						if (index.isUpToDate(resourceFile)) {
@@ -141,9 +142,9 @@
 								String filename = next.getFileName().getString();
 								initRawPackageInfo(rawPackageInfo, filename, filename.endsWith("/"), compliance); //$NON-NLS-1$
 							}
-	
+
 							// Locate all the classfile entries
-							for (NdType type : resourceFile.getTypes()) {	
+							for (NdType type : resourceFile.getTypes()) {
 								String path = new String(type.getTypeId().getBinaryName()) + ".class"; //$NON-NLS-1$
 								initRawPackageInfo(rawPackageInfo, path, false, compliance);
 							}
@@ -177,7 +178,7 @@
 							}
 						}
 					}
-					
+
 					String[] supportedVersions = versions.toArray(new String[versions.size()]);
 					if (supportedVersions.length > 0) {
 						this.multiVersion = true;
@@ -479,7 +480,7 @@
 	public URL getIndexPath() {
 		try {
 			IClasspathEntry entry = ((JavaProject) getParent()).getClasspathEntryFor(getPath());
-			if (entry != null) return ((ClasspathEntry)entry).getLibraryIndexLocation();	
+			if (entry != null) return ((ClasspathEntry)entry).getLibraryIndexLocation();
 		} catch (JavaModelException e) {
 			// ignore exception
 		}
@@ -492,8 +493,11 @@
 		try {
 			jar = getJar();
 			ZipEntry mfEntry = jar.getEntry(TypeConstants.META_INF_MANIFEST_MF);
-			if (mfEntry != null)
-				return new Manifest(jar.getInputStream(mfEntry));
+			if (mfEntry != null) {
+				try (InputStream is = jar.getInputStream(mfEntry)) {
+					return new Manifest(is);
+				}
+			}
 		} catch (CoreException | IOException e) {
 			// must do without manifest
 		} finally {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java
index 1de10d2..fd4e91c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JarPackageFragmentRootInfo.java
@@ -24,5 +24,5 @@
 	// a map from package name (String[]) to a size-2 array of Array<String>, the first element being the .class file names, and the second element being the non-Java resource names
 	HashtableOfArrayToObject rawPackageInfo;
 	Map<String, String> overriddenClasses;
-	
+
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
index ecbed84..65cdf03 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -112,6 +112,7 @@
 		defaultOptionsMap.put(JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, JavaCore.DISABLED);
 		defaultOptionsMap.put(JavaCore.CODEASSIST_CAMEL_CASE_MATCH, JavaCore.ENABLED);
 		defaultOptionsMap.put(JavaCore.CODEASSIST_SUBSTRING_MATCH, JavaCore.ENABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_SUBWORD_MATCH, JavaCore.ENABLED);
 		defaultOptionsMap.put(JavaCore.CODEASSIST_SUGGEST_STATIC_IMPORTS, JavaCore.ENABLED);
 		defaultOptionsMap.put(ChunkCache.CHUNK_CACHE_SIZE_MB, Double.toString(ChunkCache.CHUNK_CACHE_SIZE_MB_DEFAULT));
 		defaultOptionsMap.put(ChunkCache.CHUNK_CACHE_SIZE_PERCENT,
@@ -134,9 +135,9 @@
 	}
 
 	/**
-	 * Note: For deprecated formatter options, you may also add migration to their replacement options in 
+	 * Note: For deprecated formatter options, you may also add migration to their replacement options in
 	 * {@link org.eclipse.jdt.internal.formatter.DefaultCodeFormatterOptions#setDeprecatedOptions}.
-	 * 
+	 *
 	 * @deprecated As using deprecated options
 	 */
 	private void initializeDeprecatedOptions() {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
index 2650b22..0b53db6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElement.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -101,23 +101,23 @@
 	public static final char JEM_LAMBDA_METHOD = '&';
 	public static final char JEM_STRING = '"';
 	public static final char JEM_MODULE = '`';
-	
+
 	/**
 	 * Before ')', '&' and '"' became the newest additions as delimiters, the former two
-	 * were allowed as part of element attributes and possibly stored. Trying to recreate 
-	 * elements from such memento would cause undesirable results. Consider the following 
+	 * were allowed as part of element attributes and possibly stored. Trying to recreate
+	 * elements from such memento would cause undesirable results. Consider the following
 	 * valid project name: (abc)
 	 * If we were to use ')' alone as the delimiter and decode the above name, the memento
-	 * would be wrongly identified to contain a lambda expression.  
+	 * would be wrongly identified to contain a lambda expression.
 	 *
-	 * In order to differentiate delimiters from characters that are part of element attributes, 
-	 * the following escape character is being introduced and all the new delimiters must 
+	 * In order to differentiate delimiters from characters that are part of element attributes,
+	 * the following escape character is being introduced and all the new delimiters must
 	 * be escaped with this. So, a lambda expression would be written as: "=)..."
-	 * 
+	 *
 	 * @see JavaElement#appendEscapedDelimiter(StringBuffer, char)
 	 */
 	public static final char JEM_DELIMITER_ESCAPE = JEM_JAVAPROJECT;
-	
+
 
 	/**
 	 * This element's parent, or <code>null</code> if this
@@ -128,7 +128,7 @@
 	protected static final String[] NO_STRINGS = new String[0];
 	protected static final JavaElement[] NO_ELEMENTS = new JavaElement[0];
 	protected static final Object NO_INFO = new Object();
-	
+
 	private static Set<String> invalidURLs = null;
 	private static Set<String> validURLs = null;
 
@@ -606,11 +606,13 @@
 			}
 			if (info == null) { // a source ref element could not be opened
 				// close the buffer that was opened for the openable parent
-			    // close only the openable's buffer (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=62854)
-			    Openable openable = (Openable) getOpenable();
-			    if (newElements.containsKey(openable)) {
-			        openable.closeBuffer();
-			    }
+				Openable openable = (Openable) getOpenable();
+				// Bug 62854: close only the openable's buffer
+				if (newElements.containsKey(openable)
+						// Bug 526116: do not close current working copy, which can impact save actions
+						&& !(openable instanceof ICompilationUnit && ((ICompilationUnit) openable).isWorkingCopy())) {
+					openable.closeBuffer();
+				}
 				throw newNotPresentException();
 			}
 			if (!hadTemporaryCache) {
@@ -749,7 +751,7 @@
 			catch(JavaModelException jme) {
 				// Proceed with raw classpath
 			}
-			
+
 			entry= root.getRawClasspathEntry();
 			switch (entry.getEntryKind()) {
 				case IClasspathEntry.CPE_LIBRARY:
@@ -757,7 +759,7 @@
 					return getLibraryJavadocLocation(entry);
 				default:
 					return null;
-			}			
+			}
 		}
 		return null;
 	}
@@ -815,15 +817,15 @@
 		}
 		return false;
 	}
-	
+
 	/*
-	 * This method caches a list of good and bad Javadoc locations in the current eclipse session. 
+	 * This method caches a list of good and bad Javadoc locations in the current eclipse session.
 	 */
 	protected void validateAndCache(URL baseLoc, FileNotFoundException e) throws JavaModelException {
 		String url = baseLoc.toString();
 		if (validURLs != null && validURLs.contains(url)) return;
-		
-		if (invalidURLs != null && invalidURLs.contains(url)) 
+
+		if (invalidURLs != null && invalidURLs.contains(url))
 				throw new JavaModelException(e, IJavaModelStatusConstants.CANNOT_RETRIEVE_ATTACHED_JAVADOC);
 
 		InputStream input = null;
@@ -835,7 +837,7 @@
 			}
 			validURLs.add(url);
 		} catch (Exception e1) {
-			if (invalidURLs == null) { 
+			if (invalidURLs == null) {
 				invalidURLs = new HashSet<String>(1);
 			}
 			invalidURLs.add(url);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java
index e4af009..df24d77 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementDelta.java
@@ -74,12 +74,12 @@
 	 * Empty array of IJavaElementDelta
 	 */
 	static  IJavaElementDelta[] EMPTY_DELTA= new IJavaElementDelta[] {};
-	
+
 	/**
 	 * Child index is needed iff affectedChildren.length >= NEED_CHILD_INDEX
 	*/
 	static int NEED_CHILD_INDEX = 3;
-	
+
 	/**
 	 * On-demand index into affectedChildren
 	 */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java
index 00308e0..0fe7444 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementRequestor.java
@@ -153,7 +153,7 @@
 	if (this.modules == null) {
 		this.modules= new ArrayList();
 	}
-	this.modules.add(module);	
+	this.modules.add(module);
 }
 
 /**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java
index 723b503..b1024ce 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelCache.java
@@ -78,7 +78,7 @@
 	 * Cache of open children of openable Java Model Java elements
 	 */
 	protected Map<IJavaElement, Object> childrenCache;
-	
+
 	/**
 	 * Cache of access rules
 	 */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
index 5b727d3..6a3f3c9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -2491,6 +2491,7 @@
 		defaultOptionsMap.put(JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, JavaCore.DISABLED);
 		defaultOptionsMap.put(JavaCore.CODEASSIST_CAMEL_CASE_MATCH, JavaCore.ENABLED);
 		defaultOptionsMap.put(JavaCore.CODEASSIST_SUBSTRING_MATCH, JavaCore.ENABLED);
+		defaultOptionsMap.put(JavaCore.CODEASSIST_SUBWORD_MATCH, JavaCore.ENABLED);
 		defaultOptionsMap.put(JavaCore.CODEASSIST_SUGGEST_STATIC_IMPORTS, JavaCore.ENABLED);
 
 		// Time out for parameter names
@@ -5399,7 +5400,7 @@
 					| IResourceChangeEvent.PRE_DELETE
 					| IResourceChangeEvent.PRE_CLOSE
 					| IResourceChangeEvent.PRE_REFRESH);
-			
+
 			// New index is disabled, see bug 544898
 			// Indexer.getInstance().addListener(this.deltaState);
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java
index 93f49de..3d9139b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelStatus.java
@@ -381,7 +381,7 @@
 						return Messages.bind(Messages.status_cannot_retrieve_attached_javadoc, this.string, "");//$NON-NLS-1$
 					}
 					break;
-					
+
 				case CANNOT_RETRIEVE_ATTACHED_JAVADOC_TIMEOUT :
 					if (this.elements != null && this.elements.length == 1) {
 						if (this.string != null) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
index d91f251..d12f2cf 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
@@ -289,7 +289,7 @@
 			return false;
 		return true;
 	}
-	
+
 	private static boolean areClasspathsEqual(IClasspathEntry[] first, IClasspathEntry[] second) {
 		if (first != second){
 		    if (first == null) return false;
@@ -320,7 +320,7 @@
 		if (IS_CASE_SENSITIVE) {
 			return externalPath;
 		}
-		
+
 		// if not external path, return original path
 		IWorkspace workspace = ResourcesPlugin.getWorkspace();
 		if (workspace == null) return externalPath; // protection during shutdown (30487)
@@ -429,7 +429,7 @@
 						cycleString.append('}');
 						first = false;
 					}
-					
+
 					IMarker cycleMarker = project.getCycleMarker();
 					String circularCPOption = project.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true);
 					int circularCPSeverity = JavaCore.ERROR.equals(circularCPOption) ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING;
@@ -496,7 +496,7 @@
 			module = root.getModuleDescription();
 			if (module != null) {
 				if (current != null) {
-					throw new JavaModelException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, 
+					throw new JavaModelException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID,
 							Messages.bind(Messages.classpath_duplicateEntryPath, TypeConstants.MODULE_INFO_FILE_NAME_STRING, getElementName())));
 				}
 				current = module;
@@ -531,7 +531,7 @@
 	/**
 	 * Internal computation of an expanded classpath. It will eliminate duplicates, and produce copies
 	 * of exported or restricted classpath entries to avoid possible side-effects ever after.
-	 * @param excludeTestCode 
+	 * @param excludeTestCode
 	 */
 	private void computeExpandedClasspath(
 		ClasspathEntry referringEntry,
@@ -566,7 +566,7 @@
 							rootIDs.put(rootID, Boolean.FALSE);
 							for (int j = 0; j < accumulatedEntries.size(); j++) {
 								// it is unclear how oldEntry and combinedEntry could be merged.
-								// main code compilation should remain untouched as far as possible, 
+								// main code compilation should remain untouched as far as possible,
 								// so take all settings from oldEntry and just remove WITHOUT_TEST_CODE
 								ClasspathEntry oldEntry = accumulatedEntries.get(j);
 								if (oldEntry.rootID().equals(rootID)) {
@@ -817,7 +817,7 @@
 			boolean isPotentialRoot = !isJavaDotStart;	// always include non-java.*
 			if (!hasJavaDotSE)
 				isPotentialRoot |= isJavaDotStart;		// no java.se => add all java.*
-			
+
 			if (isPotentialRoot) {
 				IModule module = getModule.apply(mod);
 				if (module != null) {
@@ -860,7 +860,7 @@
 		Map<String, JrtPackageFragmentRoot> modNames2Roots = new HashMap<>();
 		Map<String, IModule> modules = new HashMap<>();
 		Set<IModule> resultModuleSet = new HashSet<>();
-		
+
 		public ModuleLookup(File jrtFile) {
 			this.jrtFile = jrtFile;
 		}
@@ -928,7 +928,7 @@
 		}
 	}
 
-	private void loadModulesInJimage(final IPath imagePath, final ObjectVector roots, final Map rootToResolvedEntries, 
+	private void loadModulesInJimage(final IPath imagePath, final ObjectVector roots, final Map rootToResolvedEntries,
 				final IClasspathEntry resolvedEntry, final IClasspathEntry referringEntry) {
 		try {
 			org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imagePath.toFile(),
@@ -947,7 +947,7 @@
 				public FileVisitResult visitModule(java.nio.file.Path path, String name) throws IOException {
 					JrtPackageFragmentRoot root = new JrtPackageFragmentRoot(imagePath, name, JavaProject.this, resolvedEntry.getExtraAttributes());
 					roots.add(root);
-					if (rootToResolvedEntries != null) 
+					if (rootToResolvedEntries != null)
 						rootToResolvedEntries.put(root, ((ClasspathEntry)resolvedEntry).combineWith((ClasspathEntry) referringEntry));
 					return FileVisitResult.SKIP_SUBTREE;
 				}
@@ -1258,8 +1258,8 @@
 	/**
 	 * Reads and decode an XML classpath string. Returns a two-dimensional array, where the number of elements in the row is fixed to 2.
 	 * The first element is an array of raw classpath entries and the second element is an array of referenced entries that may have been stored
-	 * by the client earlier. See {@link IJavaProject#getReferencedClasspathEntries()} for more details. 
-	 * 
+	 * by the client earlier. See {@link IJavaProject#getReferencedClasspathEntries()} for more details.
+	 *
 	 */
 	public IClasspathEntry[][] decodeClasspath(String xmlClasspath, Map unknownElements) throws IOException, ClasspathEntry.AssertionFailedException {
 
@@ -1300,7 +1300,7 @@
 		entries[0] = new IClasspathEntry[pathSize + (defaultOutput == null ? 0 : 1)];
 		paths.toArray(entries[0]);
 		if (defaultOutput != null) entries[0][pathSize] = defaultOutput; // ensure output is last item
-		
+
 		paths.clear();
 		list = cpElement.getElementsByTagName(ClasspathEntry.TAG_REFERENCED_ENTRY);
 		length = list.getLength();
@@ -1409,7 +1409,7 @@
 					((ClasspathEntry) referencedEntries[i]).elementEncode(xmlWriter, this.project.getFullPath(), indent, true, unknownElements, true);
 				}
 			}
-			
+
 			xmlWriter.endTag(ClasspathEntry.TAG_CLASSPATH, indent, true/*insert new line*/);
 			writer.flush();
 			writer.close();
@@ -2003,7 +2003,7 @@
 							token = memento.nextToken();
 							if (token != null) {
 								mod = token;
-							
+
 							}
 						}
 						continue;
@@ -2018,7 +2018,7 @@
 					rootPath += token;
 				}
 				IClasspathAttribute[] attributesArray = null;
-				if (!attributes.isEmpty()) 
+				if (!attributes.isEmpty())
 					attributesArray = attributes.toArray(new IClasspathAttribute[attributes.size()]);
 				JavaElement root = (mod == null) ?
 						(JavaElement)getPackageFragmentRoot(new Path(rootPath), attributesArray) :
@@ -2392,7 +2392,7 @@
 	public IClasspathEntry[] getReferencedClasspathEntries() throws JavaModelException {
 		return getPerProjectInfo().referencedEntries;
 	}
-	
+
 	/**
 	 * @see IJavaProject#getRequiredProjectNames()
 	 */
@@ -2572,7 +2572,7 @@
 	public int hashCode() {
 		return this.project.hashCode();
 	}
-	
+
 	private boolean hasUTF8BOM(byte[] bytes) {
 		if (bytes.length > IContentDescription.BOM_UTF_8.length) {
 			for (int i = 0, length = IContentDescription.BOM_UTF_8.length; i < length; i++) {
@@ -2675,7 +2675,7 @@
 			if (isOnClasspathEntry(elementPath, isFolderPath, isPackageFragmentRoot, resolvedClasspath[index]))
 				return true;
 		}
-		
+
 		return false;
 	}
 
@@ -2826,7 +2826,7 @@
 	 * and that should be used as a temporary info.
 	 */
 	public PerProjectInfo newTemporaryInfo() {
-		return 
+		return
 			new PerProjectInfo(this.project.getProject()) {
 				@Override
 				protected ClasspathChange addClasspathChange() {
@@ -2926,8 +2926,8 @@
 	 * Reads the classpath file entries of this project's .classpath file.
 	 * Returns a two-dimensional array, where the number of elements in the row is fixed to 2.
 	 * The first element is an array of raw classpath entries, which includes the output entry,
-	 * and the second element is an array of referenced entries that may have been stored 
-	 * by the client earlier. 
+	 * and the second element is an array of referenced entries that may have been stored
+	 * by the client earlier.
 	 * See {@link IJavaProject#getReferencedClasspathEntries()} for more details.
 	 * As a side effect, unknown elements are stored in the given map (if not null)
 	 * Throws exceptions if the file cannot be accessed or is malformed.
@@ -3063,15 +3063,15 @@
 			// project doesn't exist
 			return null;
 		}
-	}		
-	
+	}
+
 	/*
 	 * Resolve the given raw classpath.
 	 */
 	public IClasspathEntry[] resolveClasspath(IClasspathEntry[] rawClasspath) throws JavaModelException {
 		return resolveClasspath(rawClasspath, false/*don't use previous session*/, true/*resolve chained libraries*/).resolvedClasspath;
 	}
-	
+
 	static class ResolvedClasspath {
 		IClasspathEntry[] resolvedClasspath;
 		IJavaModelStatus unresolvedEntryStatus = JavaModelStatus.VERIFIED_OK;
@@ -3079,7 +3079,7 @@
 		Map rootPathToResolvedEntries = new HashMap();
 		IClasspathEntry[] referencedEntries = null;
 	}
-	
+
 	public ResolvedClasspath resolveClasspath(IClasspathEntry[] rawClasspath, boolean usePreviousSession, boolean resolveChainedLibraries) throws JavaModelException {
 		return resolveClasspath(rawClasspath, null, usePreviousSession, resolveChainedLibraries);
 	}
@@ -3093,10 +3093,10 @@
 		Map referencedEntriesMap = new HashMap();
 		Set<IPath> rawLibrariesPath = new LinkedHashSet<>();
 		LinkedHashSet resolvedEntries = new LinkedHashSet();
-		
+
 		if(resolveChainedLibraries) {
 			for (int index = 0; index < rawClasspath.length; index++) {
-				IClasspathEntry currentEntry = rawClasspath[index]; 
+				IClasspathEntry currentEntry = rawClasspath[index];
 				if (currentEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
 					rawLibrariesPath.add(ClasspathEntry.resolveDotDot(getProject().getLocation(), currentEntry.getPath()));
 				}
@@ -3118,7 +3118,7 @@
 				}
 			}
 		}
-		
+
 		int length = rawClasspath.length;
 		for (int i = 0; i < length; i++) {
 
@@ -3183,12 +3183,12 @@
 						}
 						// if container is exported or restricted, then its nested entries must in turn be exported  (21749) and/or propagate restrictions
 						cEntry = cEntry.combineWith((ClasspathEntry) rawEntry);
-						
+
 						if (cEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
 							// resolve ".." in library path
 							cEntry = cEntry.resolvedDotDot(getProject().getLocation());
 							// https://bugs.eclipse.org/bugs/show_bug.cgi?id=313965
-							// Do not resolve if the system attribute is set to false	
+							// Do not resolve if the system attribute is set to false
 							if (resolveChainedLibraries
 									&& JavaModelManager.getJavaModelManager().resolveReferencedLibrariesForContainers
 									&& result.rawReverseMap.get(cEntry.getPath()) == null) {
@@ -3208,7 +3208,7 @@
 				case IClasspathEntry.CPE_LIBRARY:
 					// resolve ".." in library path
 					resolvedEntry = ((ClasspathEntry) rawEntry).resolvedDotDot(getProject().getLocation());
-					
+
 					if (resolveChainedLibraries && result.rawReverseMap.get(resolvedEntry.getPath()) == null) {
 						// resolve Class-Path: in manifest
 						ClasspathEntry[] extraEntries = ((ClasspathEntry) resolvedEntry).resolvedChainedLibraries();
@@ -3276,12 +3276,12 @@
 			resolvedEntry.extraAttributes = attributes;
 		}
 	}
-	
+
 	/*
 	 * File#exists() takes lot of time for an unmapped drive. Hence, cache the info.
 	 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=338649
 	 */
-	private boolean driveExists(IPath sourcePath, Map knownDrives) {	
+	private boolean driveExists(IPath sourcePath, Map knownDrives) {
 		String drive = sourcePath.getDevice();
 		if (drive == null) return true;
 		Boolean good = (Boolean)knownDrives.get(drive);
@@ -3296,7 +3296,7 @@
 		}
 		return good.booleanValue();
 	}
-	
+
 	/*
 	 * Resolve the given perProjectInfo's raw classpath and store the resolved classpath in the perProjectInfo.
 	 */
@@ -3323,7 +3323,7 @@
 			}
 
 			ResolvedClasspath result = resolveClasspath(classpath[0], classpath[1], usePreviousSession, true/*resolve chained libraries*/);
-			
+
 			if (CP_RESOLUTION_BP_LISTENERS != null)
 				breakpoint(2, this);
 
@@ -3337,7 +3337,7 @@
 				breakpoint(3, this);
 		}
 	}
-	
+
 	/**
 	 * Answers an ID which is used to distinguish project/entries during package
 	 * fragment root computations
@@ -3362,7 +3362,7 @@
 
 		Map unknownElements = new HashMap();
 		IClasspathEntry[][] fileEntries = readFileEntries(unknownElements);
-		if (fileEntries[0] != JavaProject.INVALID_CLASSPATH && 
+		if (fileEntries[0] != JavaProject.INVALID_CLASSPATH &&
 				areClasspathsEqual(newClasspath, newOutputLocation, fileEntries[0])
 				&& (referencedEntries == null || areClasspathsEqual(referencedEntries, fileEntries[1])) ) {
 			// no need to save it, it is the same
@@ -3549,13 +3549,13 @@
 			true/*can change resource (as per API contract)*/,
 			monitor);
 	}
-	
+
 	@Override
 	public void setRawClasspath(IClasspathEntry[] entries, IClasspathEntry[] referencedEntries, IPath outputLocation,
 			IProgressMonitor monitor) throws JavaModelException {
 		setRawClasspath(entries, referencedEntries, outputLocation, true, monitor);
 	}
-	
+
 	protected void setRawClasspath(IClasspathEntry[] newRawClasspath, IClasspathEntry[] referencedEntries, IPath newOutputLocation,
 			boolean canModifyResources,	IProgressMonitor monitor) throws JavaModelException {
 
@@ -3636,16 +3636,16 @@
 
 		private List<IPath> pathToCycle;
 		public final List<IPath> cycle;
-		
+
 		public CycleInfo(List<IPath> pathToCycle, List<IPath> cycle) {
 			this.pathToCycle = new ArrayList<>(pathToCycle);
 			this.cycle = new ArrayList<>(cycle);
 		}
-		
+
 		public static Optional<CycleInfo> findCycleContaining(Collection<List<CycleInfo>> infos, IPath path) {
 			return infos.stream().flatMap(l -> l.stream()).filter(c -> c.cycle.contains(path)).findAny();
 		}
-		
+
 		public static void add(IPath project, List<IPath> prefix, List<IPath> cycle, Map<IPath, List<CycleInfo>> cyclesPerProject) {
 			List<CycleInfo> list = cyclesPerProject.get(project);
 			if (list == null) {
@@ -3664,11 +3664,11 @@
 			}
 			list.add(new CycleInfo(prefix, cycle));
 		}
-		
+
 		public String pathToCycleAsString() {
 			return this.pathToCycle.stream().map(IPath::lastSegment).collect(Collectors.joining(", ")); //$NON-NLS-1$
 		}
-		
+
 		public String cycleAsString() {
 			return this.cycle.stream().map(IPath::lastSegment).collect(Collectors.joining(", ")); //$NON-NLS-1$
 		}
@@ -3874,7 +3874,7 @@
 	}
 
 	public void setModuleDescription(IModuleDescription module) throws JavaModelException {
-		JavaProjectElementInfo info = (JavaProjectElementInfo) getElementInfo();	
+		JavaProjectElementInfo info = (JavaProjectElementInfo) getElementInfo();
 		IModuleDescription current = info.getModule();
 		if (current != null) {
 			IPackageFragmentRoot root = (IPackageFragmentRoot) current.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
@@ -3885,7 +3885,7 @@
 		}
 		info.setModule(module);
 	}
-	
+
 	private boolean isUnNamedModule() throws JavaModelException {
 		JavaProjectElementInfo info = (JavaProjectElementInfo) getElementInfo();
 		IModuleDescription module = info.getModule();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocContents.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocContents.java
index 7cba0a4..7883d84 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocContents.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavadocContents.java
@@ -26,27 +26,27 @@
 import org.eclipse.jdt.internal.core.util.Util;
 
 public class JavadocContents {
-	private static final int[] UNKNOWN_FORMAT = new int[0]; 
-	
+	private static final int[] UNKNOWN_FORMAT = new int[0];
+
 	private BinaryType type;
 	private char[] content;
-	
+
 	private int childrenStart;
-	
+
 	private boolean hasComputedChildrenSections = false;
 	private int indexOfFieldDetails;
 	private int indexOfConstructorDetails;
 	private int indexOfMethodDetails;
 	private int indexOfEndOfClassData;
-	
+
 	private int indexOfFieldsBottom;
 	private int indexOfAllMethodsTop;
 	private int indexOfAllMethodsBottom;
-	
+
 	private int[] typeDocRange;
 	private HashtableOfObjectToIntArray fieldDocRanges;
 	private HashtableOfObjectToIntArray methodDocRanges;
-	
+
 	private int[] fieldAnchorIndexes;
 	private int fieldAnchorIndexesCount;
 	private int fieldLastAnchorFoundIndex;
@@ -59,12 +59,12 @@
 	private int[] tempAnchorIndexes;
 	private int tempAnchorIndexesCount;
 	private int tempLastAnchorFoundIndex;
-	
+
 	public JavadocContents(BinaryType type, String content) {
 		this(content);
 		this.type = type;
 	}
-	
+
 	public JavadocContents(String content) {
 		this.content = content != null ? content.toCharArray() : null;
 	}
@@ -73,20 +73,20 @@
 	 */
 	public String getTypeDoc() throws JavaModelException {
 		if (this.content == null) return null;
-		
+
 		synchronized (this) {
 			if (this.typeDocRange == null) {
 				computeTypeRange();
 			}
 		}
-		
+
 		if (this.typeDocRange != null) {
 			if (this.typeDocRange == UNKNOWN_FORMAT) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, this.type));
 			return String.valueOf(CharOperation.subarray(this.content, this.typeDocRange[0], this.typeDocRange[1]));
 		}
 		return null;
 	}
-	
+
 	public String getPackageDoc() throws JavaModelException {
 		if (this.content == null) return null;
 		int[] range = null;
@@ -97,7 +97,7 @@
 		if (index != -1) {
 			index = CharOperation.indexOf(JavadocConstants.ANCHOR_SUFFIX, this.content, false, index);
 			if (index == -1) return null;
-			
+
 			int start = CharOperation.indexOf(JavadocConstants.H2_PREFIX, this.content, false, index);
 			if (start != -1) {
 				start = CharOperation.indexOf(JavadocConstants.H2_SUFFIX, this.content, false, start);
@@ -114,7 +114,7 @@
 		}
 		return null;
 	}
-	
+
 	public String getModuleDoc() throws JavaModelException {
 		if (this.content == null) return null;
 		int index = CharOperation.indexOf(JavadocConstants.MODULE_DESCRIPTION_START, this.content, false, 0);
@@ -123,13 +123,13 @@
 		if (end == -1) end = this.content.length -1;
 		return String.valueOf(CharOperation.subarray(this.content, index, end));
 	}
-	
+
 	/*
 	 * Returns the part of the javadoc that describe a field of the type
 	 */
 	public String getFieldDoc(IField child) throws JavaModelException {
 		if (this.content == null) return null;
-		
+
 		int[] range = null;
 		synchronized (this) {
 			if (this.fieldDocRanges == null) {
@@ -137,26 +137,26 @@
 			} else {
 				range = this.fieldDocRanges.get(child);
 			}
-			
+
 			if (range == null) {
 				range = computeFieldRange(child);
 				this.fieldDocRanges.put(child, range);
 			}
 		}
-		
+
 		if (range != null) {
 			if (range == UNKNOWN_FORMAT) throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, child));
 			return String.valueOf(CharOperation.subarray(this.content, range[0], range[1]));
 		}
 		return null;
 	}
-	
+
 	/*
 	 * Returns the part of the javadoc that describe a method of the type
 	 */
 	public String getMethodDoc(IMethod child) throws JavaModelException {
 		if (this.content == null) return null;
-		
+
 		int[] range = null;
 		synchronized (this) {
 			if (this.methodDocRanges == null) {
@@ -164,13 +164,13 @@
 			} else {
 				range = this.methodDocRanges.get(child);
 			}
-			
+
 			if (range == null) {
 				range = computeMethodRange(child);
 				this.methodDocRanges.put(child, range);
 			}
 		}
-		
+
 		if (range != null) {
 			if (range == UNKNOWN_FORMAT) {
 				throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.UNKNOWN_JAVADOC_FORMAT, child));
@@ -179,29 +179,29 @@
 		}
 		return null;
 	}
-	
+
 	/*
 	 * Compute the ranges of the parts of the javadoc that describe each method of the type
 	 */
 	private int[] computeChildRange(char[] anchor, int indexOfSectionBottom) throws JavaModelException {
-		
+
 		// checks each known anchor locations
 		if (this.tempAnchorIndexesCount > 0) {
 			for (int i = 0; i < this.tempAnchorIndexesCount; i++) {
 				int anchorEndStart = this.tempAnchorIndexes[i];
-				
+
 				if (anchorEndStart != -1 && CharOperation.prefixEquals(anchor, this.content, false, anchorEndStart)) {
-					
+
 					this.tempAnchorIndexes[i] = -1;
-					
+
 					return computeChildRange(anchorEndStart, anchor, indexOfSectionBottom);
 				}
 			}
 		}
-		
+
 		int fromIndex = this.tempLastAnchorFoundIndex;
 		int[] index;
-		
+
 		// check each next unknown anchor locations
 		index = getAnchorIndex(fromIndex);
 		while (index[0] != -1 && (index[0] < indexOfSectionBottom || indexOfSectionBottom == -1)) {
@@ -210,19 +210,19 @@
 			int anchorEndStart = index[0] + index[1];
 
 			this.tempLastAnchorFoundIndex = anchorEndStart;
-			
+
 			if (CharOperation.prefixEquals(anchor, this.content, false, anchorEndStart)) {
 				return computeChildRange(anchorEndStart, anchor, indexOfSectionBottom);
 			} else {
 				if (this.tempAnchorIndexes.length == this.tempAnchorIndexesCount) {
 					System.arraycopy(this.tempAnchorIndexes, 0, this.tempAnchorIndexes = new int[this.tempAnchorIndexesCount + 20], 0, this.tempAnchorIndexesCount);
 				}
-				
+
 				this.tempAnchorIndexes[this.tempAnchorIndexesCount++] = anchorEndStart;
 			}
 			index = getAnchorIndex(fromIndex);
 		}
-		
+
 		return null;
 	}
 	private int[] getAnchorIndex(int fromIndex) {
@@ -241,7 +241,7 @@
 	}
 	private int[] computeChildRange(int anchorEndStart, char[] anchor, int indexOfBottom) {
 		int[] range = null;
-				
+
 		// try to find the bottom of the section
 		if (indexOfBottom != -1) {
 			// try to find the end of the anchor
@@ -249,7 +249,7 @@
 			if (indexOfEndLink != -1) {
 				// try to find the next anchor
 				int indexOfNextElement = getAnchorIndex(indexOfEndLink)[0];
-				
+
 				int javadocStart = indexOfEndLink + JavadocConstants.ANCHOR_SUFFIX_LENGTH;
 				int javadocEnd = indexOfNextElement == -1 ? indexOfBottom : Math.min(indexOfNextElement, indexOfBottom);
 				range = new int[]{javadocStart, javadocEnd};
@@ -261,7 +261,7 @@
 			// the detail section has no bottom
 			range = UNKNOWN_FORMAT;
 		}
-		
+
 		return range;
 	}
 
@@ -273,31 +273,31 @@
 		// try to find field detail start
 		this.indexOfFieldDetails = CharOperation.indexOf(JavadocConstants.FIELD_DETAIL, this.content, false, lastIndex);
 		lastIndex = this.indexOfFieldDetails == -1 ? lastIndex : this.indexOfFieldDetails;
-		
+
 		// try to find constructor detail start
 		this.indexOfConstructorDetails = CharOperation.indexOf(JavadocConstants.CONSTRUCTOR_DETAIL, this.content, false, lastIndex);
 		lastIndex = this.indexOfConstructorDetails == -1 ? lastIndex : this.indexOfConstructorDetails;
-		
+
 		// try to find method detail start
 		this.indexOfMethodDetails = CharOperation.indexOf(JavadocConstants.METHOD_DETAIL, this.content, false, lastIndex);
 		lastIndex = this.indexOfMethodDetails == -1 ? lastIndex : this.indexOfMethodDetails;
-		
+
 		// we take the end of class data
 		this.indexOfEndOfClassData = CharOperation.indexOf(JavadocConstants.END_OF_CLASS_DATA, this.content, false, lastIndex);
-		
+
 		// try to find the field detail end
 		this.indexOfFieldsBottom =
 			this.indexOfConstructorDetails != -1 ? this.indexOfConstructorDetails :
 				this.indexOfMethodDetails != -1 ? this.indexOfMethodDetails:
 					this.indexOfEndOfClassData;
-		
+
 		this.indexOfAllMethodsTop =
 			this.indexOfConstructorDetails != -1 ?
 					this.indexOfConstructorDetails :
 						this.indexOfMethodDetails;
-		
+
 		this.indexOfAllMethodsBottom = this.indexOfEndOfClassData;
-	
+
 		this.hasComputedChildrenSections = true;
 	}
 
@@ -308,13 +308,13 @@
 		if (!this.hasComputedChildrenSections) {
 			computeChildrenSections();
 		}
-		
+
 		StringBuffer buffer = new StringBuffer(field.getElementName());
 		buffer.append(JavadocConstants.ANCHOR_PREFIX_END);
 		char[] anchor = String.valueOf(buffer).toCharArray();
-		
+
 		int[] range = null;
-		
+
 		if (this.indexOfFieldDetails == -1 || this.indexOfFieldsBottom == -1) {
 			// the detail section has no top or bottom, so the doc has an unknown format
 			if (this.unknownFormatAnchorIndexes == null) {
@@ -322,13 +322,13 @@
 				this.unknownFormatAnchorIndexesCount = 0;
 				this.unknownFormatLastAnchorFoundIndex = this.childrenStart;
 			}
-			
+
 			this.tempAnchorIndexes = this.unknownFormatAnchorIndexes;
 			this.tempAnchorIndexesCount = this.unknownFormatAnchorIndexesCount;
 			this.tempLastAnchorFoundIndex = this.unknownFormatLastAnchorFoundIndex;
-			
+
 			range = computeChildRange(anchor, this.indexOfFieldsBottom);
-			
+
 			this.unknownFormatLastAnchorFoundIndex = this.tempLastAnchorFoundIndex;
 			this.unknownFormatAnchorIndexesCount = this.tempAnchorIndexesCount;
 			this.unknownFormatAnchorIndexes = this.tempAnchorIndexes;
@@ -338,21 +338,21 @@
 				this.fieldAnchorIndexesCount = 0;
 				this.fieldLastAnchorFoundIndex = this.indexOfFieldDetails;
 			}
-			
+
 			this.tempAnchorIndexes = this.fieldAnchorIndexes;
 			this.tempAnchorIndexesCount = this.fieldAnchorIndexesCount;
 			this.tempLastAnchorFoundIndex = this.fieldLastAnchorFoundIndex;
-			
+
 			range = computeChildRange(anchor, this.indexOfFieldsBottom);
-			
+
 			this.fieldLastAnchorFoundIndex = this.tempLastAnchorFoundIndex;
 			this.fieldAnchorIndexesCount = this.tempAnchorIndexesCount;
 			this.fieldAnchorIndexes = this.tempAnchorIndexes;
 		}
-		
+
 		return range;
 	}
-	
+
 	/*
 	 * Compute the ranges of the parts of the javadoc that describe each method of the type
 	 */
@@ -360,11 +360,11 @@
 		if (!this.hasComputedChildrenSections) {
 			computeChildrenSections();
 		}
-		
+
 		char[] anchor = computeMethodAnchorPrefixEnd((BinaryMethod)method).toCharArray();
-		
+
 		int[] range = null;
-		
+
 		if (this.indexOfAllMethodsTop == -1 || this.indexOfAllMethodsBottom == -1) {
 			// the detail section has no top or bottom, so the doc has an unknown format
 			if (this.unknownFormatAnchorIndexes == null) {
@@ -372,43 +372,43 @@
 				this.unknownFormatAnchorIndexesCount = 0;
 				this.unknownFormatLastAnchorFoundIndex = this.childrenStart;
 			}
-			
+
 			this.tempAnchorIndexes = this.unknownFormatAnchorIndexes;
 			this.tempAnchorIndexesCount = this.unknownFormatAnchorIndexesCount;
 			this.tempLastAnchorFoundIndex = this.unknownFormatLastAnchorFoundIndex;
-			
+
 			range = computeChildRange(anchor, this.indexOfFieldsBottom);
 			if (range == null) {
 				range = computeChildRange(getJavadoc8Anchor(anchor), this.indexOfAllMethodsBottom);
 			}
-			
+
 			this.unknownFormatLastAnchorFoundIndex = this.tempLastAnchorFoundIndex;
 			this.unknownFormatAnchorIndexesCount = this.tempAnchorIndexesCount;
 			this.unknownFormatAnchorIndexes = this.tempAnchorIndexes;
-		} else {			
+		} else {
 			if (this.methodAnchorIndexes == null) {
 				this.methodAnchorIndexes = new int[this.type.getFields().length];
 				this.methodAnchorIndexesCount = 0;
 				this.methodLastAnchorFoundIndex = this.indexOfAllMethodsTop;
 			}
-			
+
 			this.tempAnchorIndexes = this.methodAnchorIndexes;
 			this.tempAnchorIndexesCount = this.methodAnchorIndexesCount;
 			this.tempLastAnchorFoundIndex = this.methodLastAnchorFoundIndex;
-			
+
 			range = computeChildRange(anchor, this.indexOfAllMethodsBottom);
 			if (range == null) {
 				range = computeChildRange(getJavadoc8Anchor(anchor), this.indexOfAllMethodsBottom);
 			}
-			
+
 			this.methodLastAnchorFoundIndex = this.tempLastAnchorFoundIndex;
 			this.methodAnchorIndexesCount = this.tempAnchorIndexesCount;
 			this.methodAnchorIndexes = this.tempAnchorIndexes;
 		}
-		
+
 		return range;
 	}
-	
+
 	private static char[] getJavadoc8Anchor(char[] anchor) {
 		// fix for bug 432284: [1.8] Javadoc-8-style anchors not found by IMethod#getAttachedJavadoc(..)
 		char[] anchor8 = new char[anchor.length];
@@ -454,7 +454,7 @@
 		} else {
 			typeQualifiedName = this.type.getElementName();
 		}
-		
+
 		String methodName = method.getElementName();
 		if (method.isConstructor()) {
 			methodName = typeQualifiedName;
@@ -493,7 +493,7 @@
 		}
 		return anchor + JavadocConstants.ANCHOR_PREFIX_END;
 	}
-	
+
 	/*
 	 * Compute the range of the part of the javadoc that describe the type
 	 */
@@ -533,7 +533,7 @@
 			// try to find method summary start
 			indexOfNextSummary = CharOperation.indexOf(JavadocConstants.METHOD_SUMMARY, this.content, false, indexOfNextSeparator);
 		}
-		
+
 		if (indexOfNextSummary == -1) {
 			// we take the end of class data
 			indexOfNextSummary = CharOperation.indexOf(JavadocConstants.END_OF_CLASS_DATA, this.content, false, indexOfNextSeparator);
@@ -541,7 +541,7 @@
 			// improve performance of computation of children ranges
 			this.childrenStart = indexOfNextSummary + 1;
 		}
-		
+
 		if (indexOfNextSummary == -1) {
 			this.typeDocRange = UNKNOWN_FORMAT;
 			return;
@@ -564,7 +564,7 @@
 		if (afterHierarchy != indexOfNextSummary) {
 			start = afterHierarchy;
 		}
-		
+
 		this.typeDocRange = new int[]{start, indexOfNextSummary};
 	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java
index 576d9a0..0028c34 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JrtPackageFragmentRoot.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2015, 2018 IBM Corporation and others.
+ * Copyright (c) 2015, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -45,9 +45,9 @@
 public class JrtPackageFragmentRoot extends JarPackageFragmentRoot implements IModulePathEntry {
 
 	String moduleName;
-	
+
 	public static final ThreadLocal<Boolean> workingOnOldClasspath = new ThreadLocal<>();
-	
+
 	/**
 	 * Constructs a package fragment root which represents a module
 	 * contained in a JRT.
@@ -155,7 +155,7 @@
 		}
 		return null;
 	}
-	
+
 	@Override
 	protected boolean isComplianceJava9OrHigher() {
 		return true;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java
index 9f7ab01..eb72da6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java
@@ -38,24 +38,24 @@
 
 	SourceTypeElementInfo elementInfo;
 	LambdaMethod lambdaMethod;
-	
-	// These fields could be materialized from elementInfo, but for ease of use stashed here 
+
+	// These fields could be materialized from elementInfo, but for ease of use stashed here
 	protected int sourceStart;
 	protected int sourceEnd;
 	protected int arrowPosition;
 	protected String interphase;
-	
-	
+
+
 	// Construction from AST node
 	LambdaExpression(JavaElement parent, org.eclipse.jdt.internal.compiler.ast.LambdaExpression lambdaExpression) {
 		super(parent, new String(CharOperation.NO_CHAR));
 		this.sourceStart = lambdaExpression.sourceStart;
 		this.sourceEnd = lambdaExpression.sourceEnd;
 		this.arrowPosition = lambdaExpression.arrowPosition;
-		
+
 		TypeBinding supertype = findLambdaSuperType(lambdaExpression);
 		this.interphase = new String(CharOperation.replaceOnCopy(supertype.genericTypeSignature(), '/', '.'));
-		this.elementInfo = makeTypeElementInfo(this, this.interphase, this.sourceStart, this.sourceEnd, this.arrowPosition); 
+		this.elementInfo = makeTypeElementInfo(this, this.interphase, this.sourceStart, this.sourceEnd, this.arrowPosition);
 		this.lambdaMethod = LambdaFactory.createLambdaMethod(this, lambdaExpression);
 		this.elementInfo.children = new IJavaElement[] { this.lambdaMethod };
 	}
@@ -96,7 +96,7 @@
 		}
 		return original;
 	}
-	
+
 	// Construction from memento
 	LambdaExpression(JavaElement parent, String interphase, int sourceStart, int sourceEnd, int arrowPosition) {
 		super(parent, new String(CharOperation.NO_CHAR));
@@ -107,7 +107,7 @@
 		this.elementInfo = makeTypeElementInfo(this, interphase, this.sourceStart = sourceStart, sourceEnd, arrowPosition);
 		// Method is in the process of being fabricated, will be attached shortly.
 	}
-	
+
 	// Construction from subtypes.
 	LambdaExpression(JavaElement parent, String interphase, int sourceStart, int sourceEnd, int arrowPosition, LambdaMethod lambdaMethod) {
 		super(parent, new String(CharOperation.NO_CHAR));
@@ -118,33 +118,33 @@
 		this.elementInfo = makeTypeElementInfo(this, interphase, this.sourceStart = sourceStart, sourceEnd, arrowPosition);
 		this.elementInfo.children = new IJavaElement[] { this.lambdaMethod = lambdaMethod };
 	}
-	
+
 	// Lambda expression is not backed by model, fabricate element information structure and stash it.
 	static private SourceTypeElementInfo makeTypeElementInfo (LambdaExpression handle, String interphase, int sourceStart, int sourceEnd, int arrowPosition) {
-		
+
 		SourceTypeElementInfo elementInfo = new SourceTypeElementInfo();
-		
+
 		elementInfo.setFlags(0);
 		elementInfo.setHandle(handle);
 		elementInfo.setSourceRangeStart(sourceStart);
 		elementInfo.setSourceRangeEnd(sourceEnd);
-		
+
 		elementInfo.setNameSourceStart(sourceStart);
 		elementInfo.setNameSourceEnd(arrowPosition);
 		elementInfo.setSuperclassName(null);
 		elementInfo.addCategories(handle, null);
-		
+
 		JavaModelManager manager = JavaModelManager.getJavaModelManager();
 		char[][] superinterfaces = new char [][] { manager.intern(Signature.toString(interphase).toCharArray()) }; // drops marker interfaces - to fix.
 		elementInfo.setSuperInterfaceNames(superinterfaces);
 		return elementInfo;
 	}
-	
+
 	@Override
 	protected void closing(Object info) throws JavaModelException {
 		// nothing to do, not backed by model ATM.
 	}
-	
+
 	@Override
 	public boolean equals(Object o) {
 		if (this == o)
@@ -163,12 +163,12 @@
 		}
 		return false;
 	}
-	
+
 	@Override
 	public int hashCode() {
 		return Util.combineHashCodes(super.hashCode(), this.sourceStart);
 	}
-	
+
 	@Override
 	public Object getElementInfo(IProgressMonitor monitor) throws JavaModelException {
 		return this.elementInfo;
@@ -178,16 +178,16 @@
 	protected char getHandleMementoDelimiter() {
 		return JavaElement.JEM_LAMBDA_EXPRESSION;
 	}
-	
+
 	@Override
 	protected void getHandleMemento(StringBuffer buff) {
 		getHandleMemento(buff, true, true);
 		// lambda method and lambda expression cannot share the same memento - add a trailing discriminator.
 		appendEscapedDelimiter(buff, getHandleMementoDelimiter());
 	}
-	
+
 	protected void getHandleMemento(StringBuffer buff, boolean serializeParent, boolean serializeChild) {
-		if (serializeParent) 
+		if (serializeParent)
 			((JavaElement)getParent()).getHandleMemento(buff);
 		appendEscapedDelimiter(buff, getHandleMementoDelimiter());
 		appendEscapedDelimiter(buff, JEM_STRING);
@@ -201,13 +201,13 @@
 		if (serializeChild)
 			this.lambdaMethod.getHandleMemento(buff, false);
 	}
-	
+
 	@Override
 	public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
 
 		if (token.charAt(0) != JEM_LAMBDA_METHOD)
 			return null;
-		
+
 		// ----
 		if (!memento.hasMoreTokens()) return this;
 		String selector = memento.nextToken();
@@ -242,7 +242,7 @@
 				return this.lambdaMethod.getHandleFromMemento(memento, workingCopyOwner);
 			case JEM_LAMBDA_EXPRESSION:
 			default:
-				return this;	
+				return this;
 		}
 	}
 
@@ -255,7 +255,7 @@
 	public boolean isLocal() {
 		return true;
 	}
-	
+
 	@Override
 	public JavaElement resolved(Binding binding) {
 		ResolvedLambdaExpression resolvedHandle = new ResolvedLambdaExpression(this.parent, this, new String(binding.computeUniqueKey()));
@@ -265,7 +265,7 @@
 	public IMethod getMethod() {
 		return this.lambdaMethod;
 	}
-	
+
 	@Override
 	public boolean isLambda() {
 		return true;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaFactory.java
index e2536b1..0447bd6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaFactory.java
@@ -90,7 +90,7 @@
 		info.setExceptionTypeNames(CharOperation.NO_CHAR_CHAR);
 		info.arguments = null; // will be updated shortly, parent has to come into existence first.
 
-		return isBinary ? new BinaryLambdaMethod(parent, selector, key, sourceStart, parameterTypes, parameterNames, returnType, info) : 
+		return isBinary ? new BinaryLambdaMethod(parent, selector, key, sourceStart, parameterTypes, parameterNames, returnType, info) :
 				new LambdaMethod(parent, selector, key, sourceStart, parameterTypes, parameterNames, returnType, info);
 	}
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaMethod.java
index a71d8af..aa6742e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaMethod.java
@@ -29,7 +29,7 @@
 	private String returnTypeString;
 	SourceMethodElementInfo elementInfo;
 	private String key;
-	
+
 	LambdaMethod(JavaElement parent, String name, String key, int sourceStart, String [] parameterTypes, String [] parameterNames, String returnType, SourceMethodElementInfo elementInfo) {
 		super(parent, name, parameterTypes);
 		this.sourceStart = sourceStart;
@@ -38,7 +38,7 @@
 		this.elementInfo = elementInfo;
 		this.key = key;
 	}
-	
+
 	/**
 	 * @see IMethod
 	 */
@@ -60,12 +60,12 @@
 	public boolean isLambdaMethod() {
 		return true;
 	}
-	
+
 	@Override
 	protected void closing(Object info) {
 		// nothing to do.
 	}
-	
+
 	@Override
 	public boolean equals(Object o) {
 		if (!(o instanceof LambdaMethod)) return false;
@@ -77,7 +77,7 @@
 	public Object getElementInfo(IProgressMonitor monitor) throws JavaModelException {
 		return this.elementInfo;
 	}
-	
+
 	public void getHandleMemento(StringBuffer buff, boolean serializeParent) {
 		if (serializeParent) {
 			((LambdaExpression) getParent()).getHandleMemento(buff, true, false);
@@ -108,27 +108,27 @@
 		// lambda method and lambda expression cannot share the same memento - add a trailing discriminator.
 		appendEscapedDelimiter(buff, getHandleMementoDelimiter());
 	}
-	
+
 	@Override
 	protected char getHandleMementoDelimiter() {
 		return JavaElement.JEM_LAMBDA_METHOD;
 	}
-	
+
 	@Override
 	public String getKey() {
 		return this.key;
 	}
-	
+
 	@Override
 	public int hashCode() {
 	   return Util.combineHashCodes(super.hashCode(), this.sourceStart);
 	}
-	
+
 	@Override
 	public boolean isResolved() {
 		return true;  // we maintain enough information so as not to need another layer of abstraction.
 	}
-	
+
 	@Override
 	public JavaElement resolved(Binding binding) {
 		return this;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java
index 5fab350..f5b4153 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LocalVariable.java
@@ -41,7 +41,7 @@
 public class LocalVariable extends SourceRefElement implements ILocalVariable {
 
 	public static final ILocalVariable[] NO_LOCAL_VARIABLES = new ILocalVariable[0];
-	
+
 	String name;
 	public int declarationSourceStart, declarationSourceEnd;
 	public int nameStart, nameEnd;
@@ -86,7 +86,7 @@
 			int flags,
 			boolean isParameter,
 		org.eclipse.jdt.internal.compiler.ast.Annotation[][] astAnnotationsOnDimensions) {
-		
+
 		this(parent, name, declarationSourceStart, declarationSourceEnd, nameStart,
 				nameEnd, typeSignature, astAnnotations, flags, isParameter);
 
@@ -281,9 +281,9 @@
 	protected void getHandleMemento(StringBuffer buff) {
 		getHandleMemento(buff, true);
 	}
-	
+
 	protected void getHandleMemento(StringBuffer buff, boolean memoizeParent) {
-		if (memoizeParent) 
+		if (memoizeParent)
 			((JavaElement)getParent()).getHandleMemento(buff);
 		buff.append(getHandleMementoDelimiter());
 		buff.append(this.name);
@@ -316,7 +316,7 @@
 	public IResource getCorrespondingResource() {
 		return null;
 	}
-	
+
 	/**
 	 * {@inheritDoc}
 	 * @since 3.7
@@ -477,7 +477,7 @@
 	public int hashCode() {
 		return Util.combineHashCodes(this.parent.hashCode(), this.nameStart);
 	}
-	
+
 	/**
 	 * {@inheritDoc}
 	 * @since 3.7
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java
index 1abf002..5c2e247 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Member.java
@@ -185,17 +185,17 @@
 				return this;
 			if (!memento.hasMoreTokens()) return this;
 			String interphase = memento.nextToken();
-			if (!memento.hasMoreTokens() || memento.nextToken() != MementoTokenizer.COUNT) 
+			if (!memento.hasMoreTokens() || memento.nextToken() != MementoTokenizer.COUNT)
 				return this;
 			int sourceStart = Integer.parseInt(memento.nextToken());
-			if (!memento.hasMoreTokens() || memento.nextToken() != MementoTokenizer.COUNT) 
+			if (!memento.hasMoreTokens() || memento.nextToken() != MementoTokenizer.COUNT)
 				return this;
 			int sourceEnd = Integer.parseInt(memento.nextToken());
-			if (!memento.hasMoreTokens() || memento.nextToken() != MementoTokenizer.COUNT) 
+			if (!memento.hasMoreTokens() || memento.nextToken() != MementoTokenizer.COUNT)
 				return this;
 			int arrowPosition = Integer.parseInt(memento.nextToken());
 			LambdaExpression expression = LambdaFactory.createLambdaExpression(this, interphase, sourceStart, sourceEnd, arrowPosition);
-			if (!memento.hasMoreTokens() || (token = memento.nextToken()) != MementoTokenizer.LAMBDA_METHOD) 
+			if (!memento.hasMoreTokens() || (token = memento.nextToken()) != MementoTokenizer.LAMBDA_METHOD)
 				return expression;
 			return expression.getHandleFromMemento(token, memento, workingCopyOwner);
 		case JEM_TYPE:
@@ -389,7 +389,7 @@
 		int flags= method.getFlags();
 		IType declaringType = null;
 		if (Flags.isStatic(flags) &&
-				(Flags.isPublic(flags) || 
+				(Flags.isPublic(flags) ||
 						((declaringType = getDeclaringType()) != null && declaringType.isInterface()))) {
 			String[] paramTypes= method.getParameterTypes();
 			if (paramTypes.length == 1) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java
index 7fdf13e..a475da6 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/MemberElementInfo.java
@@ -40,7 +40,7 @@
 	public int getNameSourceStart() {
 		return -1;
 	}
-	
+
 	/**
 	 * @see org.eclipse.jdt.internal.compiler.env.IGenericType#getModifiers()
 	 * @see org.eclipse.jdt.internal.compiler.env.IGenericMethod#getModifiers()
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModularClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModularClassFile.java
index 9928ec4..14addc3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModularClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModularClassFile.java
@@ -43,7 +43,7 @@
 	}
 
 	/**
-	 * Creates the single child element for this class file adding the resulting 
+	 * Creates the single child element for this class file adding the resulting
 	 * new handle (of type {@link IBinaryModule}) and info object to the newElements table.
 	 * Returns true if successful, or false if an error is encountered parsing the class file.
 	 *
@@ -59,8 +59,8 @@
 			info.setChildren(JavaElement.NO_ELEMENTS);
 			return false;
 		}
-		
-		// Create & link a handle:	
+
+		// Create & link a handle:
 		BinaryModule module = new BinaryModule(this, moduleInfo);
 		newElements.put(module, moduleInfo);
 		info.setChildren(new IJavaElement[] {module});
@@ -103,17 +103,17 @@
 	public IType findPrimaryType() {
 		return null;
 	}
-	
+
 	@Override
 	public boolean isClass() throws JavaModelException {
 		return false;
 	}
-	
+
 	@Override
 	public boolean isInterface() throws JavaModelException {
 		return false;
 	}
-	
+
 	@Override
 	public IType getType() {
 		throw new UnsupportedOperationException("IClassFile#getType() cannot be used on an IModularClassFile"); //$NON-NLS-1$
@@ -154,10 +154,10 @@
 			}
 		}
 	}
-	
+
 	private IBinaryModule getJarBinaryModuleInfo() throws CoreException, IOException, ClassFormatException {
 		BinaryModuleDescriptor descriptor = BinaryModuleFactory.createDescriptor(this);
-	
+
 		if (descriptor == null) {
 			return null;
 		}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Module.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Module.java
index 73cbf39..9fd6fa1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Module.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Module.java
@@ -41,7 +41,7 @@
 //	}
 //	@Override
 //	public IModuleDeclaration getDeclaration() {
-//		// 
+//		//
 //		if (this.declaration == null) {
 //			try {
 //				if (this.isBinary) {
@@ -56,9 +56,9 @@
 //		}
 //		return this.declaration;
 //	}
-//	
+//
 //	public String toString() {
 //		return new String(this.name());
-//		
+//
 //	}
 //}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleDescriptionInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleDescriptionInfo.java
index cead80a..9795cfe 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleDescriptionInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleDescriptionInfo.java
@@ -132,8 +132,8 @@
 				mod.requires[i+1].modifiers = refs[i].modifiers;
 			}
 		} else {
-			mod.requires = CharOperation.equals(module.moduleName, TypeConstants.JAVA_BASE) 
-					? NO_REQUIRES 
+			mod.requires = CharOperation.equals(module.moduleName, TypeConstants.JAVA_BASE)
+					? NO_REQUIRES
 					: new ModuleReferenceInfo[] { getJavaBaseReference() };
 		}
 		if (module.exportsCount > 0) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModulePathContainer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModulePathContainer.java
index b503fe2..f6c05b2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModulePathContainer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModulePathContainer.java
@@ -64,19 +64,19 @@
 
 	@Override
 	public String getDescription() {
-		// 
+		//
 		return "Module path"; //$NON-NLS-1$
 	}
 
 	@Override
 	public int getKind() {
-		// 
+		//
 		return K_APPLICATION;
 	}
 
 	@Override
 	public IPath getPath() {
-		// 
+		//
 		return new Path(JavaCore.MODULE_PATH_CONTAINER_ID);
 	}
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleSourcePathManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleSourcePathManager.java
index 5256cc7..689ad61 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleSourcePathManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ModuleSourcePathManager.java
@@ -102,7 +102,7 @@
 		try {
 			seekModule(name, false, requestor);
 		} catch (JavaModelException e) {
-			// 
+			//
 		}
 		IModuleDescription[] modules = requestor.getModules();
 		if (modules.length > 0) {
@@ -113,7 +113,7 @@
 				e.printStackTrace();
 			}
 		}
-		return null; 
+		return null;
 	}
 //	public IModuleDeclaration[] getModules() {
 //		if (this.knownModules.size() == 0) {
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 8984f57..092f13d 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
@@ -55,7 +55,7 @@
 	 * Detects any ADD_EXPORTS or ADD_READS classpath attributes, parses the value,
 	 * and collects the resulting module updates.
 	 * @param entry a classpath entry of the current project.
-	 * @throws JavaModelException 
+	 * @throws JavaModelException
 	 */
 	public void computeModuleUpdates(IClasspathEntry entry) throws JavaModelException {
 		for (IClasspathAttribute attribute : entry.getExtraAttributes()) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java
index d360352..69a500a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - contribution for bug 337868 - [compiler][model] incomplete support for package-info.java when using SearchableEnvironment
@@ -179,6 +179,13 @@
 	public static final int ACCEPT_ENUMS = ASTNode.Bit4;
 
 	/**
+	 * Accept flag for specifying records.
+	 * @noreference This field is not intended to be referenced by clients.
+	 * TODO Clients should add code if any special treatment is needed.
+	 */
+	public static final int ACCEPT_RECORDS = ASTNode.Bit25;
+
+	/**
 	 * Accept flag for specifying annotations.
 	 */
 	public static final int ACCEPT_ANNOTATIONS = ASTNode.Bit5;
@@ -186,7 +193,7 @@
 	/*
 	 * Accept flag for all kinds of types
 	 */
-	public static final int ACCEPT_ALL = ACCEPT_CLASSES | ACCEPT_INTERFACES | ACCEPT_ENUMS | ACCEPT_ANNOTATIONS;
+	public static final int ACCEPT_ALL = ACCEPT_CLASSES | ACCEPT_INTERFACES | ACCEPT_ENUMS | ACCEPT_ANNOTATIONS | ACCEPT_RECORDS;
 
 	public static boolean VERBOSE = false;
 
@@ -374,11 +381,13 @@
 					: TypeDeclaration.kind(((IBinaryType) ((BinaryType) type).getElementInfo()).getModifiers());
 			switch (kind) {
 				case TypeDeclaration.CLASS_DECL :
-					return (acceptFlags & ACCEPT_CLASSES) != 0;
+					return (acceptFlags & (ACCEPT_CLASSES | ACCEPT_RECORDS)) != 0;
 				case TypeDeclaration.INTERFACE_DECL :
 					return (acceptFlags & ACCEPT_INTERFACES) != 0;
 				case TypeDeclaration.ENUM_DECL :
 					return (acceptFlags & ACCEPT_ENUMS) != 0;
+				case TypeDeclaration.RECORD_DECL :
+					return (acceptFlags & ACCEPT_RECORDS) != 0;
 				default:
 					//case IGenericType.ANNOTATION_TYPE :
 					return (acceptFlags & ACCEPT_ANNOTATIONS) != 0;
@@ -953,6 +962,7 @@
 	 * @see #ACCEPT_INTERFACES
 	 * @see #ACCEPT_ENUMS
 	 * @see #ACCEPT_ANNOTATIONS
+	 * @see #ACCEPT_RECORDS
 	 */
 	public IType findType(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, boolean waitForIndices, boolean considerSecondaryTypes) {
 		if (pkg == null)
@@ -988,6 +998,7 @@
 	 * @see #ACCEPT_INTERFACES
 	 * @see #ACCEPT_ENUMS
 	 * @see #ACCEPT_ANNOTATIONS
+	 * @see #ACCEPT_RECORDS
 	 */
 	public IType findType(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags) {
 		if (pkg == null) return null;
@@ -1013,6 +1024,7 @@
 	 * @see #ACCEPT_INTERFACES
 	 * @see #ACCEPT_ENUMS
 	 * @see #ACCEPT_ANNOTATIONS
+	 * @see #ACCEPT_RECORDS
 	 */
 	public IType findType(String name, boolean partialMatch, int acceptFlags) {
 		NameLookup.Answer answer = findType(name, partialMatch, acceptFlags, false/*don't check restrictions*/);
@@ -1073,7 +1085,7 @@
 	public boolean isPackage(String[] pkgName, IPackageFragmentRoot[] moduleContext) {
 		if (moduleContext == null) // includes the case where looking for module UNNAMED or ANY
 			return isPackage(pkgName);
-		
+
 		for (IPackageFragmentRoot moduleRoot : moduleContext) {
 			if (moduleRoot.getPackageFragment(String.join(".", pkgName)).exists()) //$NON-NLS-1$
 				return true;
@@ -1160,16 +1172,16 @@
 	 * @param partialMatch partial name matches qualify when <code>true</code>;
 	 *	only exact name matches qualify when <code>false</code>
 	 */
-	public void seekTypes(String pkgName, String name, boolean partialMatch, IJavaElementRequestor requestor, 
+	public void seekTypes(String pkgName, String name, boolean partialMatch, IJavaElementRequestor requestor,
 			int acceptFlags, IPackageFragmentRoot[] moduleContext, String moduleName) {
 		Selector selector = new Selector(moduleName);
-		seekPackageFragments(pkgName, true /*partialMatch*/, selector, moduleContext);	
+		seekPackageFragments(pkgName, true /*partialMatch*/, selector, moduleContext);
 		if (selector.pkgFragments.size() == 0) return;
 		for (IPackageFragment pkg : selector.pkgFragments) {
 			seekTypes(name, pkg, partialMatch, acceptFlags, requestor);
 		}
 	}
-	
+
 	private void seekModuleAwarePartialPackageFragments(String name, IJavaElementRequestor requestor, IPackageFragmentRoot[] moduleContext) {
 		boolean allPrefixMatch = CharOperation.equals(name.toCharArray(), CharOperation.ALL_PREFIX);
 		String lName = name.toLowerCase();
@@ -1280,8 +1292,8 @@
 	}
 	public void seekModule(char[] name, boolean prefixMatch, IJavaElementRequestor requestor) {
 
-		IPrefixMatcherCharArray prefixMatcher = prefixMatch 
-				? CharOperation.equals(name, CharOperation.ALL_PREFIX) 
+		IPrefixMatcherCharArray prefixMatcher = prefixMatch
+				? CharOperation.equals(name, CharOperation.ALL_PREFIX)
 						? (x, y, isCaseSensitive) -> true
 						: CharOperation::prefixEquals
 				: CharOperation::equals;
@@ -1322,6 +1334,7 @@
 	 * @see #ACCEPT_INTERFACES
 	 * @see #ACCEPT_ENUMS
 	 * @see #ACCEPT_ANNOTATIONS
+	 * @see #ACCEPT_RECORDS
 	 */
 	public void seekTypes(String name, IPackageFragment pkg, boolean partialMatch, int acceptFlags, IJavaElementRequestor requestor, boolean considerSecondaryTypes) {
 /*		if (VERBOSE) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java
index 0bf5f9b..2f5b387 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/PackageFragment.java
@@ -587,7 +587,7 @@
 	String contents = getURLContents(baseLocation, String.valueOf(pathBuffer));
 	if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
 	if (contents == null) return null;
-	
+
 	contents = (new JavadocContents(contents)).getPackageDoc();
 	if (contents == null) contents = ""; //$NON-NLS-1$
 	synchronized (projectInfo.javadocCache) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ProjectEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ProjectEntry.java
index 7b0447e..4173c0e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ProjectEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ProjectEntry.java
@@ -38,9 +38,9 @@
 	}
 
 	JavaProject project;
-	
+
 	public ProjectEntry(JavaProject project) {
-		// 
+		//
 		this.project = project;
 	}
 	@Override
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java
index c49a4ec..e75550f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ResolvedBinaryType.java
@@ -41,7 +41,7 @@
 	public String getKey() {
 		return this.uniqueKey;
 	}
-	
+
 	@Override
 	public String getKey(boolean forceOpen) throws JavaModelException {
 		return this.uniqueKey;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
index ec2e047..1fe4af8 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SearchableEnvironment.java
@@ -502,7 +502,7 @@
 	/**
 	 * Must be used only by CompletionEngine.
 	 * The progress monitor is used to be able to cancel completion operations
-	 * 
+	 *
 	 * Find the top-level types that are defined
 	 * in the current environment and whose name starts with the
 	 * given prefix. The prefix is a qualified name separated by periods
@@ -518,7 +518,7 @@
 	 * types are found relative to their enclosing type.
 	 */
 	public void findTypes(char[] prefix, final boolean findMembers, boolean camelCaseMatch, int searchFor, final ISearchRequestor storage, IProgressMonitor monitor) {
-		
+
 		/*
 			if (true){
 				findTypes(new String(prefix), storage, NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_INTERFACES);
@@ -605,7 +605,7 @@
 					storage.acceptType(packageName, simpleTypeName, enclosingTypeNames, modifiers, access);
 				}
 			};
-			
+
 			int matchRule = SearchPattern.R_PREFIX_MATCH;
 			if (camelCaseMatch) matchRule |= SearchPattern.R_CAMELCASE_MATCH;
 			if (monitor != null) {
@@ -678,11 +678,11 @@
 				convertSearchFilterToModelFilter(searchFor));
 		}
 	}
-	
+
 	/**
 	 * Must be used only by CompletionEngine.
 	 * The progress monitor is used to be able to cancel completion operations
-	 * 
+	 *
 	 * Find constructor declarations that are defined
 	 * in the current environment and whose name starts with the
 	 * given prefix. The prefix is a qualified name separated by periods
@@ -699,7 +699,7 @@
 			} else {
 				excludePath = null;
 			}
-			
+
 			int lastDotIndex = CharOperation.lastIndexOf('.', prefix);
 			char[] qualification, simpleName;
 			if (lastDotIndex < 0) {
@@ -755,7 +755,7 @@
 					// implements interface method
 				}
 			};
-			
+
 			IRestrictedAccessConstructorRequestor constructorRequestor = new IRestrictedAccessConstructorRequestor() {
 				@Override
 				public void acceptConstructor(
@@ -772,14 +772,14 @@
 						AccessRestriction access) {
 					if (excludePath != null && excludePath.equals(path))
 						return;
-					
+
 					storage.acceptConstructor(
 							modifiers,
 							simpleTypeName,
 							parameterCount,
 							signature,
 							parameterTypes,
-							parameterNames, 
+							parameterNames,
 							typeModifiers,
 							packageName,
 							extraFlags,
@@ -787,7 +787,7 @@
 							access);
 				}
 			};
-			
+
 			int matchRule = SearchPattern.R_PREFIX_MATCH;
 			if (camelCaseMatch) matchRule |= SearchPattern.R_CAMELCASE_MATCH;
 			if (monitor != null) {
@@ -818,7 +818,7 @@
 					public String getJobFamily() {
 						return ""; //$NON-NLS-1$
 					}
-				
+
 				}, IJob.WaitUntilReady, monitor);
 				new BasicSearchEngine(this.workingCopies).searchAllConstructorDeclarations(
 						qualification,
@@ -907,7 +907,7 @@
 				return null;
 			case Unnamed:
 			case Any:
-				// if in pre-9 mode we may still search the unnamed module 
+				// if in pre-9 mode we may still search the unnamed module
 				if (this.knownModuleLocations == null) {
 					if ((this.owner != null && this.owner.isPackage(pkgName))
 							|| this.nameLookup.isPackage(pkgName))
@@ -958,7 +958,7 @@
 				return false;
 			case Unnamed:
 			case Any:
-				// if in pre-9 mode we may still search the unnamed module 
+				// if in pre-9 mode we may still search the unnamed module
 				if (this.knownModuleLocations == null) {
 					if (this.nameLookup.hasCompilationUnit(pkgName, null))
 						return true;
@@ -1103,7 +1103,7 @@
 						result.add(root);
 					}
 				}
-			}			
+			}
 		}
 		if (!result.isEmpty())
 			return result.toArray(new IPackageFragmentRoot[result.size()]);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
index ed6a95b..09e37c2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SelectionRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -199,7 +199,7 @@
 			acceptFlags = NameLookup.ACCEPT_INTERFACES;
 			break;
 		default:
-			acceptFlags = NameLookup.ACCEPT_CLASSES;
+			acceptFlags = NameLookup.ACCEPT_CLASSES | NameLookup.ACCEPT_RECORDS ;
 			break;
 	}
 	IType type = null;
@@ -466,7 +466,7 @@
 		HashSet existingElements = new HashSet();
 		HashMap knownScopes = new HashMap();
 		parent = this.handleFactory.createElement(binding.declaringScope, local.sourceStart, (ICompilationUnit) unit, existingElements, knownScopes);
-	} else {		
+	} else {
 		parent = findLocalElement(local.sourceStart, binding.declaringScope.methodScope()); // findLocalElement() cannot find local variable
 	}
 	LocalVariable localVar = null;
@@ -636,12 +636,32 @@
 
 	// if no matches, nothing to report
 	if (this.elementIndex == -1) {
-		// no match was actually found, but a method was originally given -> default constructor
-		addElement(type);
-		if(SelectionEngine.DEBUG){
-			System.out.print("SELECTION - accept type("); //$NON-NLS-1$
-			System.out.print(type.toString());
-			System.out.println(")"); //$NON-NLS-1$
+		try {
+			if (type.isRecord()) {
+				IField field= type.getField(name);
+				if (field != null) {
+					 if (!Flags.isStatic(field.getFlags())) {
+						// no match was actually found, but a method was originally given -> default accessor
+						 addElement(field);
+						 if(SelectionEngine.DEBUG){
+								System.out.print("SELECTION - accept field("); //$NON-NLS-1$
+								System.out.print(field.toString());
+								System.out.println(")"); //$NON-NLS-1$
+						 }
+					 }
+				}
+			}
+		} catch (JavaModelException e) {
+			// Do Nothing
+		}
+		if (this.elementIndex == -1) {
+			// no match was actually found, but a method was originally given -> default constructor
+			addElement(type);
+			if(SelectionEngine.DEBUG){
+				System.out.print("SELECTION - accept type("); //$NON-NLS-1$
+				System.out.print(type.toString());
+				System.out.println(")"); //$NON-NLS-1$
+			}
 		}
 		return;
 	}
@@ -902,7 +922,7 @@
 
 /**
  * This method returns an IMethod element from the given method and declaring type bindings. However,
- * unlike {@link Util#findMethod(IType, char[], String[], boolean)} , this does not require an IType to get 
+ * unlike {@link Util#findMethod(IType, char[], String[], boolean)} , this does not require an IType to get
  * the IMethod element.
  * @param method the given method binding
  * @param signatures the type signatures of the method arguments
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java
index 5956c85..bdd12ae 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java
@@ -45,7 +45,7 @@
 
 		this(project, newRawClasspath, null, newOutputLocation, canChangeResource);
 	}
-	
+
 	/**
 	 * When executed, this operation sets the raw classpath and output location of the given project.
 	 */
@@ -84,7 +84,7 @@
 			done();
 		}
 	}
-	
+
 	@Override
 	protected ISchedulingRule getSchedulingRule() {
 		if (this.canChangeResources) {
@@ -92,7 +92,7 @@
 			return new MultiRule(new ISchedulingRule[] {
 				// use project modification rule as this is needed to create the .classpath file if it doesn't exist yet, or to update project references
 				ruleFactory.modifyRule(this.project.getProject()),
-				
+
 				// and external project modification rule in case the external folders are modified
 				ruleFactory.modifyRule(JavaModelManager.getExternalManager().getExternalFoldersProject())
 			});
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetContainerOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetContainerOperation.java
index b981426..a4d9c70 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetContainerOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetContainerOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -16,9 +16,11 @@
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.jdt.core.IClasspathContainer;
 import org.eclipse.jdt.core.IClasspathEntry;
 import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaModelStatusConstants;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.internal.core.util.Util;
@@ -122,6 +124,8 @@
 							// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=148970
 							if (!ExternalJavaProject.EXTERNAL_PROJECT_NAME.equals(affectedProject.getElementName()))
 								throw e;
+						} catch (OperationCanceledException ex) {
+							throw new JavaModelException(ex, IJavaModelStatusConstants.EVALUATION_ERROR);
 						}
 					}
 				}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java
index 0b3544a..5d8e499 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SingleTypeRequestor.java
@@ -62,7 +62,7 @@
  */
 @Override
 public void acceptModule(IModuleDescription module) {
-	// implements interface method	
+	// implements interface method
 }
 /**
  * @see IJavaElementRequestor
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceConstructorWithChildrenInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceConstructorWithChildrenInfo.java
index fdb4906..c5a0962 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceConstructorWithChildrenInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceConstructorWithChildrenInfo.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -18,7 +18,7 @@
 public class SourceConstructorWithChildrenInfo extends SourceConstructorInfo {
 
 	protected IJavaElement[] children;
-	
+
 	public SourceConstructorWithChildrenInfo(IJavaElement[] children) {
 		this.children = children;
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldWithChildrenInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldWithChildrenInfo.java
index a6397ac..7a3049d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldWithChildrenInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceFieldWithChildrenInfo.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -18,7 +18,7 @@
 public class SourceFieldWithChildrenInfo extends SourceFieldElementInfo {
 
 	protected IJavaElement[] children;
-	
+
 	public SourceFieldWithChildrenInfo(IJavaElement[] children) {
 		this.children = children;
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
index 4c99d4a..d715aea 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMapper.java
@@ -74,7 +74,7 @@
 
 /**
  * A SourceMapper maps source code in a ZIP file to binary types or
- * binary modules in a JAR. The SourceMapper uses the fuzzy parser 
+ * binary modules in a JAR. The SourceMapper uses the fuzzy parser
  * to identify source fragments in a .java file, and attempts to match
  * the source code with children in a binary type.
  * Since a module has no children in the Java Model no such matching
@@ -91,7 +91,7 @@
 	public static class LocalVariableElementKey {
 		String parent;
 		String name;
-		
+
 		public LocalVariableElementKey(IJavaElement method, String name) {
 			StringBuffer buffer = new StringBuffer();
 			buffer
@@ -199,7 +199,7 @@
 	 * Keys are the special local variable elements, entries are <code>char[][]</code>.
 	 */
 	protected HashMap parametersRanges;
-	
+
 	/**
 	 * Set that contains all final local variables.
 	 */
@@ -261,7 +261,7 @@
 	SourceRange moduleNameRange;
 	int moduleDeclarationStart;
 	int moduleModifiers;
-	
+
 	/**
 	 *  Anonymous counter in case we want to map the source of an anonymous class.
 	 */
@@ -496,12 +496,12 @@
 			this.containsADefaultPackage = containsADefaultPackage;
 			this.containsJavaSource = containsJavaSource;
 		}
-		
+
 		@Override
 		public FileVisitResult visitPackage(java.nio.file.Path dir, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException {
 			return FileVisitResult.CONTINUE;
 		}
-		
+
 		@Override
 		public FileVisitResult visitFile(java.nio.file.Path file, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException {
 			String entryName = file.toString();
@@ -554,7 +554,7 @@
 		String complianceLevel = null;
 		if (Util.isJrt(pkgFragmentRootPath.toOSString())) {
 			try {
-				JrtPackageNamesAdderVisitor jrtPackageNamesAdderVisitor = new JrtPackageNamesAdderVisitor(firstLevelPackageNames, 
+				JrtPackageNamesAdderVisitor jrtPackageNamesAdderVisitor = new JrtPackageNamesAdderVisitor(firstLevelPackageNames,
 						sourceLevel, complianceLevel, containsADefaultPackage, containsJavaSource, root);
 				org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(root.getPath().toFile(), jrtPackageNamesAdderVisitor, JRTUtil.NOTIFY_FILES);
 				sourceLevel = jrtPackageNamesAdderVisitor.sourceLevel;
@@ -854,14 +854,14 @@
 		// categories
 		addCategories(currentType, typeInfo.categories);
 	}
-	
+
 	@Override
 	public void enterModule(ModuleInfo moduleInfo) {
 		this.moduleNameRange =
 			new SourceRange(moduleInfo.nameSourceStart, moduleInfo.nameSourceEnd - moduleInfo.nameSourceStart + 1);
 		this.moduleDeclarationStart = moduleInfo.declarationStart;
-	
-	
+
+
 		// module type modifiers
 		this.moduleModifiers = moduleInfo.modifiers;
 
@@ -1235,7 +1235,7 @@
 			} catch (CoreException e) {
 				// Ignore
 			}
-			
+
 			// try to get the entry
 			ZipEntry entry = null;
 			ZipFile zip = null;
@@ -1581,7 +1581,7 @@
 				}
 				sourceFileName = ((BinaryType) this.binaryTypeOrModule).sourceFileName(info);
 				boolean isAnonymousClass = info.isAnonymous();
-				
+
 				char[] fullName = info.getName();
 				if (isAnonymousClass) {
 					String eltName = this.binaryTypeOrModule.getParent().getElementName();
@@ -1594,7 +1594,7 @@
 				}
 				doFullParse = hasToRetrieveSourceRangesForLocalClass(fullName);
 			} else {
-				sourceFileName = TypeConstants.MODULE_INFO_CLASS_NAME_STRING; 
+				sourceFileName = TypeConstants.MODULE_INFO_CLASS_NAME_STRING;
 			}
 			parser = new SourceElementParser(this, factory, new CompilerOptions(this.options), doFullParse, true/*optimize string literals*/);
 			parser.javadocParser.checkDocComment = false; // disable javadoc parsing
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java
index f2206e6..3d31be1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodElementInfo.java
@@ -41,7 +41,7 @@
 	 * For example, Hashtable or java.util.Hashtable.
 	 */
 	protected char[][] exceptionTypes;
-	
+
 	protected ILocalVariable[] arguments;
 
 	/*
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodWithChildrenInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodWithChildrenInfo.java
index 082cebf..d702e2d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodWithChildrenInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceMethodWithChildrenInfo.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -18,7 +18,7 @@
 public class SourceMethodWithChildrenInfo extends SourceMethodInfo {
 
 	protected IJavaElement[] children;
-	
+
 	public SourceMethodWithChildrenInfo(IJavaElement[] children) {
 		this.children = children;
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java
index f58f253..ad7a689 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -196,7 +196,7 @@
 @Override
 public boolean equals(Object o) {
 	if (!(o instanceof SourceType)) return false;
-	if (((SourceType) o).isLambda()) 
+	if (((SourceType) o).isLambda())
 		return false;
 	return super.equals(o);
 }
@@ -648,6 +648,16 @@
 }
 
 /**
+ * @see IType#isRecord()
+ * @noreference This method is not intended to be referenced by clients as it is a part of Java preview feature.
+ */
+@Override
+public boolean isRecord() throws JavaModelException {
+	SourceTypeElementInfo info = (SourceTypeElementInfo) getElementInfo();
+	return TypeDeclaration.kind(info.getModifiers()) == TypeDeclaration.RECORD_DECL;
+}
+
+/**
  * @see IType
  */
 @Override
@@ -840,7 +850,7 @@
 @Override
 public ITypeHierarchy newTypeHierarchy(IProgressMonitor monitor) throws JavaModelException {
 	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=228845, The new type hierarchy should consider changes in primary
-	// working copy. 
+	// working copy.
 	return newTypeHierarchy(DefaultWorkingCopyOwner.PRIMARY, monitor);
 }
 
@@ -919,7 +929,9 @@
 		}
 	} else {
 		try {
-			if (isEnum()) {
+			if (isRecord()) {
+				buffer.append("record "); //$NON-NLS-1$
+			} else if (isEnum()) {
 				buffer.append("enum "); //$NON-NLS-1$
 			} else if (isAnnotation()) {
 				buffer.append("@interface "); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java
index 1bfc71e..de6bb33 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceTypeElementInfo.java
@@ -34,7 +34,7 @@
 	protected static final SourceType[] NO_TYPES = new SourceType[0];
 
 	protected IJavaElement[] children = JavaElement.NO_ELEMENTS;
-	
+
 	/**
 	 * The name of the superclass for this type. This name
 	 * is fully qualified for binary types and is NOT always
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameter.java
index e100ee6..db05df7 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameter.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameter.java
@@ -40,28 +40,28 @@
 		TypeParameterElementInfo info = (TypeParameterElementInfo) getElementInfo();
 		return CharOperation.toStrings(info.bounds);
 	}
-	
+
 	@Override
 	public String[] getBoundsSignatures() throws JavaModelException {
-		
+
 		String[] boundSignatures = null;
 		TypeParameterElementInfo info = (TypeParameterElementInfo) this.getElementInfo();
-		
+
 		// For a binary type or method, the signature is already available from the .class file.
 		// No need to construct again
 		if (this.parent instanceof BinaryMember) {
 			char[][] boundsSignatures = info.boundsSignatures;
 			if (boundsSignatures == null || boundsSignatures.length == 0) {
-				return CharOperation.NO_STRINGS;	
+				return CharOperation.NO_STRINGS;
 			}
 			return CharOperation.toStrings(info.boundsSignatures);
 		}
-		
+
 		char[][] bounds = info.bounds;
 		if (bounds == null || bounds.length == 0) {
 			return CharOperation.NO_STRINGS;
 		}
-	
+
 		int boundsLength = bounds.length;
 		boundSignatures = new String[boundsLength];
 		for (int i = 0; i < boundsLength; i++) {
@@ -69,7 +69,7 @@
 		}
 		return boundSignatures;
 	}
-	
+
 	@Override
 	public IMember getDeclaringMember() {
 		return (IMember) getParent();
@@ -89,18 +89,18 @@
 	protected char getHandleMementoDelimiter() {
 		return JavaElement.JEM_TYPE_PARAMETER;
 	}
-	
+
 	public String getKey(boolean forceOpen) throws JavaModelException {
 		StringBuilder buf = new StringBuilder();
 		if (this.parent instanceof IType) {
 			if (this.parent instanceof BinaryType)
 				buf.append(((BinaryType) this.parent).getKey(forceOpen));
-			else 
+			else
 				buf.append(((IType) this.parent).getKey());
 		} else if (this.parent instanceof IMember) {
 			if (this.parent instanceof BinaryMember)
 				buf.append(((BinaryMember) this.parent).getKey(forceOpen));
-			else 
+			else
 				buf.append(((IMethod) this.parent).getKey());
 		}
 		buf.append(":T"); //$NON-NLS-1$
@@ -145,7 +145,7 @@
 	public IClassFile getClassFile() {
 		return ((JavaElement)getParent()).getClassFile();
 	}
-	
+
 	/**
 	 * {@inheritDoc}
 	 * @since 3.7
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameterElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameterElementInfo.java
index f45a306..8f1f093 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameterElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeParameterElementInfo.java
@@ -31,9 +31,9 @@
 	 * The bounds names of this type parameter.
 	 */
 	public char[][] bounds;
-	
+
 	/*
-	 * The bounds' signatures for this type parameter. 
+	 * The bounds' signatures for this type parameter.
 	 */
 	public char[][] boundsSignatures;
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java
index fe63810..5c660db 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/TypeVector.java
@@ -26,7 +26,7 @@
 	int maxSize;
 	IType[] elements;
 	/**
-	 * {@link HashMap} that contains the same elements as the {@link #elements}. Used to speed up {@link #contains} 
+	 * {@link HashMap} that contains the same elements as the {@link #elements}. Used to speed up {@link #contains}
 	 * for large lists. It is lazily constructed the first time it is needed for vectors larger than
 	 * {@link #MIN_ELEMENTS_FOR_HASHSET}. Set to null if not constructed yet. The keys and values are the same
 	 */
@@ -79,13 +79,13 @@
 		return this.elementSet.containsKey(element);
 	}
 
-	for (int i = this.size; --i >= 0;) 
+	for (int i = this.size; --i >= 0;)
 		if (element.equals(this.elements[i]))
 			return true;
 	return false;
 }
 /**
- * 
+ *
  */
 private void constructElementSetIfNecessary() {
 	if (this.elementSet == null && this.size >= MIN_ELEMENTS_FOR_HASHSET) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibrary.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibrary.java
index 6666c14..ebcdc4c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibrary.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibrary.java
@@ -177,7 +177,7 @@
 					String pathString = element.getAttribute(TAG_PATH);
 					String sourceAttachString = element.hasAttribute(TAG_SOURCEATTACHMENT) ? element.getAttribute(TAG_SOURCEATTACHMENT) : null;
 					String sourceAttachRootString = element.hasAttribute(TAG_SOURCEATTACHMENTROOT) ? element.getAttribute(TAG_SOURCEATTACHMENTROOT) : null;
-					IPath entryPath = null; 
+					IPath entryPath = null;
 					IPath sourceAttachPath = null;
 					IPath sourceAttachRootPath = null;
 					if (version.equals(VERSION_ONE)) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryManager.java
index 969b6de..d3bce17 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibraryManager.java
@@ -153,7 +153,7 @@
 		} catch (IOException | ClasspathEntry.AssertionFailedException ase) {
 			Util.log(ase, "Exception while decoding user library '"+ libName +"'."); //$NON-NLS-1$ //$NON-NLS-2$
 		}
-		
+
 	}
 
 	public void removeUserLibrary(String libName)  {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java
index abd5402..1d14cb5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java
@@ -696,7 +696,7 @@
 		// we may use a different resource for certain problems such as IProblem.MissingNonNullByDefaultAnnotationOnPackage
 		// but at the start of the next problem we should reset it to the source file's resource
 		IResource resource = sourceFile.resource;
-		
+
 		// handle buildpath problems (missing classfile, unresolved add-reads...)
 		String buildPathProblemMessage = null;
 		if (id == IProblem.IsClassPathCorrect) {
@@ -741,7 +741,7 @@
 				PackageFragment pkg = null;
 				if (pkgEnd != -1)
 					pkg = (PackageFragment) Util.getPackageFragment(sourceFile.getFileName(), pkgEnd, -1 /*no jar separator for java files*/);
-				
+
 				if (pkg != null) {
 					try {
 						IMarker[] existingMarkers = pkg.resource().findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java
index 5150da2..ec2f1f1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java
@@ -108,7 +108,7 @@
 	if (deleteAll) {
 		if (this.compilationGroup != CompilationGroup.TEST) {
 			// CompilationGroup.MAIN is done first, so this notifies the participants only once
-			// calling this for CompilationGroup.TEST could cases generated files for CompilationGroup.MAIN to be deleted. 
+			// calling this for CompilationGroup.TEST could cases generated files for CompilationGroup.MAIN to be deleted.
 			if (this.javaBuilder.participants != null)
 				for (int i = 0, l = this.javaBuilder.participants.length; i < l; i++)
 					this.javaBuilder.participants[i].cleanStarting(this.javaBuilder.javaProject);
@@ -291,7 +291,7 @@
 	long lineCount = compilerStats.lineCount;
 	double speed = ((int) (lineCount * 10000.0 / time)) / 10.0;
 	System.out.println(">FULL BUILD STATS for: "+this.javaBuilder.javaProject.getElementName()); //$NON-NLS-1$
-	System.out.println(">   compiled " + lineCount + " lines in " + time + "ms:" + speed + "lines/s"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+	System.out.println(">   compiled " + lineCount + " lines in " + time + "ms:" + speed + " lines/s"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
 	System.out.print(">   parse: " + compilerStats.parseTime + " ms (" + ((int) (compilerStats.parseTime * 1000.0 / time)) / 10.0 + "%)"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 	System.out.print(", resolve: " + compilerStats.resolveTime + " ms (" + ((int) (compilerStats.resolveTime * 1000.0 / time)) / 10.0 + "%)"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 	System.out.print(", analyze: " + compilerStats.analyzeTime + " ms (" + ((int) (compilerStats.analyzeTime * 1000.0 / time)) / 10.0 + "%)"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
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 012a927..28cda7d 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, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -97,6 +97,7 @@
 	}
 	return null;
 }
+/** Lists all java-like files and also sub-directories (for recursive tests). */
 String[] directoryList(String qualifiedPackageName) {
 	String[] dirList = (String[]) this.directoryCache.get(qualifiedPackageName);
 	if (dirList == this.missingPackageHolder) return null; // package exists in another classpath directory or jar
@@ -111,7 +112,8 @@
 			for (int i = 0, l = members.length; i < l; i++) {
 				IResource m = members[i];
 				String name = m.getName();
-				if (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name)) {
+				if (m.getType() == IResource.FOLDER || // include folders so we recognize empty parent packages
+						(m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name))) {
 					// add exclusion pattern check here if we want to hide .class files
 					dirList[index++] = name;
 				}
@@ -215,7 +217,23 @@
 		if (this.module == null || !moduleName.equals(String.valueOf(this.module.name())))
 			return false;
 	}
-	return directoryList(qualifiedPackageName) != null;
+	String[] list = directoryList(qualifiedPackageName);
+	if (list != null) {
+		// 1. search files here:
+		for (String entry : list) {
+			String entryLC = entry.toLowerCase();
+			if (entryLC.endsWith(SuffixConstants.SUFFIX_STRING_class) || entryLC.endsWith(SuffixConstants.SUFFIX_STRING_java))
+				return true;
+		}
+		// 2. recurse into sub directories
+		for (String entry : list) {
+			if (entry.indexOf('.') == -1) { // no plain files without '.' are returned by directoryList()
+				if (isPackage(qualifiedPackageName+'/'+entry, null/*already checked*/))
+					return true;
+			}
+		}
+	}
+	return false;
 }
 @Override
 public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) {
@@ -250,7 +268,7 @@
 
 @Override
 public NameEnvironmentAnswer findClass(String typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) {
-	// 
+	//
 	return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false, null);
 }
 
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 ca01706..365a8ab 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
@@ -18,6 +18,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.Enumeration;
@@ -251,7 +252,7 @@
 	if (!Util.equalOrNull(this.compliance, jar.compliance)) {
 		return false;
 	}
-	return this.zipFilename.equals(jar.zipFilename) 
+	return this.zipFilename.equals(jar.zipFilename)
 			&& lastModified() == jar.lastModified()
 			&& this.isOnModulePath == jar.isOnModulePath
 			&& areAllModuleOptionsEqual(jar);
@@ -292,8 +293,8 @@
 			}
 			if (this.accessRuleSet == null)
 				return new NameEnvironmentAnswer(reader, null, modName);
-			return new NameEnvironmentAnswer(reader, 
-					this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), 
+			return new NameEnvironmentAnswer(reader,
+					this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()),
 					modName);
 		}
 	} catch (IOException | ClassFormatException e) { // treat as if class file is missing
@@ -387,16 +388,16 @@
 
 @Override
 public NameEnvironmentAnswer findClass(String typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) {
-	// 
+	//
 	return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false, null);
 }
 public Manifest getManifest() {
 	if (!scanContent()) // ensure zipFile is initialized
 		return null;
 	ZipEntry entry = this.zipFile.getEntry(TypeConstants.META_INF_MANIFEST_MF);
-	try {
-		if (entry != null)
-			return new Manifest(this.zipFile.getInputStream(entry));
+	try(InputStream is = entry != null ? this.zipFile.getInputStream(entry) : null) {
+		if (is != null)
+			return new Manifest(is);
 	} catch (IOException e) {
 		// cannot use manifest
 	}
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 197e682..c09b30a 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
@@ -82,7 +82,7 @@
 	PackageCache.put(zipFileName, packagesInModule);
 	try {
 		final File imageFile = new File(zipFileName);
-		org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile, 
+		org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(imageFile,
 				new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor<Path>() {
 			SimpleSet packageSet = null;
 			@Override
@@ -164,7 +164,7 @@
 	return this.zipFilename;
 }
 void acceptModule(byte[] content) {
-	if (content == null) 
+	if (content == null)
 		return;
 	ClassFileReader reader = null;
 	try {
@@ -252,7 +252,7 @@
 @Override
 public char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) {
 	List<String> moduleNames = JRTUtil.getModulesDeclaringPackage(new File(this.zipFilename), qualifiedPackageName, moduleName);
-	return CharOperation.toCharArrays(moduleNames); 
+	return CharOperation.toCharArrays(moduleNames);
 }
 @Override
 public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) {
@@ -335,7 +335,7 @@
 }
 @Override
 public NameEnvironmentAnswer findClass(String typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) {
-	// 
+	//
 	return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false, null);
 }
 /** TEST ONLY */
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java
index 5a3dc95..7220b0e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathJrtWithReleaseOption.java
@@ -104,16 +104,16 @@
 		} catch (IOException e) {
 			this.fs = null;
 		}
-		return false; 
+		return false;
 	}
 	/*
 	 * Set up the paths where modules and regular classes need to be read. We need to deal with two different kind of
 	 * formats of cy.sym: Post JDK 12: ct.sym -> 9 -> java/ -> lang/* 9-modules -> java.base -> module-info.sig
-	 * 
+	 *
 	 * From JDK 12 onward: ct.sym -> 9 -> java.base -> module-info.sig java/ -> lang/* Notably, 1) in JDK 12 modules
 	 * classes and ordinary classes are located in the same location 2) in JDK 12, ordinary classes are found inside
 	 * their respective modules
-	 * 
+	 *
 	 */
 	protected void initialize() throws CoreException {
 		this.releaseInHex = Integer.toHexString(Integer.parseInt(this.release)).toUpperCase();
@@ -144,7 +144,7 @@
 			this.modulePath = modPath;
 			this.modPathString = this.zipFilename + "|"+ modPath.toString(); //$NON-NLS-1$
 		}
-		
+
 		if (!Files.exists(this.releasePath.resolve(this.releaseInHex))) {
 			Exception e = new IllegalArgumentException("release " + this.release + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$
 			throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, e.getMessage(), e));
@@ -299,7 +299,7 @@
 					inner: if (this.isJRE12Plus) {
 						if (moduleName != null) {
 							p = this.fs.getPath(rel, moduleName, qualifiedBinaryFileName);
-						} 
+						}
 						else {
 							try (DirectoryStream<java.nio.file.Path> stream = Files
 									.newDirectoryStream(this.fs.getPath(rel))) {
@@ -332,7 +332,7 @@
 						moduleNameFilter);
 			}
 			return createAnswer(fileNameWithoutExtension, reader);
-		} catch (ClassFormatException | IOException e) { 
+		} catch (ClassFormatException | IOException e) {
 			// treat as if class file is missing
 		}
 		return null;
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 436922d..4cdb930 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
@@ -129,9 +129,9 @@
 	return new ClasspathDirectory(binaryFolder, isOutputFolder, accessRuleSet, externalAnnotationPath, autoModule);
 }
 
-static ClasspathLocation forLibrary(String libraryPathname, 
-										long lastModified, 
-										AccessRuleSet accessRuleSet, 
+static ClasspathLocation forLibrary(String libraryPathname,
+										long lastModified,
+										AccessRuleSet accessRuleSet,
 										IPath annotationsPath,
 										boolean isOnModulePath,
 										String compliance) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java
index fd384f2..96b26f2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ClasspathMultiDirectory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -58,7 +58,7 @@
 //	if (this.module != md.module)
 //		if (this.module == null || !this.module.equals(md.module))
 //			return false;
-	return this.ignoreOptionalProblems == md.ignoreOptionalProblems 
+	return this.ignoreOptionalProblems == md.ignoreOptionalProblems
 		&& this.sourceFolder.equals(md.sourceFolder) && this.binaryFolder.equals(md.binaryFolder)
 		&& CharOperation.equals(this.inclusionPatterns, md.inclusionPatterns)
 		&& CharOperation.equals(this.exclusionPatterns, md.exclusionPatterns);
@@ -82,17 +82,20 @@
 			IResource[] members = ((IContainer) container).members();
 			dirList = new String[members.length];
 			int index = 0;
+			boolean foundClass = false;
 			if (members.length > 0) {
 				for (int i = 0, l = members.length; i < l; i++) {
 					IResource m = members[i];
 					String name = m.getName();
-					if (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name)) {
+					boolean isClass = m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isClassFileName(name);
+					if (m.getType() == IResource.FOLDER || isClass) {
 						// add exclusion pattern check here if we want to hide .class files
 						dirList[index++] = name;
+						foundClass |= isClass;
 					}
 				}
 			}
-			if(index==0) {
+			if(!foundClass) {
 				container = this.sourceFolder.findMember(qualifiedPackageName);
 				if (container instanceof IContainer) {
 					members = ((IContainer) container).members();
@@ -102,7 +105,8 @@
 						for (int i = 0, l = members.length; i < l; i++) {
 							IResource m = members[i];
 							String name = m.getName();
-							if (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(name)) {
+							if (m.getType() == IResource.FOLDER
+									|| (m.getType() == IResource.FILE && org.eclipse.jdt.internal.compiler.util.Util.isJavaFileName(name))) {
 								// FIXME: check if .java file has any declarations?
 								dirList[index++] = name;
 							}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java
index 7844e0a..eaaf803 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java
@@ -137,6 +137,9 @@
 
 			this.notifier.subTask(Messages.build_analyzingSources);
 			addAffectedSourceFiles();
+			if (this.testImageBuilder != null) {
+				this.testImageBuilder.addAffectedSourceFiles();
+			}
 			this.notifier.updateProgressDelta(0.05f);
 		}
 
@@ -956,6 +959,15 @@
 			addDependentsOf(new Path(fileName), true);
 			this.newState.wasStructurallyChanged(fileName);
 		}
+	} catch (JavaModelException jme) {
+		Throwable e = jme.getCause();
+		if (e instanceof CoreException) {
+			// assuming a ResourceException during IFile.getContents(), treat it like a corrupt file
+			addDependentsOf(new Path(fileName), true);
+			this.newState.wasStructurallyChanged(fileName);
+		} else {
+			throw jme;
+		}
 	} catch (ClassFormatException e) {
 		addDependentsOf(new Path(fileName), true);
 		this.newState.wasStructurallyChanged(fileName);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleEntryProcessor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleEntryProcessor.java
index 69a77ba..f26d20d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleEntryProcessor.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleEntryProcessor.java
@@ -27,7 +27,7 @@
 import org.eclipse.jdt.internal.core.JavaProject;
 import org.eclipse.jdt.internal.core.ModuleUpdater;
 
-/** 
+/**
  * Collection of functions to process classpath attributes relating to modules (from JEP 261).
  * For <code>add-exports</code> and <code>add-reads</code> see {@link ModuleUpdater}.
  */
@@ -100,7 +100,7 @@
 		String extraAttribute = ClasspathEntry.getExtraAttribute(entry, IClasspathAttribute.LIMIT_MODULES);
 		if (extraAttribute == null)
 			return null;
-		
+
 		// collect the transitive closure of modules contained in limitSet
 		return new LinkedHashSet<>(Arrays.asList(extraAttribute.split(","))); //$NON-NLS-1$
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleInfoBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleInfoBuilder.java
index d987595..849fa02 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleInfoBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/ModuleInfoBuilder.java
@@ -40,7 +40,7 @@
 
 /** Implementation of {@link org.eclipse.jdt.core.JavaCore#compileWithAttributes(IModuleDescription, Map)}. */
 public class ModuleInfoBuilder {
-	
+
 	static class BytecodeCollector implements ICompilerRequestor {
 		byte[] bytes;
 
@@ -52,14 +52,14 @@
 			this.bytes = classFiles[0].getBytes();
 		}
 	}
-	
+
 	public byte[] compileWithAttributes(IModuleDescription module, Map<String,String> classFileAttributes) throws JavaModelException {
 		IJavaProject javaProject = module.getJavaProject();
 		NameEnvironment nameEnvironment = new NameEnvironment(javaProject, CompilationGroup.MAIN);
 
 		addModuleUpdates(module, nameEnvironment.moduleUpdater, classFileAttributes);
-		
-		ClasspathMultiDirectory sourceLocation = getSourceLocation(javaProject, nameEnvironment, module); 
+
+		ClasspathMultiDirectory sourceLocation = getSourceLocation(javaProject, nameEnvironment, module);
 		IFile file = (IFile) module.getCompilationUnit().getCorrespondingResource();
 		ICompilationUnit[] sourceUnits = { new SourceFile(file, sourceLocation) };
 		BytecodeCollector collector = new BytecodeCollector();
@@ -95,7 +95,7 @@
 	private ClasspathMultiDirectory getSourceLocation(IJavaProject javaProject, NameEnvironment nameEnvironment, IModuleDescription module)
 			throws JavaModelException {
 		IPackageFragmentRoot root = (IPackageFragmentRoot) module.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
-		IResource rootResource = root.getCorrespondingResource(); 
+		IResource rootResource = root.getCorrespondingResource();
 		for (ClasspathMultiDirectory sourceLocation : nameEnvironment.sourceLocations) {
 			if (sourceLocation.sourceFolder.equals(rootResource)) {
 				return sourceLocation;
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 d94b9ac..577b3ee 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
@@ -10,7 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     Terry Parker <tparker@google.com> 
+ *     Terry Parker <tparker@google.com>
  *           - Contribution for https://bugs.eclipse.org/bugs/show_bug.cgi?id=372418
  *           -  Another problem with inner classes referenced from jars or class folders: "The type ... cannot be resolved"
  *     Stephan Herrmann - Contribution for
@@ -177,9 +177,9 @@
 					bLocation.patchModuleName = patchedModuleName;
 				} else {
 					ClasspathLocation sourceLocation = ClasspathLocation.forSourceFolder(
-								(IContainer) target, 
+								(IContainer) target,
 								outputFolder,
-								entry.fullInclusionPatternChars(), 
+								entry.fullInclusionPatternChars(),
 								entry.fullExclusionPatternChars(),
 								entry.ignoreOptionalProblems());
 					if (patchedModule != null) {
@@ -378,7 +378,7 @@
 		this.binaryLocations[index++] = (ClasspathLocation) outputFolders.get(i);
 	for (int i = 0, l = bLocations.size(); i < l; i++)
 		this.binaryLocations[index++] = (ClasspathLocation) bLocations.get(i);
-	
+
 	if (moduleEntries != null && !moduleEntries.isEmpty())
 		this.modulePathEntries = moduleEntries;
 }
@@ -482,7 +482,7 @@
 		// if we answer X.java & it no longer defines Y then the binary type looking for Y will think the class path is wrong
 		// let the recompile loop fix up dependents when the secondary type Y has been deleted from X.java
 		// Only enclosing type names are present in the additional units table, so strip off inner class specifications
-		// when doing the lookup (https://bugs.eclipse.org/372418). 
+		// when doing the lookup (https://bugs.eclipse.org/372418).
 		// Also take care of $ in the name of the class (https://bugs.eclipse.org/377401)
 		// and prefer name with '$' if unit exists rather than failing to search for nested class (https://bugs.eclipse.org/392727)
 		SourceFile unit = (SourceFile) this.additionalUnits.get(qualifiedTypeName); // doesn't have file extension
@@ -545,7 +545,7 @@
 	if (compoundName != null)
 		return findClass(
 			String.valueOf(CharOperation.concatWith(compoundName, '/')),
-			compoundName[compoundName.length - 1], 
+			compoundName[compoundName.length - 1],
 			LookupStrategy.get(moduleName),
 			LookupStrategy.getStringName(moduleName));
 	return 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 7afd3dc..cbdedca 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
@@ -572,21 +572,17 @@
 			out.writeUTF(jar.externalAnnotationPath != null ? jar.externalAnnotationPath : ""); //$NON-NLS-1$
 			out.writeBoolean(jar.isOnModulePath);
 			out.writeUTF(jar.compliance == null ? "" : jar.compliance); //$NON-NLS-1$
-			
+
 		} else if (c instanceof ClasspathJrt) {
 			ClasspathJrt jrt = (ClasspathJrt) c;
 			out.writeByte(EXTERNAL_JAR);
 			out.writeUTF(jrt.zipFilename);
 			writeRestriction(jrt.accessRuleSet, out);
 			out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$
-			out.writeUTF(""); //$NON-NLS-1$
-		} else {
-			ClasspathJrtWithReleaseOption jrt = (ClasspathJrtWithReleaseOption) c;
-			out.writeByte(EXTERNAL_JAR);
-			out.writeUTF(jrt.zipFilename);
-			writeRestriction(jrt.accessRuleSet, out);
-			out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$
-			out.writeUTF(jrt.release);
+			if (jrt instanceof ClasspathJrtWithReleaseOption)
+				out.writeUTF(((ClasspathJrtWithReleaseOption) jrt).release);
+			else
+				out.writeUTF(""); //$NON-NLS-1$
 		}
 		char[] patchName = c.patchModuleName == null ? CharOperation.NO_CHAR : c.patchModuleName.toCharArray();
 		writeName(patchName, out);
@@ -618,7 +614,7 @@
 					} catch (IOException e) {
 						// ignore
 					}
-					
+
 				});
 			} else {
 				out.writeInt(0);
@@ -698,14 +694,10 @@
 				out.writeUTF(jrt.zipFilename);
 				writeRestriction(jrt.accessRuleSet, out);
 				out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$
-				out.writeUTF(""); //$NON-NLS-1$
-			} else {
-				ClasspathJrtWithReleaseOption jrt = (ClasspathJrtWithReleaseOption) c;
-				out.writeByte(EXTERNAL_JAR);
-				out.writeUTF(jrt.zipFilename);
-				writeRestriction(jrt.accessRuleSet, out);
-				out.writeUTF(jrt.externalAnnotationPath != null ? jrt.externalAnnotationPath : ""); //$NON-NLS-1$
-				out.writeUTF(jrt.release);
+				if (jrt instanceof ClasspathJrtWithReleaseOption)
+					out.writeUTF(((ClasspathJrtWithReleaseOption) jrt).release);
+				else
+					out.writeUTF(""); //$NON-NLS-1$
 			}
 		}
 
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java
index fb7b677..a92f2fc 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBinaryType.java
@@ -301,6 +301,9 @@
 		case TypeDeclaration.ENUM_DECL :
 			buffer.append("enum "); //$NON-NLS-1$
 			break;
+		case TypeDeclaration.RECORD_DECL :
+			buffer.append("record "); //$NON-NLS-1$
+			break;
 	}
 	if (this.name != null) {
 		buffer.append(this.name);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
index 1cd98c4..8defc29 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -181,6 +181,7 @@
 				break;
 			case TypeDeclaration.INTERFACE_DECL :
 			case TypeDeclaration.ANNOTATION_TYPE_DECL :
+			case TypeDeclaration.RECORD_DECL :
 				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=329663
 				if (this.hierarchy.typeToSuperInterfaces.get(typeHandle) == null)
 					this.hierarchy.addInterface(typeHandle);
@@ -246,6 +247,9 @@
 			case TypeDeclaration.ENUM_DECL :
 				flag = NameLookup.ACCEPT_ENUMS;
 				break;
+			case TypeDeclaration.RECORD_DECL :
+				flag = NameLookup.ACCEPT_RECORDS;
+				break;
 			default:
 				//case IGenericType.ANNOTATION :
 				flag = NameLookup.ACCEPT_ANNOTATIONS;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
index b3545ec..31b997a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyResolver.java
@@ -146,7 +146,7 @@
 		CompilationResult unitResult = new CompilationResult(sourceUnit, 1, 1, this.options.maxProblemsPerUnit);
 		CompilationUnitDeclaration parsedUnit = basicParser().dietParse(sourceUnit, unitResult);
 		this.lookupEnvironment.buildTypeBindings(parsedUnit, accessRestriction);
-		this.lookupEnvironment.completeTypeBindings(parsedUnit, true); // work done inside checkAndSetImports() 
+		this.lookupEnvironment.completeTypeBindings(parsedUnit, true); // work done inside checkAndSetImports()
 	} else {
 		//System.out.println("Cannot accept compilation units inside the HierarchyResolver.");
 		this.lookupEnvironment.problemReporter.abortDueToInternalError(
@@ -515,11 +515,11 @@
 	}
 	if (!includeLocalTypes || (parsedUnit.localTypes == null && parsedUnit.functionalExpressions == null))
 		return;
-	
+
 	HandleFactory factory = new HandleFactory();
 	HashSet existingElements = new HashSet(parsedUnit.localTypeCount + parsedUnit.functionalExpressionsCount);
 	HashMap knownScopes = new HashMap(parsedUnit.localTypeCount + parsedUnit.functionalExpressionsCount);
-	
+
 	if (parsedUnit.localTypes != null) {
 		for (int i = 0; i < parsedUnit.localTypeCount; i++) {
 			LocalTypeBinding localType = parsedUnit.localTypes[i];
@@ -584,7 +584,7 @@
 	for (int current = this.typeIndex; current >= 0; current--) {
 		if (progressMonitor != null && progressMonitor.isCanceled())
 			throw new OperationCanceledException();
-		
+
 		ReferenceBinding typeBinding = this.typeBindings[current];
 
 		// java.lang.Object treated at the end
@@ -757,10 +757,10 @@
 							flags,
 							this.lookupEnvironment.problemReporter,
 							result);
-					
-					// We would have got all the necessary local types by now and hence there is no further need 
-					// to parse the method bodies. Parser.getMethodBodies, which is called latter in this function, 
-					// will not parse the method statements if ASTNode.HasAllMethodBodies is set. 
+
+					// We would have got all the necessary local types by now and hence there is no further need
+					// to parse the method bodies. Parser.getMethodBodies, which is called latter in this function,
+					// will not parse the method statements if ASTNode.HasAllMethodBodies is set.
 					if (containsLocalType && parsedUnit != null) parsedUnit.bits |= ASTNode.HasAllMethodBodies;
 				} else {
 					// create parsed unit from file
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyType.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyType.java
index 31584a7..ec728ca 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyType.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/HierarchyType.java
@@ -69,7 +69,7 @@
 public boolean isBinaryType() {
 	return false;
 }
-/** 
+/**
  * Answer whether the receiver is an anonymous type
  */
 public boolean isAnonymous() {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
index 47de70d..fb8074e 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
@@ -380,7 +380,7 @@
 			System.out.println("    for hierarchy focused on " + ((JavaElement)this.focusType).toStringWithAncestors()); //$NON-NLS-1$
 		}
 	}
-	
+
 	for (int i= 0; i < listeners.size(); i++) {
 		final ITypeHierarchyChangedListener listener= listeners.get(i);
 		SafeRunner.run(new ISafeRunnable() {
@@ -1041,7 +1041,7 @@
 protected boolean isAffectedByOpenable(IJavaElementDelta delta, IJavaElement element, int eventType) {
 	if (element instanceof CompilationUnit) {
 		CompilationUnit cu = (CompilationUnit)element;
-		ICompilationUnit focusCU = 
+		ICompilationUnit focusCU =
 			this.focusType != null ? this.focusType.getCompilationUnit() : null;
 		if (focusCU != null && focusCU.getOwner() != cu.getOwner())
 			return false;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java
index 42e54f8..5950a77 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/jdom/DOMNode.java
@@ -870,9 +870,7 @@
  */
 protected int[] rangeCopy(int[] range) {
 	int[] copy= new int[range.length];
-	for (int i= 0; i < range.length; i++) {
-		copy[i]= range[i];
-	}
+	System.arraycopy(range, 0, copy, 0, range.length);
 	return copy;
 }
 /**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyParser.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyParser.java
index 8fc649f..be908a4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyParser.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyParser.java
@@ -375,7 +375,7 @@
 			while (this.index < this.source.length && "0123456789".indexOf(this.source[this.index]) != -1) //$NON-NLS-1$
 				this.index++;
 		}
-		
+
 		void skipThrownStart() {
 			while (this.index < this.source.length && this.source[this.index] == C_THROWN)
 				this.index++;
@@ -396,12 +396,12 @@
 			if (this.index < this.source.length && this.source[this.index] == ';')
 				this.index++;
 		}
-		
+
 		void skipRankStart() {
 			if (this.index < this.source.length && this.source[this.index] == '{')
 				this.index++;
 		}
-		
+
 		void skipRankEnd() {
 			if (this.index < this.source.length && this.source[this.index] == '}')
 				this.index++;
@@ -487,11 +487,11 @@
 	private Scanner scanner;
 
 	private boolean hasTypeName = true;
-	
+
 	private boolean hasModuleName;
 
 	private boolean isMalformed;
-	
+
 	private boolean isParsingThrownExceptions = false;	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=336451
 
 	public BindingKeyParser(BindingKeyParser parser) {
@@ -520,7 +520,7 @@
 	}
 
 	public void consumeCapture18ID(int id, int position) {
-		// default is to do nothing		
+		// default is to do nothing
 	}
 
 	public void consumeException() {
@@ -614,7 +614,7 @@
 	public void consumeWildCard(int kind) {
 		// default is to do nothing
 	}
-	
+
 	public void consumeWildcardRank(int rank) {
 		// default is to do nothing
 	}
@@ -791,7 +791,7 @@
 					malformedKey();
 					return;
 				}
-				
+
 				int start = this.scanner.start;
 				if (this.scanner.nextToken() == Scanner.TYPE) {
 					if (!CharOperation.equals(this.scanner.getTokenSource(), new char[] {'i', 'n', 'f', 'o'})) {
@@ -939,9 +939,9 @@
 		source = this.scanner.getTokenSource();
 		int id = Integer.parseInt(new String(source));
 		this.scanner.skipRankEnd(); // }
-		
+
 		consumeCapture18ID(id, position);
-		
+
 		this.scanner.skipTypeEnd();
 	}
 
@@ -1118,7 +1118,7 @@
 		consumeWildcardRank(Integer.parseInt(new String(source)));
 		this.scanner.skipRankEnd();
 	}
-	
+
 	private void parseWildcardBound() {
 		/*
 		 * The call parser.parse() might have a side-effect on the current token type
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java
index 722ce5b..4b6934f 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BindingKeyResolver.java
@@ -89,7 +89,7 @@
 			}
 			return this.key;
 		}
-		
+
 		@Override
 		public MethodBinding getEnclosingMethod() {
 			return this.enclosingMethod;
@@ -125,7 +125,7 @@
 	TypeBinding typeBinding;
 	TypeDeclaration typeDeclaration;
 	ArrayList types = new ArrayList();
-	
+
 	int wildcardRank;
 
 	CompilationUnitDeclaration outerMostParsedUnit;
@@ -630,7 +630,7 @@
 	public void consumeWildcardRank(int aRank) {
 		this.wildcardRank = aRank;
 	}
-	
+
 	@Override
 	public void consumeWildCard(int kind) {
 		switch (kind) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BootstrapMethodsAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BootstrapMethodsAttribute.java
index 6c60e60..fcb0f81 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BootstrapMethodsAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BootstrapMethodsAttribute.java
@@ -47,7 +47,7 @@
 			BootstrapMethodsEntry entry;
 			for (int i = 0; i < length; i++) {
 				this.entries[i] = entry = new BootstrapMethodsEntry(classFileBytes, constantPool, offset + readOffset);
-				readOffset += 4 + 2 * entry.getBootstrapArguments().length; 
+				readOffset += 4 + 2 * entry.getBootstrapArguments().length;
 			}
 		} else {
 			this.entries = NO_ENTRIES;
@@ -61,7 +61,7 @@
 	public IBootstrapMethodsEntry[] getBootstrapMethods() {
 		return this.entries;
 	}
-	
+
 	@Override
 	public int getBootstrapMethodsLength() {
 		return this.numberOfBootstrapMethods;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java
index f75bdf4..3203fce 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java
@@ -30,6 +30,7 @@
 import org.eclipse.jdt.core.util.IMethodInfo;
 import org.eclipse.jdt.core.util.IModifierConstants;
 import org.eclipse.jdt.core.util.INestMembersAttribute;
+import org.eclipse.jdt.core.util.IRecordAttribute;
 import org.eclipse.jdt.core.util.ISourceAttribute;
 import org.eclipse.jdt.internal.compiler.util.Util;
 
@@ -59,6 +60,7 @@
 	private ISourceAttribute sourceFileAttribute;
 	private char[] superclassName;
 	private int superclassNameIndex;
+	private IRecordAttribute recordAttribute;
 
 	/**
 	 * Constructor for ClassFileReader.
@@ -309,6 +311,9 @@
 						} else if (equals(attributeName, IAttributeNamesConstants.NEST_MEMBERS)) {
 							this.nestMembersAttribute = new NestMembersAttribute(classFileBytes, this.constantPool, readOffset);
 							this.attributes[attributesIndex++] = this.nestMembersAttribute;
+						} else if (equals(attributeName, IAttributeNamesConstants.RECORD)) {
+							this.recordAttribute = new RecordAttribute(classFileBytes, this.constantPool, readOffset);
+							this.attributes[attributesIndex++] = this.recordAttribute;
 						} else {
 							this.attributes[attributesIndex++] = new ClassFileAttribute(classFileBytes, this.constantPool, readOffset);
 						}
@@ -509,4 +514,8 @@
 	private boolean isModule() {
 		return (getAccessFlags() & IModifierConstants.ACC_MODULE) != 0;
 	}
+	@Override
+	public IRecordAttribute getRecordAttribute() {
+		return this.recordAttribute;
+	}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeSnippetParsingUtil.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeSnippetParsingUtil.java
index 3ec66d4..2301b4c 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeSnippetParsingUtil.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeSnippetParsingUtil.java
@@ -36,7 +36,7 @@
 
 	public RecordedParsingInformation recordedParsingInformation;
 	public boolean ignoreMethodBodies;
-	
+
 	public CodeSnippetParsingUtil(boolean ignoreMethodBodies) {
 		this.ignoreMethodBodies = ignoreMethodBodies;
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ComponentInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ComponentInfo.java
new file mode 100644
index 0000000..756d349
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ComponentInfo.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2019 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
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.util;
+
+import org.eclipse.jdt.core.util.ClassFormatException;
+import org.eclipse.jdt.core.util.IAttributeNamesConstants;
+import org.eclipse.jdt.core.util.IClassFileAttribute;
+import org.eclipse.jdt.core.util.IConstantPool;
+import org.eclipse.jdt.core.util.IConstantPoolConstant;
+import org.eclipse.jdt.core.util.IConstantPoolEntry;
+import org.eclipse.jdt.core.util.IComponentInfo;
+
+/**
+ * Default implementation of IComponentInfo.
+ */
+public class ComponentInfo extends ClassFileStruct implements IComponentInfo {
+	private int attributeBytes;
+	private IClassFileAttribute[] attributes;
+	private int attributesCount;
+	private char[] descriptor;
+	private int descriptorIndex;
+	private char[] name;
+	private int nameIndex;
+
+	/**
+	 * @param classFileBytes byte[]
+	 * @param constantPool IConstantPool
+	 * @param offset int
+	 */
+	public ComponentInfo(byte classFileBytes[], IConstantPool constantPool, int offset)
+		throws ClassFormatException {
+		this.nameIndex = u2At(classFileBytes, 0, offset);
+		IConstantPoolEntry constantPoolEntry = constantPool.decodeEntry(this.nameIndex);
+		if (constantPoolEntry.getKind() != IConstantPoolConstant.CONSTANT_Utf8) {
+			throw new ClassFormatException(ClassFormatException.INVALID_CONSTANT_POOL_ENTRY);
+		}
+		this.name = constantPoolEntry.getUtf8Value();
+
+		this.descriptorIndex = u2At(classFileBytes, 2, offset);
+		constantPoolEntry = constantPool.decodeEntry(this.descriptorIndex);
+		if (constantPoolEntry.getKind() != IConstantPoolConstant.CONSTANT_Utf8) {
+			throw new ClassFormatException(ClassFormatException.INVALID_CONSTANT_POOL_ENTRY);
+		}
+		this.descriptor = constantPoolEntry.getUtf8Value();
+
+		this.attributesCount = u2At(classFileBytes, 4, offset);
+		this.attributes = ClassFileAttribute.NO_ATTRIBUTES;
+		int readOffset = 6;
+		if (this.attributesCount != 0) {
+			this.attributes = new IClassFileAttribute[this.attributesCount];
+		}
+		int attributesIndex = 0;
+		for (int i = 0; i < this.attributesCount; i++) {
+			constantPoolEntry = constantPool.decodeEntry(u2At(classFileBytes, readOffset, offset));
+			if (constantPoolEntry.getKind() != IConstantPoolConstant.CONSTANT_Utf8) {
+				throw new ClassFormatException(ClassFormatException.INVALID_CONSTANT_POOL_ENTRY);
+			}
+			char[] attributeName = constantPoolEntry.getUtf8Value();
+			if (equals(attributeName, IAttributeNamesConstants.SIGNATURE)) {
+				this.attributes[attributesIndex++] = new SignatureAttribute(classFileBytes, constantPool, offset + readOffset);
+			} else if (equals(attributeName, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS)) {
+				this.attributes[attributesIndex++] = new RuntimeVisibleAnnotationsAttribute(classFileBytes, constantPool, offset + readOffset);
+			} else if (equals(attributeName, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS)) {
+				this.attributes[attributesIndex++] = new RuntimeInvisibleAnnotationsAttribute(classFileBytes, constantPool, offset + readOffset);
+			} else if (equals(attributeName, IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS)) {
+				this.attributes[attributesIndex++] = new RuntimeVisibleTypeAnnotationsAttribute(classFileBytes, constantPool, offset + readOffset);
+			} else if (equals(attributeName, IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS)) {
+				this.attributes[attributesIndex++] = new RuntimeInvisibleTypeAnnotationsAttribute(classFileBytes, constantPool, offset + readOffset);
+			} else {
+				this.attributes[attributesIndex++] = new ClassFileAttribute(classFileBytes, constantPool, offset + readOffset);
+			}
+			readOffset += (6 + u4At(classFileBytes, readOffset + 2, offset));
+		}
+
+		this.attributeBytes = readOffset;
+	}
+	/**
+	 * @see IComponentInfo#getAttributeCount()
+	 */
+	@Override
+	public int getAttributeCount() {
+		return this.attributesCount;
+	}
+
+	/**
+	 * @see IComponentInfo#getAttributes()
+	 */
+	@Override
+	public IClassFileAttribute[] getAttributes() {
+		return this.attributes;
+	}
+
+	/**
+	 * @see IComponentInfo#getDescriptor()
+	 */
+	@Override
+	public char[] getDescriptor() {
+		return this.descriptor;
+	}
+
+	/**
+	 * @see IComponentInfo#getDescriptorIndex()
+	 */
+	@Override
+	public int getDescriptorIndex() {
+		return this.descriptorIndex;
+	}
+
+	/**
+	 * @see IComponentInfo#getName()
+	 */
+	@Override
+	public char[] getName() {
+		return this.name;
+	}
+
+	/**
+	 * @see IComponentInfo#getNameIndex()
+	 */
+	@Override
+	public int getNameIndex() {
+		return this.nameIndex;
+	}
+
+	@Override
+	public int sizeInBytes() {
+		return this.attributeBytes;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry2.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry2.java
index ab1df0f..9ac5702 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry2.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry2.java
@@ -26,7 +26,7 @@
 	private int referenceKind;
 	private int referenceIndex;
 	private int bootstrapMethodAttributeIndex;
-	
+
 	private int moduleIndex;
 	private char[] moduleName;
 	private int packageIndex;
@@ -87,7 +87,7 @@
 	public void setBootstrapMethodAttributeIndex(int bootstrapMethodAttributeIndex) {
 		this.bootstrapMethodAttributeIndex = bootstrapMethodAttributeIndex;
 	}
-	
+
 	public void setModuleIndex(int moduleIndex) {
 		this.moduleIndex = moduleIndex;
 	}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DOMFinder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DOMFinder.java
index 9a5a7ca..28253e4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DOMFinder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DOMFinder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2017 IBM Corporation and others.
+ * Copyright (c) 2005, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -42,6 +42,7 @@
 import org.eclipse.jdt.core.dom.NormalAnnotation;
 import org.eclipse.jdt.core.dom.PackageDeclaration;
 import org.eclipse.jdt.core.dom.ParameterizedType;
+import org.eclipse.jdt.core.dom.RecordDeclaration;
 import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
 import org.eclipse.jdt.core.dom.TypeDeclaration;
@@ -203,6 +204,13 @@
 	}
 
 	@Override
+	public boolean visit(RecordDeclaration node) {
+		if (found(node, node.getName()) && this.resolveBinding)
+			this.foundBinding = node.resolveBinding();
+		return true;
+	}
+
+	@Override
 	public boolean visit(TypeParameter node) {
 		if (found(node, node.getName()) && this.resolveBinding)
 			this.foundBinding = node.resolveBinding();
@@ -220,7 +228,7 @@
 	public boolean visit(SingleVariableDeclaration node) {
 		if (found(node, node.getName()) && this.resolveBinding)
 			this.foundBinding = node.resolveBinding();
-		return true;		
+		return true;
 	}
 
 	@Override
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java
index 8956c79..8bb273a 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -264,7 +264,7 @@
 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
 		buffer.append(Messages.disassembler_annotationentryend);
 	}
-	
+
 	private void disassemble(IExtendedAnnotation extendedAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
 		final int typeIndex = extendedAnnotation.getTypeIndex();
@@ -324,7 +324,7 @@
 						Integer.toString(extendedAnnotation.getAnnotationTypeIndex()),
 					}));
 				break;
-				
+
 			case IExtendedAnnotationConstants.CLASS_TYPE_PARAMETER_BOUND :
 			case IExtendedAnnotationConstants.METHOD_TYPE_PARAMETER_BOUND :
 				buffer.append(
@@ -332,7 +332,7 @@
 							Integer.toString(extendedAnnotation.getTypeParameterIndex()),
 							Integer.toString(extendedAnnotation.getTypeParameterBoundIndex()),
 						}));
-				break;				
+				break;
 			case IExtendedAnnotationConstants.FIELD :
 			case IExtendedAnnotationConstants.METHOD_RETURN :
 			case IExtendedAnnotationConstants.METHOD_RECEIVER :
@@ -378,7 +378,7 @@
 							Integer.toString(extendedAnnotation.getExceptionTableIndex()),
 						}));
 				break;
-				
+
 			case IExtendedAnnotationConstants.INSTANCEOF :
 			case IExtendedAnnotationConstants.NEW :
 			case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE :
@@ -974,7 +974,7 @@
 		final int classNameLength = className.length;
 		final int accessFlags = classFileReader.getAccessFlags();
 		final boolean isEnum = (accessFlags & IModifierConstants.ACC_ENUM) != 0;
-	
+
 		StringBuffer buffer = new StringBuffer();
 		ISourceAttribute sourceAttribute = classFileReader.getSourceFileAttribute();
 		IClassFileAttribute classFileAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.SIGNATURE);
@@ -1013,7 +1013,7 @@
 			}
 		}
 		final int lastDotIndexInClassName = CharOperation.lastIndexOf('.', className);
-	
+
 		if (checkMode(mode, WORKING_COPY) && lastDotIndexInClassName != -1) {
 			// we print a package declaration
 			buffer.append("package ");//$NON-NLS-1$
@@ -1021,7 +1021,7 @@
 			buffer.append(';');
 			writeNewLine(buffer, lineSeparator, 0);
 		}
-	
+
 		INestMembersAttribute nestMembersAttribute = classFileReader.getNestMembersAttribute();
 		IInnerClassesAttribute innerClassesAttribute = classFileReader.getInnerClassesAttribute();
 		IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
@@ -1031,6 +1031,7 @@
 
 		IClassFileAttribute bootstrapMethods = Util.getAttribute(classFileReader, IAttributeNamesConstants.BOOTSTRAP_METHODS);
 		IModuleAttribute moduleAttribute = (IModuleAttribute) Util.getAttribute(classFileReader, IAttributeNamesConstants.MODULE);
+		IRecordAttribute recordAttribute = classFileReader.getRecordAttribute();
 
 		if (checkMode(mode, DETAILED)) {
 			// disassemble compact version of annotations
@@ -1069,7 +1070,7 @@
 				}
 			}
 		}
-	
+
 		final boolean isAnnotation = (accessFlags & IModifierConstants.ACC_ANNOTATION) != 0;
 		final boolean isModule = (accessFlags & IModifierConstants.ACC_MODULE) != 0;
 		boolean isInterface = false;
@@ -1078,7 +1079,12 @@
 		} else if (isModule) {
 			// skip - process under module attribute
 		} else if (classFileReader.isClass()) {
-			buffer.append("class "); //$NON-NLS-1$
+			if (CharOperation.equals(classFileReader.getSuperclassName(), TypeConstants.CharArray_JAVA_LANG_RECORD_SLASH)) {
+				buffer.append("record "); //$NON-NLS-1$
+			}
+			else {
+				buffer.append("class "); //$NON-NLS-1$
+			}
 		} else {
 			if (isAnnotation) {
 				buffer.append("@"); //$NON-NLS-1$
@@ -1086,7 +1092,7 @@
 			buffer.append("interface "); //$NON-NLS-1$
 			isInterface = true;
 		}
-	
+
 		if (checkMode(mode, WORKING_COPY)) {
 			// we print the simple class name
 			final int start = lastDotIndexInClassName + 1;
@@ -1098,7 +1104,7 @@
 		} else if (!isModule) {
 			buffer.append(className);
 		}
-	
+
 		char[] superclassName = classFileReader.getSuperclassName();
 		if (superclassName != null) {
 			CharOperation.replace(superclassName, '/', '.');
@@ -1184,6 +1190,7 @@
 					|| nestMembersAttribute != null
 					|| bootstrapMethods != null
 					|| moduleAttribute != null
+					|| recordAttribute != null
 					|| remainingAttributesLength != 0) {
 				// this test is to ensure we don't insert more than one line separator
 				if (buffer.lastIndexOf(lineSeparator) != buffer.length() - lineSeparator.length()) {
@@ -1202,6 +1209,9 @@
 			if (nestMembersAttribute != null) {
 				disassemble(nestMembersAttribute, buffer, lineSeparator, 0);
 			}
+			if (recordAttribute != null) {
+				disassemble(recordAttribute, buffer, lineSeparator, 0, mode);
+			}
 			if (bootstrapMethods != null) {
 				disassemble((IBootstrapMethodsAttribute) bootstrapMethods, buffer, lineSeparator, 0, classFileReader.getConstantPool());
 			}
@@ -1224,6 +1234,7 @@
 						if (attribute != innerClassesAttribute
 								&& attribute != nestHostAttribute
 								&& attribute != nestMembersAttribute
+								&& attribute != recordAttribute
 								&& attribute != sourceAttribute
 								&& attribute != signatureAttribute
 								&& attribute != enclosingMethodAttribute
@@ -1296,7 +1307,7 @@
 		}
 	}
 	private void convertModuleNames(StringBuffer buffer, char[] name) {
-		buffer.append(CharOperation.replaceOnCopy(CharOperation.replaceOnCopy(name, '$','.'), '/','.'));				
+		buffer.append(CharOperation.replaceOnCopy(CharOperation.replaceOnCopy(name, '$','.'), '/','.'));
 	}
 
 	private void disassembleModule(IModulePackagesAttribute modulePackagesAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
@@ -1307,7 +1318,7 @@
 		char[][] names = modulePackagesAttribute.getPackageNames();
 		for (int i = 0, l = modulePackagesAttribute.getPackagesCount(); i < l; ++i) {
 			writeNewLine(buffer, lineSeparator, tabNumber + 1);
-			convertModuleNames(buffer, names[i]);				
+			convertModuleNames(buffer, names[i]);
 		}
 		writeNewLine(buffer, lineSeparator, 0);
 	}
@@ -1317,7 +1328,7 @@
 		writeNewLine(buffer, lineSeparator, tabNumber);
 		buffer.append(Messages.disassembler_modulemainclassattributeheader);
 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
-		convertModuleNames(buffer, moduleMainClassAttribute.getMainClassName());				
+		convertModuleNames(buffer, moduleMainClassAttribute.getMainClassName());
 		writeNewLine(buffer, lineSeparator, 0);
 	}
 
@@ -1336,10 +1347,10 @@
 						.append(Messages.disassembler_comma)
 						.append(Messages.disassembler_space);
 				}
-				convertModuleNames(buffer, implementations[i]);				
+				convertModuleNames(buffer, implementations[i]);
 			}
 		}
-		buffer.append(';');		
+		buffer.append(';');
 	}
 
 	private void disassemble(INestHostAttribute nestHostAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
@@ -1352,6 +1363,94 @@
 			.append(" ")//$NON-NLS-1$
 			.append(nestHostAttribute.getNestHostName());
 	}
+	private void disassemble(IRecordAttribute recordAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
+		writeNewLine(buffer, lineSeparator, tabNumber);
+		writeNewLine(buffer, lineSeparator, tabNumber); // additional line
+		buffer.append(Messages.disassembler_record);
+		buffer
+			.append(Messages.disassembler_constantpoolindex)
+			.append(recordAttribute.getAttributeName());
+		writeNewLine(buffer, lineSeparator, tabNumber);
+		buffer.append(Messages.disassembler_components);
+		writeNewLine(buffer, lineSeparator, tabNumber + 1);
+		IComponentInfo[] entries = recordAttribute.getComponentInfos();
+		for (IComponentInfo e : entries) {
+			disassemble(e, buffer, lineSeparator, tabNumber, mode);
+		}
+	}
+	private void disassemble(IComponentInfo componentInfo, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
+		writeNewLine(buffer, lineSeparator, tabNumber);
+		final char[] descriptor = componentInfo.getDescriptor();
+		final ISignatureAttribute signatureAttribute = (ISignatureAttribute) Util.getAttribute(componentInfo, IAttributeNamesConstants.SIGNATURE);
+		if (checkMode(mode, SYSTEM | DETAILED)) {
+			buffer.append(Messages.bind(Messages.classfileformat_componentdescriptor,
+				new String[] {
+					Integer.toString(componentInfo.getDescriptorIndex()),
+					new String(descriptor)
+				}));
+			writeNewLine(buffer, lineSeparator, tabNumber);
+			if (signatureAttribute != null) {
+				buffer.append(Messages.bind(Messages.disassembler_signatureattributeheader, new String(signatureAttribute.getSignature())));
+				writeNewLine(buffer, lineSeparator, tabNumber);
+			}
+		}
+		final IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(componentInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS);
+		final IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(componentInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS);
+		final IClassFileAttribute runtimeVisibleTypeAnnotationsAttribute = Util.getAttribute(componentInfo, IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
+		final IClassFileAttribute runtimeInvisibleTypeAnnotationsAttribute = Util.getAttribute(componentInfo, IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
+		if (checkMode(mode, DETAILED)) {
+			// disassemble compact version of annotations
+			if (runtimeInvisibleAnnotationsAttribute != null) {
+				disassembleAsModifier((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
+				writeNewLine(buffer, lineSeparator, tabNumber);
+			}
+			if (runtimeVisibleAnnotationsAttribute != null) {
+				disassembleAsModifier((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
+				writeNewLine(buffer, lineSeparator, tabNumber);
+			}
+		}
+		if (checkMode(mode, WORKING_COPY)) {
+			if (signatureAttribute != null) {
+				buffer.append(returnClassName(getSignatureForComponent(signatureAttribute.getSignature()), '.', mode));
+			} else {
+				buffer.append(returnClassName(getSignatureForComponent(descriptor), '.', mode));
+			}
+		} else {
+			buffer.append(returnClassName(getSignatureForComponent(descriptor), '.', mode));
+		}
+		buffer.append(' ');
+		buffer.append(new String(componentInfo.getName()));
+
+		buffer.append(Messages.disassembler_endofcomponent);
+		if (checkMode(mode, SYSTEM)) {
+			IClassFileAttribute[] attributes = componentInfo.getAttributes();
+			int length = attributes.length;
+			if (length != 0) {
+				for (int i = 0; i < length; i++) {
+					IClassFileAttribute attribute = attributes[i];
+					if (attribute != signatureAttribute
+						&& attribute != runtimeInvisibleAnnotationsAttribute
+						&& attribute != runtimeVisibleAnnotationsAttribute
+						&& attribute != runtimeInvisibleTypeAnnotationsAttribute
+						&& attribute != runtimeVisibleTypeAnnotationsAttribute) {
+						disassemble(attribute, buffer, lineSeparator, tabNumber, mode);
+					}
+				}
+			}
+			if (runtimeVisibleAnnotationsAttribute != null) {
+				disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
+			}
+			if (runtimeInvisibleAnnotationsAttribute != null) {
+				disassemble((IRuntimeInvisibleAnnotationsAttribute) runtimeInvisibleAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
+			}
+			if (runtimeVisibleTypeAnnotationsAttribute != null) {
+				disassemble((IRuntimeVisibleTypeAnnotationsAttribute) runtimeVisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
+			}
+			if (runtimeInvisibleTypeAnnotationsAttribute != null) {
+				disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) runtimeInvisibleTypeAnnotationsAttribute, buffer, lineSeparator, tabNumber, mode);
+ 			}
+		}
+	}
 
 	private void disassemble(INestMembersAttribute nestMembersAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) {
 		writeNewLine(buffer, lineSeparator, tabNumber);
@@ -1384,7 +1483,7 @@
 		buffer.append(isExports ? "exports" : "opens"); //$NON-NLS-1$ //$NON-NLS-2$
 		buffer.append(Messages.disassembler_space);
 		convertModuleNames(buffer, iPackageVisibilityInfo.getPackageName());
-		char[][] targets = iPackageVisibilityInfo.getTargetModuleNames();		
+		char[][] targets = iPackageVisibilityInfo.getTargetModuleNames();
 		if (targets.length > 0) {
 			buffer.append(Messages.disassembler_space);
 			buffer.append( "to"); //$NON-NLS-1$
@@ -1398,14 +1497,14 @@
 				buffer.append(targets[i]);
 			}
 		}
-		buffer.append(';');		
+		buffer.append(';');
 	}
 
 	private void disassemble(IRequiresInfo iRequiresInfo, StringBuffer buffer, String lineSeparator, int tabNumber) {
 		buffer.append("requires "); //$NON-NLS-1$
 		decodeModifiersForModuleRequires(buffer, iRequiresInfo.getRequiresFlags());
 		buffer.append(iRequiresInfo.getRequiresModuleName());
-		buffer.append(';');		
+		buffer.append(';');
 	}
 
 	private void disassembleGenericSignature(int mode, StringBuffer buffer, final char[] signature) {
@@ -1621,7 +1720,7 @@
 				} else if (CharOperation.equals(attribute.getAttributeName(),IAttributeNamesConstants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS)) {
 					disassemble((IRuntimeVisibleTypeAnnotationsAttribute) attribute, buffer, lineSeparator, tabNumber, mode);
 				} else if (CharOperation.equals(attribute.getAttributeName(),IAttributeNamesConstants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS)) {
-					disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) attribute, buffer, lineSeparator, tabNumber, mode);					
+					disassemble((IRuntimeInvisibleTypeAnnotationsAttribute) attribute, buffer, lineSeparator, tabNumber, mode);
 				} else if (attribute != lineNumberAttribute
 						&& attribute != localVariableAttribute
 						&& attribute != localVariableTypeAttribute) {
@@ -1802,6 +1901,12 @@
 					ConstantPoolEntry2 constantPoolEntry2 = (ConstantPoolEntry2) constantPoolEntry;
 					StringBuilder builder = new StringBuilder(10);
 					switch(constantPoolEntry2.getReferenceKind()) {
+						case IConstantPoolConstant.METHOD_TYPE_REF_GetField:
+							builder.append("REF_getField "); //$NON-NLS-1$
+							constantPoolEntry = (ConstantPoolEntry) constantPool.decodeEntry(constantPoolEntry2.getReferenceIndex());
+							builder.append(Messages.bind("{0}:{1}", fieldDescription(constantPoolEntry))); //$NON-NLS-1$
+							arguments[i] =  builder.toString();
+							break;
 						case IConstantPoolConstant.METHOD_TYPE_REF_InvokeStatic:
 							builder.append("invokestatic "); //$NON-NLS-1$
 							//$FALL-THROUGH$
@@ -1816,11 +1921,22 @@
 				case IConstantPoolConstant.CONSTANT_MethodType:
 					arguments[i] = new String(((ConstantPoolEntry2) constantPoolEntry).getMethodDescriptor());
 					break;
+				case IConstantPoolConstant.CONSTANT_Class:
+					arguments[i] = new String(constantPoolEntry.getClassInfoName());
+					break;
+				case IConstantPoolConstant.CONSTANT_String:
+					arguments[i] = constantPoolEntry.getStringValue();
+					break;
 			}
 		}
 		return arguments;
 	}
 
+	private String[] fieldDescription(IConstantPoolEntry constantPoolEntry) {
+		return new String[] { new String(constantPoolEntry.getFieldName()),
+				new String(constantPoolEntry.getFieldDescriptor())};
+	}
+
 	private String[] methodDescription(IConstantPoolEntry constantPoolEntry) {
 		return new String[] { new String(constantPoolEntry.getClassName()),
 				new String(constantPoolEntry.getMethodName()),
@@ -1986,7 +2102,7 @@
 			}
 		}
 	}
-	
+
 	private String getReferenceKind(int referenceKind) {
 		String message = null;
 		switch(referenceKind) {
@@ -2355,7 +2471,7 @@
 			disassemble(i, parameterAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode);
 		}
 	}
-	
+
 	private void disassemble(IRuntimeInvisibleTypeAnnotationsAttribute runtimeInvisibleTypeAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
 		buffer.append(Messages.disassembler_runtimeinvisibletypeannotationsattributeheader);
@@ -2364,7 +2480,7 @@
 			disassemble(extendedAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode);
 		}
 	}
-		
+
 	private void disassemble(IRuntimeVisibleAnnotationsAttribute runtimeVisibleAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
 		buffer.append(Messages.disassembler_runtimevisibleannotationsattributeheader);
@@ -2382,7 +2498,7 @@
 			disassemble(i, parameterAnnotations[i], buffer, lineSeparator, tabNumber + 1, mode);
 		}
 	}
-	
+
 	private void disassemble(IRuntimeVisibleTypeAnnotationsAttribute runtimeVisibleTypeAnnotationsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) {
 		writeNewLine(buffer, lineSeparator, tabNumber + 1);
 		buffer.append(Messages.disassembler_runtimevisibletypeannotationsattributeheader);
@@ -2767,6 +2883,13 @@
 		CharOperation.replace(fieldDescriptorSignature, '%', '$');
 		return fieldDescriptorSignature;
 	}
+	private char[] getSignatureForComponent(char[] componentDescriptor) {
+		char[] newComponentDescriptor = CharOperation.replaceOnCopy(componentDescriptor, '/', '.');
+		newComponentDescriptor = CharOperation.replaceOnCopy(newComponentDescriptor, '$', '%');
+		char[] componentDescriptorSignature = Signature.toCharArray(newComponentDescriptor);
+		CharOperation.replace(componentDescriptorSignature, '%', '$');
+		return componentDescriptorSignature;
+	}
 
 	private boolean isDeprecated(IClassFileReader classFileReader) {
 		IClassFileAttribute[] attributes = classFileReader.getAttributes();
@@ -2816,7 +2939,7 @@
 		buffer.append(lineSeparator);
 		dumpTab(tabNumber, buffer);
 	}
-	
+
 	private String toTypePathString(int[][] typepath) {
 		StringBuffer buffer = new StringBuffer();
 		buffer.append('[');
@@ -2847,7 +2970,7 @@
 			}
 		}
 		buffer.append(']');
-		return String.valueOf(buffer);	
+		return String.valueOf(buffer);
 	}
 
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExtendedAnnotation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExtendedAnnotation.java
index 078f80e..58b7a53 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExtendedAnnotation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ExtendedAnnotation.java
@@ -76,7 +76,7 @@
 	private int parameterIndex;
 	private int exceptionTableIndex;
 	private ILocalVariableReferenceInfo[] localVariableTable = NO_LOCAL_VARIABLE_TABLE_ENTRIES;
-	
+
 	/**
 	 * Constructor for ExtendedAnnotation, builds an annotation from the supplied bytestream.
 	 *
@@ -94,7 +94,7 @@
 		int index = u1At(classFileBytes,0,offset);
 		this.targetType = index;
 		this.readOffset = 1;
-		
+
 		readTargetInfo(index, classFileBytes, constantPool, offset);
 
 		// Read type_path
@@ -111,7 +111,7 @@
 				typePathEntry[1] = u1At(classFileBytes, this.readOffset++, offset);
 			}
 		}
-		
+
 		// Read annotation
 		index = u2At(classFileBytes, this.readOffset, offset);
 		this.typeIndex = index;
@@ -142,7 +142,7 @@
 			this.annotationTypeIndex = -1;
 		}
 	}
-	
+
 	private void readTargetInfo(
 			int localTargetType,
 			byte[] classFileBytes,
@@ -167,24 +167,24 @@
 				this.typeParameterBoundIndex = u1At(classFileBytes, this.readOffset, localOffset);
 				this.readOffset++;
 				break;
-				
+
 			case IExtendedAnnotationConstants.FIELD :
 			case IExtendedAnnotationConstants.METHOD_RETURN :
 			case IExtendedAnnotationConstants.METHOD_RECEIVER :
 				// nothing to do, target_info is empty_target
 				break;
-				
+
 			case IExtendedAnnotationConstants.METHOD_FORMAL_PARAMETER :
 				this.parameterIndex = u1At(classFileBytes, this.readOffset, localOffset);
 				this.readOffset++;
 				break;
-				
+
 			case IExtendedAnnotationConstants.THROWS :
 				this.annotationTypeIndex = u2At(classFileBytes, this.readOffset, localOffset);
 				this.readOffset+=2;
 				break;
 
-				
+
 			case IExtendedAnnotationConstants.LOCAL_VARIABLE :
 			case IExtendedAnnotationConstants.RESOURCE_VARIABLE :
 				int tableLength = u2At(classFileBytes, this.readOffset, localOffset);
@@ -207,11 +207,11 @@
 			case IExtendedAnnotationConstants.CONSTRUCTOR_REFERENCE :
 				this.offset = u2At(classFileBytes, this.readOffset, localOffset);
 				this.readOffset += 2;
-				break;	
+				break;
 
 			case IExtendedAnnotationConstants.CAST :
 				this.offset = u2At(classFileBytes, this.readOffset, localOffset);
-				this.readOffset += 2; 
+				this.readOffset += 2;
 				// read type_argument_index
 				this.annotationTypeIndex = u1At(classFileBytes, this.readOffset, localOffset);
 				this.readOffset++;
@@ -258,7 +258,7 @@
 	public int getTargetType() {
 		return this.targetType;
 	}
-	
+
 	@Override
 	public int getExceptionTableIndex() {
 		return this.exceptionTableIndex;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
index 51cfb8e..afed2c1 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HandleFactory.java
@@ -45,7 +45,6 @@
 import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
 import org.eclipse.jdt.internal.core.*;
 import org.eclipse.jdt.internal.core.search.AbstractJavaSearchScope;
-import org.eclipse.jdt.internal.core.util.Util;
 
 /**
  * Creates java element handles.
@@ -105,7 +104,7 @@
 			String module = null;
 			String rootPath = this.lastPkgFragmentRoot.getPath().toOSString();
 			if (org.eclipse.jdt.internal.compiler.util.Util.isJrt(rootPath)) {
-				module = resourcePath.substring(separatorIndex + 1, 
+				module = resourcePath.substring(separatorIndex + 1,
 						(separatorIndex = resourcePath.lastIndexOf(IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR)));
 			}
 			String classFilePath= resourcePath.substring(separatorIndex + 1);
@@ -241,7 +240,7 @@
 				if (scope.isLambdaScope()) {
 					parentElement = createElement(scope.parent, elementPosition, unit, existingElements, knownScopes);
 					LambdaExpression expression = (LambdaExpression) scope.originalReferenceContext();
-					if (expression.resolvedType != null && expression.resolvedType.isValidBinding() && 
+					if (expression.resolvedType != null && expression.resolvedType.isValidBinding() &&
 							!(expression.descriptor instanceof ProblemMethodBinding)) { // chain in lambda element only if resolved properly.
 						//newElement = new org.eclipse.jdt.internal.core.SourceLambdaExpression((JavaElement) parentElement, expression).getMethod();
 						newElement = LambdaFactory.createLambdaExpression((JavaElement) parentElement, expression).getMethod();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HashtableOfArrayToObject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HashtableOfArrayToObject.java
index e3984a7..b1a180b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HashtableOfArrayToObject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/HashtableOfArrayToObject.java
@@ -100,7 +100,7 @@
 		}
 		return -1;
 	}
-	
+
 	public Object[] getKey(Object[] key, int keyLength) {
 		int length = this.keyTable.length;
 		int index = hashCode(key, keyLength) % length;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java
index 744396e..52af349 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MementoTokenizer.java
@@ -63,9 +63,9 @@
 			case JavaElement.JEM_COUNT:
 				return COUNT;
 			case JavaElement.JEM_JAVAPROJECT:
-				// Also covers JavaElement#JEM_DELIMITER_ESCAPE, in which case, 
+				// Also covers JavaElement#JEM_DELIMITER_ESCAPE, in which case,
 				// we seek ahead by one char and check if it's an escaped delimiter
-				// and if that's true, we return that as the token. 
+				// and if that's true, we return that as the token.
 				// Else, we decide that JEM_JAVAPROJECT is the current token.
 				if (this.index < this.length) {
 					char nextChar = this.memento[this.index++];
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
index a75bd65..989b64b 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
@@ -281,6 +281,9 @@
 	public static String disassembler_inner_accessflags;
 	public static String disassembler_nesthost;
 	public static String disassembler_nestmembers;
+	public static String disassembler_record;
+	public static String disassembler_components;
+	public static String disassembler_endofcomponent;
 	public static String disassembler_genericattributeheader;
 	public static String disassembler_signatureattributeheader;
 	public static String disassembler_bootstrapmethodattributesheader;
@@ -403,6 +406,7 @@
 	public static String classfileformat_linenumbertableentry;
 	public static String classfileformat_localvariabletableentry;
 	public static String classfileformat_versionUnknown;
+	public static String classfileformat_componentdescriptor;
 
 	public static String disassembler_frame_same_locals_1_stack_item_extended;
 	public static String disassembler_frame_chop;
@@ -412,7 +416,7 @@
 	public static String disassembler_frame_same_frame;
 	public static String disassembler_frame_same_locals_1_stack_item;
 	public static String internal_error;
-	
+
 	public static String disassembler_method_type_ref_getfield;
 	public static String disassembler_method_type_ref_putfield;
 	public static String disassembler_method_type_ref_getstatic;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MethodParametersAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MethodParametersAttribute.java
index 8ee67ab..7cc80b5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MethodParametersAttribute.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/MethodParametersAttribute.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     Jesper Steen Moeller - initial API and implementation
  *******************************************************************************/
@@ -27,15 +27,15 @@
 
 	private static final char[][] NO_NAMES = new char[0][];
 	private static final short[] NO_ACCES_FLAGS = new short[0];
-	
+
 	private final int numberOfEntries;
 	private final char[][] names;
 	private final short[] accessFlags;
-	
+
 
 	MethodParametersAttribute(byte[] classFileBytes, IConstantPool constantPool, int offset) throws ClassFormatException {
 		super(classFileBytes, constantPool, offset);
-		
+
 		final int length = u1At(classFileBytes, 6, offset);
 		this.numberOfEntries = length;
 		if (length != 0) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ModuleUtil.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ModuleUtil.java
index cba6c05..c6268bd 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ModuleUtil.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ModuleUtil.java
@@ -123,7 +123,7 @@
 						if (units.length != 0) {
 							String pack = fragment.getElementName();
 							for (ICompilationUnit iUnit : units) {
-								org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceFile = 
+								org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceFile =
 										new BasicCompilationUnit(iUnit.getSource().toCharArray(),
 												CharOperation.splitOn('.', pack.toCharArray()),
 												iUnit.getPath().toOSString(),
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/NestMembersAttributeEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/NestMembersAttributeEntry.java
index 5456c78..7185085 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/NestMembersAttributeEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/NestMembersAttributeEntry.java
@@ -43,7 +43,7 @@
 	public int getNestMemberIndex() {
 		return this.memberClassNameIndex;
 	}
-	
+
 	@Override
 	public String toString() {
 		return new String(this.memberClassName);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java
index 13c78fd..d7d6bc3 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/PublicScanner.java
@@ -806,14 +806,14 @@
 }
 /*
  * This method consumes digits as well as underscores if underscores are located between digits
- * @throws InvalidInputException if underscores are not located between digits or if underscores are used in source < 1.7 
+ * @throws InvalidInputException if underscores are not located between digits or if underscores are used in source < 1.7
  */
 private final void consumeDigits(int radix) throws InvalidInputException {
 	consumeDigits(radix, false);
 }
 /*
  * This method consumes digits as well as underscores if underscores are located between digits
- * @throws InvalidInputException if underscores are not located between digits or if underscores are used in source < 1.7 
+ * @throws InvalidInputException if underscores are not located between digits or if underscores are used in source < 1.7
  */
 private final void consumeDigits(int radix, boolean expectingDigitFirst) throws InvalidInputException {
 	final int USING_UNDERSCORE = 1;
@@ -2074,7 +2074,7 @@
 											firstClosingBrace = this.currentPosition;
 										break;
 									case '\r' :
-										if (this.source[this.currentPosition] == '\n') 
+										if (this.source[this.currentPosition] == '\n')
 											this.currentPosition++;
 										//$FALL-THROUGH$
 									case '\n' :
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RecordAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RecordAttribute.java
new file mode 100644
index 0000000..df63810
--- /dev/null
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/RecordAttribute.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2019 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
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.util;
+
+import org.eclipse.jdt.core.util.ClassFormatException;
+import org.eclipse.jdt.core.util.IComponentInfo;
+import org.eclipse.jdt.core.util.IConstantPool;
+import org.eclipse.jdt.core.util.IRecordAttribute;
+
+/**
+ * Default implementation of {@link IRecordAttribute}.
+ */
+public class RecordAttribute extends ClassFileAttribute implements IRecordAttribute {
+	private static final IComponentInfo[] NO_ENTRIES = new IComponentInfo[0];
+
+	private int nComponents;
+	private IComponentInfo[] entries;
+
+	public RecordAttribute(
+		byte[] classFileBytes,
+		IConstantPool constantPool,
+		int offset)
+		throws ClassFormatException {
+		super(classFileBytes, constantPool, offset);
+		this.nComponents = u2At(classFileBytes, 6, offset);
+		final int length = this.nComponents;
+		if (length != 0) {
+			int readOffset = 8;
+			this.entries = new IComponentInfo[length];
+			for (int i = 0; i < length; i++) {
+				this.entries[i] = new ComponentInfo(classFileBytes, constantPool, offset + readOffset);
+				readOffset += this.entries[i].sizeInBytes();
+			}
+		} else {
+			this.entries = NO_ENTRIES;
+		}
+	}
+
+	@Override
+	public int getNumberOfComponents() {
+		return this.nComponents;
+	}
+
+	@Override
+	public IComponentInfo[] getComponentInfos() {
+		return this.entries;
+	}
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
index 2b323ea..9ec1f1d 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Util.java
@@ -41,6 +41,7 @@
 import org.eclipse.jdt.core.util.IClassFileAttribute;
 import org.eclipse.jdt.core.util.IClassFileReader;
 import org.eclipse.jdt.core.util.ICodeAttribute;
+import org.eclipse.jdt.core.util.IComponentInfo;
 import org.eclipse.jdt.core.util.IFieldInfo;
 import org.eclipse.jdt.core.util.IMethodInfo;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
@@ -742,6 +743,15 @@
 		}
 		return null;
 	}
+	public static IClassFileAttribute getAttribute(IComponentInfo componentInfo, char[] attributeName) {
+		IClassFileAttribute[] attributes = componentInfo.getAttributes();
+		for (int i = 0, max = attributes.length; i < max; i++) {
+			if (CharOperation.equals(attributes[i].getAttributeName(), attributeName)) {
+				return attributes[i];
+			}
+		}
+		return null;
+	}
 
 	public static IClassFileAttribute getAttribute(IMethodInfo methodInfo, char[] attributeName) {
 		IClassFileAttribute[] attributes = methodInfo.getAttributes();
@@ -922,7 +932,7 @@
 				if (lineSeparator != null)
 					return lineSeparator;
 			}
-	
+
 			// line delimiter in workspace preference
 			scopeContext= new IScopeContext[] { InstanceScope.INSTANCE };
 			lineSeparator = Platform.getPreferencesService().getString(Platform.PI_RUNTIME, Platform.PREF_LINE_SEPARATOR, null, scopeContext);
@@ -1038,7 +1048,7 @@
 
 	/**
 	 * Encode the argument by doubling the '#' if present into the argument value.
-	 * 
+	 *
 	 * <p>This stores the encoded argument into the given buffer.</p>
 	 *
 	 * @param argument the given argument
@@ -2717,7 +2727,7 @@
 		}
 		return signature;
 	}
-	
+
 	private static String[] typeSignatures(TypeReference[] types) {
 		int length = types.length;
 		String[] typeSignatures = new String[length];
@@ -2827,7 +2837,7 @@
 		char[] typeName = org.eclipse.jdt.core.Signature.toCharArray(CharOperation.replaceOnCopy(binaryAnnotation.getTypeName(), '/', '.'));
 		return new Annotation(parent, new String(typeName), memberValuePairName);
 	}
-	
+
 	public static Object getAnnotationMemberValue(JavaElement parent, MemberValuePair memberValuePair, Object binaryValue) {
 		if (binaryValue instanceof Constant) {
 			return getAnnotationMemberValue(memberValuePair, (Constant) binaryValue);
@@ -2916,7 +2926,7 @@
 				return null;
 		}
 	}
-	
+
 	/*
 	 * Creates a member value from the given constant in case of negative numerals,
 	 * and sets the valueKind on the given memberValuePair
@@ -3312,8 +3322,8 @@
 		}
 	}
 	/**
-	 * Finds the IMethod element corresponding to the given selector, 
-	 * without creating a new dummy instance of a binary method. 
+	 * Finds the IMethod element corresponding to the given selector,
+	 * without creating a new dummy instance of a binary method.
 	 * @param type the type in which the method is declared
 	 * @param selector the method name
 	 * @param paramTypeSignatures the type signatures of the method arguments
@@ -3326,7 +3336,7 @@
 		int startingIndex = 0;
 		String[] args;
 		IType enclosingType = type.getDeclaringType();
-		// If the method is a constructor of a non-static inner type, add the enclosing type as an 
+		// If the method is a constructor of a non-static inner type, add the enclosing type as an
 		// additional parameter to the constructor
 		if (enclosingType != null
 				&& isConstructor
@@ -3342,7 +3352,7 @@
 			args[i] = paramTypeSignatures[i-startingIndex];
 		}
 		method = type.getMethod(new String(selector), args);
-		
+
 		IMethod[] methods = type.findMethods(method);
 		if (methods != null && methods.length > 0) {
 			method = methods[0];
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
index 725a1cc..cb269da 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
@@ -301,6 +301,9 @@
 disassembler_arraydimensions = []
 disassembler_nesthost = Nest Host:
 disassembler_nestmembers = Nest Members:
+disassembler_record = Record:
+disassembler_components = Components:
+disassembler_endofcomponent = ;
 disassembler_innerattributesheader = Inner classes:
 disassembler_inner_class_info_name = inner class info:
 disassembler_outer_class_info_name = outer class info:
@@ -412,6 +415,7 @@
 classfileformat_clinitname = '{'}
 classformat_classformatexception = Class Format Exception
 classfileformat_versionUnknown = unknown
+classfileformat_componentdescriptor = // Component descriptor #{0} {1}
 
 ### string displayed for each opcode
 classformat_anewarray = {0} {2} [{1}]
diff --git a/org.eclipse.jdt.core/plugin.xml b/org.eclipse.jdt.core/plugin.xml
index 315397d..b2365fb 100644
--- a/org.eclipse.jdt.core/plugin.xml
+++ b/org.eclipse.jdt.core/plugin.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?eclipse version="3.0"?>
 <!--
-    Copyright (c) 2004, 2014 IBM Corporation and others.
+    Copyright (c) 2004, 2020 IBM Corporation and others.
 
     This program and the accompanying materials
     are made available under the terms of the Eclipse Public License 2.0
@@ -13,6 +13,7 @@
     Contributors:
         IBM Corporation - initial API and implementation
         Harry Terkelsen (het@google.com) - Bug 449262 - Allow the use of third-party Java formatters
+        Jonah Graham - Bug 543363 - Move Java Code Formatter to its own bundle
  -->
 
 <!-- =================================================================================== -->
@@ -214,17 +215,6 @@
 </extension>
 
 <!-- =================================================================================== -->
-<!-- Extension: Java Code Formatter                                                      -->
-<!-- =================================================================================== -->
-<extension
-      id="JavaCodeFormatter"
-      point="org.eclipse.core.runtime.applications">
-      	<application>
-      		<run class="org.eclipse.jdt.core.formatter.CodeFormatterApplication" />
-		</application>
-</extension>
-
-<!-- =================================================================================== -->
 <!-- Extension: Java Generate Indexer                                                    -->
 <!-- =================================================================================== -->
 <extension
diff --git a/org.eclipse.jdt.core/pom.xml b/org.eclipse.jdt.core/pom.xml
index c2ce2e6..f59c0f2 100644
--- a/org.eclipse.jdt.core/pom.xml
+++ b/org.eclipse.jdt.core/pom.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-  Copyright (c) 2012, 2019 Eclipse Foundation and others.
+  Copyright (c) 2012, 2020 Eclipse Foundation and others.
   All rights reserved. This program and the accompanying materials
   are made available under the terms of the Eclipse Distribution License v1.0
   which accompanies this distribution, and is available at
@@ -14,11 +14,11 @@
   <parent>
     <artifactId>eclipse.jdt.core</artifactId>
     <groupId>eclipse.jdt.core</groupId>
-    <version>4.14.0-SNAPSHOT</version>
+    <version>4.16.0-SNAPSHOT</version>
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.core</artifactId>
-  <version>3.20.0-SNAPSHOT</version>
+  <version>3.22.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 
   <properties>
@@ -34,14 +34,14 @@
 			<execution>
 				<phase>prepare-package</phase>
 				<configuration>
-					<tasks>
+					<target>
 						<replace token="bundle_qualifier," value="${buildQualifier}," dir="${project.build.directory}/classes">
 							<include name="org/eclipse/jdt/internal/compiler/batch/messages.properties"/>
 						</replace>
 						<replace token="bundle_version" value="${unqualifiedVersion}" dir="${project.build.directory}/classes">
 							<include name="org/eclipse/jdt/internal/compiler/batch/messages.properties"/>
 						</replace>
-					</tasks>
+					</target>
 				</configuration>
 				<goals>
 					<goal>run</goal>
diff --git a/org.eclipse.jdt.core/scripts/GenerateBuildScript.java b/org.eclipse.jdt.core/scripts/GenerateBuildScript.java
index 4c19a8d..8cee0ab 100644
--- a/org.eclipse.jdt.core/scripts/GenerateBuildScript.java
+++ b/org.eclipse.jdt.core/scripts/GenerateBuildScript.java
@@ -75,7 +75,7 @@
 		writer.write("        <echo message=\"compiling resources   -> .o\"/>" + LINE_SEPARATOR); //$NON-NLS-1$
 		for (int i = 0, max = collector.size(); i < max; i++) {
 			String absolutePath = (String) collector.get(i);
-			String fileName = absolutePath.substring(sourceDir.getAbsolutePath().length() + 1); 
+			String fileName = absolutePath.substring(sourceDir.getAbsolutePath().length() + 1);
 			writer.write(MessageFormat.format("  		<exec dir=\"{1}\" executable=\"$'{'gcc-path'}'/bin/{0}\">" + LINE_SEPARATOR, new Object[] { gcj_exe, dest_dir})); //$NON-NLS-1$
 			writer.write("  		<arg line=\"--resource "); //$NON-NLS-1$
 			writer.write(fileName + " " + fileName + " -c -o " + getObjectName(fileName) + "\"/>" + LINE_SEPARATOR); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
@@ -110,7 +110,7 @@
 	private static String getObjectName(String fileName) {
 		return fileName.substring(0, fileName.lastIndexOf('.')) + ".o"; //$NON-NLS-1$
 	}
-			
+
 	public static void main(String[] args) {
 		if (args.length != 5) {
 			System.out.println("Usage: script_name directory gcj_exe_name dest_dir source/bin"); //$NON-NLS-1$
@@ -120,7 +120,7 @@
 			BufferedWriter writer = new BufferedWriter(new FileWriter(new File(args[0])));
 			writer.write(HEADER);
 			File sourceDir = new File(args[1]);
-			if (sourceDir.exists()) { 
+			if (sourceDir.exists()) {
 				ArrayList collector = new ArrayList();
 				collectAllFiles(sourceDir, collector, new FileFilter() {
 					public boolean accept(File pathname) {
@@ -139,7 +139,7 @@
 							return pathname.isDirectory() || fileName.endsWith(".class"); //$NON-NLS-1$
 						}
 					});
-					dumpAllClassFiles(writer, sourceDir, collector, args[2], args[3]);				
+					dumpAllClassFiles(writer, sourceDir, collector, args[2], args[3]);
 				}
 			}
 			writer.write(MessageFormat.format(FOOTER, new Object[] {args[2], args[3]}));
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexer.java
index 64351fa..5d9f52f 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexer.java
@@ -21,7 +21,7 @@
 /**
  * {@link JavaIndexer} provides functionality to generate index files which can be used by the JDT {@link SearchEngine}.
  * The generated index files can be used as a classpath attribute for the particular classpath entry.
- * 
+ *
  * <p> The search engine indexes all the elements referred in the classpath entries of the project into
  * index files. These index files are used to search the elements faster. Indexing for bigger jars could
  * take some time. To avoid this time, one can generate the index file and specify it when the jar is added
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexerApplication.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexerApplication.java
index c552c3c..9b00a10 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexerApplication.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/index/JavaIndexerApplication.java
@@ -7,7 +7,7 @@
  *  https://www.eclipse.org/legal/epl-2.0/
  *
  *  SPDX-License-Identifier: EPL-2.0
- * 
+ *
  *  Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
@@ -24,14 +24,14 @@
 
 /**
  * Implements an Eclipse Application for {@link org.eclipse.jdt.core.index.JavaIndexer}.
- * 
+ *
  * <p>
  * On MacOS, when invoked using the Eclipse executable, the "user.dir" property is set to the folder in which the
  * eclipse.ini file is located. This makes it harder to use relative paths to point to the files to be jar'd or to
  * the index file that is generated.
  * </p>
- * 
- * 
+ *
+ *
  * @since 3.8
  * @noinstantiate This class is not intended to be instantiated by clients.
  * @noextend This class is not intended to be subclassed by clients.
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/MethodNameRequestor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/MethodNameRequestor.java
index 27e9b71..1be01eb 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/MethodNameRequestor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/MethodNameRequestor.java
@@ -14,27 +14,27 @@
 package org.eclipse.jdt.core.search;
 
  /**
-  * 
+  *
   * A <code> MethodDeclarationRequestor</code> collects search results from a <code> searchAllMethodDeclarations</code>
   * query to a <code>SearchEngine</code>. Clients must subclass this abstract class and pass an instance to the
-  * <code>SearchEngine.searchAllMethodDeclarations</code> method. 
-  * 
+  * <code>SearchEngine.searchAllMethodDeclarations</code> method.
+  *
   * <p>
   * This class may be subclassed by clients
   * </p>
  * @since 3.12
-  * 
+  *
   */
 public abstract class MethodNameRequestor {
-	
+
 	/**
 	 * Accepts a method.
-	 * 
+	 *
 	 * <p>
-	 * The default implementation of this method does nothing. 
+	 * The default implementation of this method does nothing.
 	 * Subclasses should override.
 	 * </p>
-	 * 
+	 *
 	 * @param methodName name of the method.
 	 * @param parameterCount number of parameters in this method.
 	 * @param declaringQualifier the qualified name of parent of the enclosing type of this method.
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ModuleReferenceMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ModuleReferenceMatch.java
index 1e99e6a..e88a6a8 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ModuleReferenceMatch.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ModuleReferenceMatch.java
@@ -7,7 +7,7 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ReferenceMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ReferenceMatch.java
index 0a55569..afefd39 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ReferenceMatch.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/ReferenceMatch.java
@@ -18,7 +18,7 @@
 
 /**
  * An abstract Java search match that represents a reference.
- * 
+ *
  * @since 3.4
  */
 public abstract class ReferenceMatch extends SearchMatch {
@@ -125,7 +125,7 @@
  * Store the local element in the match.
  *
  * @param element The local element to be stored
- * 
+ *
  * @since 3.5
  */
 final public void setLocalElement(IJavaElement element) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchDocument.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchDocument.java
index e2bdb3b..730db15 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchDocument.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchDocument.java
@@ -121,7 +121,7 @@
 	public SourceElementParser getParser() {
 		return this.parser;
 	}
-	
+
 	/**
 	 * Returns the participant that created this document.
 	 *
@@ -151,7 +151,7 @@
 		if (this.index != null)
 			this.index.remove(getContainerRelativePath());
 	}
-	
+
 	/**
 	 * @nooverride This method is not intended to be re-implemented or extended by clients.
 	 * @noreference This method is not intended to be referenced by clients.
@@ -159,7 +159,7 @@
 	public void setIndex(Index indexToSet) {
 		this.index = indexToSet;
 	}
-	
+
 	/**
 	 * @nooverride This method is not intended to be re-implemented or extended by clients.
 	 * @noreference This method is not intended to be referenced by clients.
@@ -168,16 +168,16 @@
 		this.parser = sourceElementParser;
 	}
 
-	/** Flags the document as requiring indexing after symbol and type resolution. A participant would be asked 
-	 *  to resolve the document via {@link SearchParticipant#resolveDocument} and to index the document adding 
-	 *  additional entries via {@link SearchParticipant#indexResolvedDocument} 
-	 *  
-	 * @since 3.10 
+	/** Flags the document as requiring indexing after symbol and type resolution. A participant would be asked
+	 *  to resolve the document via {@link SearchParticipant#resolveDocument} and to index the document adding
+	 *  additional entries via {@link SearchParticipant#indexResolvedDocument}
+	 *
+	 * @since 3.10
 	 */
 	public void requireIndexingResolvedDocument() {
 		this.shouldIndexResolvedDocument = true;
 	}
-	
+
 	/**
 	 * @nooverride This method is not intended to be re-implemented or extended by clients.
 	 * @noreference This method is not intended to be referenced by clients.
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
index 19d37e3..e845aeb 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
@@ -206,16 +206,16 @@
 	 * <p>
 	 * By default, hierarchy scopes include all direct and indirect supertypes and subtypes of the
 	 * focus type. This method, however, allows to restrict the hierarchy to true subtypes,
-	 * and exclude supertypes. Also, inclusion of the focus type itself is controlled by a parameter. 
+	 * and exclude supertypes. Also, inclusion of the focus type itself is controlled by a parameter.
 	 * </p>
-	 * 
+	 *
 	 * @param project the project to which to constrain the search, or <code>null</code> if
-	 *        search should consider all types in the workspace 
+	 *        search should consider all types in the workspace
 	 * @param type the focus of the hierarchy scope
 	 * @param onlySubtypes if <code>true</code> only subtypes of <code>type</code> are considered
-	 * @param includeFocusType if true the focus type <code>type</code> is included in the resulting scope, 
+	 * @param includeFocusType if true the focus type <code>type</code> is included in the resulting scope,
 	 * 		  otherwise it is excluded
-	 * @param owner the owner of working copies that take precedence over original compilation units, 
+	 * @param owner the owner of working copies that take precedence over original compilation units,
 	 *        or <code>null</code> if the primary working copy owner should be used
 	 * @return a new hierarchy scope
 	 * @exception JavaModelException if the hierarchy could not be computed on the given type
@@ -507,8 +507,8 @@
 	/**
 	 * Create a method name match on a given method with specific modifiers.
 	 * <p>
-	 * NOTE: this is a first-cut version and might have noticeable delay times in some cases. 
-	 * Targeted for optimization during 4.7. It is recommended to contact JDT Team if 
+	 * NOTE: this is a first-cut version and might have noticeable delay times in some cases.
+	 * Targeted for optimization during 4.7. It is recommended to contact JDT Team if
 	 * anyone plans to use this.
 	 * </p>
 	 * @param method The Java model handle of the method
@@ -674,11 +674,11 @@
 	 * Searches for all method declarations in the given scope. Accepted matches will be returned by
 	 * {@link MethodNameRequestor#acceptMethod}.
 	 * <p>
-	 * NOTE: this is a first-cut version and might have noticeable delay times in some cases. 
-	 * Targeted for optimization during 4.7. It is recommended to contact JDT Team if 
+	 * NOTE: this is a first-cut version and might have noticeable delay times in some cases.
+	 * Targeted for optimization during 4.7. It is recommended to contact JDT Team if
 	 * anyone plans to use this.
 	 * </p>
-	 * 
+	 *
 	 * @param packageName the full name of the package of the searched types, or a prefix for this
 	 *						package, or a wild-carded string for this package.
 	 *						May be <code>null</code>, then any package name is accepted.
@@ -702,7 +702,7 @@
 	 * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
 	 *							monitor is provided
 	 * @exception JavaModelException if the search failed.
-	 * 
+	 *
 	 * @since 3.12
 	 */
 	public void searchAllMethodNames(
@@ -720,27 +720,27 @@
 			IProgressMonitor progressMonitor)  throws JavaModelException {
 		MethodNameRequestorWrapper requestorWrapper = new MethodNameRequestorWrapper(nameRequestor);
 		this.basicEngine.searchAllMethodNames(
-				packageName, pkgMatchRule, 
-				declaringQualification, declQualificationMatchRule, 
-				declaringSimpleName, declSimpleNameMatchRule, 
-				methodName, methodMatchRule, 
-				scope, requestorWrapper, 
+				packageName, pkgMatchRule,
+				declaringQualification, declQualificationMatchRule,
+				declaringSimpleName, declSimpleNameMatchRule,
+				methodName, methodMatchRule,
+				scope, requestorWrapper,
 				waitingPolicy, progressMonitor);
 	}
 
 	/**
-	 * Searches for all method declarations in the given scope. 
+	 * Searches for all method declarations in the given scope.
 	 * <p>
 	 * Provided {@link MethodNameMatchRequestor} requestor will collect the {@link MethodNameMatch}
 	 * matches found during the search.
 
 	 * </p>
 	 * <p>
-	 * NOTE: this is a first-cut version and might have noticeable delay times in some cases. 
-	 * Targeted for optimization during 4.7. It is recommended to contact JDT Team if 
+	 * NOTE: this is a first-cut version and might have noticeable delay times in some cases.
+	 * Targeted for optimization during 4.7. It is recommended to contact JDT Team if
 	 * anyone plans to use this.
 	 * </p>
-	 * 
+	 *
 	 * @param packageName the full name of the package of the searched types, or a prefix for this
 	 *						package, or a wild-carded string for this package.
 	 *						May be <code>null</code>, then any package name is accepted.
@@ -764,7 +764,7 @@
 	 * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
 	 *							monitor is provided
 	 * @exception JavaModelException if the search failed.
-	 * 
+	 *
 	 * @since 3.12
 	 */
 	public void searchAllMethodNames(
@@ -786,7 +786,7 @@
 				declaringQualification, declQualificationMatchRule,
 				declaringSimpleName, declSimpleNameMatchRule,
 				methodName, methodMatchRule,
-				scope, requestorWrapper, 
+				scope, requestorWrapper,
 				waitingPolicy, progressMonitor);
 	}
 
@@ -794,11 +794,11 @@
 	 * Searches for all method declarations in the given scope. Accepted matches will be returned by
 	 * {@link MethodNameRequestor#acceptMethod}.
 	 * <p>
-	 * NOTE: this is a first-cut version and might have noticeable delay times in some cases. 
-	 * Targeted for optimization during 4.7. It is recommended to contact JDT Team if 
+	 * NOTE: this is a first-cut version and might have noticeable delay times in some cases.
+	 * Targeted for optimization during 4.7. It is recommended to contact JDT Team if
 	 * anyone plans to use this.
 	 * </p>
-	 * 
+	 *
 	 * @param qualifier qualifier including package name and qualified type name
 	 *	May be <code>null</code>, then any qualifier name is accepted.
 	 * @param qualifierMatchRule match rule for the qualifier and can be one of
@@ -812,7 +812,7 @@
 	 *		<li>{@link SearchPattern#R_CAMELCASE_MATCH} if the package name and types are
 	 *			camel case of the package and type of searched methods.</li>
 	 *		<li>{@link SearchPattern#R_CAMELCASE_SAME_PART_COUNT_MATCH}
-	 *			if the package name and type names are camel case with same part count of the 
+	 *			if the package name and type names are camel case with same part count of the
 	 *			package and types of searched methods.</li>
 	 * </ul>
 	 * @param methodName the method name searched for.
@@ -822,7 +822,7 @@
 	 *			is exact.</li>
 	 *		<li>{@link SearchPattern#R_PREFIX_MATCH} if method
 	 *			name is prefix of the names of the searched methods.</li>
-	 *		<li>{@link SearchPattern#R_PATTERN_MATCH} if the method name 
+	 *		<li>{@link SearchPattern#R_PATTERN_MATCH} if the method name
 	 *			contains wild-cards.</li>
 	 *		<li>{@link SearchPattern#R_CAMELCASE_MATCH} if the method name is a
 	 *			camel case of the searched method name.</li>
@@ -843,7 +843,7 @@
 	 * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
 	 *							monitor is provided
 	 * @exception JavaModelException if the search failed.
-	 * 
+	 *
 	 * @since 3.12
 	 */
 	public void searchAllMethodNames(
@@ -857,24 +857,24 @@
 			IProgressMonitor progressMonitor)  throws JavaModelException {
 		MethodNameRequestorWrapper requestorWrapper = new MethodNameRequestorWrapper(nameRequestor);
 		this.basicEngine.searchAllMethodNames(
-				qualifier, qualifierMatchRule, 
-				methodName, methodMatchRule, 
-				scope, requestorWrapper, 
+				qualifier, qualifierMatchRule,
+				methodName, methodMatchRule,
+				scope, requestorWrapper,
 				waitingPolicy, progressMonitor);
 	}
 
 	/**
-	 * Searches for all method declarations in the given scope. 
+	 * Searches for all method declarations in the given scope.
 	 * <p>
 	 * Provided {@link MethodNameMatchRequestor} requestor will collect the {@link MethodNameMatch}
 	 * matches found during the search.
 	 * </p>
 	 * <p>
-	 * NOTE: this is a first-cut version and might have noticeable delay times in some cases. 
-	 * Targeted for optimization during 4.7. It is recommended to contact JDT Team if 
+	 * NOTE: this is a first-cut version and might have noticeable delay times in some cases.
+	 * Targeted for optimization during 4.7. It is recommended to contact JDT Team if
 	 * anyone plans to use this.
 	 * </p>
-	 * 
+	 *
 	 * @param qualifier qualifier including package name and qualified type name
 	 *	May be <code>null</code>, then any qualifier name is accepted.
 	 * @param qualifierMatchRule match rule for the qualifier and can be one of
@@ -888,7 +888,7 @@
 	 *		<li>{@link SearchPattern#R_CAMELCASE_MATCH} if the package name and types are
 	 *			camel case of the package and type of searched methods.</li>
 	 *		<li>{@link SearchPattern#R_CAMELCASE_SAME_PART_COUNT_MATCH}
-	 *			if the package name and type names are camel case with same part count of the 
+	 *			if the package name and type names are camel case with same part count of the
 	 *			package and types of searched methods.</li>
 	 * </ul>
 	 * @param methodName the method name searched for.
@@ -898,7 +898,7 @@
 	 *			is exact.</li>
 	 *		<li>{@link SearchPattern#R_PREFIX_MATCH} if method
 	 *			name is prefix of the names of the searched methods.</li>
-	 *		<li>{@link SearchPattern#R_PATTERN_MATCH} if the method name 
+	 *		<li>{@link SearchPattern#R_PATTERN_MATCH} if the method name
 	 *			contains wild-cards.</li>
 	 *		<li>{@link SearchPattern#R_CAMELCASE_MATCH} if the method name is a
 	 *			camel case of the searched method name.</li>
@@ -919,7 +919,7 @@
 	 * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
 	 *							monitor is provided
 	 * @exception JavaModelException if the search failed.
-	 * 
+	 *
 	 * @since 3.12
 	 */
 	public void searchAllMethodNames(
@@ -935,7 +935,7 @@
 		this.basicEngine.searchAllMethodNames(
 				qualifier, qualifierMatchRule,
 				methodName, methodMatchRule,
-				scope, requestorWrapper, 
+				scope, requestorWrapper,
 				waitingPolicy, progressMonitor);
 	}
 	/**
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java
index 5a9b19e..9c99967 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchParticipant.java
@@ -158,7 +158,7 @@
 	 *
 	 * @param document the document to index
 	 * @param indexLocation the location in the file system to the index
-	 * 
+	 *
 	 * @since 3.10
 	 */
 	public void indexResolvedDocument(SearchDocument document, IPath indexLocation) {
@@ -212,7 +212,7 @@
 	}
 
 	/**
-	 * Resolves the given document. A search participant asked to resolve a document should parse it and 
+	 * Resolves the given document. A search participant asked to resolve a document should parse it and
 	 * resolve the types and preserve enough state to be able to tend to a indexResolvedDocument call
 	 * subsequently. This API is invoked without holding any index related locks or monitors.
 	 * <p>
@@ -227,7 +227,7 @@
 	public void resolveDocument(SearchDocument document) {
 		// do nothing, subtypes should do the "appropriate thing"
 	}
-	
+
 	/**
 	 * Schedules the indexing of the given document.
 	 * Once the document is ready to be indexed,
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
index 7ea10a3..28b5a6e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchPattern.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -218,7 +218,7 @@
 	 * of other match rule flags are combined with this one, then match rule validation
 	 * will return a modified rule in order to perform a better appropriate search request
 	 * (see {@link #validateMatchRule(String, int)} for more details).
-	 * 
+	 *
 	 * <p>
 	 * This is implemented only for code assist and not available for normal search.
 	 *
@@ -226,6 +226,28 @@
 	 */
 	public static final int R_SUBSTRING_MATCH = 0x0200;
 
+	/**
+	 * Match rule: The search pattern contains a subword expression in a case-insensitive way.
+	 * <p>
+	 * Examples:
+	 * <ul>
+	 * 	<li>'addlist' string pattern will match
+	 * 		'addListener' and 'addChangeListener'</li>
+	 * </ul>
+	 *
+	 * This rule is not intended to be combined with any other match rule. In case
+	 * of other match rule flags are combined with this one, then match rule validation
+	 * will return a modified rule in order to perform a better appropriate search request
+	 * (see {@link #validateMatchRule(String, int)} for more details).
+	 *
+	 * <p>
+	 * This is implemented only for code assist and not available for normal search.
+	 *
+	 * @noreference This is not intended to be referenced by clients as it is a part of Java preview feature.
+	 * @since 3.21
+	 */
+	public static final int R_SUBWORD_MATCH = 0x0400;
+
 	private static final int MODE_MASK = R_EXACT_MATCH
 		| R_PREFIX_MATCH
 		| R_PATTERN_MATCH
@@ -237,7 +259,7 @@
 
 	/**
 	 * The focus element (used for reference patterns)
-	 * @noreference This field is not intended to be referenced by clients. 
+	 * @noreference This field is not intended to be referenced by clients.
 	 */
 	public IJavaElement focus;
 
@@ -245,12 +267,12 @@
 	 * @noreference This field is not intended to be referenced by clients.
 	 */
 	public int kind;
-	
+
 	/**
 	 * @noreference This field is not intended to be referenced by clients.
 	 */
 	public boolean mustResolve = true;
-	
+
 /**
  * Creates a search pattern with the rule to apply for matching index keys.
  * It can be exact match, prefix match, pattern match or regexp match.
@@ -332,14 +354,14 @@
 		String documentPath = buffer.toString();
 		boolean encloses = (scope instanceof HierarchyScope) ? ((HierarchyScope)scope).encloses(documentPath, monitor)
 							: scope.encloses(documentPath);
-		if (encloses) 
+		if (encloses)
 			if (!requestor.acceptIndexMatch(documentPath, pattern, participant, null))
 				throw new OperationCanceledException();
 
 	}
 }
 /**
- * @noreference This method is not intended to be referenced by clients. 
+ * @noreference This method is not intended to be referenced by clients.
  * @nooverride This method is not intended to be re-implemented or extended by clients.
  */
 public SearchPattern currentPattern() {
@@ -810,7 +832,7 @@
  *     <code>'?*'</code>, <code>'???'</code>, etc.) when using a pattern
  *     match rule.
  *     </p>
- * 
+ *
  * @since 3.5
  */
 public static final int[] getMatchingRegions(String pattern, String name, int matchRule) {
@@ -872,6 +894,8 @@
 				return next >= 0 ? new int[] {next, patternLength} : null;
 			}
 			break;
+		case SearchPattern.R_SUBWORD_MATCH:
+			return CharOperation.getSubWordMatchingRegions(pattern, name);
 	}
 	return null;
 }
@@ -1450,7 +1474,7 @@
  *      Unnamed modules can also be included and are represented either by an absence of module name implicitly
  *      or explicitly by specifying ALL-UNNAMED for module name.
  * 		Module graph search is also supported with the limitTo option set to <code>IJavaSearchConstants.MODULE_GRAPH</code>.
- *      In the module graph case, the given type is searched in all the modules required directly as well 
+ *      In the module graph case, the given type is searched in all the modules required directly as well
  *      as indirectly by the given module(s).
  *      </p>
  *      <p>
@@ -1462,7 +1486,7 @@
  * 				<li><code>java.base/java.lang.Object</code></li>
  *				<li><code>mod.one, mod.two/pack.X</code> find declaration in the list of given modules.</li>
  *				<li><code>/pack.X</code> find in the unnamed module.</li>
- *				<li><code>ALL-UNNAMED/pack.X</code> find in the unnamed module.</li> 
+ *				<li><code>ALL-UNNAMED/pack.X</code> find in the unnamed module.</li>
  *			</ul>
  *			<p>
  * 	</li>
@@ -1538,12 +1562,12 @@
  *				Note that types may be only classes or only interfaces if {@link IJavaSearchConstants#CLASS CLASS} or
  *				{@link IJavaSearchConstants#INTERFACE INTERFACE} is respectively used instead of {@link IJavaSearchConstants#TYPE TYPE}.
  *		</li>
- *		 <li>{@link IJavaSearchConstants#MODULE_GRAPH MODULE_GRAPH}: for types with a module prefix, 
+ *		 <li>{@link IJavaSearchConstants#MODULE_GRAPH MODULE_GRAPH}: for types with a module prefix,
  *             will find all types present in required modules (directly or indirectly required) ie
  *             in any module present in the module graph of the given module.
  *		</li>
  *		 <li>All other fine grain constants defined in the <b>limitTo</b> category
- *				of the {@link IJavaSearchConstants} are also accepted nature: 
+ *				of the {@link IJavaSearchConstants} are also accepted nature:
  * 			<table>
  *     			<tr>
  *         		<th>Fine grain constant
@@ -1637,7 +1661,7 @@
  * 	on non-generic types/methods search.</p>
  *
  * 	<p>Note that {@link #R_REGEXP_MATCH} is supported since 3.14  for the special case of
- * {@link IJavaSearchConstants#DECLARATIONS DECLARATIONS} search of 
+ * {@link IJavaSearchConstants#DECLARATIONS DECLARATIONS} search of
  * {@link IJavaSearchConstants#MODULE MODULE}</p>
  * 	<p>
  * 	Note also that the default behavior for generic types/methods search is to find exact matches.</p>
@@ -1729,7 +1753,7 @@
  *				references as specified above.
  *		</li>
  *		 <li>All other fine grain constants defined in the <b>limitTo</b> category
- *				of the {@link IJavaSearchConstants} are also accepted nature: 
+ *				of the {@link IJavaSearchConstants} are also accepted nature:
  * 			<table>
  *     			<tr>
  *         		<th>Fine grain constant
@@ -1841,7 +1865,7 @@
  *				references as specified above.
  *		</li>
  *		 <li>All other fine grain constants defined in the <b>limitTo</b> category
- *				of the {@link IJavaSearchConstants} are also accepted nature: 
+ *				of the {@link IJavaSearchConstants} are also accepted nature:
  * 			<table>
  *     			<tr>
  *         		<th>Fine grain constant
@@ -2378,8 +2402,8 @@
 }
 /**
  * Query a given index for matching entries. Assumes the sender has opened the index and will close when finished.
- * 
- * @noreference This method is not intended to be referenced by clients. 
+ *
+ * @noreference This method is not intended to be referenced by clients.
  * @nooverride This method is not intended to be re-implemented or extended by clients.
  */
 public void findIndexMatches(Index index, IndexQueryRequestor requestor, SearchParticipant participant, IJavaSearchScope scope, IProgressMonitor monitor) throws IOException {
@@ -2462,7 +2486,7 @@
 	return this.matchRule;
 }
 /**
- * @noreference This method is not intended to be referenced by clients. 
+ * @noreference This method is not intended to be referenced by clients.
  * @nooverride This method is not intended to be re-implemented or extended by clients.
  */
 public boolean isPolymorphicSearch() {
@@ -2650,7 +2674,7 @@
 
 // enabling special cases (read regular expressions) based on searchFor and limitTo
 private static int validateMatchRule(String stringPattern, int searchFor, int limitTo, int matchRule) {
-	if (searchFor == IJavaSearchConstants.MODULE && 
+	if (searchFor == IJavaSearchConstants.MODULE &&
 			limitTo == IJavaSearchConstants.DECLARATIONS &&
 			matchRule == SearchPattern.R_REGEXP_MATCH)
 		return matchRule;
@@ -2683,7 +2707,7 @@
 }
 
 /**
- * @noreference This method is not intended to be referenced by clients. 
+ * @noreference This method is not intended to be referenced by clients.
  * @nooverride This method is not intended to be re-implemented or extended by clients.
  */
 public EntryResult[] queryIn(Index index) throws IOException {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
index 06425d2..d5e7eb6 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
@@ -168,7 +168,7 @@
 	if (this.categoryOffsets == null) return null; // file is empty
 
 	HashtableOfObject results = null; // initialized if needed
-	
+
 	// No need to check the results table for duplicates while processing the
 	// first category table or if the first category tables doesn't have any results.
 	boolean prevResults = false;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/FileIndexLocation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/FileIndexLocation.java
index 60cecd5..726b881 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/FileIndexLocation.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/FileIndexLocation.java
@@ -70,7 +70,7 @@
 	public String fileName() {
 		return this.indexFile.getName();
 	}
-	
+
 	@Override
 	public File getIndexFile() {
 		return this.indexFile;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java
index bddc8e5..7a333cb 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/Index.java
@@ -187,7 +187,7 @@
 }
 /**
  * Reset memory and disk indexes.
- * 
+ *
  * @throws IOException
  */
 public void reset() throws IOException {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IndexLocation.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IndexLocation.java
index b913ec1..bcac151 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IndexLocation.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/IndexLocation.java
@@ -26,13 +26,13 @@
 
 /**
  * The location of the index files are represented as {@link IndexLocation}
- * 
+ *
  * This is an abstract class to allow different implementation for a jar entry and a file
  * on the disk. Some of these functions could mean different for a jar entry or a file
- * 
+ *
  */
 public abstract class IndexLocation {
-	
+
 	public static IndexLocation createIndexLocation(URL url) {
 		URL localUrl;
 		try {
@@ -53,16 +53,16 @@
 		}
 		return new JarIndexLocation(url, localUrl);
 	}
-	
+
 	private final URL url; // url of the given index location
 
 	/**
 	 * Set to true if this index location is of an index file specified
-	 * by a participant through 
+	 * by a participant through
 	 * {@link org.eclipse.jdt.core.search.SearchParticipant#scheduleDocumentIndexing}
 	 */
 	protected boolean participantIndex;
-	
+
 	protected IndexLocation(File file) {
 		URL tempUrl = null;
 		try {
@@ -72,7 +72,7 @@
 		}
 		this.url = tempUrl;
 	}
-	
+
 	public IndexLocation(URL url) {
 		this.url = url;
 	}
@@ -94,7 +94,7 @@
 	public abstract boolean delete();
 
 	public abstract boolean exists();
-	
+
 	public abstract String fileName();
 
 	/**
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java
index 785f59f..ed2b90e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/IndexExceptionBuilder.java
@@ -50,7 +50,7 @@
 	/**
 	 * Adds an address range to this problem description, given a field that may be corrupt, the base
 	 * address for its struct, and a custom description for the field.
-	 * 
+	 *
 	 * @return this
 	 */
 	public IndexExceptionBuilder addProblemAddress(String description, IField field, long address) {
@@ -62,7 +62,7 @@
 	/**
 	 * Adds an address range to this problem description, given the field that may be corrupt
 	 * and the base address for its struct.
-	 * 
+	 *
 	 * @return this
 	 */
 	public IndexExceptionBuilder addProblemAddress(IField field, long address) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java
index 44d48f7..13f0276 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java
@@ -171,7 +171,7 @@
 	}
 
 	/**
-	 * Inserts a cookie that can be later retrieved via getData(String). 
+	 * Inserts a cookie that can be later retrieved via getData(String).
 	 */
 	public <T> void setData(Class<T> key, T value) {
 		synchronized (this.cookies) {
@@ -711,7 +711,7 @@
 	}
 
 	/**
-	 * Creates a {@link IndexExceptionBuilder} object that collects information about database corruption after it is 
+	 * Creates a {@link IndexExceptionBuilder} object that collects information about database corruption after it is
 	 * detected.
 	 */
 	public IndexExceptionBuilder describeProblem() {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java
index 7279420..e3ed5c9 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java
@@ -28,7 +28,7 @@
  * <p>
  * The memory format contains a header is as follows:
  * <p>
- * 
+ *
  * <pre>
  * Byte				Meaning
  * --------------------------------------------
@@ -38,7 +38,7 @@
  * ...
  * k...k+4			Record [inlineRecordCount-1]
  * </pre>
- * 
+ *
  * As shown above, the first few records are stored inline with the array. inlineRecordCount is a tunable parameter
  * which may be 0. If there are fewer than inlineRecordCount records, there is no growable block and all records are
  * stored in the header. Storing the first few records in the header is intended as an optimization for very small
@@ -49,7 +49,7 @@
  * <p>
  * The memory format for a growable block is as follows:
  * <p>
- * 
+ *
  * <pre>
  * Byte				Meaning
  * --------------------------------------------
@@ -61,7 +61,7 @@
  * ...
  * k...k+4			Record [blockSize-1]
  * </pre>
- * 
+ *
  * <p>
  * The growable block itself begins with a 4-byte int holding the size of the array, followed by a 4-byte int holding
  * the capacity of the growable block. In the event that the array is larger than
@@ -103,7 +103,7 @@
 	private static final FieldPointer GROWABLE_BLOCK_ADDRESS;
 	private static final int ARRAY_HEADER_BYTES;
 
-	private static final StructDef<RawGrowableArray> type; 
+	private static final StructDef<RawGrowableArray> type;
 
 	static {
 		type = StructDef.createAbstract(RawGrowableArray.class);
@@ -141,7 +141,7 @@
 		/**
 		 * Holds the number of pages used for the metablock. Note that the start of the metablock array needs to be
 		 * 4-byte aligned. Since all malloc calls are always 2 bytes away from 4-byte alignment, we need to use at
-		 * least one short in this struct. */ 
+		 * least one short in this struct. */
 		public static final FieldShort METABLOCK_NUM_PAGES;
 		public static final int META_BLOCK_HEADER_BYTES;
 
@@ -157,7 +157,7 @@
 			META_BLOCK_HEADER_BYTES = type.size();
 		}
 	}
-	
+
 	private final int inlineSize;
 
 	public RawGrowableArray(int inlineRecords) {
@@ -170,7 +170,7 @@
 
 	/**
 	 * Returns the size of the array.
-	 * 
+	 *
 	 * @param address address of the array
 	 * @return the array size, in number elements
 	 */
@@ -246,7 +246,7 @@
 
 		Database db = nd.getDB();
 
-		int neededBlockSize = getGrowableRegionSizeFor(desiredSize); 
+		int neededBlockSize = getGrowableRegionSizeFor(desiredSize);
 		if (neededBlockSize > GrowableBlockHeader.MAX_GROWABLE_SIZE) {
 			// We need a metablock.
 			long metablockAddress = growableBlockAddress;
@@ -482,7 +482,7 @@
 	/**
 	 * Checks if we should reduce the amount of allocated in the growable region, such that the array can hold the given
 	 * number of elements.
-	 * 
+	 *
 	 * @param desiredSize
 	 *            the new current size of the array or 0 to free up all memory
 	 */
@@ -632,10 +632,10 @@
 		repackIfNecessary(nd, address, 0);
 	}
 
-	
+
 	/**
 	 * Returns true iff the size of the array is 0
-	 * 
+	 *
 	 * @param address address of the array
 	 * @return the array size, in number elements
 	 */
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Chunk.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Chunk.java
index 1f4841b..e389c7c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Chunk.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Chunk.java
@@ -28,7 +28,7 @@
 	final Database fDatabase;
 	/**
 	 * Holds the database-specific chunk number. This is the index into the database's chunk array and indicates the
-	 * start of the range of addresses held by this chunk. Non-negative. 
+	 * start of the range of addresses held by this chunk. Non-negative.
 	 */
 	final int fSequenceNumber;
 	/**
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ChunkWriter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ChunkWriter.java
index bc3723c..d4049ee 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ChunkWriter.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ChunkWriter.java
@@ -34,11 +34,11 @@
 	/**
 	 * Interface used to perform the uninterruptable writes when the buffer fills up.
 	 */
-	@FunctionalInterface 
+	@FunctionalInterface
 	public interface WriteCallback {
 		/**
 		 * Performs an uninterruptable write of the given bytes to the given file position.
-		 * 
+		 *
 		 * @param buffer
 		 *            the bytes to write
 		 * @param position
@@ -54,14 +54,14 @@
 	@FunctionalInterface
 	public interface SleepCallback {
 		/**
-		 * Sleeps the caller for the given time (in milliseconds) 
+		 * Sleeps the caller for the given time (in milliseconds)
 		 */
 		void sleep(long millisecond) throws InterruptedException;
 	}
 
 	/**
 	 * Constructs a new {@link ChunkWriter}
-	 * 
+	 *
 	 * @param bufferSize
 	 *            size of the write buffer (the maximum number of bytes that will be written in a single write).
 	 * @param maxBytesPerMillisecond
@@ -80,7 +80,7 @@
 
 	/**
 	 * Writes the given bytes to the given file position.
-	 * 
+	 *
 	 * @return true iff any attempt was made to interrupt the thread using {@link Thread#interrupt()}. The write
 	 *         succeeds regardless of the return value.
 	 * @throws IOException if unable to perform the write
@@ -104,7 +104,7 @@
 
 	/**
 	 * Flushes any outstanding writes to disk immediately.
-	 * 
+	 *
 	 * @return true iff any attempt was made to interrupt the thread using {@link Thread#interrupt()}. The write
 	 *         succeeds regardless of the return value.
 	 * @throws IOException if unable to perform the write
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java
index 01b8e97..a831e9a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java
@@ -65,7 +65,7 @@
  * INT_SIZE * (M + 1)   | pointer to head of linked list of blocks of size (M + MIN_BLOCK_DELTAS) * BLOCK_SIZE_DELTA
  * FREE_BLOCK_OFFSET    | chunk number for the root of the large block free space trie
  * WRITE_NUMBER_OFFSET  | long integer which is incremented on every write
- * MALLOC_STATS_OFFSET  | memory usage statistics  
+ * MALLOC_STATS_OFFSET  | memory usage statistics
  * DATA_AREA            | The database singletons are stored here and use the remainder of chunk 0
  *
  * M = CHUNK_SIZE / BLOCK_SIZE_DELTA - MIN_BLOCK_DELTAS
@@ -84,7 +84,7 @@
  * offset            content
  * 	                 _____________________________
  * 0                | size of block (negative indicates the block is in use) (2 bytes)
- * 2                | content of the struct 
+ * 2                | content of the struct
  *
  */
 public class Database {
@@ -99,7 +99,7 @@
 
 	public static final int BLOCK_SIZE_DELTA_BITS = 3;
 	public static final int BLOCK_SIZE_DELTA= 1 << BLOCK_SIZE_DELTA_BITS;
-	
+
 	// Fields that are only used by free blocks
 	private static final int BLOCK_PREV_OFFSET = BLOCK_HEADER_SIZE;
 	private static final int BLOCK_NEXT_OFFSET = BLOCK_HEADER_SIZE + INT_SIZE;
@@ -309,8 +309,8 @@
 
 	/**
 	 * Attempts to perform an uninterruptable write operation on the database. Returns true if an attempt was made
-	 * to interrupt it. 
-	 * 
+	 * to interrupt it.
+	 *
 	 * @throws IOException
 	 */
 	private boolean performUninterruptableWrite(IORunnable runnable) throws IOException {
@@ -334,7 +334,7 @@
 			}
 		}
 	}
-	
+
 	public void transferTo(FileChannel target) throws IOException {
 		assert this.fLocked;
         final FileChannel from= this.fFile.getChannel();
@@ -365,7 +365,7 @@
 	 * Empty the contents of the Database, make it ready to start again. Interrupting the thread with
 	 * {@link Thread#interrupt()} won't interrupt the write. Returns true iff the thread was interrupted
 	 * with {@link Thread#interrupt()}.
-	 * 
+	 *
 	 * @throws IndexException
 	 */
 	public boolean clear(int version) throws IndexException {
@@ -434,7 +434,7 @@
 
 	/**
 	 * Return the Chunk that contains the given offset.
-	 * 
+	 *
 	 * @throws IndexException
 	 */
 	public Chunk getChunk(long offset) throws IndexException {
@@ -531,7 +531,7 @@
 		assert this.fExclusiveLock;
 		assert datasize >= 0;
 		assert datasize <= MAX_MALLOC_SIZE;
-		
+
 		long result;
 		int usedSize;
 		this.log.start(this.mallocTag);
@@ -549,7 +549,7 @@
 				if (needDeltas < MIN_BLOCK_DELTAS) {
 					needDeltas = MIN_BLOCK_DELTAS;
 				}
-	
+
 				// Which block size.
 				int useDeltas;
 				for (useDeltas = needDeltas; useDeltas <= MAX_BLOCK_DELTAS; useDeltas++) {
@@ -557,7 +557,7 @@
 					if (freeBlock != 0)
 						break;
 				}
-	
+
 				// Get the block.
 				Chunk chunk;
 				if (freeBlock == 0) {
@@ -579,18 +579,18 @@
 					}
 					removeBlock(chunk, useDeltas * BLOCK_SIZE_DELTA, freeBlock);
 				}
-	
+
 				final int unusedDeltas = useDeltas - needDeltas;
 				if (unusedDeltas >= MIN_BLOCK_DELTAS) {
 					// Add in the unused part of our block.
 					addBlock(chunk, unusedDeltas * BLOCK_SIZE_DELTA, freeBlock + needDeltas * BLOCK_SIZE_DELTA);
 					useDeltas = needDeltas;
 				}
-	
+
 				// Make our size negative to show in use.
 				usedSize = useDeltas * BLOCK_SIZE_DELTA;
 				chunk.putShort(freeBlock, (short) -usedSize);
-	
+
 				// Clear out the block, lots of people are expecting this.
 				chunk.clear(freeBlock + BLOCK_HEADER_SIZE, usedSize - BLOCK_HEADER_SIZE);
 				result = freeBlock + BLOCK_HEADER_SIZE;
@@ -616,7 +616,7 @@
 
 	/**
 	 * Clears all the bytes in the given range by setting them to zero.
-	 * 
+	 *
 	 * @param startAddress first address to clear
 	 * @param bytesToClear number of addresses to clear
 	 */
@@ -649,7 +649,7 @@
 	/**
 	 * Obtains a new block that can fit the given number of bytes (at minimum). Returns the
 	 * chunk number.
-	 * 
+	 *
 	 * @param datasize minimum number of bytes needed
 	 * @return the chunk number
 	 */
@@ -733,7 +733,7 @@
 	/**
 	 * Unlinks a free block (which currently belongs to the free block trie) so that it may
 	 * be reused.
-	 * 
+	 *
 	 * @param freeBlockChunkNum chunk number of the block to be unlinked
 	 */
 	private void unlinkFreeBlock(int freeBlockChunkNum) {
@@ -809,7 +809,7 @@
 	/**
 	 * Returns the chunk number of a free block that contains at least the given number of chunks, or
 	 * 0 if there is no existing contiguous free block containing at least the given number of chunks.
-	 * 
+	 *
 	 * @param numChunks minumum number of chunks desired
 	 * @return the chunk number of a free block containing at least the given number of chunks or 0
 	 * if there is no existing free block containing that many chunks.
@@ -834,7 +834,7 @@
 	/**
 	 * Given the chunk number of a block somewhere in the free space trie, this returns the smallest
 	 * child in the subtree that is no smaller than the given number of chunks.
-	 * 
+	 *
 	 * @param trieNodeChunkNum chunk number of a block in the free space trie
 	 * @param numChunks desired number of chunks
 	 * @return the chunk number of the first chunk in a contiguous free block containing at least the
@@ -876,7 +876,7 @@
 	/**
 	 * Link the given unused block into the free block tries. The block does not need to have
 	 * its header filled in already.
-	 * 
+	 *
 	 * @param freeBlockChunkNum chunk number of the start of the block
 	 * @param numChunks number of chunks in the block
 	 */
@@ -1056,11 +1056,11 @@
 			}
 		}
 	}
-	
+
 	/**
 	 * Adds the given child block to the given parent subtree of the free space trie. Any existing
 	 * subtree under the given child block will be retained.
-	 * 
+	 *
 	 * @param parentChunkNum root of the existing tree, or 0 if the child is going to be the new root
 	 * @param newChildChunkNum the new child to insert
 	 */
@@ -1097,7 +1097,7 @@
 	 * Adds the given block to the linked list of equally-sized free chunks in the free space trie.
 	 * Both chunks must be unused, must be the same size, and the previous chunk must already
 	 * be linked into the free space trie. The newly-added chunk must not have any children.
-	 * 
+	 *
 	 * @param prevChunkNum chunk number of previous block in the existing list
 	 * @param newChunkNum new chunk to be added to the list
 	 */
@@ -1118,7 +1118,7 @@
 	/**
 	 * Returns the chunk number of the chunk at the start of a block, given the
 	 * chunk number of the chunk at the start of the following block.
-	 * 
+	 *
 	 * @param chunkNum the chunk number of the chunk immediately following the
 	 * chunk being queried
 	 * @return the chunk number of the chunk at the start of the previous block
@@ -1131,7 +1131,7 @@
 	/**
 	 * Sets the block header and footer for the given range of chunks which make
 	 * up a contiguous block.
-	 * 
+	 *
 	 * @param firstChunkNum chunk number of the first chunk in the block
 	 * @param headerContent the content of the header. Its magnitude is the number of
 	 * chunks in the block. It is positive if the chunk is free and negative if
@@ -1325,11 +1325,11 @@
 				}
 				addBlock(chunk, (int) blockSize, block);
 			}
-	
+
 			if (DEBUG_FREE_SPACE) {
 				periodicValidateFreeSpace();
 			}
-	
+
 			this.freed += blockSize;
 			this.memoryUsage.recordFree(poolId, blockSize);
 		} finally {
@@ -1668,7 +1668,7 @@
 	/**
 	 * Interrupting the thread with {@link Thread#interrupt()} won't interrupt the write. Returns true iff an attempt
 	 * was made to interrupt the thread with {@link Thread#interrupt()}.
-	 * 
+	 *
 	 * @throws IndexException
 	 */
 	private boolean flushAndUnlockChunks(final ArrayList<Chunk> dirtyChunks, boolean isComplete) throws IndexException {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IBTreeVisitor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IBTreeVisitor.java
index f3c5727..fd15faf 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IBTreeVisitor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IBTreeVisitor.java
@@ -14,7 +14,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.nd.db;
 
-/** 
+/**
  * The visitor visits all records where compare returns 0.
  */
 public interface IBTreeVisitor {
@@ -22,7 +22,7 @@
 	 * Compare the record against an internally held key. The comparison must be
 	 * compatible with the one used for the btree.
 	 * Used for visiting.
-	 * 
+	 *
 	 * @param record
 	 * @return -1 if record < key, 0 if record == key, 1 if record > key
 	 * @throws IndexException
@@ -35,5 +35,5 @@
 	 * @return <code>true</code> to continue the visit, <code>false</code> to abort it.
 	 * @throws IndexException
 	 */
-	public abstract boolean visit(long record) throws IndexException;	
+	public abstract boolean visit(long record) throws IndexException;
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IString.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IString.java
index 7493430..610e39a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IString.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IString.java
@@ -17,8 +17,8 @@
 
 /**
  * Interface for strings stored in the database. There is more than one string
- * format. This interface hides that fact. 
- * 
+ * format. This interface hides that fact.
+ *
  * @author Doug Schaefer
  */
 public interface IString {
@@ -26,7 +26,7 @@
 	 * Get the offset of this IString record in the Nd
 	 */
 	public long getRecord();
-	
+
 	// strcmp equivalents
 	/**
 	 * Compare this IString record and the specified IString record
@@ -39,7 +39,7 @@
 	 * @throws IndexException
 	 */
 	public int compare(IString string, boolean caseSensitive) throws IndexException;
-	
+
 	/**
 	 * Compare this IString record and the specified String object
 	 * @param string
@@ -51,7 +51,7 @@
 	 * @throws IndexException
 	 */
 	public int compare(String string, boolean caseSensitive) throws IndexException;
-	
+
 	/**
 	 * Compare this IString record and the specified character array
 	 * @param chars
@@ -87,7 +87,7 @@
 	 * @throws IndexException
 	 */
 	public int compareCompatibleWithIgnoreCase(char[] chars) throws IndexException;
-	
+
 	/**
 	 * Compare this IString record and the specified character array
 	 * @param name the name to compare to
@@ -108,7 +108,7 @@
 	 * @throws IndexException
 	 */
 	public char[] getChars() throws IndexException;
-	
+
 	/**
 	 * Get an equivalent String object to this IString record<p>
 	 * <b>N.B. This method can be expensive: compare and equals can be used for
@@ -117,7 +117,7 @@
 	 * @throws IndexException
 	 */
 	public String getString() throws IndexException;
-	
+
 	/**
 	 * Free the associated record in the Nd
 	 * @throws IndexException
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java
index 5de64a6..4404222 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/IndexException.java
@@ -39,8 +39,8 @@
 	/**
 	 * Sets the time that the exception occurred at (in terms of the write number
 	 * from the modification log)
-	 * 
-	 * @param writeNumber 
+	 *
+	 * @param writeNumber
 	 */
 	public void setTime(long writeNumber) {
 		this.time = writeNumber;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/MemoryStats.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/MemoryStats.java
index 5e8139a..b672e99 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/MemoryStats.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/MemoryStats.java
@@ -206,7 +206,7 @@
 			if (idx > 0 && next.poolId == 0) {
 				break;
 			}
-			
+
 			result.add(next);
 		}
 		return result;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java
index 2dd0ebe..94e90fa 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ModificationLog.java
@@ -183,7 +183,7 @@
 
 		/**
 		 * Search for anomalies in the log and produce a reduced report
-		 * 
+		 *
 		 * @return a log containing the most interesting results
 		 */
 		public MemoryAccessLog reduce(int maxWrites) {
@@ -256,7 +256,7 @@
 	}
 
 	private static int getBufferEntriesFor(int sizeInMegs) {
-		long sizeOfABufferEntry = 8 + 4 + 1; // size, in bytes, of one long, one int, and one byte 
+		long sizeOfABufferEntry = 8 + 4 + 1; // size, in bytes, of one long, one int, and one byte
 		return (int) (sizeInMegs * 1024L * 1024L / sizeOfABufferEntry);
 	}
 
@@ -422,7 +422,7 @@
 				long nextAddress = this.buffer0[currentPosition];
 				int nextArgument = this.buffer1[currentPosition];
 				byte nextOp = this.operation[currentPosition];
-	
+
 				switch (nextOp) {
 					case POP_OPERATION: {
 						tags.add(getTagForId(nextArgument));
@@ -445,7 +445,7 @@
 								isMatch = true;
 							}
 						}
-	
+
 						if (isMatch) {
 							List<Tag> stack = new ArrayList<>();
 							stack.addAll(tags);
@@ -453,7 +453,7 @@
 									nextArgument, stack);
 							operations.add(nextOperation);
 						}
-	
+
 						currentWrite--;
 					}
 				}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java
index 17017ab..d41a590 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/Field.java
@@ -18,7 +18,7 @@
 import org.eclipse.jdt.internal.core.nd.db.Database;
 
 /**
- * Used to represent a single field of an object stored in the database. Objects 
+ * Used to represent a single field of an object stored in the database. Objects
  * which store themselves in the database should store a set of static final
  * FieldDefinitions at the top of their class definition to indicate their memory map.
  * This serves as a standard way to document the memory map for such structs, provides
@@ -29,7 +29,7 @@
  * manually. The get function is more convenient but allocates objects and so should
  * probably not be used for frequently-accessed fields or primitive types that would
  * end up being autoboxed unnecessarily.
- * 
+ *
  * @param <T>
  */
 public final class Field<T> extends BaseField implements IDestructableField {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldList.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldList.java
index 18248c8..92009a4 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldList.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldList.java
@@ -98,7 +98,7 @@
 	/**
 	 * Creates a new {@link FieldList} in the given struct which contains elements of the given type. The resulting list
 	 * will grow by 1 element each time it overflows.
-	 * 
+	 *
 	 * @param ownerStruct
 	 *            the struct to which the new list field will be added. Must not have had {@link StructDef#done()}
 	 *            invoked on it yet.
@@ -113,7 +113,7 @@
 	/**
 	 * Creates a new {@link FieldList} in the given struct which contains elements of the given type. The resulting list
 	 * will grow by the given number of elements each time it overflows.
-	 * 
+	 *
 	 * @param ownerStruct
 	 *            the struct to which the new list field will be added. Must not have had {@link StructDef#done()}
 	 *            invoked on it yet.
@@ -142,7 +142,7 @@
 
 	/**
 	 * Returns the contents of the receiver as a {@link List}.
-	 * 
+	 *
 	 * @param nd the database to be queried.
 	 * @param address the address of the parent struct
 	 */
@@ -181,7 +181,7 @@
 		try {
 			long headerStartAddress = address + this.offset;
 			long nextBlockAddress = LAST_BLOCK_WITH_ELEMENTS.get(nd, headerStartAddress);
-	
+
 			// Ensure that there's at least one block
 			long insertionBlockAddress = nextBlockAddress;
 			if (nextBlockAddress == 0) {
@@ -190,11 +190,11 @@
 				FIRST_BLOCK.put(nd, headerStartAddress, newBlockAddress);
 				insertionBlockAddress = newBlockAddress;
 			}
-	
+
 			// Check if there's any free space in this block
 			int elementsInBlock = BlockHeader.ELEMENTS_IN_USE.get(nd, insertionBlockAddress);
 			int blockSize = BlockHeader.BLOCK_SIZE.get(nd, insertionBlockAddress);
-	
+
 			if (elementsInBlock >= blockSize) {
 				long nextBlock = BlockHeader.NEXT_BLOCK.get(nd, insertionBlockAddress);
 				if (nextBlock == 0) {
@@ -203,12 +203,12 @@
 				}
 				LAST_BLOCK_WITH_ELEMENTS.put(nd, headerStartAddress, nextBlock);
 				insertionBlockAddress = nextBlock;
-				elementsInBlock = BlockHeader.ELEMENTS_IN_USE.get(nd, insertionBlockAddress); 
+				elementsInBlock = BlockHeader.ELEMENTS_IN_USE.get(nd, insertionBlockAddress);
 			}
-	
+
 			BlockHeader.ELEMENTS_IN_USE.put(nd, insertionBlockAddress, (short) (elementsInBlock + 1));
 			int elementSize = getElementSize();
-	
+
 			long resultAddress = insertionBlockAddress + BlockHeader.BLOCK_HEADER_BYTES + elementsInBlock * elementSize;
 			assert ((resultAddress - Database.BLOCK_HEADER_SIZE) & (Database.BLOCK_SIZE_DELTA - 1)) == 0;
 			return this.elementType.getFactory().create(nd, resultAddress);
@@ -233,7 +233,7 @@
 			}
 			long headerStartAddress = address + this.offset;
 			long nextBlockAddress = LAST_BLOCK_WITH_ELEMENTS.get(nd, headerStartAddress);
-	
+
 			int maxBlockSizeThatFitsInAChunk = (int) ((MAX_BYTES_IN_A_CHUNK - BlockHeader.BLOCK_HEADER_BYTES)
 					/ getElementSize());
 
@@ -244,7 +244,7 @@
 				LAST_BLOCK_WITH_ELEMENTS.put(nd, headerStartAddress, nextBlockAddress);
 				FIRST_BLOCK.put(nd, headerStartAddress, nextBlockAddress);
 			}
-	
+
 			// Check if there's any free space in this block
 			int remainingToAllocate = numElements;
 			while (true) {
@@ -252,12 +252,12 @@
 				nextBlockAddress = BlockHeader.NEXT_BLOCK.get(nd, currentBlockAddress);
 				int elementsInUse = BlockHeader.ELEMENTS_IN_USE.get(nd, currentBlockAddress);
 				int blockSize = BlockHeader.BLOCK_SIZE.get(nd, currentBlockAddress);
-	
+
 				remainingToAllocate -= (blockSize - elementsInUse);
 				if (remainingToAllocate <= 0) {
 					break;
 				}
-	
+
 				if (nextBlockAddress == 0) {
 					nextBlockAddress = allocateNewBlock(nd, Math.min(maxBlockSizeThatFitsInAChunk, numElements));
 					BlockHeader.NEXT_BLOCK.put(nd, currentBlockAddress, nextBlockAddress);
@@ -302,7 +302,7 @@
 			short poolId = getMemoryPoolId(nd);
 			long headerStartAddress = address + this.offset;
 			long firstBlockAddress = FIRST_BLOCK.get(nd, headerStartAddress);
-	
+
 			long nextBlockAddress = firstBlockAddress;
 			while (nextBlockAddress != 0) {
 				long currentBlockAddress = nextBlockAddress;
@@ -311,11 +311,11 @@
 				destructElements(nd, currentBlockAddress + BlockHeader.BLOCK_HEADER_BYTES, elementsInBlock);
 				db.free(currentBlockAddress, poolId);
 			}
-	
+
 			db.clearRange(headerStartAddress, getRecordSize());
 		} finally {
 			db.getLog().end(this.destructTag);
-		} 
+		}
 	}
 
 	private void destructElements(Nd nd, long nextElementAddress, int count) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java
index 3291833..ad10962 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldManyToOne.java
@@ -91,7 +91,7 @@
 	/**
 	 * Creates a many-to-one pointer which points to this object's owner. If the pointer is non-null when the owner is
 	 * deleted, this object will be deleted too.
-	 * 
+	 *
 	 * @param builder the struct to which the field will be added
 	 * @param forwardPointer the field which holds the pointer in the other direction
 	 * @return a newly constructed field
@@ -105,7 +105,7 @@
 		if (!NdNode.class.isAssignableFrom(builder.getStructClass())) {
 			throw new IllegalArgumentException(FieldManyToOne.class.getSimpleName() + " can't be the owner of " //$NON-NLS-1$
 					+ builder.getStructClass().getSimpleName() + " because the latter isn't a subclass of " //$NON-NLS-1$
-					+ NdNode.class.getSimpleName()); 
+					+ NdNode.class.getSimpleName());
 		}
 
 		FieldManyToOne<T> result = new FieldManyToOne<T>(builder, forwardPointer, true);
@@ -117,7 +117,7 @@
 
 	/**
 	 * Sets whether or not this field permits nulls to be assigned.
-	 * 
+	 *
 	 * @param permitted true iff the field permits nulls
 	 * @return this
 	 */
@@ -163,14 +163,14 @@
 				throw new IllegalStateException(
 						getClass().getSimpleName() + " must be associated with a " + FieldOneToMany.class.getSimpleName()); //$NON-NLS-1$
 			}
-	
+
 			long oldTargetAddress = TARGET.get(nd, fieldStart);
 			if (oldTargetAddress == newTargetAddress) {
 				return;
 			}
-	
+
 			detachFromOldTarget(nd, address, oldTargetAddress);
-	
+
 			TARGET.put(nd, fieldStart, newTargetAddress);
 			if (newTargetAddress != 0) {
 				// Note that newValue is the address of the backpointer list and record (the address of the struct
@@ -197,7 +197,7 @@
 				short targetTypeId = NdNode.NODE_TYPE.get(nd, oldTargetAddress);
 				ITypeFactory<? extends NdNode> typeFactory = nd.getTypeFactory(targetTypeId);
 
-				if (typeFactory.getDeletionSemantics() == StructDef.DeletionSemantics.REFCOUNTED 
+				if (typeFactory.getDeletionSemantics() == StructDef.DeletionSemantics.REFCOUNTED
 						&& typeFactory.isReadyForDeletion(nd, oldTargetAddress)) {
 					nd.scheduleDeletion(oldTargetAddress);
 				}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java
index 6b1a860..919cb0b 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToMany.java
@@ -58,8 +58,8 @@
 
 	/**
 	 * Creates a {@link FieldOneToMany} using the given builder. It will hold the many side of a one-to-many
-	 * relationship with nodeType. 
-	 * 
+	 * relationship with nodeType.
+	 *
 	 * @param builder builder that is being used to construct the struct containing this field
 	 * @param forwardPointer field of the model object which holds the one side of this one-to-many relationship
 	 * @param inlineElementCount number of inline elements. If this is nonzero, space for this number elements is
@@ -68,7 +68,7 @@
 	 * offer a performance improvement. For relationships that will normally be empty, this should be 0.
 	 * @return the newly constructed backpointer field
 	 */
-	public static <T extends INdStruct, B extends INdStruct> FieldOneToMany<T> create(StructDef<B> builder, 
+	public static <T extends INdStruct, B extends INdStruct> FieldOneToMany<T> create(StructDef<B> builder,
 			FieldManyToOne<B> forwardPointer, int inlineElementCount) {
 		FieldOneToMany<T> result = new FieldOneToMany<T>(builder, forwardPointer, inlineElementCount);
 		builder.add(result);
@@ -77,7 +77,7 @@
 		return result;
 	}
 
-	public static <T extends INdStruct, B extends INdStruct> FieldOneToMany<T> create(StructDef<B> builder, 
+	public static <T extends INdStruct, B extends INdStruct> FieldOneToMany<T> create(StructDef<B> builder,
 			FieldManyToOne<B> forwardPointer) {
 		return create(builder, forwardPointer, 0);
 	}
@@ -106,7 +106,7 @@
 	public boolean isEmpty(Nd nd, long address) {
 		return this.backPointerArray.isEmpty(nd, address + this.offset);
 	}
-	
+
 	public int size(Nd nd, long address) {
 		return this.backPointerArray.size(nd, address + this.offset);
 	}
@@ -146,7 +146,7 @@
 	}
 
 	/**
-	 * Returns the record size of the back pointer list 
+	 * Returns the record size of the back pointer list
 	 */
 	@Override
 	public int getRecordSize() {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java
index 20313f1..6695fcd 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldOneToOne.java
@@ -24,7 +24,7 @@
  * Represents a 1-to-0..1 relationship in a Nd database.
  */
 public class FieldOneToOne<T extends INdStruct> extends BaseField implements IDestructableField, IRefCountedField {
-	public final StructDef<T> nodeType; 
+	public final StructDef<T> nodeType;
 	FieldOneToOne<?> backPointer;
 	private boolean pointsToOwner;
 	private final Tag putTag;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchIndex.java
index 2b6aaeb..1fd37f8 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/FieldSearchIndex.java
@@ -41,7 +41,7 @@
 			return 1;
 		}
 	};
- 
+
 	public static final class SearchCriteria {
 		private boolean matchCase = true;
 		private boolean isPrefix = false;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IRefCountedField.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IRefCountedField.java
index 8abca7f..fbe8afb 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IRefCountedField.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/IRefCountedField.java
@@ -23,6 +23,6 @@
 	 * <p>
 	 * Implementations should return false if the refcount is 0 or true if the refcount
 	 * is nonzero.
-	 */	
+	 */
 	public boolean hasReferences(Nd nd, long address);
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java
index 5e5b658..ec9ebf6 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/field/StructDef.java
@@ -137,7 +137,7 @@
 
 			@Override
 			public boolean hasDestructor() {
-				return StructDef.this.hasUserDestructor || hasDestructableFields(); 
+				return StructDef.this.hasUserDestructor || hasDestructableFields();
 			}
 
 			@Override
@@ -170,7 +170,7 @@
 			public boolean isReadyForDeletion(Nd dom, long address) {
 				return StructDef.this.isReadyForDeletion(dom, address);
 			}
-			
+
 			@Override
 			public DeletionSemantics getDeletionSemantics() {
 				return StructDef.this.getDeletionSemantics();
@@ -251,7 +251,7 @@
 	}
 
 	protected boolean hasDestructableFields() {
-		return (!StructDef.this.destructableFields.isEmpty() || 
+		return (!StructDef.this.destructableFields.isEmpty() ||
 				(StructDef.this.superClass != null && StructDef.this.superClass.hasDestructableFields()));
 	}
 
@@ -369,7 +369,7 @@
 					+ "that uses " + this.superClass.deletionSemantics.toString() + " semantics");  //$NON-NLS-1$//$NON-NLS-2$
 			}
 		}
-		
+
 		this.offsetsComputed = true;
 
 		for (StructDef<? extends T> next : this.dependents) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java
index c57f399..3271fdc 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java
@@ -107,8 +107,8 @@
 	}
 
 	/**
-	 * Adds a type to the index, given an input class file and a binary name. Note that the given binary name is 
-	 * 
+	 * Adds a type to the index, given an input class file and a binary name. Note that the given binary name is
+	 *
 	 * @param binaryType an object used for parsing the .class file itself
 	 * @param fieldDescriptor the name that is used to locate the class, computed from the .class file's name and location.
 	 * In the event that the .class file has been moved, this may differ from the binary name stored in the .class file
@@ -350,15 +350,15 @@
 		int numArgumentsInGenericSignature = countMethodArguments(signature);
 		int numCompilerDefinedParameters = Math.max(0,
 				parameterFieldDescriptors.size() - numArgumentsInGenericSignature);
-		
+
 		boolean compilerDefinedParametersAreIncludedInSignature = (next.getGenericSignature() == null);
 
 		// If there is no generic signature, then fall back to heuristics based on what we know about
 		// where the java compiler likes to create compiler-defined arguments
 		if (compilerDefinedParametersAreIncludedInSignature) {
 			// Constructors for non-static member types get a compiler-defined first argument
-			if (binaryType.isMember() 
-					&& next.isConstructor() 
+			if (binaryType.isMember()
+					&& next.isConstructor()
 					&& ((binaryType.getModifiers() & Modifier.STATIC) == 0)
 					&& parameterFieldDescriptors.size() > 0) {
 
@@ -483,7 +483,7 @@
 			variable.allocateTypeAnnotations(typeAnnotations.length);
 			for (IBinaryTypeAnnotation next : typeAnnotations) {
 				NdTypeAnnotation annotation = variable.createTypeAnnotation();
-	
+
 				initTypeAnnotation(annotation, next);
 			}
 		}
@@ -844,7 +844,7 @@
 			case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER:
 			case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER:
 				annotation.setTargetInfo(next.getTypeParameterIndex());
-				break;				
+				break;
 			case AnnotationTargetTypeConstants.CLASS_EXTENDS:
 				annotation.setTargetInfo(next.getSupertypeIndex());
 				break;
@@ -870,7 +870,7 @@
 	}
 
 	private void initAnnotation(NdAnnotation annotation, IBinaryAnnotation next) {
-		annotation.setType(createTypeIdFromBinaryName(next.getTypeName())); 
+		annotation.setType(createTypeIdFromBinaryName(next.getTypeName()));
 
 		IBinaryElementValuePair[] pairs = next.getElementValuePairs();
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/FileStateCache.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/FileStateCache.java
index 0bfae70..30228d5 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/FileStateCache.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/FileStateCache.java
@@ -57,7 +57,7 @@
 
 	/**
 	 * Inserts a new entry into the cache.
-	 * 
+	 *
 	 * @param location absolute filesystem path to the file
 	 * @param result true if the file is definitely in sync with the index, false if there is any possibility of it
 	 * being out of sync.
@@ -79,7 +79,7 @@
 
 	/**
 	 * Removes a single entry from the cache.
-	 * 
+	 *
 	 * @param location absolute filesystem path to the file.
 	 */
 	public void remove(String location) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java
index adc43da..5bbb644 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java
@@ -97,7 +97,7 @@
 	public static boolean DEBUG_INSERTIONS;
 	public static boolean DEBUG_SELFTEST;
 	public static int DEBUG_LOG_SIZE_MB;
-	
+
 	// New index is disabled, see bug 544898
 //	private static final String ENABLE_NEW_JAVA_INDEX = "enableNewJavaIndex"; //$NON-NLS-1$
 //	private static IPreferenceChangeListener listener = new IPreferenceChangeListener() {
@@ -181,7 +181,7 @@
 	 * when running the unit tests, since indexing will not occur unless it is triggered
 	 * explicitly.
 	 * <p>
-	 * Synchronize on {@link #automaticIndexingMutex} before accessing. 
+	 * Synchronize on {@link #automaticIndexingMutex} before accessing.
 	 */
 	public void enableAutomaticIndexing(boolean enabled) {
 		boolean runRescan = false;
@@ -200,7 +200,7 @@
 				// Force a rescan when re-enabling automatic indexing since we may have missed an update
 				this.rescanJob.schedule();
 			}
-	
+
 			if (!enabled) {
 				// Wait for any existing indexing operations to finish when disabling automatic indexing since
 				// we only want explicitly-triggered indexing operations to run after the method returns
@@ -471,7 +471,7 @@
 	private int cleanGarbage(long currentTimeMillis, Collection<IPath> allIndexables, IProgressMonitor monitor) {
 		JavaIndex index = JavaIndex.getIndex(this.nd);
 
-		int result = 0; 
+		int result = 0;
 		HashSet<IPath> paths = new HashSet<>();
 		paths.addAll(allIndexables);
 		SubMonitor subMonitor = SubMonitor.convert(monitor, 3);
@@ -555,7 +555,7 @@
 				if (!toDelete.isInIndex()) {
 					break;
 				}
-		
+
 				int numChildren = toDelete.getTypeCount();
 				deletionMonitor.setWorkRemaining(numChildren + 1);
 				if (numChildren == 0) {
@@ -1076,7 +1076,7 @@
 	/**
 	 * Dirties the given filesystem location. This must point to a single file (not a folder) that needs to be
 	 * rescanned. The file may have been added, removed, or changed.
-	 * 
+	 *
 	 * @param location an absolute filesystem location
 	 */
 	public void makeDirty(IPath location) {
@@ -1096,7 +1096,7 @@
 	 * Schedules a rescan of the given path (which may be either a workspace path or an absolute path on the local
 	 * filesystem). This may point to either a single file or a folder that needs to be rescanned. Any resource that
 	 * has this path as a prefix will be rescanned.
-	 * 
+	 *
 	 * @param pathToRescan
 	 */
 	public void makeWorkspacePathDirty(IPath pathToRescan) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/WorkspaceSnapshot.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/WorkspaceSnapshot.java
index 5b04005..69cf4f7 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/WorkspaceSnapshot.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/WorkspaceSnapshot.java
@@ -154,11 +154,11 @@
 						IPath defaultOutputLocation = javaProject.getOutputLocation();
 						for (IClasspathEntry next : entries) {
 							IPath nextOutputLocation = next.getOutputLocation();
-	
+
 							if (nextOutputLocation == null) {
 								nextOutputLocation = defaultOutputLocation;
 							}
-	
+
 							IResource resource = root.findMember(nextOutputLocation);
 							if (resource != null) {
 								resourcesToScan.add(resource);
@@ -198,7 +198,7 @@
 		return allIndexables;
 	}
 
-	private static void collectAllClassFiles(IWorkspaceRoot root, List<? super IClassFile> result, 
+	private static void collectAllClassFiles(IWorkspaceRoot root, List<? super IClassFile> result,
 			Collection<? extends IResource> toScan, IProgressMonitor monitor) {
 		SubMonitor subMonitor = SubMonitor.convert(monitor);
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java
index 1f5f3dd..5ce5c1c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java
@@ -143,7 +143,7 @@
 
 	/**
 	 * Returns true iff the file existed at the time the fingerprint was computed.
-	 * 
+	 *
 	 * @return true iff the file existed at the time the fingerprint was computed.
 	 */
 	public boolean fileExists() {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java
index afef5b8..e044514 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java
@@ -99,9 +99,9 @@
 	/**
 	 * Returns true iff the given resource file is up-to-date with the filesystem. Returns false
 	 * if the argument is null or there is a possibility it being out-of-date with the file system.
-	 * 
+	 *
 	 * @param file the index file to look up or null
-	 * @throws CoreException 
+	 * @throws CoreException
 	 */
 	public boolean isUpToDate(NdResourceFile file) throws CoreException {
 		if (file != null && file.isDoneIndexing()) {
@@ -219,7 +219,7 @@
 	}
 
 	/**
-	 * @return always return {@code false} see bug 544898. New index is disabled now. 
+	 * @return always return {@code false} see bug 544898. New index is disabled now.
 	 */
 	public static boolean isEnabled() {
 		return false;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaNames.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaNames.java
index 3919825..ffc81c1 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaNames.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaNames.java
@@ -105,7 +105,7 @@
 		char[] className = CharArrayUtils.subarray(fieldDescriptor, separatorPosition + 1, fieldDescriptor.length - 1);
 		return className;
 	}
-	
+
 	/**
 	 * Converts a field descriptor to a java name. If fullyQualified is true, it returns a fully qualified class name.
 	 * If it is false, it returns a source name.
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java
index 055386f..90dc097 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdMethod.java
@@ -235,7 +235,7 @@
 
 	/**
 	 * Creates the {@link NdMethodAnnotationData} struct for this method if it does not already exist. Returns
-	 * the existing or newly-created struct. 
+	 * the existing or newly-created struct.
 	 */
 	public NdMethodAnnotationData createAnnotationData() {
 		NdMethodAnnotationData result = getAnnotationData();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java
index 7dbac48..7accb29 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdResourceFile.java
@@ -79,7 +79,7 @@
 		type.done();
 	}
 
-	private long jdkLevel; 
+	private long jdkLevel;
 
 	public NdResourceFile(Nd dom, long address) {
 		super(dom, address);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeInterface.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeInterface.java
index 25aefe0..e1df69e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeInterface.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/NdTypeInterface.java
@@ -36,7 +36,7 @@
 		IMPLEMENTS = FieldManyToOne.create(type, NdTypeSignature.IMPLEMENTATIONS);
 		type.done();
 	}
-	
+
 	public NdTypeInterface(Nd nd, long address) {
 		super(nd, address);
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleDescriptor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleDescriptor.java
index de74b4a..03a6e63 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleDescriptor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleDescriptor.java
@@ -28,7 +28,7 @@
 
 	/**
 	 * Constructs a new descriptor
-	 * 
+	 *
 	 * @param location
 	 *            location where the archive (.jar or .class) can be found in the local filesystem
 	 * @param moduleName
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleFactory.java
index 95342d8..0733edb 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleFactory.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryModuleFactory.java
@@ -86,8 +86,8 @@
 	 * the file on disk, the type is read from the index. Otherwise the type is read from disk. Returns null if
 	 * no such type exists.
 	 * <strong>caveat</strong> modules are not yet supported in the index.
-	 * 
-	 * @throws ClassFormatException 
+	 *
+	 * @throws ClassFormatException
 	 */
 	public static IBinaryModule readModule(BinaryModuleDescriptor descriptor, IProgressMonitor monitor) throws JavaModelException, ClassFormatException {
 // FIXME: support module in the new index
@@ -100,7 +100,7 @@
 //		}
 		return rawReadModule(descriptor, true);
 	}
-	
+
 	public static IBinaryModule rawReadModule(BinaryModuleDescriptor descriptor, boolean fullyInitialize) throws JavaModelException, ClassFormatException {
 		try {
 			return rawReadModuleTestForExists(descriptor, fullyInitialize, true);
@@ -112,7 +112,7 @@
 	/**
 	 * Read the class file from disk, circumventing the index's cache. This should only be used by callers
 	 * that need to read information from the class file which aren't present in the index (such as method bodies).
-	 * 
+	 *
 	 * @return the newly-created IBinaryModule or null if the given class file does not exist.
 	 * @throws ClassFormatException if the class file existed but was corrupt
 	 * @throws JavaModelException if unable to read the class file due to a transient failure
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeDescriptor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeDescriptor.java
index 1b1ae6a..737ef1c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeDescriptor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeDescriptor.java
@@ -28,7 +28,7 @@
 
 	/**
 	 * Constructs a new descriptor
-	 * 
+	 *
 	 * @param location
 	 *            location where the archive (.jar or .class) can be found in the local filesystem
 	 * @param fieldDescriptor
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java
index 2f31849..f046d3e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java
@@ -121,7 +121,7 @@
 	 * Reads the given binary type. If the type can be found in the index with a fingerprint that exactly matches
 	 * the file on disk, the type is read from the index. Otherwise the type is read from disk. Returns null if
 	 * no such type exists.
-	 * @throws ClassFormatException 
+	 * @throws ClassFormatException
 	 */
 	public static IBinaryType readType(BinaryTypeDescriptor descriptor, IProgressMonitor monitor) throws JavaModelException, ClassFormatException {
 
@@ -147,7 +147,7 @@
 	/**
 	 * Read the class file from disk, circumventing the index's cache. This should only be used by callers
 	 * that need to read information from the class file which aren't present in the index (such as method bodies).
-	 * 
+	 *
 	 * @return the newly-created ClassFileReader or null if the given class file does not exist.
 	 * @throws ClassFormatException if the class file existed but was corrupt
 	 * @throws JavaModelException if unable to read the class file due to a transient failure
@@ -210,7 +210,7 @@
 	 * able to determine that the requested class does not exist in that file.
 	 */
 	public static IBinaryType readFromIndex(JavaIndex index, BinaryTypeDescriptor descriptor, IProgressMonitor monitor) throws JavaModelException, NotInIndexException {
-		// If the new index is enabled, check if we have this class file cached in the index already		
+		// If the new index is enabled, check if we have this class file cached in the index already
 		char[] fieldDescriptor = descriptor.fieldDescriptor;
 
 		Nd nd = index.getNd();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java
index ad3de80..a46a254 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/IndexBinaryType.java
@@ -455,7 +455,7 @@
 		method.getGenericSignature(result, method.hasAllFlags(NdMethod.FLG_THROWS_SIGNATURE_PRESENT));
 		return result.getContents();
 	}
-	
+
 	private char[][] getArgumentNames(NdMethod ndMethod) {
 		// Unlike what its JavaDoc says, IBinaryType returns an empty array if no argument names are available, so
 		// we replicate this weird undocumented corner case here.
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/CharArrayUtils.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/CharArrayUtils.java
index f84f0ea..aeb2e31 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/CharArrayUtils.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/CharArrayUtils.java
@@ -97,7 +97,7 @@
 
 	/**
 	 * Returns {@code true} if the contents of a section of a character array are the same as contents of a string.
-	 * 
+	 *
 	 * @since 5.5
 	 */
 	public static final boolean equals(char[] str1, int start1, int length1, String str2) {
@@ -460,9 +460,7 @@
     public static void overWrite(char[] buff, int i, char[] charImage) {
         if (buff.length < i + charImage.length)
             return;
-        for (int j = 0; j < charImage.length; j++) {
-            buff[i + j] = charImage[j];
-        }
+		System.arraycopy(charImage, 0, buff, i, charImage.length);
     }
 
     /**
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/PathMap.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/PathMap.java
index b5c5711..e1ecc4d 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/PathMap.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/util/PathMap.java
@@ -100,7 +100,7 @@
 	    	if (this.children == null) {
 	    		return;
 	    	}
-	
+
 	    	for (Entry<String, Node<T>> next : this.children.entrySet()) {
 	    		String key = next.getKey();
 	    		IPath nextPath = buildChildPath(parent, key);
@@ -112,7 +112,7 @@
 	      IPath nextPath = parent.append(key);
 	      return nextPath;
 	    }
-		
+
 	    public void toString(StringBuilder builder, IPath parentPath) {
 		    if (this.exists) {
 		    	builder.append("["); //$NON-NLS-1$
@@ -121,7 +121,7 @@
 		    	builder.append(this.value);
 		    	builder.append("\n"); //$NON-NLS-1$
 		    }
-		    if (this.children != null) { 
+		    if (this.children != null) {
 		    	for (Entry<String, Node<T>> next : this.children.entrySet()) {
 		    		String key = next.getKey();
 		    		IPath nextPath = buildChildPath(parentPath, key);
@@ -165,7 +165,7 @@
     		nextPath.setDevice(key);
     		return nextPath;
 		}
-		
+
 		@Override
 		public void toString(StringBuilder builder, IPath parentPath) {
 			this.noDevice.toString(builder, parentPath);
@@ -226,7 +226,7 @@
 	@Override
 	public String toString() {
 		StringBuilder builder = new StringBuilder();
-		
+
 		this.root.toString(builder, Path.EMPTY);
 		return builder.toString();
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
index a8763cc..ea1f5e6 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
@@ -144,7 +144,7 @@
 		}
 		return createJavaSearchScope(excludeTestCode, elements, includeMask);
 	}
-	
+
 	public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements, int includeMask) {
 		return createJavaSearchScope(false, elements, includeMask);
 	}
@@ -488,7 +488,7 @@
 		boolean isPkgCaseSensitive = (matchRulePkg & SearchPattern.R_CASE_SENSITIVE) != 0;
 		if (patternPkg != null && !CharOperation.equals(patternPkg, pkg, isPkgCaseSensitive))
 			return false;
-		
+
 		boolean isCaseSensitive = (matchRuleType & SearchPattern.R_CASE_SENSITIVE) != 0;
 		if (patternTypeName != null) {
 			boolean isCamelCase = (matchRuleType & (SearchPattern.R_CAMELCASE_MATCH | SearchPattern.R_CAMELCASE_SAME_PART_COUNT_MATCH)) != 0;
@@ -546,28 +546,28 @@
 					return matchFirstChar && CharOperation.camelCaseMatch(patternName, name, true);
 			}
 		}
-		return true;		
+		return true;
 	}
 
-	boolean match(char[] patternPkg, int matchRulePkg, 
+	boolean match(char[] patternPkg, int matchRulePkg,
 			char[] patternDeclaringQualifier, int matchRuleDeclaringQualifier,
 			char[] patternDeclaringSimpleName, int matchRuleDeclaringSimpleName,
-			char[] patternMethodName, int methodMatchRule, 
+			char[] patternMethodName, int methodMatchRule,
 			char[] packageName, char[] declaringQualifier, char[] declaringSimpleName, char[] methodName) {
-		
+
 		if (patternPkg != null && !CharOperation.equals(patternPkg, packageName, (matchRulePkg & SearchPattern.R_CASE_SENSITIVE) != 0))
 			return false;
-		
+
 		return match(patternDeclaringQualifier, matchRuleDeclaringQualifier, declaringQualifier) &&
 				match(patternDeclaringSimpleName, matchRuleDeclaringSimpleName, declaringSimpleName) &&
 				match(patternMethodName, methodMatchRule, methodName);
-		
+
 	}
-	
-	boolean match(char[] patternFusedQualifier, int matchRuleFusedQualifier, 
-			char[] patternMethodName, int methodMatchRule, 
+
+	boolean match(char[] patternFusedQualifier, int matchRuleFusedQualifier,
+			char[] patternMethodName, int methodMatchRule,
 			char[] packageName, char[] declaringQualifier, char[] declaringSimpleName, char[] methodName) {
-		
+
 		char[] q = packageName != null ? packageName : CharOperation.NO_CHAR;
 		if (declaringQualifier != null && declaringQualifier.length > 0) {
 			q = q.length > 0 ? CharOperation.concat(q, declaringQualifier, '.') : declaringQualifier;
@@ -575,10 +575,10 @@
 		if (declaringSimpleName != null && declaringSimpleName.length > 0) {
 			q = q.length > 0 ? CharOperation.concat(q, declaringSimpleName, '.') : declaringSimpleName;
 		}
-			
+
 		return match(patternFusedQualifier, matchRuleFusedQualifier, q) &&
 				match(patternMethodName, methodMatchRule, methodName);
-		
+
 	}
 	/**
 	 * Searches for matches of a given search pattern. Search patterns can be created using helper
@@ -594,7 +594,7 @@
 		}
 		findMatches(pattern, participants, scope, requestor, monitor);
 	}
-	
+
 	public void searchAllConstructorDeclarations(
 		final char[] packageName,
 		final char[] typeName,
@@ -607,10 +607,10 @@
 		try {
 			// Validate match rule first
 			final int validatedTypeMatchRule = SearchPattern.validateMatchRule(typeName == null ? null : new String (typeName), typeMatchRule);
-			
+
 			final int pkgMatchRule = SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE;
 			final char NoSuffix = IIndexConstants.TYPE_SUFFIX; // Used as TYPE_SUFFIX has no effect in method #match(char, char[] , int, char[], int , int, char[], char[])
-	
+
 			// Debug
 			if (VERBOSE) {
 				Util.verbose("BasicSearchEngine.searchAllConstructorDeclarations(char[], char[], int, IJavaSearchScope, IRestrictedAccessConstructorRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
@@ -623,14 +623,14 @@
 				Util.verbose("	- scope: "+scope); //$NON-NLS-1$
 			}
 			if (validatedTypeMatchRule == -1) return; // invalid match rule => return no results
-	
+
 			// Create pattern
 			IndexManager indexManager = JavaModelManager.getIndexManager();
 			final ConstructorDeclarationPattern pattern = new ConstructorDeclarationPattern(
 					packageName,
 					typeName,
 					validatedTypeMatchRule);
-	
+
 			// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
 			final HashSet workingCopyPaths = new HashSet();
 			String workingCopyPath = null;
@@ -647,14 +647,14 @@
 				}
 			}
 			final String singleWkcpPath = workingCopyPath;
-	
+
 			// Index requestor
 			IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
 				@Override
 				public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
 					// Filter unexpected types
 					ConstructorDeclarationPattern record = (ConstructorDeclarationPattern)indexRecord;
-					
+
 					if ((record.extraFlags & ExtraFlags.IsMemberType) != 0) {
 						return true; // filter out member classes
 					}
@@ -675,7 +675,7 @@
 							}
 							break;
 					}
-	
+
 					// Accept document path
 					AccessRestriction accessRestriction = null;
 					if (access != null) {
@@ -714,7 +714,7 @@
 					return true;
 				}
 			};
-	
+
 			SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 1000);
 			// add type names from indexes
 			indexManager.performConcurrentJob(
@@ -725,7 +725,7 @@
 					searchRequestor),
 				waitingPolicy,
 				subMonitor.split(Math.max(1000-copiesLength, 0)));
-	
+
 			// add type names from working copies
 			if (copies != null) {
 				for (int i = 0; i < copiesLength; i++) {
@@ -736,7 +736,7 @@
 					} else {
 						if (!scope.encloses(workingCopy)) continue;
 					}
-					
+
 					final String path = workingCopy.getPath().toString();
 					if (workingCopy.isConsistent()) {
 						IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
@@ -746,17 +746,17 @@
 							IType type = allTypes[j];
 							char[] simpleName = type.getElementName().toCharArray();
 							if (match(NoSuffix, packageName, pkgMatchRule, typeName, validatedTypeMatchRule, 0/*no kind*/, packageDeclaration, simpleName) && !type.isMember()) {
-								
+
 								int extraFlags = ExtraFlags.getExtraFlags(type);
-								
+
 								boolean hasConstructor = false;
-								
+
 								IMethod[] methods = type.getMethods();
 								for (int k = 0; k < methods.length; k++) {
 									IMethod method = methods[k];
 									if (method.isConstructor()) {
 										hasConstructor = true;
-										
+
 										String[] stringParameterNames = method.getParameterNames();
 										String[] stringParameterTypes = method.getParameterTypes();
 										int length = stringParameterNames.length;
@@ -766,13 +766,13 @@
 											parameterNames[l] = stringParameterNames[l].toCharArray();
 											parameterTypes[l] = Signature.toCharArray(Signature.getTypeErasure(stringParameterTypes[l]).toCharArray());
 										}
-										
+
 										nameRequestor.acceptConstructor(
 												method.getFlags(),
 												simpleName,
 												parameterNames.length,
 												null,// signature is not used for source type
-												parameterTypes, 
+												parameterTypes,
 												parameterNames,
 												type.getFlags(),
 												packageDeclaration,
@@ -781,7 +781,7 @@
 												null);
 									}
 								}
-								
+
 								if (!hasConstructor) {
 									nameRequestor.acceptConstructor(
 											Flags.AccPublic,
@@ -808,10 +808,10 @@
 							class AllConstructorDeclarationsVisitor extends ASTVisitor {
 								private TypeDeclaration[] declaringTypes = new TypeDeclaration[0];
 								private int declaringTypesPtr = -1;
-								
+
 								private void endVisit(TypeDeclaration typeDeclaration) {
 									if (!hasConstructor(typeDeclaration) && typeDeclaration.enclosingType == null) {
-									
+
 										if (match(NoSuffix, packageName, pkgMatchRule, typeName, validatedTypeMatchRule, 0/*no kind*/, packageDeclaration, typeDeclaration.name)) {
 											nameRequestor.acceptConstructor(
 													Flags.AccPublic,
@@ -827,21 +827,21 @@
 													null);
 										}
 									}
-									
+
 									this.declaringTypes[this.declaringTypesPtr] = null;
 									this.declaringTypesPtr--;
 								}
-								
+
 								@Override
 								public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
 									endVisit(typeDeclaration);
 								}
-								
+
 								@Override
 								public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
 									endVisit(memberTypeDeclaration);
 								}
-								
+
 								private boolean hasConstructor(TypeDeclaration typeDeclaration) {
 									AbstractMethodDeclaration[] methods = typeDeclaration.methods;
 									int length = methods == null ? 0 : methods.length;
@@ -850,7 +850,7 @@
 											return true;
 										}
 									}
-									
+
 									return false;
 								}
 								@Override
@@ -870,7 +870,7 @@
 												parameterTypes[l] = CharOperation.concatWith(((QualifiedTypeReference)argument.type).tokens, '.');
 											}
 										}
-										
+
 										TypeDeclaration enclosing = typeDeclaration.enclosingType;
 										char[][] enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
 										while (enclosing != null) {
@@ -881,7 +881,7 @@
 												enclosing = null;
 											}
 										}
-										
+
 										nameRequestor.acceptConstructor(
 												constructorDeclaration.modifiers,
 												typeName,
@@ -899,9 +899,9 @@
 								}
 								@Override
 								public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
-									return false; 
+									return false;
 								}
-								
+
 								private boolean visit(TypeDeclaration typeDeclaration) {
 									if(this.declaringTypes.length <= ++this.declaringTypesPtr) {
 										int length = this.declaringTypesPtr;
@@ -910,12 +910,12 @@
 									this.declaringTypes[this.declaringTypesPtr] = typeDeclaration;
 									return true;
 								}
-								
+
 								@Override
 								public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
 									return visit(typeDeclaration);
 								}
-								
+
 								@Override
 								public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
 									return visit(memberTypeDeclaration);
@@ -934,12 +934,12 @@
 	}
 
 	/**
-	 * Searches for all method declarations in the given scope. 
+	 * Searches for all method declarations in the given scope.
 	 * 	 * <p>
 	 * Warning: This API is in experimental phase and may be modified/removed. Do not use this until this
 	 * comment is removed.
 	 * </p>
-	 * 
+	 *
 	 * @see SearchEngine#searchAllMethodNames(char[], int, char[], int, IJavaSearchScope, MethodNameMatchRequestor, int, IProgressMonitor)
 	 * for detailed comments
 	 */
@@ -995,7 +995,7 @@
 				@Override
 				public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
 					MethodDeclarationPattern record = (MethodDeclarationPattern)indexRecord;
-					
+
 					if ((record.extraFlags & ExtraFlags.IsLocalType) != 0) {
 						return true; // filter out local and anonymous classes
 					}
@@ -1041,21 +1041,21 @@
 							accessRestriction = access.getViolatedRestriction(path);
 						}
 					}
-					if (match(qualifier, qualifierMatchRule, methodName, methodMatchRule, 
+					if (match(qualifier, qualifierMatchRule, methodName, methodMatchRule,
 							record.declaringPackageName, record.declaringQualification, record.declaringSimpleName, record.selector)) {
 						nameRequestor.acceptMethod(
-								record.selector, 
+								record.selector,
 								record.parameterCount,
 								record.declaringQualification,
-								record.declaringSimpleName, 
-								record.declaringTypeModifiers, 
+								record.declaringSimpleName,
+								record.declaringTypeModifiers,
 								record.declaringPackageName,
-								record.signature, 
-								record.parameterTypes, 
+								record.signature,
+								record.parameterTypes,
 								record.parameterNames,
 								record.returnSimpleName,
-								record.modifiers, 
-								documentPath, 
+								record.modifiers,
+								documentPath,
 								accessRestriction,
 								-1 /* method index not applicable as there is no IType here */);
 					}
@@ -1089,7 +1089,7 @@
 					if (workingCopy.isConsistent()) {
 						IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
 						char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
-						
+
 						IType[] allTypes = workingCopy.getAllTypes();
 						for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
 							IType type = allTypes[j];
@@ -1100,7 +1100,7 @@
 							if (!match(qualifier, qualifierMatchRule, q))
 								continue;
 							reportMatchingMethods(methodName, methodMatchRule, nameRequestor, path,
-									packageDeclaration, type, rDeclaringQualification, rSimpleName); 
+									packageDeclaration, type, rDeclaringQualification, rSimpleName);
 						}
 					} else {
 						Parser basicParser = getParser();
@@ -1116,7 +1116,7 @@
 									public IType type;
 									public boolean visitMethods;
 									public char[] enclosingTypeName;
-									
+
 									TypeInfo(TypeDeclaration typeDecl, boolean visitMethods, char[] enclosingTypeName) {
 										this.typeDecl = typeDecl;
 										this.type = workingCopy.getType(new String(typeDecl.name));
@@ -1164,13 +1164,13 @@
 									if (typeInfo.visitMethods &&
 										match(methodName, methodMatchRule, methodDeclaration.selector)) {
 										reportMatchingMethod(path, packageDeclaration,
-												typeInfo.enclosingTypeName, 
-												typeInfo.typeDecl, 
+												typeInfo.enclosingTypeName,
+												typeInfo.typeDecl,
 												methodDeclaration,
 												getCurrentType(),
 												nameRequestor);
 									}
-									
+
 									return false; // no need to find methods from local/anonymous type
 								}
 								@Override
@@ -1198,12 +1198,12 @@
 		}
 
 	/**
-	 * Searches for all method declarations in the given scope. 
+	 * Searches for all method declarations in the given scope.
 	 * 	 * <p>
 	 * Warning: This API is in experimental phase and may be modified/removed. Do not use this until this
 	 * comment is removed.
 	 * </p>
-	 * 
+	 *
 	 * @see SearchEngine#searchAllMethodNames(char[], int, char[], int, char[], int, char[], int, IJavaSearchScope, MethodNameMatchRequestor, int, IProgressMonitor)
 	 * for detailed comments
 	 */
@@ -1265,7 +1265,7 @@
 				@Override
 				public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
 					MethodDeclarationPattern record = (MethodDeclarationPattern)indexRecord;
-					
+
 					if ((record.extraFlags & ExtraFlags.IsLocalType) != 0) {
 						return true; // filter out local and anonymous classes
 					}
@@ -1311,21 +1311,21 @@
 							accessRestriction = access.getViolatedRestriction(path);
 						}
 					}
-					if (match(packageName, pkgMatchRule, declaringQualification, declQualificationMatchRule, declaringSimpleName, declSimpleNameMatchRule, methodName, methodMatchRule, 
+					if (match(packageName, pkgMatchRule, declaringQualification, declQualificationMatchRule, declaringSimpleName, declSimpleNameMatchRule, methodName, methodMatchRule,
 							record.declaringPackageName, record.declaringQualification, record.declaringSimpleName, record.selector)) {
 						nameRequestor.acceptMethod(
-								record.selector, 
+								record.selector,
 								record.parameterCount,
 								record.declaringQualification,
-								record.declaringSimpleName, 
-								record.declaringTypeModifiers, 
+								record.declaringSimpleName,
+								record.declaringTypeModifiers,
 								record.declaringPackageName,
-								record.signature, 
-								record.parameterTypes, 
+								record.signature,
+								record.parameterTypes,
 								record.parameterNames,
 								record.returnSimpleName,
-								record.modifiers, 
-								documentPath, 
+								record.modifiers,
+								documentPath,
 								accessRestriction,
 								-1 /* method index not applicable as there is no IType here */);
 					}
@@ -1346,7 +1346,7 @@
 
 			// add type names from working copies
 			if (copies != null) {
-				boolean isPkgCaseSensitive = (pkgMatchRule & SearchPattern.R_CASE_SENSITIVE) != 0; 
+				boolean isPkgCaseSensitive = (pkgMatchRule & SearchPattern.R_CASE_SENSITIVE) != 0;
 				for (int i = 0; i < copiesLength; i++) {
 					SubMonitor iterationMonitor = subMonitor.split(1);
 					final ICompilationUnit workingCopy = copies[i];
@@ -1362,7 +1362,7 @@
 						char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
 						if (packageName != null && !CharOperation.equals(packageName, packageDeclaration, isPkgCaseSensitive))
 							continue;
-						
+
 						IType[] allTypes = workingCopy.getAllTypes();
 						for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
 							IType type = allTypes[j];
@@ -1373,7 +1373,7 @@
 									!match(declaringSimpleName, declSimpleNameMatchRule, rSimpleName))
 								continue;
 							reportMatchingMethods(methodName, methodMatchRule, nameRequestor, path,
-									packageDeclaration, type, rDeclaringQualification, rSimpleName); 
+									packageDeclaration, type, rDeclaringQualification, rSimpleName);
 						}
 					} else {
 						Parser basicParser = getParser();
@@ -1389,7 +1389,7 @@
 									public IType type;
 									public boolean visitMethods;
 									public char[] enclosingTypeName;
-									
+
 									TypeInfo(TypeDeclaration typeDecl, boolean visitMethods, char[] enclosingTypeName) {
 										this.typeDecl = typeDecl;
 										this.type = workingCopy.getType(new String(typeDecl.name));
@@ -1437,13 +1437,13 @@
 									if (typeInfo.visitMethods &&
 										match(methodName, methodMatchRule, methodDeclaration.selector)) {
 										reportMatchingMethod(path, packageDeclaration,
-												typeInfo.enclosingTypeName, 
-												typeInfo.typeDecl, 
+												typeInfo.enclosingTypeName,
+												typeInfo.typeDecl,
 												methodDeclaration,
 												getCurrentType(),
 												nameRequestor);
 									}
-									
+
 									return false; // no need to find methods from local/anonymous type
 								}
 								@Override
@@ -1475,7 +1475,7 @@
 			final String path,
 			final char[] packageDeclaration,
 			final char[] declaringQualifier,
-			final TypeDeclaration typeDeclaration, 
+			final TypeDeclaration typeDeclaration,
 			final MethodDeclaration methodDeclaration,
 			final IType type,
 			final IRestrictedAccessMethodRequestor nameRequestor) {
@@ -1500,19 +1500,19 @@
 		} else {
 			char[] returnType = CharOperation.toString(methodDeclaration.returnType.getTypeName()).toCharArray();
 			nameRequestor.acceptMethod(
-					methodDeclaration.selector, 
-					argsLength, 
-					declaringQualifier, 
-					typeDeclaration.name, 
-					typeDeclaration.modifiers, 
-					packageDeclaration, 
-					null, 
-					parameterTypes, 
-					parameterNames, 
-					returnType, 
-					methodDeclaration.modifiers, 
-					path, 
-					null, 
+					methodDeclaration.selector,
+					argsLength,
+					declaringQualifier,
+					typeDeclaration.name,
+					typeDeclaration.modifiers,
+					packageDeclaration,
+					null,
+					parameterTypes,
+					parameterNames,
+					returnType,
+					methodDeclaration.modifiers,
+					path,
+					null,
 					-1 /* method index */);
 		}
 	}
@@ -1521,11 +1521,11 @@
 			IType type, char[] rDeclaringQualification, char[] rSimpleName)
 					throws JavaModelException {
 		IMethod[] methods = type.getMethods();
-		
+
 		for (int k = 0; k < methods.length; k++) {
 			IMethod method = methods[k];
 			if (method.isConstructor()) continue;
-			
+
 			char[] rMethodName = method.getElementName().toCharArray();
 			if (match(methodName, methodMatchRule, rMethodName)) {
 				if (nameRequestor instanceof MethodNameMatchRequestorWrapper) {
@@ -1546,20 +1546,20 @@
 					char[] returnErasure = Signature.toCharArray(Signature.getTypeErasure(signature));
 					CharOperation.replace(returnErasure, '$', '.');
 					char[] returnTypeName =  returnErasure;
-					
+
 					nameRequestor.acceptMethod(
-							rMethodName, 
-							parameterNames.length, 
-							rDeclaringQualification, 
-							rSimpleName, 
+							rMethodName,
+							parameterNames.length,
+							rDeclaringQualification,
+							rSimpleName,
 							type.getFlags(),
-							packageDeclaration, 
-							null, // signature not used for source 
-							parameterTypes, 
-							parameterNames, 
-							returnTypeName, 
-							method.getFlags(), 
-							path, 
+							packageDeclaration,
+							null, // signature not used for source
+							parameterTypes,
+							parameterNames,
+							returnTypeName,
+							method.getFlags(),
+							path,
 							null,
 							k);
 				}
@@ -1595,10 +1595,10 @@
 				buffer.append(waitForIndexes);
 				Util.verbose(buffer.toString());
 			}
-	
+
 			IndexManager indexManager = JavaModelManager.getIndexManager();
 			final TypeDeclarationPattern pattern = new SecondaryTypeDeclarationPattern();
-	
+
 			// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
 			final HashSet workingCopyPaths = new HashSet();
 			String workingCopyPath = null;
@@ -1615,7 +1615,7 @@
 				}
 			}
 			final String singleWkcpPath = workingCopyPath;
-	
+
 			// Index requestor
 			IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
 				@Override
@@ -1642,7 +1642,7 @@
 							}
 							break;
 					}
-	
+
 					// Accept document path
 					AccessRestriction accessRestriction = null;
 					if (access != null) {
@@ -1670,7 +1670,7 @@
 					return true;
 				}
 			};
-	
+
 			// add type names from indexes
 			try {
 				SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 100);
@@ -1716,7 +1716,7 @@
 		try {
 			// Validate match rule first
 			final int validatedTypeMatchRule = SearchPattern.validateMatchRule(typeName == null ? null : new String (typeName), typeMatchRule);
-	
+
 			// Debug
 			if (VERBOSE) {
 				Util.verbose("BasicSearchEngine.searchAllTypeNames(char[], char[], int, int, IJavaSearchScope, IRestrictedAccessTypeRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
@@ -1731,7 +1731,7 @@
 				Util.verbose("	- scope: "+scope); //$NON-NLS-1$
 			}
 			if (validatedTypeMatchRule == -1) return; // invalid match rule => return no results
-	
+
 			// Create pattern
 			IndexManager indexManager = JavaModelManager.getIndexManager();
 			final char typeSuffix;
@@ -1774,7 +1774,7 @@
 					typeName,
 					typeSuffix,
 					validatedTypeMatchRule);
-	
+
 			// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
 			final HashSet workingCopyPaths = new HashSet();
 			String workingCopyPath = null;
@@ -1791,7 +1791,7 @@
 				}
 			}
 			final String singleWkcpPath = workingCopyPath;
-	
+
 			// Index requestor
 			IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
 				@Override
@@ -1815,7 +1815,7 @@
 							}
 							break;
 					}
-	
+
 					// Accept document path
 					AccessRestriction accessRestriction = null;
 					if (access != null) {
@@ -1845,7 +1845,7 @@
 					return true;
 				}
 			};
-	
+
 			SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 1000);
 			// add type names from indexes
 			indexManager.performConcurrentJob(
@@ -1856,7 +1856,7 @@
 					searchRequestor),
 				waitingPolicy,
 				subMonitor.split(Math.max(1000-copiesLength, 0)));
-	
+
 			// add type names from working copies
 			if (copies != null) {
 				for (int i = 0; i < copiesLength; i++) {
@@ -1888,7 +1888,7 @@
 								kind = TypeDeclaration.ENUM_DECL;
 							} else if (type.isAnnotation()) {
 								kind = TypeDeclaration.ANNOTATION_TYPE_DECL;
-							}	else if (type.isClass()) {
+							}	else if (type.isClass() || type.isRecord()) {
 								kind = TypeDeclaration.CLASS_DECL;
 							} else /*if (type.isInterface())*/ {
 								kind = TypeDeclaration.INTERFACE_DECL;
@@ -1993,7 +1993,7 @@
 				Util.verbose("	- scope: "+scope); //$NON-NLS-1$
 			}
 			IndexManager indexManager = JavaModelManager.getIndexManager();
-	
+
 			// Create pattern
 			final char typeSuffix;
 			switch(searchFor){
@@ -2023,7 +2023,7 @@
 					break;
 			}
 			final MultiTypeDeclarationPattern pattern = new MultiTypeDeclarationPattern(qualifications, typeNames, typeSuffix, matchRule);
-	
+
 			// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
 			final HashSet workingCopyPaths = new HashSet();
 			String workingCopyPath = null;
@@ -2040,7 +2040,7 @@
 				}
 			}
 			final String singleWkcpPath = workingCopyPath;
-	
+
 			// Index requestor
 			IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
 				@Override
@@ -2064,7 +2064,7 @@
 							}
 							break;
 					}
-	
+
 					// Accept document path
 					AccessRestriction accessRestriction = null;
 					if (access != null) {
@@ -2076,7 +2076,7 @@
 						if (qualificationLength > 0) {
 							System.arraycopy(record.qualification, 0, path, pos, qualificationLength - 1);
 							CharOperation.replace(path, '.', '/');
-	
+
 							// Access rules work on package level and should not discriminate on enclosing types.
 							boolean isNestedType = record.enclosingTypeNames != null && record.enclosingTypeNames.length > 0;
 							path[qualificationLength-1] = isNestedType ? '$' : '/';
@@ -2095,7 +2095,7 @@
 					return true;
 				}
 			};
-	
+
 			SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 100);
 			// add type names from indexes
 			indexManager.performConcurrentJob(
@@ -2106,7 +2106,7 @@
 					searchRequestor),
 				waitingPolicy,
 				subMonitor.split(100));
-	
+
 			// add type names from working copies
 			if (copies != null) {
 				for (int i = 0, length = copies.length; i < length; i++) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java
index 5b5c3ff..0066665 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/HierarchyScope.java
@@ -68,13 +68,13 @@
 
 	/**
 	 * Creates a new hierarchy scope for the given type with the given configuration options.
-	 * @param project      constrain the search result to this project, 
-	 *                     or <code>null</code> if search should consider all types in the workspace 
+	 * @param project      constrain the search result to this project,
+	 *                     or <code>null</code> if search should consider all types in the workspace
 	 * @param type         the focus type of the hierarchy
-	 * @param owner 	   the owner of working copies that take precedence over original compilation units, 
+	 * @param owner 	   the owner of working copies that take precedence over original compilation units,
 	 *                     or <code>null</code> if the primary working copy owner should be used
 	 * @param onlySubtypes if true search only subtypes of 'type'
-	 * @param noMembersOrEnclosingTypes if true the hierarchy is strict, 
+	 * @param noMembersOrEnclosingTypes if true the hierarchy is strict,
 	 * 					   i.e., no additional member types or enclosing types of types spanning the hierarchy are included,
 	 * 					   otherwise all member and enclosing types of types in the hierarchy are included.
 	 * @param includeFocusType if true the focus type <code>type</code> is included in the resulting scope, otherwise it is excluded
@@ -326,15 +326,15 @@
 		}
 		return false;
 	}
-	/** 
+	/**
 	 * Optionally perform additional checks after element has already passed matching based on index/documents.
-	 * 
+	 *
 	 * @param element the given element
-	 * @return <code>true</code> if the element is enclosed or if no fine grained checking 
+	 * @return <code>true</code> if the element is enclosed or if no fine grained checking
 	 *         (regarding subtypes and members) is requested
 	 */
 	public boolean enclosesFineGrained(IJavaElement element) {
-		if ((this.subTypes == null) && this.allowMemberAndEnclosingTypes) 
+		if ((this.subTypes == null) && this.allowMemberAndEnclosingTypes)
 			return true; // no fine grained checking requested
 		return encloses(element, null);
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
index 092f4b6..fdf45f8 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/IndexSelector.java
@@ -42,12 +42,12 @@
  */
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class IndexSelector {
-	
+
 	//TODO: Bug 386113: "Search references" and "Type hierarchy" show inconsistent results with "External Plug-in Libraries" project
 	public static final int PROJECT_CAN_SEE_FOCUS= 0;
 	public static final int PROJECT_SOURCE_CAN_NOT_SEE_FOCUS= 1;
 	public static final int PROJECT_CAN_NOT_SEE_FOCUS= 2;
-	
+
 	IJavaSearchScope searchScope;
 	SearchPattern pattern;
 	IndexLocation[] indexLocations; // cache of the keys for looking index up
@@ -216,7 +216,7 @@
 	} else {
 		try {
 			// See whether the state builder might be used to reduce the number of index locations
-		
+
 			// find the projects from projectsAndJars that see the focus then walk those projects looking for the jars from projectsAndJars
 			int length = projectsAndJars.length;
 			JavaProject[] projectsCanSeeFocus = new JavaProject[length];
@@ -329,7 +329,7 @@
 		if (primaryType != null) {
 			focusQualifiedNames = new char[size+1][][];
 			focusQualifiedNames[index++] = CharOperation.splitOn('.', primaryType.getFullyQualifiedName().toCharArray());
-		} 
+		}
 	}
 	if (focusQualifiedNames == null) {
 		focusQualifiedNames = new char[size][][];
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchMethodNameMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchMethodNameMatch.java
index 895bce5..ac0c164 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchMethodNameMatch.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchMethodNameMatch.java
@@ -22,10 +22,10 @@
  *
  */
 public class JavaSearchMethodNameMatch extends MethodNameMatch {
-	
+
 	IMethod method = null;
 	int modifiers = -1;
-	
+
 	private int accessibility = IAccessRule.K_ACCESSIBLE; // TODO: this pertains to class/type - need to revisit whether this is required in method name match
 	public JavaSearchMethodNameMatch(IMethod method, int modifiers) {
 		this.method = method;
@@ -46,11 +46,11 @@
 	public IMethod getMethod() {
 		return this.method;
 	}
-	
+
 	public void setAccessibility(int accessibility) {
 		this.accessibility = accessibility;
 	}
-	
+
 	@Override
 	public String toString() {
 		return this.method == null ? super.toString() : this.method.toString();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchTypeNameMatch.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchTypeNameMatch.java
index f4eda90..fd001f9 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchTypeNameMatch.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/JavaSearchTypeNameMatch.java
@@ -85,7 +85,7 @@
 
 /**
  * Sets the accessibility of the accepted match.
- * 
+ *
  * @param accessibility the accessibility of the current match
  */
 public void setAccessibility(int accessibility) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameMatchRequestorWrapper.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameMatchRequestorWrapper.java
index 75cb2d0..b393cc5 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameMatchRequestorWrapper.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameMatchRequestorWrapper.java
@@ -36,7 +36,7 @@
  * IJavaSearchScope scope,
  * IRestrictedAccessMethodRequestor methodRequestor,
  * int waitingPolicy,
- * IProgressMonitor progressMonitor)} from  API method 
+ * IProgressMonitor progressMonitor)} from  API method
  * {@link org.eclipse.jdt.core.search.SearchEngine#searchAllMethodNames(
  * char[] packageName,
  * int pkgMatchRule,
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameRequestorWrapper.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameRequestorWrapper.java
index d8b4a78..51dfb4a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameRequestorWrapper.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameRequestorWrapper.java
@@ -45,13 +45,13 @@
  * IJavaSearchScope scope,
  * MethodNameRequestor methodRequestor,
  * int waitingPolicy,
- * IProgressMonitor progressMonitor)}.  
+ * IProgressMonitor progressMonitor)}.
  *
  */
 public class MethodNameRequestorWrapper implements IRestrictedAccessMethodRequestor {
-	
+
 	MethodNameRequestor requestor;
-	
+
 	public MethodNameRequestorWrapper(MethodNameRequestor requestor) {
 		this.requestor = requestor;
 	}
@@ -61,7 +61,7 @@
 			char[] simpleTypeName, int typeModifiers, char[] packageName, char[] signature, char[][] parameterTypes,
 			char[][] parameterNames, char[] returnType, int modifiers, String path,
 			AccessRestriction access, int methodIndex) {
-		this.requestor.acceptMethod(methodName, parameterCount, declaringQualification, simpleTypeName, typeModifiers, 
+		this.requestor.acceptMethod(methodName, parameterCount, declaringQualification, simpleTypeName, typeModifiers,
 				packageName, signature, parameterTypes, parameterNames, returnType, modifiers, path, methodIndex);
 	}
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/NameMatchRequestorWrapper.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/NameMatchRequestorWrapper.java
index 923e425..2480f99 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/NameMatchRequestorWrapper.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/NameMatchRequestorWrapper.java
@@ -125,7 +125,7 @@
 	IPackageFragment pkgFragment= (IPackageFragment) this.packageHandles.get(pkgName);
 	if (pkgFragment == null) {
 		pkgFragment= ((PackageFragmentRoot) this.lastPkgFragmentRoot).getPackageFragment(pkgName, moduleName); //BUG 478143
-		// filter org.apache.commons.lang.enum package for projects above 1.5 
+		// filter org.apache.commons.lang.enum package for projects above 1.5
 		// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=317264
 		if (length == 5 && pkgName[4].equals("enum")) { //$NON-NLS-1$
 			IJavaProject proj = (IJavaProject)pkgFragment.getAncestor(IJavaElement.JAVA_PROJECT);
@@ -136,7 +136,7 @@
 			}
 			if (this.complianceValue >= ClassFileConstants.JDK1_5)
 				return null;
-		} 
+		}
 		this.packageHandles.put(pkgName, pkgFragment);
 	}
 	return pkgFragment.getOrdinaryClassFile(simpleNames[length]).getType();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/UnindexedSearchScope.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/UnindexedSearchScope.java
index 1b6135b..5fdc740 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/UnindexedSearchScope.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/UnindexedSearchScope.java
@@ -26,7 +26,7 @@
 
 public class UnindexedSearchScope extends AbstractSearchScope {
 	private IJavaSearchScope searchScope;
-	
+
 	private UnindexedSearchScope(IJavaSearchScope scope) {
 		this.searchScope = scope;
 	}
@@ -34,7 +34,7 @@
 	public static IJavaSearchScope filterEntriesCoveredByTheNewIndex(IJavaSearchScope scope) {
 		return new UnindexedSearchScope(scope);
 	}
-	
+
 	@Override
 	public boolean encloses(String resourcePathString) {
 		int separatorIndex = resourcePathString.indexOf(JAR_FILE_ENTRY_SEPARATOR);
@@ -76,9 +76,9 @@
 	@Override
 	public IPath[] enclosingProjectsAndJars() {
 		IPath[] unfiltered = this.searchScope.enclosingProjectsAndJars();
-		
+
 		List<IPath> result = new ArrayList<>();
-		
+
 		for (IPath next : unfiltered) {
 			if (isJarFile(next.lastSegment())) {
 				continue;
@@ -92,7 +92,7 @@
 	public void processDelta(IJavaElementDelta delta, int eventType) {
 		if (this.searchScope instanceof AbstractSearchScope) {
 			AbstractSearchScope inner = (AbstractSearchScope) this.searchScope;
-			
+
 			inner.processDelta(delta, eventType);
 		}
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
index 94f3465..39ca9d1 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AbstractIndexer.java
@@ -97,7 +97,7 @@
 						packageName,
 						typeModifiers,
 						extraFlags));
-		
+
 		if (parameterTypes != null) {
 			for (int i = 0; i < argCount; i++)
 				addTypeReference(parameterTypes[i]);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java
index aa6f0e5..ea72272 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJarFileToIndex.java
@@ -92,7 +92,7 @@
 
 		if (hasPreBuiltIndex()) {
 			boolean added = this.manager.addIndex(this.containerPath, this.indexFileURL);
-			if (added) return true;	
+			if (added) return true;
 			this.indexFileURL = null;
 		}
 
@@ -235,7 +235,7 @@
 					// iterate each entry to index it
 					ZipEntry ze = (ZipEntry) e.nextElement();
 					String zipEntryName = ze.getName();
-					if (Util.isClassFileName(zipEntryName) && 
+					if (Util.isClassFileName(zipEntryName) &&
 							isValidPackageNameForClassOrisModule(zipEntryName)) {
 						hasModuleInfoClass |= zipEntryName.contains(TypeConstants.MODULE_INFO_NAME_STRING);
 						// index only classes coming from valid packages - https://bugs.eclipse.org/bugs/show_bug.cgi?id=293861
@@ -293,7 +293,7 @@
 		if (this.resource != null)
 			return super.getJobFamily();
 		return this.containerPath.toOSString(); // external jar
-	}	
+	}
 	@Override
 	protected Integer updatedIndexState() {
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJrtToIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJrtToIndex.java
index baa8c67..6401cbc 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJrtToIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/AddJrtToIndex.java
@@ -43,7 +43,7 @@
 	private IndexLocation indexFileURL;
 	private final boolean forceIndexUpdate;
 	static final char JAR_SEPARATOR = IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR.charAt(0);
-	
+
 	enum FILE_INDEX_STATE {
 		EXISTS,
 		DELETED
@@ -79,9 +79,9 @@
 			return this.containerPath.hashCode();
 		return -1;
 	}
-	
+
 	private class JrtTraverser implements org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor<java.nio.file.Path> {
-		
+
 		SimpleLookupTable indexedFileNames;
 		public JrtTraverser() {
 		}
@@ -99,7 +99,7 @@
 		public FileVisitResult visitFile(java.nio.file.Path path, java.nio.file.Path mod, BasicFileAttributes attrs)
 				throws IOException {
 			String name = JRTUtil.sanitizedFileName(path);
-			if (Util.isClassFileName(name) && 
+			if (Util.isClassFileName(name) &&
 					isValidPackageNameForClassOrisModule(name)) {
 				this.indexedFileNames.put(name, FILE_INDEX_STATE.EXISTS);
 			}
@@ -110,7 +110,7 @@
 			return FileVisitResult.CONTINUE;
 		}
 	}
-	
+
 	private class JrtIndexer extends JrtTraverser {
 		final SearchParticipant participant;
 		final IPath indexPath;
@@ -133,7 +133,7 @@
 		public FileVisitResult visitFile(java.nio.file.Path path, java.nio.file.Path mod, BasicFileAttributes attrs)
 				throws IOException {
 			String name = JRTUtil.sanitizedFileName(path);
-			if (Util.isClassFileName(name) && 
+			if (Util.isClassFileName(name) &&
 					isValidPackageNameForClassOrisModule(name)) {
 				try {
 					String fullPath = path.toString();
@@ -157,7 +157,7 @@
 
 		if (hasPreBuiltIndex()) {
 			boolean added = this.manager.addIndex(this.containerPath, this.indexFileURL);
-			if (added) return true;	
+			if (added) return true;
 			this.indexFileURL = null;
 		}
 
@@ -211,7 +211,7 @@
 					container =  this.resource.getFullPath().makeRelative();
 					// absolute path relative to the workspace
 				} else {
-					
+
 					fileName = this.containerPath.toOSString();
 					container = this.containerPath;
 				}
@@ -228,12 +228,12 @@
 					 * If not, then we want to check that there is no missing entry, if
 					 * one entry is missing then we recreate the index
 					 */
-					
+
 					final SimpleLookupTable indexedFileNames = new SimpleLookupTable(max == 0 ? 33 : max + 11);
 					for (int i = 0; i < max; i++)
 						indexedFileNames.put(paths[i], FILE_INDEX_STATE.DELETED);
-					
-					org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(new File(fileName), 
+
+					org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(new File(fileName),
 							new JrtTraverser(indexedFileNames), JRTUtil.NOTIFY_FILES);
 
 					boolean needToReindex = indexedFileNames.elementSize != max; // a new file was added
@@ -263,9 +263,9 @@
 					this.manager.removeIndex(this.containerPath);
 					return false;
 				}
-				
+
 				File jrt = new File(fileName);
-				org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(jrt, 
+				org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(jrt,
 						new JrtIndexer(jrt, SearchEngine.getDefaultSearchParticipant(), index, container, this.manager), JRTUtil.NOTIFY_FILES);
 
 				if(this.forceIndexUpdate) {
@@ -296,7 +296,7 @@
 		if (this.resource != null)
 			return super.getJobFamily();
 		return this.containerPath.toOSString(); // external jar
-	}	
+	}
 	@Override
 	protected Integer updatedIndexState() {
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryContainer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryContainer.java
index 44ccb0b..882f879 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryContainer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryContainer.java
@@ -29,7 +29,7 @@
 
 	private boolean isIdentifier() throws InvalidInputException {
 		switch(this.scanner.scanIdentifier()) {
-			// assert and enum will not be recognized as java identifiers 
+			// assert and enum will not be recognized as java identifiers
 			// in 1.7 mode, which are in 1.3.
 			case TerminalTokens.TokenNameIdentifier:
 			case TerminalTokens.TokenNameassert:
@@ -40,7 +40,7 @@
 		}
 	}
 	protected boolean isValidPackageNameForClassOrisModule(String className) {
-		if (className.substring(0, className.length() - (SuffixConstants.SUFFIX_CLASS.length)).equals(new String(IIndexConstants.MODULE_INFO))) 
+		if (className.substring(0, className.length() - (SuffixConstants.SUFFIX_CLASS.length)).equals(new String(IIndexConstants.MODULE_INFO)))
 			return true;
 		char[] classNameArray = className.toCharArray();
 		// use 1.7 as the source level as there are more valid identifiers in 1.7 mode
@@ -48,8 +48,8 @@
 		if (this.scanner == null)
 			this.scanner = new Scanner(false /* comment */, true /* whitespace */, false /* nls */,
 					ClassFileConstants.JDK1_7/* sourceLevel */, null/* taskTag */, null/* taskPriorities */, true /* taskCaseSensitive */);
-		
-		this.scanner.setSource(classNameArray); 
+
+		this.scanner.setSource(classNameArray);
 		this.scanner.eofPosition = classNameArray.length - SuffixConstants.SUFFIX_CLASS.length;
 		try {
 			if (isIdentifier()) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java
index 8e1fb39..571f08f 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -161,6 +161,13 @@
 			}
 			addFieldReference(TypeConstants.UPPER_MODULE);
 		}
+		if ((bits & TagBits.AnnotationForRecordComponent) != 0) {
+			if (compoundName == null) {
+				compoundName = TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE;
+				addTypeReference(compoundName[compoundName.length-1]);
+			}
+			addFieldReference(TypeConstants.UPPER_RECORD_COMPONENT);
+		}
 	}
 	private void addBinaryRetentionAnnotation(long bits) {
 		char[][] compoundName = TypeConstants.JAVA_LANG_ANNOTATION_RETENTIONPOLICY;
@@ -650,7 +657,7 @@
 			if (contents == null) return;
 			final String path = this.document.getPath();
 			ClassFileReader reader = new ClassFileReader(contents, path == null ? null : path.toCharArray());
-			
+
 			IModule module = reader.getModuleDeclaration();
 			if (module != null) {
 				indexModule(module);
@@ -721,6 +728,10 @@
 				case TypeDeclaration.ANNOTATION_TYPE_DECL :
 					addAnnotationTypeDeclaration(modifiers, packageName, name, enclosingTypeNames, false);
 					break;
+				case TypeDeclaration.RECORD_DECL :
+					superclass = replace('/', '.', reader.getSuperclassName());
+					addClassDeclaration(modifiers, packageName, name, enclosingTypeNames, superclass, superinterfaces, typeParameterSignatures, false);
+					break;
 			}
 
 			// Look for references in class annotations
@@ -735,7 +746,7 @@
 			if (tagBits != 0) {
 				addBinaryStandardAnnotations(tagBits);
 			}
-			
+
 			int extraFlags = ExtraFlags.getExtraFlags(reader);
 
 			// first reference all methods declarations and field declarations
@@ -762,7 +773,7 @@
 						addConstructorDeclaration(
 								name,
 								parameterTypes == null ? 0 : parameterTypes.length,
-								signature,	
+								signature,
 								parameterTypes,
 								method.getArgumentNames(),
 								method.getModifiers(),
@@ -784,7 +795,7 @@
 										null,
 										selector,
 										parameterTypes == null ? 0 : parameterTypes.length,
-												signature,	
+												signature,
 												parameterTypes,
 												method.getArgumentNames(),
 												returnType,
@@ -847,7 +858,7 @@
 					e));
 		}
 	}
-	
+
 	private void indexModule(IModule module) {
 		addModuleDeclaration(module.name());
 		IModuleReference[] requiredModules = module.requires();
@@ -897,7 +908,7 @@
 			return;
 		addTypeReference(ref);
 	}
-	
+
 	private char[] removeFirstSyntheticParameter(char[] descriptor) {
 		if (descriptor == null) return null;
 		if (descriptor.length < 3) return descriptor;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/DefaultJavaIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/DefaultJavaIndexer.java
index 8fdf254..f298e30 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/DefaultJavaIndexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/DefaultJavaIndexer.java
@@ -33,7 +33,7 @@
 @SuppressWarnings("rawtypes")
 public class DefaultJavaIndexer {
 	private static final char JAR_SEPARATOR = IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR.charAt(0);
-	
+
 	public void generateIndexForJar(String pathToJar, String pathToIndexFile) throws IOException {
 		File f = new File(pathToJar);
 		if (!f.exists()) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
index 8d61692..41efb7e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
@@ -93,7 +93,7 @@
 	public static final Integer REBUILDING_STATE = 3;
 	public static final Integer REUSE_STATE = 4;
 
-	private final IndexNamesRegistry nameRegistry = new IndexNamesRegistry(new File(getSavedIndexesDirectory(), 
+	private final IndexNamesRegistry nameRegistry = new IndexNamesRegistry(new File(getSavedIndexesDirectory(),
 			"savedIndexNames.txt"), getJavaPluginWorkingLocation()); //$NON-NLS-1$
 	// search participants who register indexes with the index manager
 	private SimpleLookupTable participantsContainers = null;
@@ -472,8 +472,8 @@
 			}
 		}
 	} else {
-		// All the index files are getting deleted and hence there is no need to 
-		// further check for change in javaLikeNames. 
+		// All the index files are getting deleted and hence there is no need to
+		// further check for change in javaLikeNames.
 		writeJavaLikeNamesFile();
 		this.javaLikeNamesChanged = false;
 		deleteIndexFiles();
@@ -499,12 +499,12 @@
 /*
  * see https://bugs.eclipse.org/bugs/show_bug.cgi?id=286379
  * Returns true if there is a change in javaLikeNames since it
- * has been last stored. 
- * The javaLikeNames stored in the file javaLikeNames.txt 
- * is compared with the current javaLikeNames and if there is a change, this 
- * function returns true. If the file javaLikeNames.txt doesn't exist and there 
- * is only one javaLikeName (.java), then this returns false so that no-reindexing 
- * happens. 
+ * has been last stored.
+ * The javaLikeNames stored in the file javaLikeNames.txt
+ * is compared with the current javaLikeNames and if there is a change, this
+ * function returns true. If the file javaLikeNames.txt doesn't exist and there
+ * is only one javaLikeName (.java), then this returns false so that no-reindexing
+ * happens.
  */
 private boolean hasJavaLikeNamesChanged() {
 	char[][] currentNames = Util.getJavaLikeExtensions();
@@ -522,12 +522,12 @@
 		return true;
 	}
 	if (current > 1) {
-		// Sort the current java like names. 
+		// Sort the current java like names.
 		// Copy the array to avoid modifying the Util static variable
 		System.arraycopy(currentNames, 0, currentNames = new char[current][], 0, current);
 		Util.sort(currentNames);
 	}
-	
+
 	// The JavaLikeNames would have been sorted before getting stored in the file,
 	// hence just do a direct compare.
 	for (int i = 0; i < current; i++) {
@@ -550,12 +550,12 @@
 public void indexResolvedDocument(SearchDocument searchDocument, SearchParticipant searchParticipant, Index index, IPath indexLocation) {
 	searchParticipant.resolveDocument(searchDocument);
 	ReadWriteMonitor monitor = index.monitor;
-	if (monitor == null) 
+	if (monitor == null)
 		return; // index got deleted since acquired
 	try {
 		monitor.enterWrite(); // ask permission to write
 		searchDocument.setIndex(index);
-		searchParticipant.indexResolvedDocument(searchDocument, indexLocation);	
+		searchParticipant.indexResolvedDocument(searchDocument, indexLocation);
 	} finally {
 		searchDocument.setIndex(null);
 		monitor.exitWrite();
@@ -640,7 +640,7 @@
 	IndexRequest request = null;
 	Object target = JavaModel.getTarget(path, true);
 	if (target instanceof IFile) {
-		request = isJrt(((IFile) target).getFullPath().toOSString()) ? 
+		request = isJrt(((IFile) target).getFullPath().toOSString()) ?
 				new AddJrtToIndex((IFile) target, indexFile, this, forceIndexUpdate) :
 					new AddJarFileToIndex((IFile) target, indexFile, this, forceIndexUpdate);
 	} else if (target instanceof File) {
@@ -719,7 +719,7 @@
 }
 private char[][] readJavaLikeNamesFile() {
 	try {
-		String pathName = getJavaPluginWorkingLocation().toOSString();	
+		String pathName = getJavaPluginWorkingLocation().toOSString();
 		File javaLikeNamesFile = new File(pathName, "javaLikeNames.txt"); //$NON-NLS-1$
 		if (!javaLikeNamesFile.exists())
 			return null;
@@ -755,7 +755,7 @@
 	} else if (target instanceof IFolder) {
 		request = new IndexBinaryFolder((IFolder) target, this);
 	} else if (target instanceof IFile) {
-		request = isJrt(((IFile) target).getFullPath().toOSString()) ? 
+		request = isJrt(((IFile) target).getFullPath().toOSString()) ?
 				new AddJrtToIndex((IFile) target, null, this, updateIndex) :
 					new AddJarFileToIndex((IFile) target, null, this, updateIndex);
 	} else if (target instanceof File) {
@@ -1121,7 +1121,7 @@
 					this.indexLocations.put(new Path(new String(names[i+1])), indexPath );
 					this.indexStates.put(indexPath, REUSE_STATE);
 				}
-			}		
+			}
 		}
 	} catch (IOException ignored) {
 		if (VERBOSE)
@@ -1137,14 +1137,14 @@
 			char[][] names = CharOperation.splitOn('\n', participantIndexNames);
 			if (names.length >= 3) {
 				// First line is DiskIndex signature  (see writeParticipantsIndexNamesFile())
-				if (DiskIndex.SIGNATURE.equals(new String(names[0]))) {					
+				if (DiskIndex.SIGNATURE.equals(new String(names[0]))) {
 					for (int i = 1, l = names.length-1 ; i < l ; i+=2) {
 						IndexLocation indexLocation = new FileIndexLocation(new File(new String(names[i])), true);
 						containers.put(indexLocation, new Path(new String(names[i+1])));
 					}
-				}				
+				}
 			}
-		}	
+		}
 	} catch (IOException ignored) {
 		if (VERBOSE)
 			Util.verbose("Failed to read participant index file names"); //$NON-NLS-1$
@@ -1213,11 +1213,11 @@
 private void writeJavaLikeNamesFile() {
 	BufferedWriter writer = null;
 	String pathName = getJavaPluginWorkingLocation().toOSString();
-	try {		
+	try {
 		char[][] currentNames = Util.getJavaLikeExtensions();
 		int length = currentNames.length;
 		if (length > 1) {
-			// Sort the current java like names. 
+			// Sort the current java like names.
 			// Copy the array to avoid modifying the Util static variable
 			System.arraycopy(currentNames, 0, currentNames=new char[length][], 0, length);
 			Util.sort(currentNames);
@@ -1228,9 +1228,9 @@
 			writer.write(currentNames[i]);
 			writer.write('\n');
 		}
-		if (length > 0) 
+		if (length > 0)
 			writer.write(currentNames[length-1]);
-		
+
 	} catch (IOException ignored) {
 		if (VERBOSE)
 			Util.verbose("Failed to write javaLikeNames file", System.err); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexNamesRegistry.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexNamesRegistry.java
index e9ec356..69eced3 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexNamesRegistry.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexNamesRegistry.java
@@ -100,7 +100,7 @@
 		}
 
 		subMonitor.setWorkRemaining(newContents.length);
-		
+
 		try (BufferedWriter writer = new BufferedWriter(new FileWriter(this.savedIndexNamesFile))) {
 			writer.write(DiskIndex.SIGNATURE);
 			writer.write('+');
@@ -136,6 +136,6 @@
 		synchronized (this.queueMutex) {
 			this.pendingWrite = null;
 		}
-		this.savedIndexNamesFile.delete(); 
+		this.savedIndexNamesFile.delete();
 	}
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java
index 82e1f4a..39d388a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexer.java
@@ -82,7 +82,7 @@
 	private CompilationUnit compilationUnit;
 	private CompilationUnitDeclaration cud;
 	private static final boolean DEBUG = false;
-	
+
 	public SourceIndexer(SearchDocument document) {
 		super(document);
 		this.requestor = new SourceIndexerRequestor(this);
@@ -120,7 +120,7 @@
 			}
 		}
 	}
-	
+
 	@Override
 	public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) {
 		this.lookupEnvironment.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction);
@@ -142,9 +142,9 @@
 		SourceTypeElementInfo elementInfo = (SourceTypeElementInfo) sourceType;
 		IType type = elementInfo.getHandle();
 		ICompilationUnit sourceUnit = (ICompilationUnit) type.getCompilationUnit();
-		accept(sourceUnit, accessRestriction);		
+		accept(sourceUnit, accessRestriction);
 	}
-	
+
 	public void resolveDocument() {
 		try {
 			IPath path = new Path(this.document.getPath());
@@ -219,11 +219,11 @@
 					if (lambdaExpression.binding != null && lambdaExpression.binding.isValidBinding()) {
 						final char[] superinterface = lambdaExpression.resolvedType.sourceName();
 						if (DEBUG) {
-							System.out.println('\t' + new String(superinterface) + '.' + 
+							System.out.println('\t' + new String(superinterface) + '.' +
 									new String(lambdaExpression.descriptor.selector) + "-> {}"); //$NON-NLS-1$
 						}
 						SourceIndexer.this.addIndexEntry(IIndexConstants.METHOD_DECL, MethodPattern.createIndexKey(lambdaExpression.descriptor.selector, lambdaExpression.descriptor.parameters.length));
-					
+
 						addClassDeclaration(0,  // most entries are blank, that is fine, since lambda type/method cannot be searched.
 								CharOperation.NO_CHAR, // package name
 								ONE_ZERO,
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java
index a68e2d5..99c96f3 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/SourceIndexerRequestor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -153,7 +153,7 @@
 
 private void addDefaultConstructorIfNecessary(TypeInfo typeInfo) {
 	boolean hasConstructor = false;
-	
+
 	TypeDeclaration typeDeclaration = typeInfo.node;
 	AbstractMethodDeclaration[] methods = typeDeclaration.methods;
 	int methodCounter = methods == null ? 0 : methods.length;
@@ -164,7 +164,7 @@
 			break done;
 		}
 	}
-	
+
 	if (!hasConstructor) {
 		this.indexer.addDefaultConstructorDeclaration(
 				typeInfo.name,
@@ -200,6 +200,11 @@
 	pushTypeName(typeInfo.name);
 }
 
+private void enterRecord(TypeInfo typeInfo) {
+	enterClass(typeInfo);
+	// TODO : Need to handle Compact Constructor here
+}
+
 private void enterClass(TypeInfo typeInfo) {
 
 	// eliminate possible qualifications, given they need to be fully resolved again
@@ -330,7 +335,7 @@
 		}
 	}
 	enterPackageVisibilityInfo(moduleInfo.exports);
-	enterPackageVisibilityInfo(moduleInfo.opens); 
+	enterPackageVisibilityInfo(moduleInfo.opens);
 	/* note: provides and uses directives processed automatically on IParser (SEParser) */
 }
 private void enterPackageVisibilityInfo(ISourceElementRequestor.PackageExportInfo[] packInfos) {
@@ -392,7 +397,7 @@
 
 	int l = nlist.size();
 	if (l == 1) return name;
-	
+
 	name = new char[size];
 	int index = 0;
 	for (int i = 0; i < l - 1; ++i) {
@@ -424,6 +429,9 @@
 		case TypeDeclaration.ENUM_DECL:
 			enterEnum(typeInfo);
 			break;
+		case TypeDeclaration.RECORD_DECL:
+			enterRecord(typeInfo);
+			break;
 	}
 }
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
index 674ab92..b64353a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ClassFileMatchLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -35,7 +35,8 @@
 	TagBits.AnnotationForField |
 	TagBits.AnnotationForConstructor |
 	TagBits.AnnotationForAnnotationType |
-	TagBits.AnnotationForModule;
+	TagBits.AnnotationForModule |
+	TagBits.AnnotationForRecordComponent;
 private static final char[] JAVA_LANG_ANNOTATION_ELEMENTTYPE = CharOperation.concatWith(TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE, '.');
 public static char[] convertClassFileFormat(char[] name) {
 	return CharOperation.replaceOnCopy(name, '/', '.');
@@ -506,7 +507,7 @@
 	int kind  = TypeDeclaration.kind(type.getModifiers());
 	switch (pattern.typeSuffix) {
 		case CLASS_SUFFIX:
-			return kind == TypeDeclaration.CLASS_DECL;
+			return kind == TypeDeclaration.CLASS_DECL || kind == TypeDeclaration.RECORD_DECL;
 		case INTERFACE_SUFFIX:
 			return kind == TypeDeclaration.INTERFACE_DECL;
 		case ENUM_SUFFIX:
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorDeclarationPattern.java
index ce2c02a..6ef6c6e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorDeclarationPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorDeclarationPattern.java
@@ -20,10 +20,10 @@
 
 public class ConstructorDeclarationPattern extends ConstructorPattern {
 	public int extraFlags;
-	
+
 	public int declaringTypeModifiers;
 	public char[] declaringPackageName;
-	
+
 	public int modifiers;
 	public char[] signature;
 	public char[][] parameterTypes;
@@ -47,11 +47,11 @@
 	int last = key.length - 1;
 	int slash = CharOperation.indexOf(SEPARATOR, key, 0);
 	this.declaringSimpleName = CharOperation.subarray(key, 0, slash);
-	
+
 	int start = slash + 1;
 	slash = CharOperation.indexOf(SEPARATOR, key, start);
 	last = slash - 1;
-	
+
 	boolean isDefaultConstructor = key[last] == '#';
 	if (isDefaultConstructor) {
 		this.parameterCount = -1;
@@ -67,23 +67,23 @@
 			}
 		}
 	}
-	
+
 	slash = slash + 3;
 	last = slash - 1;
-	
+
 	int typeModifiersWithExtraFlags = key[last-1] + (key[last]<<16);
 	this.declaringTypeModifiers = decodeModifers(typeModifiersWithExtraFlags);
 	this.extraFlags = decodeExtraFlags(typeModifiersWithExtraFlags);
-	
+
 	// initialize optional fields
 	this.declaringPackageName = null;
 	this.modifiers = 0;
 	this.signature = null;
 	this.parameterTypes = null;
 	this.parameterNames = null;
-	
+
 	boolean isMemberType = (this.extraFlags & ExtraFlags.IsMemberType) != 0;
-	
+
 	if (!isMemberType) {
 		start = slash + 1;
 		if (this.parameterCount == -1) {
@@ -93,19 +93,19 @@
 			slash = CharOperation.indexOf(SEPARATOR, key, start);
 		}
 		last = slash - 1;
-		
+
 		this.declaringPackageName = CharOperation.subarray(key, start, slash);
-		
+
 		start = slash + 1;
 		if (this.parameterCount == 0) {
 			slash = slash + 3;
 			last = slash - 1;
-			
+
 			this.modifiers = key[last-1] + (key[last]<<16);
 		} else if (this.parameterCount > 0){
 			slash = CharOperation.indexOf(SEPARATOR, key, start);
 			last = slash - 1;
-			
+
 			boolean hasParameterStoredAsSignature = (this.extraFlags & ExtraFlags.ParameterTypesStoredAsSignature) != 0;
 			if (hasParameterStoredAsSignature) {
 				this.signature  = CharOperation.subarray(key, start, slash);
@@ -116,20 +116,20 @@
 			start = slash + 1;
 			slash = CharOperation.indexOf(SEPARATOR, key, start);
 			last = slash - 1;
-			
+
 			if (slash != start) {
 				this.parameterNames = CharOperation.splitOn(PARAMETER_SEPARATOR, key, start, slash);
 			}
-			
+
 			slash = slash + 3;
 			last = slash - 1;
-			
+
 			this.modifiers = key[last-1] + (key[last]<<16);
 		} else {
 			this.modifiers = ClassFileConstants.AccPublic;
 		}
 	}
-	
+
 	removeInternalFlags(); // remove internal flags
 }
 
@@ -144,10 +144,10 @@
 @Override
 public boolean matchesDecodedKey(SearchPattern decodedPattern) {
 	ConstructorDeclarationPattern pattern = (ConstructorDeclarationPattern) decodedPattern;
-	
+
 	// only top level types
 	if ((pattern.extraFlags & ExtraFlags.IsMemberType) != 0) return false;
-	
+
 	// check package - exact match only
 	if (this.declaringPackageName != null && !CharOperation.equals(this.declaringPackageName, pattern.declaringPackageName, true))
 		return false;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
index 54f0444..a196f3d 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorLocator.java
@@ -113,7 +113,7 @@
 public int match(TypeDeclaration node, MatchingNodeSet nodeSet) {
 	if (!this.pattern.findReferences) return IMPOSSIBLE_MATCH;
 
-	if (this.pattern.fineGrain != 0 && 
+	if (this.pattern.fineGrain != 0 &&
 			(this.pattern.fineGrain & ~IJavaSearchConstants.METHOD_REFERENCE_EXPRESSION) == 0 )
 		return IMPOSSIBLE_MATCH;
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
index 28b347a..5e27d1d 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ConstructorPattern.java
@@ -61,7 +61,7 @@
 
 /**
  * Constructor entries are encoded as described
- * 
+ *
  * Binary constructor for class
  * TypeName '/' Arity '/' TypeModifers '/' PackageName '/' Signature '/' ParameterNamesopt '/' Modifiers
  * Source constructor for class
@@ -72,7 +72,7 @@
  * TypeName '/' # '/' TypeModifers '/' PackageName
  * Constructor for member type
  * TypeName '/' Arity '/' TypeModifers
- * 
+ *
  * TypeModifiers contains some encoded extra information
  * 		{@link ExtraFlags#IsMemberType}
  * 		{@link ExtraFlags#HasNonPrivateStaticMemberTypes}
@@ -88,18 +88,18 @@
 		char[] packageName,
 		int typeModifiers,
 		int extraFlags) {
-	
+
 	char[] countChars;
 	char[] parameterTypesChars = null;
 	char[] parameterNamesChars = null;
-	
+
 	if (argCount < 0) {
 		countChars = DEFAULT_CONSTRUCTOR;
 	} else {
 		countChars = argCount < 10
 		? COUNTS[argCount]
 		: ("/" + String.valueOf(argCount)).toCharArray(); //$NON-NLS-1$
-		
+
 		if (argCount > 0) {
 			if (signature == null) {
 				if (parameterTypes != null && parameterTypes.length == argCount) {
@@ -112,58 +112,58 @@
 			} else {
 				extraFlags |= ExtraFlags.ParameterTypesStoredAsSignature;
 			}
-			
+
 			if (parameterNames != null && parameterNames.length == argCount) {
 				parameterNamesChars = CharOperation.concatWith(parameterNames, PARAMETER_SEPARATOR);
 			}
 		}
 	}
-	
+
 	boolean isMemberType = (extraFlags & ExtraFlags.IsMemberType) != 0;
-	
+
 	int typeNameLength = typeName == null ? 0 : typeName.length;
 	int packageNameLength = packageName == null ? 0 : packageName.length;
 	int countCharsLength = countChars.length;
 	int parameterTypesLength = signature == null ? (parameterTypesChars == null ? 0 : parameterTypesChars.length): signature.length;
 	int parameterNamesLength = parameterNamesChars == null ? 0 : parameterNamesChars.length;
-	
+
 	int resultLength = typeNameLength + countCharsLength + 3; // SEPARATOR=1 + TypeModifers=2
 	if (!isMemberType) {
 		resultLength += packageNameLength + 1; // SEPARATOR=1
 		if (argCount >= 0) {
 			resultLength += 3; // SEPARATOR=1 + Modifiers=2
 		}
-		
+
 		if (argCount > 0) {
 			resultLength += parameterTypesLength + parameterNamesLength + 2; //SEPARATOR=1 + SEPARATOR=1
 		}
 	}
-	
+
 	char[] result = new char[resultLength];
-	
+
 	int pos = 0;
 	if (typeNameLength > 0) {
 		System.arraycopy(typeName, 0, result, pos, typeNameLength);
 		pos += typeNameLength;
 	}
-	
+
 	if (countCharsLength > 0) {
 		System.arraycopy(countChars, 0, result, pos, countCharsLength);
 		pos += countCharsLength;
 	}
-	
+
 	int typeModifiersWithExtraFlags = typeModifiers | encodeExtraFlags(extraFlags);
 	result[pos++] = SEPARATOR;
 	result[pos++] = (char) typeModifiersWithExtraFlags;
 	result[pos++] = (char) (typeModifiersWithExtraFlags>>16);
-	
+
 	if (!isMemberType) {
 		result[pos++] = SEPARATOR;
 		if (packageNameLength > 0) {
 			System.arraycopy(packageName, 0, result, pos, packageNameLength);
 			pos += packageNameLength;
 		}
-		
+
 		if (argCount == 0) {
 			result[pos++] = SEPARATOR;
 			result[pos++] = (char) modifiers;
@@ -178,20 +178,20 @@
 				}
 				pos += parameterTypesLength;
 			}
-			
+
 			result[pos++] = SEPARATOR;
 			if (parameterNamesLength > 0) {
 				System.arraycopy(parameterNamesChars, 0, result, pos, parameterNamesLength);
 				pos += parameterNamesLength;
 			}
-			
+
 			result[pos++] = SEPARATOR;
 			result[pos++] = (char) modifiers;
 			result[pos++] = (char) (modifiers>>16);
 		}
-		
+
 	}
-	
+
 	return result;
 }
 public static char[] createDefaultDeclarationIndexKey(
@@ -223,23 +223,23 @@
 }
 static int decodeExtraFlags(int modifiersWithExtraFlags) {
 	int extraFlags = 0;
-	
+
 	if ((modifiersWithExtraFlags & ASTNode.Bit28) != 0) {
 		extraFlags |= ExtraFlags.ParameterTypesStoredAsSignature;
 	}
-	
+
 	if ((modifiersWithExtraFlags & ASTNode.Bit29) != 0) {
 		extraFlags |= ExtraFlags.IsLocalType;
 	}
-	
+
 	if ((modifiersWithExtraFlags & ASTNode.Bit30) != 0) {
 		extraFlags |= ExtraFlags.IsMemberType;
 	}
-	
+
 	if ((modifiersWithExtraFlags & ASTNode.Bit31) != 0) {
 		extraFlags |= ExtraFlags.HasNonPrivateStaticMemberTypes;
 	}
-	
+
 	return extraFlags;
 }
 static int decodeModifers(int modifiersWithExtraFlags) {
@@ -247,33 +247,33 @@
 }
 private static int encodeExtraFlags(int extraFlags) {
 	int encodedExtraFlags = 0;
-	
+
 	if ((extraFlags & ExtraFlags.ParameterTypesStoredAsSignature) != 0) {
 		encodedExtraFlags |= ASTNode.Bit28;
 	}
-	
+
 	if ((extraFlags & ExtraFlags.IsLocalType) != 0) {
 		encodedExtraFlags |= ASTNode.Bit29;
 	}
-	
+
 	if ((extraFlags & ExtraFlags.IsMemberType) != 0) {
 		encodedExtraFlags |= ASTNode.Bit30;
 	}
 	if ((extraFlags & ExtraFlags.HasNonPrivateStaticMemberTypes) != 0) {
 		encodedExtraFlags |= ASTNode.Bit31;
 	}
-	
+
 	return encodedExtraFlags;
 }
 private static char[] getTypeErasure(char[] typeName) {
 	int index;
 	if ((index = CharOperation.indexOf('<', typeName)) == -1) return typeName;
-	
+
 	int length = typeName.length;
 	char[] typeErasurename = new char[length - 2];
-	
+
 	System.arraycopy(typeName, 0, typeErasurename, 0, index);
-	
+
 	int depth = 1;
 	for (int i = index + 1; i < length; i++) {
 		switch (typeName[i]) {
@@ -290,7 +290,7 @@
 				break;
 		}
 	}
-	
+
 	System.arraycopy(typeErasurename, 0, typeErasurename = new char[index], 0, index);
 	return typeErasurename;
 }
@@ -462,13 +462,13 @@
 	int last = key.length - 1;
 	int slash = CharOperation.indexOf(SEPARATOR, key, 0);
 	this.declaringSimpleName = CharOperation.subarray(key, 0, slash);
-	
+
 	int start = slash + 1;
 	slash = CharOperation.indexOf(SEPARATOR, key, start);
 	if (slash != -1) {
 		last = slash - 1;
 	}
-	
+
 	boolean isDefaultConstructor = key[last] == '#';
 	if (isDefaultConstructor) {
 		this.parameterCount = -1;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
index c021b05..5ef2789 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/FieldLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2010 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -94,6 +94,14 @@
 	}
 	return CLASS_CONTAINER;
 }
+private int matchLocal(LocalVariableBinding field, boolean matchName) {
+	//for component of a record
+	if (field == null) return INACCURATE_MATCH;
+	if (matchName && !matchesName(this.pattern.name, field.readableName())) return IMPOSSIBLE_MATCH;
+	FieldPattern fieldPattern = (FieldPattern)this.pattern;
+	int declaringLevel = resolveLevelForType(fieldPattern.declaringSimpleName, fieldPattern.declaringQualification,field.getEnclosingMethod().declaringClass);
+	return declaringLevel;
+}
 protected int matchField(FieldBinding field, boolean matchName) {
 	if (field == null) return INACCURATE_MATCH;
 
@@ -324,6 +332,12 @@
 @Override
 public int resolveLevel(Binding binding) {
 	if (binding == null) return INACCURATE_MATCH;
+	if( binding instanceof LocalVariableBinding) {
+		// for matching the component in constructor of a record
+		if ( ((LocalVariableBinding)binding).declaringScope.referenceContext() instanceof CompactConstructorDeclaration) {
+			return matchLocal((LocalVariableBinding) binding, true);
+		}
+	}
 	if (!(binding instanceof FieldBinding)) return IMPOSSIBLE_MATCH;
 
 	return matchField((FieldBinding) binding, true);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/IndexBasedJavaSearchEnvironment.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/IndexBasedJavaSearchEnvironment.java
index 7daca0c..59177b5 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/IndexBasedJavaSearchEnvironment.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/IndexBasedJavaSearchEnvironment.java
@@ -148,7 +148,7 @@
 						AccessRestriction accessRestriction = ruleSet == null? null : ruleSet.getViolatedRestriction(binaryName);
 						TypeRef typeRef = TypeRef.create(next);
 						String fileName = new String(binaryName) + ".class"; //$NON-NLS-1$
-						IBinaryType binaryType = new IndexBinaryType(typeRef, fileName.toCharArray()); 
+						IBinaryType binaryType = new IndexBinaryType(typeRef, fileName.toCharArray());
 						NameEnvironmentAnswer nextAnswer = new NameEnvironmentAnswer(binaryType, accessRestriction);
 
 						boolean useNewAnswer = isBetter(result, bestEntryPosition, nextAnswer, nextRoot);
@@ -260,9 +260,7 @@
 	@Override
 	public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
 		char[][] newArray = new char[packageName.length + 1][];
-		for (int idx = 0; idx < packageName.length; idx++) {
-			newArray[idx] = packageName[idx];
-		}
+		System.arraycopy(packageName, 0, newArray, 0, packageName.length);
 		newArray[packageName.length] = typeName;
 		return findType(newArray);
 	}
@@ -271,9 +269,9 @@
 	public boolean isPackage(char[][] parentPackageName, char[] packageName) {
 		char[] binaryPackageName = CharOperation.concatWith(parentPackageName, '/');
 		final char[] fieldDescriptorPrefix;
-		
+
 		if (parentPackageName == null || parentPackageName.length == 0) {
-			fieldDescriptorPrefix = CharArrayUtils.concat(JavaNames.FIELD_DESCRIPTOR_PREFIX, packageName, 
+			fieldDescriptorPrefix = CharArrayUtils.concat(JavaNames.FIELD_DESCRIPTOR_PREFIX, packageName,
 					new char[] { '/' });
 		} else {
 			fieldDescriptorPrefix = CharArrayUtils.concat(JavaNames.FIELD_DESCRIPTOR_PREFIX, binaryPackageName,
@@ -325,7 +323,7 @@
 	public void cleanup() {
 		// No explicit cleanup required for this class
 	}
-	
+
 	public static INameEnvironment create(List<IJavaProject> javaProjects, org.eclipse.jdt.core.ICompilationUnit[] copies) {
 		if (JavaIndex.isEnabled() && isEnabled()) {
 			return new IndexBasedJavaSearchEnvironment(javaProjects, copies);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java
index 083fbc0..751efcd 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/JavaSearchNameEnvironment.java
@@ -160,8 +160,8 @@
 			ClasspathEntry rawClasspathEntry = (ClasspathEntry) root.getRawClasspathEntry();
 			IJavaProject project = (IJavaProject) root.getParent();
 			String compliance = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
-			cp = (root instanceof JrtPackageFragmentRoot) ? 
-					ClasspathLocation.forJrtSystem(path.toOSString(), rawClasspathEntry.getAccessRuleSet(), 
+			cp = (root instanceof JrtPackageFragmentRoot) ?
+					ClasspathLocation.forJrtSystem(path.toOSString(), rawClasspathEntry.getAccessRuleSet(),
 							ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, project.getProject(), true), compliance) :
 									ClasspathLocation.forLibrary(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(),
 												ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry,
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java
index d502cb3..72212d7 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariableLocator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -17,8 +17,10 @@
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
+import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
 import org.eclipse.jdt.internal.core.LocalVariable;
+import org.eclipse.jdt.internal.core.SourceField;
 
 public class LocalVariableLocator extends VariableLocator {
 
@@ -65,6 +67,14 @@
 		this.match = locator.newDeclarationMatch(element, null, accuracy, offset, length);
 		locator.report(this.match);
 		return;
+	} else if (reference instanceof FieldReference) { // for record's component in constructor
+		FieldReference fieldReference = (FieldReference) reference;
+		long position = fieldReference.nameSourcePosition;
+		int start = (int) (position >>> 32);
+		int end = (int) position;
+		this.match = locator.newFieldReferenceMatch(element, null, elementBinding, accuracy, start, end-start+1, fieldReference);
+		locator.report(this.match);
+		return;
 	}
 	if (offset >= 0) {
 		this.match = locator.newLocalVariableReferenceMatch(element, accuracy, offset, length, reference);
@@ -95,15 +105,51 @@
 			return resolveLevel((NameReference) possiblelMatchingNode);
 	if (possiblelMatchingNode instanceof LocalDeclaration)
 		return matchLocalVariable(((LocalDeclaration) possiblelMatchingNode).binding, true);
+	if(possiblelMatchingNode instanceof FieldReference ) {
+		//for the local variable in the constructor of record matching component's name
+		FieldBinding binding = ((FieldReference)possiblelMatchingNode).binding;
+		if (binding.isRecordComponent())
+			return matchField(binding, true);
+	}
 	return IMPOSSIBLE_MATCH;
 }
 @Override
 public int resolveLevel(Binding binding) {
 	if (binding == null) return INACCURATE_MATCH;
+	// for record's component local variable matching component name
+	if(binding instanceof FieldBinding && ((FieldBinding) binding).isRecordComponent()) {
+		return matchField(binding, true);
+	}
+	if(binding instanceof LocalVariableBinding) {
+		if ( ((LocalVariableBinding)binding).declaringScope.referenceContext() instanceof CompactConstructorDeclaration) {
+			//update with binding
+			if( this.pattern instanceof FieldPattern) {
+				return matchField(binding, true);
+			}
+		}
+	}
 	if (!(binding instanceof LocalVariableBinding)) return IMPOSSIBLE_MATCH;
 
 	return matchLocalVariable((LocalVariableBinding) binding, true);
 }
+private int matchField(Binding binding, boolean matchName) {
+	if (binding == null) return INACCURATE_MATCH;
+	if(binding instanceof FieldBinding) {
+		if (! ((FieldBinding)binding).declaringClass.isRecord())
+			return IMPOSSIBLE_MATCH;
+	}
+	if(this.pattern instanceof LocalVariablePattern) {
+		LocalVariablePattern lvp = (LocalVariablePattern)this.pattern;
+		LocalVariable localVariable = lvp.localVariable;
+		IJavaElement parent = localVariable.getParent() ;
+		// if the parent is not sourceField, skip
+		if(!(parent instanceof SourceField))
+			return IMPOSSIBLE_MATCH;
+	}
+	if (matchName && matchesName(this.pattern.name, binding.readableName()))
+		return ACCURATE_MATCH;
+	return IMPOSSIBLE_MATCH;
+}
 protected int resolveLevel(NameReference nameRef) {
 	return resolveLevel(nameRef.binding);
 }
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
index dc6838a..7bd60b0 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/LocalVariablePattern.java
@@ -45,7 +45,7 @@
         IModuleDescription md = root.getModuleDescription();
         if(md != null) {
         	String module = md.getElementName();
-				documentPath = root.getPath() + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR 
+				documentPath = root.getPath() + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR
 						+ module + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR + relativePath;
         } else {
         	documentPath = root.getPath() + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR + relativePath;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
index 1c87189..0d85df5 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java
@@ -337,7 +337,7 @@
 	    			this.sourceStartOfMethodToRetain  = range.getOffset();
 	    			this.sourceEndOfMethodToRetain = this.sourceStartOfMethodToRetain + range.getLength() - 1; // offset is 0 based.
 	    		} catch (JavaModelException e) {
-	    			// drop silently. 
+	    			// drop silently.
 	    		}
 	    	}
 	    }
@@ -800,15 +800,15 @@
 	if (element != null) {
 		if (this.scope instanceof HierarchyScope)
 			return ((HierarchyScope)this.scope).encloses(element, this.progressMonitor);
-		else 
+		else
 			return this.scope.encloses(element);
 	}
 	return false;
 }
 private boolean filterEnum(SearchMatch match) {
-	
-	// filter org.apache.commons.lang.enum package for projects above 1.5 
-	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=317264	
+
+	// filter org.apache.commons.lang.enum package for projects above 1.5
+	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=317264
 	IJavaElement element = (IJavaElement)match.getElement();
 	PackageFragment pkg = (PackageFragment)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT);
 	if (pkg != null) {
@@ -1030,7 +1030,7 @@
 		for (int i = 1; i < rows; ++i) {
 			int tmp = resultsMap[i][j];
 			if (tmp < current) continue;
-			if (tmp > current)  { 
+			if (tmp > current)  {
 				current = tmp;
 				candidates.clear();
 			}
@@ -1041,7 +1041,7 @@
 	return candidates.get(0);
 }
 
-/** apply the function to map the parameter full name to an index 
+/** apply the function to map the parameter full name to an index
  */
 private int mapParameter(List <String> patternParameterFullName, List <String> methodParameterFullName) {
 	int patternLen = patternParameterFullName.size();
@@ -1506,7 +1506,7 @@
 						JavaModelManager.getLocalFile(path).toPath().toAbsolutePath().toString() :
 						pathString.split(Pattern.quote("|"))[0]; //$NON-NLS-1$
 				possibleMatch.autoModuleName = new String(AutomaticModuleNaming.determineAutomaticModuleName(s));
-			}			
+			}
 		}
 
 		// last project
@@ -1560,7 +1560,7 @@
 			if (jpkf.getModuleDescription() != null &&
 					CompilerOptions.versionToJdkLevel(javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true)) <
 					ClassFileConstants.JDK9) {
-				openable = this.handleFactory.createOpenable(pathString, 
+				openable = this.handleFactory.createOpenable(pathString,
 						getSubScope(JavaCore.COMPILER_COMPLIANCE, ClassFileConstants.JDK9, false));
 			}
 		}
@@ -1915,7 +1915,7 @@
 			if (parsedUnit.isModuleInfo()) {
 				if (mustResolve) {
 					this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
-				}				
+				}
 			} else if (!parsedUnit.isEmpty()) {
 				if (mustResolve) {
 					this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
@@ -2491,7 +2491,7 @@
 	ASTNode[] nodes = typeInHierarchy ? nodeSet.matchingNodes(lambdaExpression.sourceStart, lambdaExpression.sourceEnd) : null;
 	boolean report = (this.matchContainer & PatternLocator.METHOD_CONTAINER) != 0 && encloses(enclosingElement);
 	MemberDeclarationVisitor declarationVisitor = new MemberDeclarationVisitor(enclosingElement, report ? nodes : null, nodeSet, this, typeInHierarchy);
-	
+
 	if (lambdaExpression.arguments != null) {
 		int argumentsLength = lambdaExpression.arguments.length;
 		for (int i = 0; i < argumentsLength; i++)
@@ -2501,7 +2501,7 @@
 	if (lambdaExpression.body != null) {
 		lambdaExpression.body.traverse(declarationVisitor, (BlockScope) null);
 	}
-	
+
 	// Report all nodes and remove them
 	if (nodes != null) {
 		int length = nodes.length;
@@ -2725,8 +2725,8 @@
 	if (annotationsList != null) {
 		for (int i = 0, length = annotationsList.length; i < length; ++i) {
 			Annotation[] annotations = annotationsList[i];
-			if (annotations != null) 
-				reportMatching(annotations, enclosingElement, null, binding, nodeSet, matchedClassContainer, encloses(enclosingElement));	
+			if (annotations != null)
+				reportMatching(annotations, enclosingElement, null, binding, nodeSet, matchedClassContainer, encloses(enclosingElement));
 		}
 	}
 }
@@ -3117,7 +3117,7 @@
 				if ((type.bits & ASTNode.IsAnonymousType) != 0) {
 					if (fileName != null) {
 						if (fileName.endsWith("jar") || fileName.endsWith(SuffixConstants.SUFFIX_STRING_class)) { //$NON-NLS-1$
-							IOrdinaryClassFile classFile= binaryType.getPackageFragment().getOrdinaryClassFile(binaryType.getTypeQualifiedName() + 
+							IOrdinaryClassFile classFile= binaryType.getPackageFragment().getOrdinaryClassFile(binaryType.getTypeQualifiedName() +
 									"$" + Integer.toString(occurrenceCount) + SuffixConstants.SUFFIX_STRING_class);//$NON-NLS-1$
 							anonType =  classFile.getType();
 						}
@@ -3187,7 +3187,7 @@
 			for (int i = 0, length = superClass.annotations == null ? 0 : superClass.annotations.length; i < length; i++) {
 				Annotation[] annotations = superClass.annotations[i];
 				if (annotations == null) continue;
-				reportMatching(annotations, enclosingElement, null, type.binding, nodeSet, matchedClassContainer, enclosesElement);	
+				reportMatching(annotations, enclosingElement, null, type.binding, nodeSet, matchedClassContainer, enclosesElement);
 			}
 		}
 		TypeReference[] superInterfaces = type.superInterfaces;
@@ -3199,9 +3199,9 @@
 				if (annotations != null) {
 					for (int j = 0, length = annotations.length; j < length; j++) {
 						if (annotations[j] == null) continue;
-						reportMatching(annotations[j], enclosingElement, null, type.binding, nodeSet, matchedClassContainer, enclosesElement);	
+						reportMatching(annotations[j], enclosingElement, null, type.binding, nodeSet, matchedClassContainer, enclosesElement);
 					}
-				}			
+				}
 			}
 		}
 	}
@@ -3295,7 +3295,7 @@
 			}
 			boolean matchedClassContainer = (this.matchContainer & PatternLocator.ALL_CONTAINER) != 0;
 			if (typeParameter.annotations != null) {
-				reportMatching(typeParameter.annotations, enclosingElement, null, typeParameter.binding, nodeSet, matchedClassContainer, encloses(enclosingElement));	
+				reportMatching(typeParameter.annotations, enclosingElement, null, typeParameter.binding, nodeSet, matchedClassContainer, encloses(enclosingElement));
 			}
 			if (typeParameter.type != null) {
 				reportMatching(typeParameter.type.annotations, enclosingElement, typeParameter.binding, nodeSet, matchedClassContainer);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java
index 3a4b197..d09fe31 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocatorParser.java
@@ -614,7 +614,7 @@
 	} else if (referenceExpression.lhs instanceof QualifiedNameReference || referenceExpression.lhs instanceof QualifiedTypeReference) {
 		if ((this.patternFineGrain & IJavaSearchConstants.QUALIFIED_REFERENCE) != 0) {
 			this.patternLocator.match(referenceExpression, this.nodeSet);
-		} 
+		}
 	}
 }
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MemberDeclarationVisitor.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MemberDeclarationVisitor.java
index aa71153..adca936 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MemberDeclarationVisitor.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MemberDeclarationVisitor.java
@@ -226,7 +226,7 @@
 		if (lambdaExpression.resolvedType != null && lambdaExpression.resolvedType.isValidBinding() &&
 				!(lambdaExpression.descriptor instanceof ProblemMethodBinding))
 			this.locator.reportMatching(lambdaExpression, this.enclosingElement, level != null ? level.intValue() : -1, this.nodeSet, this.typeInHierarchy);
-		else 
+		else
 			return true;
 	} catch (CoreException e) {
 		throw new WrappedCoreException(e);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java
index 8387333..05f8d17 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java
@@ -24,7 +24,7 @@
 
 	public int extraFlags;
 	public int declaringTypeModifiers;
-	
+
 	public int modifiers;
 	public char[] signature;
 	public char[][] parameterTypes;
@@ -32,7 +32,7 @@
 	public char[] fusedDeclaringQualifier = null; // TODO: do we need this; cleanup?
 	/**
 	 * Method Declaration entries are encoded as described
-	 * 
+	 *
 	 * Binary Method Declaration for class
 	 * MethodName '/' Arity '/' DeclaringQualifier '/' TypeName '/' TypeModifers '/' PackageName '/' Signature '/' ParameterNamesopt '/' Modifiers '/' returnType
 	 * Source method for class
@@ -55,13 +55,13 @@
 			char[] packageName,
 			int typeModifiers,
 			int extraFlags) {
-		
+
 		char[] countChars;
 		char[] parameterTypesChars = null;
 		char[] parameterNamesChars = null;
-		
-		
-		countChars = argCount < 10 ? new char[] {COUNTS[argCount][1]}:  String.valueOf(argCount).toCharArray(); 
+
+
+		countChars = argCount < 10 ? new char[] {COUNTS[argCount][1]}:  String.valueOf(argCount).toCharArray();
 		if (argCount > 0) {
 			if (signature == null) {
 				if (parameterTypes != null && parameterTypes.length == argCount) {
@@ -74,20 +74,20 @@
 				parameterNamesChars = CharOperation.concatWith(parameterNames, PARAMETER_SEPARATOR);
 			}
 		}
-				
-		char[] returnTypeChars = returnType == null ? CharOperation.NO_CHAR : getTypeErasure(returnType);		
+
+		char[] returnTypeChars = returnType == null ? CharOperation.NO_CHAR : getTypeErasure(returnType);
 		int typeModifiersWithExtraFlags = typeModifiers | encodeExtraFlags(extraFlags);
 		int entryIndex = 0;
 		int numEntries = 10;
 		char [][] tmp = new char[numEntries][];
-		
+
 		tmp[entryIndex++] = methodName != null ? methodName : CharOperation.NO_CHAR;
 		tmp[entryIndex++] = countChars;
 		tmp[entryIndex++] = declaringQualification != null ? declaringQualification : CharOperation.NO_CHAR;
 		tmp[entryIndex++] = typeName != null ? typeName : CharOperation.NO_CHAR;
 		tmp[entryIndex++] = new char[] {(char) typeModifiersWithExtraFlags, (char) (typeModifiersWithExtraFlags>>16)};
 		tmp[entryIndex++] = packageName != null ? packageName : CharOperation.NO_CHAR;
-		
+
 		if (argCount == 0) {
 			tmp[entryIndex++] = CharOperation.NO_CHAR;
 			tmp[entryIndex++] = CharOperation.NO_CHAR;
@@ -99,36 +99,36 @@
 		tmp[entryIndex] = returnTypeChars;
 		return CharOperation.concatWithAll(tmp, '/');
 	}
-	
+
 	private static int encodeExtraFlags(int extraFlags) {
 		int encodedExtraFlags = 0;
-		
+
 		if ((extraFlags & ExtraFlags.ParameterTypesStoredAsSignature) != 0) {
 			encodedExtraFlags |= ASTNode.Bit28;
 		}
-		
+
 		if ((extraFlags & ExtraFlags.IsLocalType) != 0) {
 			encodedExtraFlags |= ASTNode.Bit29;
 		}
-		
+
 		if ((extraFlags & ExtraFlags.IsMemberType) != 0) {
 			encodedExtraFlags |= ASTNode.Bit30;
 		}
 		if ((extraFlags & ExtraFlags.HasNonPrivateStaticMemberTypes) != 0) {
 			encodedExtraFlags |= ASTNode.Bit31;
 		}
-		
+
 		return encodedExtraFlags;
 	}
 	private static char[] getTypeErasure(char[] typeName) {
 		int index;
 		if ((index = CharOperation.indexOf('<', typeName)) == -1) return typeName;
-		
+
 		int length = typeName.length;
 		char[] typeErasurename = new char[length - 2];
-		
+
 		System.arraycopy(typeName, 0, typeErasurename, 0, index);
-		
+
 		int depth = 1;
 		for (int i = index + 1; i < length; i++) {
 			switch (typeName[i]) {
@@ -145,29 +145,29 @@
 					break;
 			}
 		}
-		
+
 		System.arraycopy(typeErasurename, 0, typeErasurename = new char[index], 0, index);
 		return typeErasurename;
 	}
 
 public MethodDeclarationPattern(
-		char[] declaringPackageName, 
-		char[] declaringQualification, 
+		char[] declaringPackageName,
+		char[] declaringQualification,
 		char[] declaringSimpleName,
 		char[] methodName,
 		int matchRule) {
-	super(methodName, declaringQualification, declaringSimpleName, 
-			null, null, null, null, null, 
+	super(methodName, declaringQualification, declaringSimpleName,
+			null, null, null, null, null,
 			IJavaSearchConstants.DECLARATIONS, matchRule);
 	this.declaringPackageName = declaringPackageName;
 }
 
 public MethodDeclarationPattern(
-		char[] declaringQualifier, 
+		char[] declaringQualifier,
 		char[] methodName,
 		int matchRule) {
-	super(methodName, CharOperation.NO_CHAR, CharOperation.NO_CHAR, 
-			null, null, null, null, null, 
+	super(methodName, CharOperation.NO_CHAR, CharOperation.NO_CHAR,
+			null, null, null, null, null,
 			IJavaSearchConstants.DECLARATIONS, matchRule);
 	this.fusedDeclaringQualifier = declaringQualifier;
 }
@@ -178,7 +178,7 @@
 
 @Override
 public void decodeIndexKey(char[] key) {
-	
+
 	int start = 0;
 	int slash = CharOperation.indexOf(SEPARATOR, key, start);
 	this.selector = CharOperation.subarray(key, start, slash);
@@ -186,7 +186,7 @@
 	start = slash + 1;
 	slash = CharOperation.indexOf(SEPARATOR, key, start);
 	int last = slash - 1;
-	
+
 	this.parameterCount = 0;
 	int power = 1;
 	for (int i = last; i >= start; i--) {
@@ -201,29 +201,29 @@
 	start = slash + 1;
 	slash = CharOperation.indexOf(SEPARATOR, key, start);
 	this.declaringQualification = CharOperation.subarray(key, start, slash);
-	
+
 	start = slash + 1;
 	slash = CharOperation.indexOf(SEPARATOR, key, start);
 	this.declaringSimpleName = CharOperation.subarray(key, start, slash);
-	
+
 	start = slash + 1;
 	slash = CharOperation.indexOf(SEPARATOR, key, start);
 	last = slash - 1;
 	int typeModifiersWithExtraFlags = key[last-1] + (key[last]<<16);
 	this.declaringTypeModifiers = ConstructorPattern.decodeModifers(typeModifiersWithExtraFlags);
 	this.extraFlags = ConstructorPattern.decodeExtraFlags(typeModifiersWithExtraFlags);
-	
+
 	// initialize optional fields
 	this.declaringPackageName = null;
 	this.modifiers = 0;
 	this.signature = null;
 	this.parameterTypes = null;
 	this.parameterNames = null;
-	
+
 	start = slash + 1;
 	slash = CharOperation.indexOf(SEPARATOR, key, start);
 	this.declaringPackageName = CharOperation.subarray(key, start, slash);
-	
+
 	start = slash + 1;
 	slash = CharOperation.indexOf(SEPARATOR, key, start);
 	if (this.parameterCount == 0) {
@@ -245,15 +245,15 @@
 		}
 		start = slash + 1;
 		slash = CharOperation.indexOf(SEPARATOR, key, start);
-		
+
 		if (slash != start) {
 			this.parameterNames = CharOperation.splitOn(PARAMETER_SEPARATOR, key, start, slash);
 		}
-		
+
 		start = slash + 1;
 		slash = CharOperation.indexOf(SEPARATOR, key, start);
 		last = slash - 1;
-		
+
 		this.modifiers = key[last-1] + (key[last]<<16);
 	} else {
 		this.modifiers = ClassFileConstants.AccPublic;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
index e030f24..a497781 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodLocator.java
@@ -11,7 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Samrat Dhillon samrat.dhillon@gmail.com - Search for method references is
- *               returning methods as overriden even if the superclass's method is 
+ *               returning methods as overriden even if the superclass's method is
  *               only package-visible - https://bugs.eclipse.org/357547
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.search.matching;
@@ -42,7 +42,7 @@
 
 // This is set only if focus is null. In these cases
 // it will be hard to determine if the super class is of the same package
-// at a latter point. Hence, this array is created with all the super class 
+// at a latter point. Hence, this array is created with all the super class
 // names of the same package name as of the matching class name.
 // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=357547
 private char[][][] samePkgSuperDeclaringTypeNames;
@@ -117,7 +117,7 @@
 		start = System.currentTimeMillis();
 	}
 	try {
-		SuperTypeNamesCollector namesCollector = 
+		SuperTypeNamesCollector namesCollector =
 			new SuperTypeNamesCollector(
 				this.pattern,
 				this.pattern.declaringSimpleName,
@@ -127,7 +127,7 @@
 				locator.progressMonitor);
 		this.allSuperDeclaringTypeNames = namesCollector.collect();
 		this.samePkgSuperDeclaringTypeNames = namesCollector.getSamePackageSuperTypeNames();
-		this.matchLocator = locator;	
+		this.matchLocator = locator;
 	} catch (JavaModelException e) {
 		// inaccurate matches will be found
 	}
@@ -154,13 +154,13 @@
  */
 protected boolean isVirtualInvoke(MethodBinding method, MessageSend messageSend) {
 		return !method.isStatic() && !method.isPrivate() && !messageSend.isSuperAccess()
-			&& !(method.isDefault() && this.pattern.focus != null 
+			&& !(method.isDefault() && this.pattern.focus != null
 			&& !CharOperation.equals(this.pattern.declaringPackageName, method.declaringClass.qualifiedPackageName()));
 }
 protected ReferenceBinding checkMethodRef(MethodBinding method, ReferenceExpression referenceExpression) {
 	boolean result = (!method.isStatic() && !method.isPrivate()
-		&&	referenceExpression.isMethodReference()  
-		&& !(method.isDefault() && this.pattern.focus != null 
+		&&	referenceExpression.isMethodReference()
+		&& !(method.isDefault() && this.pattern.focus != null
 		&& !CharOperation.equals(this.pattern.declaringPackageName, method.declaringClass.qualifiedPackageName())));
 	if (result) {
 		Expression lhs = referenceExpression.lhs;
@@ -170,7 +170,7 @@
 				return (ReferenceBinding) binding;
 		}
 	}
-	
+
 	return null;
 }
 @Override
@@ -360,7 +360,7 @@
 				if (focusMethodBinding != null) {// textual comparison insufficient
 					TypeBinding[] parameters = focusMethodBinding.parameters;
 					if (parameters.length >= parameterCount) {
-						newLevel = (isBinary ? argType.erasure().isEquivalentTo((parameters[i].erasure())) :argType.isEquivalentTo((parameters[i]))) ? 
+						newLevel = (isBinary ? argType.erasure().isEquivalentTo((parameters[i].erasure())) :argType.isEquivalentTo((parameters[i]))) ?
 								ACCURATE_MATCH : IMPOSSIBLE_MATCH;
 						foundLevel = true;
 					}
@@ -390,7 +390,7 @@
 		}
 		if (foundTypeVariable) {
 			if (!method.isStatic() && !method.isPrivate()) {
-				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=123836, No point in textually comparing type variables, captures etc with concrete types. 
+				// https://bugs.eclipse.org/bugs/show_bug.cgi?id=123836, No point in textually comparing type variables, captures etc with concrete types.
 				if (!checkedFocus)
 					focusMethodBinding = this.matchLocator.getMethodBinding(this.pattern);
 				if (focusMethodBinding != null) {
@@ -398,7 +398,7 @@
 						return ACCURATE_MATCH;
 					}
 				}
-			} 
+			}
 			return IMPOSSIBLE_MATCH;
 		}
 	}
@@ -674,7 +674,7 @@
 		}
 		method = locator.createBinaryMethodHandle(type, methodBinding.selector, parameterTypes);
 		if (method == null || knownMethods.addIfNotIncluded(method) == null) return;
-	
+
 		IResource resource = type.getResource();
 		if (resource == null)
 			resource = type.getJavaProject().getProject();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ModuleLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ModuleLocator.java
index 3e20b13..3e4388d 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ModuleLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/ModuleLocator.java
@@ -18,10 +18,10 @@
  * https://www.eclipse.org/legal/epl-2.0/
  *
  * SPDX-License-Identifier: EPL-2.0
- * 
+ *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
+ *
  *******************************************************************************/
 public class ModuleLocator extends PatternLocator {
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
index a1c79e6..697fae3 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/PatternLocator.java
@@ -470,7 +470,7 @@
  * Set the flavors for which the locator has to be focused on.
  * If not set, the locator will accept all matches with or without flavors.
  * When set, the locator will only accept match having the corresponding flavors.
- * 
+ *
  * @param flavors Bits mask specifying the flavors to be accepted or
  * 	<code>0</code> to ignore the flavors while accepting matches.
  */
@@ -814,7 +814,7 @@
 		IntersectionTypeBinding18 i18 = (IntersectionTypeBinding18) type;
 		for (ReferenceBinding ref : i18.intersectingTypes) {
 			result = resolveLevelForType(qualifiedPattern, ref);
-			if (result == ACCURATE_MATCH) return result; 
+			if (result == ACCURATE_MATCH) return result;
 			if (result == IMPOSSIBLE_MATCH) continue;
 			if (prev == IMPOSSIBLE_MATCH) prev = result;
 		}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java
index b8467cc..3543f30 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java
@@ -115,7 +115,7 @@
 	int resultLength = this.samePackageSuperTypeName.length;
 	for (int i = 0; i < resultLength; i++)
 		if (CharOperation.equals(this.samePackageSuperTypeName[i], compoundName)) return false; // already known
-	
+
 	for (int i = 0, length = compoundName.length - 1; i < length; i ++) {
 		if (!CharOperation.equals(compoundName[i], path[i])) return false;
 	}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
index bef2fc6..4e3d8af 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationLocator.java
@@ -162,7 +162,7 @@
 			}
 		}
 	};
-	final SearchRequestor requestor = new SearchRequestor() {	
+	final SearchRequestor requestor = new SearchRequestor() {
 		@Override
 		public void acceptSearchMatch(SearchMatch searchMatch) throws CoreException {
 			System.out.println(searchMatch.toString());
@@ -198,13 +198,13 @@
 		char[][] tmp = new char[sz][];
 		for (int i = 0; i < sz; ++i) {
 			tmp[i] = ar[i].toCharArray();
-		}	
+		}
 		typePattern.moduleGraphElements = tmp;
 	}
 	return typePattern.moduleGraphElements;
 }
 private int matchModule(TypeDeclarationPattern typePattern, TypeBinding type) {
-	if (!(type instanceof ReferenceBinding)) 
+	if (!(type instanceof ReferenceBinding))
 		return INACCURATE_MATCH; // a safety net, should not come here for error free code.
 	ReferenceBinding reference = (ReferenceBinding) type;
 	ModuleBinding module = reference.module();
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
index 3415914..dff4bdb 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeDeclarationPattern.java
@@ -186,7 +186,7 @@
 	final String explicit_unnamed = new String(IJavaSearchConstants.ALL_UNNAMED);
 	String[] names = new String(modNames).split(String.valueOf(CharOperation.COMMA_SEPARATOR));
 	int len = names.length;
-	if (this.allowModuleRegex && len > 0 && names[0] != null && names[0].length() > 0 
+	if (this.allowModuleRegex && len > 0 && names[0] != null && names[0].length() > 0
 			&& names[0].charAt(0) == IIndexConstants.ZERO_CHAR) { //pattern
 		names[0] = names[0].substring(1);
 		this.modulePatterns = new Pattern[len];
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeParameterPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeParameterPattern.java
index 751233d..e3d2083 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeParameterPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeParameterPattern.java
@@ -91,7 +91,7 @@
     	    IModuleDescription md = root.getModuleDescription();
             if(md != null) {
             	String module = md.getElementName();
-            	documentPath = root.getPath() + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR 
+            	documentPath = root.getPath() + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR
             			+ module + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR + relativePath;
             } else {
             	documentPath = root.getPath() + IJavaSearchScope.JAR_FILE_ENTRY_SEPARATOR + relativePath;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
index cf3207d..fd4ff75 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/TypeReferenceLocator.java
@@ -656,7 +656,7 @@
 			return resolveLevelForType((ReferenceBinding) binding);
 		if (((SingleNameReference) nameRef).isLabel)
 			return IMPOSSIBLE_MATCH;
-		
+
 		return binding == null || binding instanceof ProblemBinding ? INACCURATE_MATCH : IMPOSSIBLE_MATCH;
 	}
 
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java
index bd89f38..eca6f1e 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/VariableLocator.java
@@ -59,6 +59,11 @@
 		: IMPOSSIBLE_MATCH;
 }
 protected int matchReference(Reference node, MatchingNodeSet nodeSet, boolean writeOnlyAccess) {
+	if(node instanceof FieldReference) {
+		//for the local variable in the constructor of record matching component's name
+		if (matchesName(this.pattern.name, ((FieldReference) node).token))
+			return nodeSet.addMatch(node, POSSIBLE_MATCH);
+	}
 	if (node instanceof NameReference) {
 		if (this.pattern.name == null) {
 			return nodeSet.addMatch(node, this.pattern.mustResolve ? POSSIBLE_MATCH : ACCURATE_MATCH);