Update jdt.core to I20220503-0220
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/SelectionTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/SelectionTest.java
index 1ec97fc..5bd523a 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/SelectionTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/parser/SelectionTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2020 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -1980,9 +1980,7 @@
 		"  public X() {\n"+
 		"  }\n"+
 		"  void foo() {\n"+
-		"    if ((x instanceof <SelectOnType:Object> s))\n" +
-		"        {\n" +
-		"        }\n" +
+		"    <SelectOnType:Object> s;\n" +
 		"  }\n"+
 		"}\n";
 	String expectedReplacedSource = "Object";
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/junit/extension/TestCase.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/junit/extension/TestCase.java
index 6ce2fe7..9df7321 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/junit/extension/TestCase.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/junit/extension/TestCase.java
@@ -824,7 +824,7 @@
 }
 
 protected void setUp() throws Exception {
-	if (JavaCore.getPlugin() != null && isIndexDisabledForTest()) {
+	if (JavaCore.getPlugin() != null && isIndexDisabledForTest() && JavaModelManager.getIndexManager().isEnabled()) {
 		JavaModelManager.getIndexManager().disable();
 	}
 	super.setUp();
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTStructuralPropertyTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTStructuralPropertyTest.java
index 52fb77e..1274f91 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTStructuralPropertyTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTStructuralPropertyTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2021 IBM Corporation and others.
+ * Copyright (c) 2004, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -423,10 +423,10 @@
 	public void testNodeClassForType() {
 //{ObjectTeams: larger range:
 /* orig:
-		Set classes = new HashSet(103);
+		Set classes = new HashSet(125);
 		// make sure node types are contiguous starting at 0
 		int hi = 0;
-		for (int nodeType = 1; nodeType < 110; nodeType++) {
+		for (int nodeType = 1; nodeType < 125; nodeType++) {
   :giro */
 		Set classes = new HashSet(133);
 		// make sure node types are contiguous starting at 0
@@ -447,7 +447,7 @@
 		}
 // {ObjectTeams: adapted for OT specific ASTNodes
 /* orig:
-		assertEquals("Wrong last known type", 109, hi); // last known one
+		assertEquals("Wrong last known type", 111, hi); // last known one
   :giro */
 		assertEquals("Wrong last known type", 127, hi); // last known one
 // jwl}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsTests.java
index a613573..9927a6f 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/formatter/FormatterCommentsTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -1243,4 +1243,157 @@
 public void testWkspJUnit01() throws JavaModelException {
 	formatUnit("wksp.junit", "X01.java");
 }
+public void testSnippet01() {
+	setComplianceLevel(CompilerOptions.VERSION_18);
+	this.formatterPrefs.comment_line_length = 40;
+	String source =
+		"/**\n" +
+		" * Code sample:" +
+		" * {@snippet lang=java :\n" +
+		" *   public static void main(String... args) {\n" +
+		" *       for (var arg : args) {                 // @highlight  type=italic regex = \"\\barg\\b\"\n" +
+		" *           if (!arg.isBlank()) {  System.out.println(arg);    }\n" +
+		" *       }                                      // @end\n" +
+		" *   }\n" +
+		" *   } OK?\n" +
+		" */" +
+		"class Test{}";
+	formatSource(source,
+		"/**\n" +
+		" * Code sample: *\n" +
+		" * {@snippet lang = java :\n" +
+		" * public static void main(String... args) {\n" +
+		" * 	for (var arg : args) {                 // @highlight type = italic regex = \"\\barg\\b\"\n" +
+		" * 		if (!arg.isBlank()) {\n" +
+		" * 			System.out.println(arg);\n" +
+		" * 		}\n" +
+		" * 	}                                      // @end\n" +
+		" * }\n" +
+		" * }\n" +
+		" * OK?\n" +
+		" */\n" +
+		"class Test {\n" +
+		"}"
+	);
+}
+public void testSnippet02() {
+	setComplianceLevel(CompilerOptions.VERSION_18);
+	this.formatterPrefs.insert_space_before_assignment_operator = false;
+	String source =
+		"/**\n" +
+		" * Here are the configuration properties:\n" +
+		" * {@snippet file=\"config.properties\" id=\"testtest\"  \n" +
+		" * lang  = properties}\n" +
+		" */\n" +
+		"public class T {}";
+	formatSource(source,
+		"/**\n" +
+		" * Here are the configuration properties:\n" +
+		" * {@snippet file= \"config.properties\" id= \"testtest\" lang= properties}\n" +
+		" */\n" +
+		"public class T {\n" +
+		"}"
+	);
+}
+public void testSnippet03() {
+	setComplianceLevel(CompilerOptions.VERSION_18);
+	this.formatterPrefs.insert_space_after_assignment_operator = false;
+	String source =
+		"/**\n" +
+		" * Here are the configuration properties:\n" +
+		" * {@snippet id=\"test   test\"   lang  = properties:\n" +
+		" *   config1=value1;\n" +
+		" *   config2=value2;\n" +
+		" * }\n" +
+		" */\n" +
+		"public class T {}";
+	formatSource(source,
+		"/**\n" +
+		" * Here are the configuration properties:\n" +
+		" * {@snippet id =\"test   test\" lang =properties:\n" +
+		" *   config1=value1;\n" +
+		" *   config2=value2;\n" +
+		" * }\n" +
+		" */\n" +
+		"public class T {\n" +
+		"}"
+	);
+}
+public void testSnippet04() {
+	setComplianceLevel(CompilerOptions.VERSION_18);
+	String source =
+		"/**\n" +
+		" * Here are the configuration properties:\n" +
+		" * {@snippet  id=\"test   test\"  \n" +
+		" * :\n" +
+		" *   config1=value1;\n" +
+		" *   config2=value2;\n" +
+		" * }\n" +
+		" */\n" +
+		"public class T {}";
+	formatSource(source,
+		"/**\n" +
+		" * Here are the configuration properties:\n" +
+		" * {@snippet id = \"test   test\" :\n" +
+		" * config1 = value1;\n" +
+		" * config2 = value2;\n" +
+		" * }\n" +
+		" */\n" +
+		"public class T {\n" +
+		"}"
+	);
+}
+public void testSnippet05() {
+	setComplianceLevel(CompilerOptions.VERSION_18);
+	this.formatterPrefs.insert_space_before_assignment_operator = false;
+	String source =
+		"/**\n" +
+		" * Here are the configuration properties:\n" +
+		" * {@snippet\n" +
+		" *  id=\"testtest\" \n" +
+		" *  lang='java' :\n" +
+		" *   // @replace region substring='value		'	replacement=\"value:	\" \n" +
+		" *   config1=\"value		1\";\n" +
+		" *   config2=\"value		2\";\n" +
+		" *   // @end\n" +
+		" * } */\n" +
+		"public class T {}";
+	formatSource(source,
+		"/**\n" +
+		" * Here are the configuration properties:\n" +
+		" * {@snippet id= \"testtest\" lang= 'java' :\n" +
+		" * // @replace region substring= 'value		' replacement= \"value:	\"\n" +
+		" * config1= \"value		1\";\n" +
+		" * config2= \"value		2\";\n" +
+		" * // @end\n" +
+		" * }\n" +
+		" */\n" +
+		"public class T {\n" +
+		"}"
+	);
+}
+public void testSnippet06() {
+	setComplianceLevel(CompilerOptions.VERSION_18);
+	this.formatterPrefs.insert_space_after_assignment_operator = false;
+	String source =
+		"/**\n" +
+		" * {@snippet :\n" +
+		" *   // @replace substring	=	'value		' replacement=\"value:	\" :\n" +
+		" *   config1=\"value		1\";\n" +
+		" *   config2=\"value		2\";\n" +
+		" * }\n" +
+		" */\n" +
+		"public class T {}";
+	formatSource(source,
+		"/**\n" +
+		" * {@snippet :\n" +
+		" * // @replace substring ='value		' replacement =\"value:	\" :\n" +
+		" * config1 =\"value		1\";\n" +
+		" * config2 =\"value		2\";\n" +
+		" * }\n" +
+		" */\n" +
+		"public class T {\n" +
+		"}"
+	);
+}
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelCompletionTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelCompletionTests.java
index bf35c12..872d41a 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelCompletionTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelCompletionTests.java
@@ -40,6 +40,8 @@
 	}
 	Hashtable<String, String> oldOptions;
 	ICompilationUnit wc = null;
+	private Hashtable<String, String> defaultOptions;
+
 public AbstractJavaModelCompletionTests(String name) {
 	super(name);
 }
@@ -168,6 +170,7 @@
 	Hashtable<String, String> options = new Hashtable<>(this.oldOptions);
 	options.put(JavaCore.CODEASSIST_SUBWORD_MATCH, JavaCore.DISABLED);
 	JavaCore.setOptions(options);
+	this.defaultOptions = options;
 	System.setProperty(AssistOptions.PROPERTY_SubstringMatch, "false");
 	waitUntilIndexesReady();
 }
@@ -191,6 +194,12 @@
 	}
 	super.tearDownSuite();
 }
+
+@Override
+protected Hashtable<String, String> getDefaultJavaCoreOptions() {
+	return this.defaultOptions;
+}
+
 @Override
 protected void tearDown() throws Exception {
 	if(this.wc != null) {
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
index 7978d04..fecb59e 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AbstractJavaModelTests.java
@@ -3905,14 +3905,33 @@
 
 		// ensure workspace options have been restored to their default
 		Hashtable options = JavaCore.getOptions();
-		Hashtable defaultOptions = JavaCore.getDefaultOptions();
-		assertEquals(
-			"Workspace options should be back to their default",
-			new CompilerOptions(defaultOptions).toString(),
-			new CompilerOptions(options).toString());
+		Hashtable defaultOptions = getDefaultJavaCoreOptions();
+		boolean resetToDefault = true;
+		try {
+			String expected = new CompilerOptions(defaultOptions).toString();
+			String actual = new CompilerOptions(options).toString();
+			assertEquals("Workspace options should be back to their default", expected, actual);
+			resetToDefault = false;
+		} finally {
+			if(resetToDefault) {
+				// Don't let all following tests use broken defaults and fail too
+				JavaCore.setOptions(defaultOptions);
+			}
+		}
 		super.tearDown();
 	}
 
+	/**
+	 * Override to supply "test class default JavaCore options"
+	 * so that these options will be restored for other tests in the class
+	 * even if one the test changes them without restoring in teardown.
+	 *
+	 * @return by default {@link JavaCore#getDefaultOptions()}
+	 */
+	protected Hashtable<String, String> getDefaultJavaCoreOptions() {
+		return JavaCore.getDefaultOptions();
+	}
+
 	protected IPath getJRE9Path() {
 		return new Path(System.getProperty("java.home") + "/lib/jrt-fs.jar");
 	}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AttachedJavadocTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AttachedJavadocTests.java
index 287d639..edf4224 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AttachedJavadocTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/AttachedJavadocTests.java
@@ -20,6 +20,7 @@
 import java.net.URI;
 import java.net.URL;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import junit.framework.Test;
 
@@ -743,6 +744,7 @@
 		this.project.setOptions(options);
 		IClasspathEntry[] entries = this.project.getRawClasspath();
 
+		AtomicBoolean stop = new AtomicBoolean();
 		try {
 			IClasspathAttribute attribute =
 					JavaCore.newClasspathAttribute(
@@ -774,6 +776,9 @@
 						synchronized (varThis) {
 							varThis.notify();
 						}
+						if(stop.get()) {
+							break;
+						}
 					}
 				}
 			};
@@ -791,6 +796,7 @@
 			paramNames = method.getParameterNames();
 			assertStringsEqual("Parameter names", new String[]{"param"}, paramNames);
 		} finally {
+			stop.set(true);
 			this.project.setRawClasspath(entries, null);
 			if (timeout != null)
 				options.put(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, timeout);
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java
index c20f98b..e8b906b 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ExternalAnnotations18Test.java
@@ -150,6 +150,8 @@
 				String annotsPath = elementsAndAnnotationPaths[i+1];
 				if ("self".equals(annotsPath))
 					this.elementAnnotationPaths.put(entryPath, entryPath);
+				else if (annotsPath != null)
+					this.elementAnnotationPaths.put(entryPath, annotsPath);
 			}
 		}
 
@@ -2894,94 +2896,58 @@
 				"Null type mismatch: required '@NonNull String' but the provided value is null",
 				markers);
 	}
+
+	// re-usable file contents for the subsequent set of tests (which exercise different configurations with same content):
+	static String mixedArtifacts_CGen_eea_content =
+			"class lib/pgen/CGen\n" +
+			"\n" +
+			"get\n" +
+			" (Ljava/lang/String;)Ljava/lang/String;\n" +
+			" (L1java/lang/String;)L1java/lang/String;\n";
+	static String mixedArtifacts_CGen2_eea_content =
+			"class lib/pgen2/CGen2\n" +
+			"\n" +
+			"get2\n" +
+			" (Ljava/lang/Exception;)Ljava/lang/String;\n" +
+			" (L1java/lang/Exception;)L1java/lang/String;\n";
+	static String mixedArtifacts_CGen_java_content =
+			"package lib.pgen;\n" +
+			"public class CGen {\n" +
+			"	public String get(String in) { return in; }\n" +
+			"}\n";
+	static String mixedArtifacts_CGen2_java_content =
+			"package lib.pgen2;\n" +
+			"public class CGen2 {\n" +
+			"	public String get2(Exception in) { return in.toString(); }\n" +
+			"}\n";
+
 	public void testMultiProject1() throws CoreException {
+		// PrjTest depends on two projects bundled with eea for their respective generated classes
+		// accessed using CORE_JAVA_BUILD_EXTERNAL_ANNOTATIONS_FROM_ALL_LOCATIONS
 		IJavaProject prj1 = null, prj2 = null;
 		myCreateJavaProject("Prj1");
 		addSourceFolderWithExternalAnnotations(this.project, "/Prj1/src-gen", null, "/Prj1/annot-gen");
 		prj1 = this.project;
 		try {
-			createFileInProject("annot-gen/pgen", "CGen.eea",
-					"class pgen/CGen\n" +
-					"\n" +
-					"get\n" +
-					" (Ljava/lang/String;)Ljava/lang/String;\n" +
-					" (L1java/lang/String;)L1java/lang/String;\n");
-
-			createFileInProject("src-gen/pgen", "CGen.java",
-					"package pgen;\n" +
-					"public class CGen {\n" +
-					"	public String get(String in) { return in; }\n" +
-					"}\n");
+			createFileInProject("annot-gen/lib/pgen", "CGen.eea",  mixedArtifacts_CGen_eea_content);
+			createFileInProject("src-gen/lib/pgen",   "CGen.java", mixedArtifacts_CGen_java_content);
 			this.project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
 
 			myCreateJavaProject("Prj2");
-			addSourceFolderWithExternalAnnotations(this.project, "/Prj2/src-gen", null, "/Prj2/annot-gen");
 			prj2 = this.project;
-			createFileInProject("annot-gen/pgen2", "CGen2.eea",
-					"class pgen2/CGen2\n" +
-					"\n" +
-					"get2\n" +
-					" (Ljava/lang/Exception;)Ljava/lang/String;\n" +
-					" (L1java/lang/Exception;)L1java/lang/String;\n");
-
-			createFileInProject("src-gen/pgen2", "CGen2.java",
-					"package pgen2;\n" +
-					"public class CGen2 {\n" +
-					"	public String get2(Exception in) { return in.toString(); }\n" +
-					"}\n");
+			addSourceFolderWithExternalAnnotations(this.project, "/Prj2/src-gen", null, "/Prj2/annot-gen");
+			createFileInProject("annot-gen/lib/pgen2", "CGen2.eea",  mixedArtifacts_CGen2_eea_content);
+			createFileInProject("src-gen/lib/pgen2",   "CGen2.java", mixedArtifacts_CGen2_java_content);
 			this.project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
 
 			myCreateJavaProject("PrjTest");
-			IClasspathEntry entry = JavaCore.newProjectEntry(
-					new Path("/Prj1"),
-					null/*access rules*/,
-					false/*combine access rules*/,
-					null,
-					false/*exported*/);
-			addClasspathEntry(this.project, entry);
-			entry = JavaCore.newProjectEntry(
-					new Path("/Prj2"),
-					null/*access rules*/,
-					false/*combine access rules*/,
-					null,
-					false/*exported*/);
-			addClasspathEntry(this.project, entry);
+			addClasspathEntry(this.project,
+					JavaCore.newProjectEntry(new Path("/Prj1"), null/*access rules*/, false/*combine access rules*/, null, false/*exported*/));
+			addClasspathEntry(this.project,
+					JavaCore.newProjectEntry(new Path("/Prj2"), null/*access rules*/, false/*combine access rules*/, null, false/*exported*/));
 			this.project.setOption(JavaCore.CORE_JAVA_BUILD_EXTERNAL_ANNOTATIONS_FROM_ALL_LOCATIONS, JavaCore.ENABLED);
 
-			createFileInProject("src/p", "Use.java",
-					"package p;\n" +
-					"import pgen.CGen;\n" +
-					"import pgen2.CGen2;\n" +
-					"import org.eclipse.jdt.annotation.NonNull;\n" +
-					"public class Use {\n" +
-					"	public @NonNull String test(CGen c) {\n" +
-					"		String s = c.get(null);\n" + // problem here (7)
-					"		return s;\n" + // no problem here
-					"	}\n" +
-					"	public @NonNull String test2(CGen2 c) {\n" +
-					"		String s = c.get2(null);\n" + // problem here (11)
-					"		return s;\n" + // no problem here
-					"	}\n" +
-					"}\n");
-			this.project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
-			IMarker[] markers = this.project.getProject().findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
-			sortMarkers(markers);
-			assertMarkers("Unexpected markers",
-					"Null type mismatch: required '@NonNull Exception' but the provided value is null\n" +
-					"Null type mismatch: required '@NonNull String' but the provided value is null",
-					markers);
-
-			ICompilationUnit unit = JavaCore.createCompilationUnitFrom(this.project.getProject().getFile("src/p/Use.java")).getWorkingCopy(null);
-			CompilationUnit reconciled = unit.reconcile(getJLS8(), true, null, new NullProgressMonitor());
-			IProblem[] problems = reconciled.getProblems();
-			assertProblems(problems,
-				new String[] {
-					"Pb(910) Null type mismatch: required '@NonNull String' but the provided value is null",
-					"Pb(910) Null type mismatch: required '@NonNull Exception' but the provided value is null"
-				},
-				new int[] {
-					7, 11
-				});
+			internalTestMixedArtifactsTest();
 		} finally {
 			if (prj1 != null)
 				prj1.getProject().delete(true, true , null);
@@ -2995,156 +2961,181 @@
 		this.project.setOption(JavaCore.CORE_JAVA_BUILD_EXTERNAL_ANNOTATIONS_FROM_ALL_LOCATIONS, JavaCore.ENABLED);
 
 		String projectLoc = this.project.getProject().getLocation().toString();
-		Util.createJar(new String[] {
-				"pgen/CGen.java",
-				"package pgen;\n" +
-				"public class CGen {\n" +
-				"	public String get(String in) { return in; }\n" +
-				"}\n"
-			},
-			new String[] {
-				"pgen/CGen.eea",
-				"class pgen/CGen\n" +
-				"\n" +
-				"get\n" +
-				" (Ljava/lang/String;)Ljava/lang/String;\n" +
-				" (L1java/lang/String;)L1java/lang/String;\n"
-			},
-			projectLoc+"/lib/prj1.jar",
-			"1.8");
-		IClasspathEntry entry = JavaCore.newLibraryEntry(
-				new Path("/PrjTest/lib/prj1.jar"),
-				null/*access rules*/,
-				null,
-				false/*exported*/);
-		addClasspathEntry(this.project, entry);
+		Util.createJar(
+			new String[] { "lib/pgen/CGen.java", mixedArtifacts_CGen_java_content },
+			new String[] { "lib/pgen/CGen.eea",  mixedArtifacts_CGen_eea_content },
+			projectLoc+"/lib/prj1.jar", "1.8");
+		addClasspathEntry(this.project,
+				JavaCore.newLibraryEntry(new Path("/PrjTest/lib/prj1.jar"), null/*access rules*/, null, false/*exported*/));
 
-		Util.createJar(new String[] {
-				"pgen2/CGen2.java",
-				"package pgen2;\n" +
-				"public class CGen2 {\n" +
-				"	public String get2(Exception in) { return in.toString(); }\n" +
-				"}\n"
-			},
-			new String[] {
-				"pgen2/CGen2.eea",
-				"class pgen2/CGen2\n" +
-				"\n" +
-				"get2\n" +
-				" (Ljava/lang/Exception;)Ljava/lang/String;\n" +
-				" (L1java/lang/Exception;)L1java/lang/String;\n",
-			},
-			projectLoc+"/lib/prj2.jar",
-			"1.8");
-		entry = JavaCore.newLibraryEntry(
-				new Path("/PrjTest/lib/prj2.jar"),
-				null/*access rules*/,
-				null,
-				false/*exported*/);
-		addClasspathEntry(this.project, entry);
-		this.project.getProject().refreshLocal(IResource.DEPTH_INFINITE, null);
+		Util.createJar(
+			new String[] { "lib/pgen2/CGen2.java", mixedArtifacts_CGen2_java_content },
+			new String[] { "lib/pgen2/CGen2.eea",  mixedArtifacts_CGen2_eea_content },
+			projectLoc+"/lib/prj2.jar", "1.8");
+		addClasspathEntry(this.project,
+				JavaCore.newLibraryEntry(new Path("/PrjTest/lib/prj2.jar"), null/*access rules*/, null, false/*exported*/));
 
-		createFileInProject("src/p", "Use.java",
-				"package p;\n" +
-				"import pgen.CGen;\n" +
-				"import pgen2.CGen2;\n" +
-				"import org.eclipse.jdt.annotation.NonNull;\n" +
-				"public class Use {\n" +
-				"	public @NonNull String test(CGen c) {\n" +
-				"		String s = c.get(null);\n" + // problem here (7)
-				"		return s;\n" + // no problem here
-				"	}\n" +
-				"	public @NonNull String test2(CGen2 c) {\n" +
-				"		String s = c.get2(null);\n" + // problem here (11)
-				"		return s;\n" + // no problem here
-				"	}\n" +
-				"}\n");
-		this.project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
-		IMarker[] markers = this.project.getProject().findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
-		sortMarkers(markers);
-		assertMarkers("Unexpected markers",
-				"Null type mismatch: required '@NonNull Exception' but the provided value is null\n" +
-				"Null type mismatch: required '@NonNull String' but the provided value is null",
-				markers);
-
-		ICompilationUnit unit = JavaCore.createCompilationUnitFrom(this.project.getProject().getFile("src/p/Use.java")).getWorkingCopy(null);
-		CompilationUnit reconciled = unit.reconcile(getJLS8(), true, null, new NullProgressMonitor());
-		IProblem[] problems = reconciled.getProblems();
-		assertProblems(problems,
-			new String[] {
-				"Pb(910) Null type mismatch: required '@NonNull String' but the provided value is null",
-				"Pb(910) Null type mismatch: required '@NonNull Exception' but the provided value is null"
-			},
-			new int[] {
-				7, 11
-			});
-
+		internalTestMixedArtifactsTest();
 	}
+
 	public void testSeparateAnnotationJar() throws CoreException, IOException {
-		// similar to selfAnnotatedJars(), but here all .eeas are deployed in a separate jar on the build path
+		// all .eeas are deployed in a separate jar on the build path
+		// accessed using CORE_JAVA_BUILD_EXTERNAL_ANNOTATIONS_FROM_ALL_LOCATIONS
 		myCreateJavaProject("PrjTest");
 		this.project.setOption(JavaCore.CORE_JAVA_BUILD_EXTERNAL_ANNOTATIONS_FROM_ALL_LOCATIONS, JavaCore.ENABLED);
 
 		String projectLoc = this.project.getProject().getLocation().toString();
-		Util.createJar(new String[0],
-			new String[] {
-				"lib/pgen/CGen.eea",
-				"class lib/pgen/CGen\n" +
-				"\n" +
-				"get\n" +
-				" (Ljava/lang/String;)Ljava/lang/String;\n" +
-				" (L1java/lang/String;)L1java/lang/String;\n",
+		Util.createJar(new String[0], new String[] {
+					"lib/pgen/CGen.eea", mixedArtifacts_CGen_eea_content,
+					"lib/pgen2/CGen2.eea", mixedArtifacts_CGen2_eea_content,
+				},
+				projectLoc+"/lib/eeas.jar", "1.8");
+		addClasspathEntry(this.project,
+				JavaCore.newLibraryEntry(new Path("/PrjTest/lib/eeas.jar"), null/*access rules*/, null, false/*exported*/));
 
-				"lib/pgen2/CGen2.eea",
-				"class lib/pgen2/CGen2\n" +
-				"\n" +
-				"get2\n" +
-				" (Ljava/lang/Exception;)Ljava/lang/String;\n" +
-				" (L1java/lang/Exception;)L1java/lang/String;\n",
-			},
-			projectLoc+"/lib/eeas.jar",
-			"1.8");
-		IClasspathEntry entry = JavaCore.newLibraryEntry(
-				new Path("/PrjTest/lib/eeas.jar"),
-				null/*access rules*/,
-				null,
-				false/*exported*/);
-		addClasspathEntry(this.project, entry);
+		// one jar dependency in the workspace
+		Util.createJar(
+				new String[] { "lib/pgen/CGen.java", mixedArtifacts_CGen_java_content },
+				projectLoc+"/lib/prj1.jar", "1.8");
+		addClasspathEntry(this.project,
+				JavaCore.newLibraryEntry(new Path("/PrjTest/lib/prj1.jar"), null/*access rules*/, null, false/*exported*/));
 
-		Util.createJar(new String[] {
-				"lib/pgen/CGen.java",
-				"package lib.pgen;\n" +
-				"public class CGen {\n" +
-				"	public String get(String in) { return in; }\n" +
-				"}\n"
-			},
-			projectLoc+"/lib/prj1.jar",
-			"1.8");
-		entry = JavaCore.newLibraryEntry(
-				new Path("/PrjTest/lib/prj1.jar"),
-				null/*access rules*/,
-				null,
-				false/*exported*/);
-		addClasspathEntry(this.project, entry);
-
+		// second dependency is external jar file
 		String externalJarLoc = Util.getOutputDirectory()+"/lib/prj2.jar";
-		Util.createJar(new String[] {
-				"lib.pgen2/CGen2.java",
-				"package lib.pgen2;\n" +
-				"public class CGen2 {\n" +
-				"	public String get2(Exception in) { return in.toString(); }\n" +
-				"}\n"
-			},
-			externalJarLoc,
-			"1.8");
-		entry = JavaCore.newLibraryEntry(
-				new Path(externalJarLoc),
-				null/*access rules*/,
-				null,
-				false/*exported*/);
-		addClasspathEntry(this.project, entry);
-		this.project.getProject().refreshLocal(IResource.DEPTH_INFINITE, null);
+		Util.createJar(
+				new String[] { "lib.pgen2/CGen2.java", mixedArtifacts_CGen2_java_content },
+				externalJarLoc, "1.8");
+		addClasspathEntry(this.project,
+				JavaCore.newLibraryEntry(new Path(externalJarLoc), null/*access rules*/, null, false/*exported*/));
 
+		internalTestMixedArtifactsTest();
+	}
+
+	public void testSeparateAnnotationJarInContainer() throws CoreException, IOException {
+		// .eeas are deployed as a member of a classpath container
+		// referenced relative to the container.
+		myCreateJavaProject("PrjTest");
+		String projectLoc = this.project.getProject().getLocation().toString();
+
+		ITestInitializer prev = ContainerInitializer.initializer;
+		String fullPathToEEA = projectLoc+"/lib/my.eeas-0.1.jar";
+		String fullPathToPrj1 = projectLoc+"/lib/prj1.jar";
+		ContainerInitializer.setInitializer(new TestCustomContainerInitializer(
+				fullPathToEEA, null,
+				fullPathToPrj1, null));
+
+		try {
+			Util.createJar(new String[0], new String[] {
+						"lib/pgen/CGen.eea",   mixedArtifacts_CGen_eea_content,
+						"lib/pgen2/CGen2.eea", mixedArtifacts_CGen2_eea_content },
+					fullPathToEEA, "1.8");
+
+			Util.createJar(
+					new String[] { "lib/pgen/CGen.java", mixedArtifacts_CGen_java_content },
+					fullPathToPrj1, "1.8");
+
+			// eeas & prj1 accessed via the Container:
+			IClasspathEntry entry = JavaCore.newContainerEntry(new Path(TestContainerInitializer.TEST_CONTAINER_NAME), null/*access rules*/,
+					externalAnnotationExtraAttributes(TestContainerInitializer.TEST_CONTAINER_NAME+"/my.eeas"),
+					false/*exported*/);
+			addClasspathEntry(this.project, entry);
+
+			// other jar accessed via separate entry, also annotated using eea in container
+			String externalJarLoc = Util.getOutputDirectory() + "/lib/prj2.jar";
+			Util.createJar(
+					new String[] { "lib.pgen2/CGen2.java", mixedArtifacts_CGen2_java_content },
+					externalJarLoc, "1.8");
+			entry = JavaCore.newLibraryEntry(new Path(externalJarLoc), null, null, null,
+					externalAnnotationExtraAttributes(TestContainerInitializer.TEST_CONTAINER_NAME+"/my.eeas"),
+					false/*exported*/);
+			addClasspathEntry(this.project, entry);
+
+			internalTestMixedArtifactsTest();
+		} finally {
+			ContainerInitializer.setInitializer(prev);
+		}
+	}
+
+	public void testAnnotationsInProjectReferencedViaContainer() throws CoreException, IOException {
+		// undeployed version of testSeparateAnnotationJarInContainer:
+		// container "resolved" the eea-artifact to a workspace project
+		myCreateJavaProject("PrjTest");
+		String projectLoc = this.project.getProject().getLocation().toString();
+
+		ITestInitializer prev = ContainerInitializer.initializer;
+		String eeaProjectName = "my.eeas";
+		String fullPathToPrj1 = projectLoc+"/lib/prj1.jar";
+		ContainerInitializer.setInitializer(new TestCustomContainerInitializer(
+				'/'+eeaProjectName, null,
+				fullPathToPrj1, null));
+
+		try {
+			createJavaProject(eeaProjectName);
+			createFolder('/'+eeaProjectName+"/lib/pgen");
+			createFolder('/'+eeaProjectName+"/lib/pgen2");
+			createFile(eeaProjectName+"/lib/pgen/CGen.eea",   mixedArtifacts_CGen_eea_content);
+			createFile(eeaProjectName+"/lib/pgen2/CGen2.eea", mixedArtifacts_CGen2_eea_content);
+
+			Util.createJar(
+					new String[] { "lib/pgen/CGen.java", mixedArtifacts_CGen_java_content },
+					fullPathToPrj1, "1.8");
+
+			// eeas & prj1 accessed via the Container:
+			IClasspathEntry entry = JavaCore.newContainerEntry(
+					new Path(TestContainerInitializer.TEST_CONTAINER_NAME), null/*access rules*/,
+					externalAnnotationExtraAttributes(TestContainerInitializer.TEST_CONTAINER_NAME+"/my.eeas"),
+					false/*exported*/);
+			addClasspathEntry(this.project, entry);
+
+			// other jar accessed via separate entry, also annotated using eea in container
+			String externalJarLoc = Util.getOutputDirectory() + "/lib/prj2.jar";
+			Util.createJar(
+					new String[] { "lib.pgen2/CGen2.java", mixedArtifacts_CGen2_java_content },
+					externalJarLoc, "1.8");
+			entry = JavaCore.newLibraryEntry(
+					new Path(externalJarLoc), null, null, null,
+					externalAnnotationExtraAttributes(TestContainerInitializer.TEST_CONTAINER_NAME+"/my.eeas"),
+					false/*exported*/);
+			addClasspathEntry(this.project, entry);
+
+			internalTestMixedArtifactsTest();
+		} finally {
+			ContainerInitializer.setInitializer(prev);
+		}
+	}
+
+	public void testMixedElementAndContainerAnnotation() throws Exception {
+		// container mixes annotations from internal resolving ("self") and client-side annotation path
+		myCreateJavaProject("PrjTest");
+		String projectLoc = this.project.getProject().getLocation().toString();
+		ITestInitializer prev = ContainerInitializer.initializer;
+		ContainerInitializer.setInitializer(new TestCustomContainerInitializer(projectLoc+"/lib1.jar", "self", projectLoc+"/lib2.jar", null));
+		try {
+
+			// jar with external annotations for its own class
+			Util.createJar(
+				new String[] { "lib/pgen/CGen.java", mixedArtifacts_CGen_java_content },
+				new String[] { "lib/pgen/CGen.eea",  mixedArtifacts_CGen_eea_content, },
+				projectLoc+"/lib1.jar", "1.8");
+			Util.createJar(
+				new String[] { "lib/pgen2/CGen2.java", mixedArtifacts_CGen2_java_content },
+				projectLoc+"/lib2.jar", "1.8");
+			IClasspathEntry containerEntry = JavaCore.newContainerEntry(
+					new Path(TestContainerInitializer.TEST_CONTAINER_NAME),
+					null,
+					externalAnnotationExtraAttributes("/PrjTest/annots"),
+					false);
+			addClasspathEntry(this.project, containerEntry);
+
+			createFileInProject("annots/lib/pgen2", "CGen2.eea", mixedArtifacts_CGen2_eea_content);
+
+			internalTestMixedArtifactsTest();
+		} finally {
+			ContainerInitializer.setInitializer(prev);
+		}
+	}
+	protected void internalTestMixedArtifactsTest() throws CoreException, JavaModelException {
+		this.project.getProject().refreshLocal(IResource.DEPTH_INFINITE, null);
 		createFileInProject("src/p", "Use.java",
 				"package p;\n" +
 				"import lib.pgen.CGen;\n" +
@@ -3161,14 +3152,16 @@
 				"	}\n" +
 				"}\n");
 		this.project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
-		IMarker[] markers = this.project.getProject().findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
+		IMarker[] markers = this.project.getProject()
+				.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
 		sortMarkers(markers);
 		assertMarkers("Unexpected markers",
 				"Null type mismatch: required '@NonNull Exception' but the provided value is null\n" +
 				"Null type mismatch: required '@NonNull String' but the provided value is null",
 				markers);
-
-		ICompilationUnit unit = JavaCore.createCompilationUnitFrom(this.project.getProject().getFile("src/p/Use.java")).getWorkingCopy(null);
+		ICompilationUnit unit = JavaCore
+				.createCompilationUnitFrom(this.project.getProject().getFile("src/p/Use.java"))
+				.getWorkingCopy(null);
 		CompilationUnit reconciled = unit.reconcile(getJLS8(), true, null, new NullProgressMonitor());
 		IProblem[] problems = reconciled.getProblems();
 		assertProblems(problems,
@@ -3176,101 +3169,9 @@
 				"Pb(910) Null type mismatch: required '@NonNull String' but the provided value is null",
 				"Pb(910) Null type mismatch: required '@NonNull Exception' but the provided value is null"
 			},
-			new int[] {
-				7, 11
-			});
+			new int[] { 7, 11 });
 	}
 
-	public void testMixedElementAndContainerAnnotation() throws Exception {
-		myCreateJavaProject("PrjTest");
-		String projectLoc = this.project.getProject().getLocation().toString();
-		ITestInitializer prev = ContainerInitializer.initializer;
-		ContainerInitializer.setInitializer(new TestCustomContainerInitializer(projectLoc+"/lib1.jar", "self", projectLoc+"/lib2.jar", null));
-		try {
-
-			// jar with external annotations for its own class
-			Util.createJar(new String[] {
-					"lib/pgen/CGen.java",
-					"package lib.pgen;\n" +
-					"public class CGen {\n" +
-					"	public String get(String in) { return in; }\n" +
-					"}\n"
-				},
-				new String[] {
-					"lib/pgen/CGen.eea",
-					"class lib/pgen/CGen\n" +
-					"\n" +
-					"get\n" +
-					" (Ljava/lang/String;)Ljava/lang/String;\n" +
-					" (L1java/lang/String;)L1java/lang/String;\n",
-				},
-				projectLoc+"/lib1.jar",
-				"1.8");
-			Util.createJar(new String[] {
-					"lib2/C2.java",
-					"package lib2;\n" +
-					"public class C2 {\n" +
-					"	public String get2(Exception in) { return in.toString(); }\n" +
-					"}\n"
-				},
-				projectLoc+"/lib2.jar",
-				"1.8");
-			IClasspathEntry containerEntry = JavaCore.newContainerEntry(
-					new Path("org.eclipse.jdt.core.tests.model.TEST_CONTAINER"),
-					null,
-					new IClasspathAttribute[] {
-							JavaCore.newClasspathAttribute(IClasspathAttribute.EXTERNAL_ANNOTATION_PATH, "/PrjTest/annots")
-					},
-					false);
-			addClasspathEntry(this.project, containerEntry);
-
-			createFileInProject("annots/lib2", "C2.eea",
-					"class lib2/C2\n" +
-					"\n" +
-					"get2\n" +
-					" (Ljava/lang/Exception;)Ljava/lang/String;\n" +
-					" (L1java/lang/Exception;)L1java/lang/String;\n");
-
-			createFileInProject("src/p", "Use.java",
-					"package p;\n" +
-					"import lib.pgen.CGen;\n" +
-					"import lib2.C2;\n" +
-					"import org.eclipse.jdt.annotation.NonNull;\n" +
-					"public class Use {\n" +
-					"	public @NonNull String test(CGen c) {\n" +
-					"		String s = c.get(null);\n" + // problem here (7)
-					"		return s;\n" + // no problem here
-					"	}\n" +
-					"	public @NonNull String test2(C2 c) {\n" +
-					"		String s = c.get2(null);\n" + // problem here (11)
-					"		return s;\n" + // no problem here
-					"	}\n" +
-					"}\n");
-
-
-			this.project.getProject().build(IncrementalProjectBuilder.FULL_BUILD, null);
-			IMarker[] markers = this.project.getProject().findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
-			sortMarkers(markers);
-			assertMarkers("Unexpected markers",
-					"Null type mismatch: required '@NonNull Exception' but the provided value is null\n" +
-					"Null type mismatch: required '@NonNull String' but the provided value is null",
-					markers);
-
-			ICompilationUnit unit = JavaCore.createCompilationUnitFrom(this.project.getProject().getFile("src/p/Use.java")).getWorkingCopy(null);
-			CompilationUnit reconciled = unit.reconcile(getJLS8(), true, null, new NullProgressMonitor());
-			IProblem[] problems = reconciled.getProblems();
-			assertProblems(problems,
-				new String[] {
-					"Pb(910) Null type mismatch: required '@NonNull String' but the provided value is null",
-					"Pb(910) Null type mismatch: required '@NonNull Exception' but the provided value is null"
-				},
-				new int[] {
-					7, 11
-				});
-		} finally {
-			ContainerInitializer.setInitializer(prev);
-		}
-	}
 	public void testAnnotatedSourceSharesOutputFolder() throws CoreException {
 		IJavaProject prj1 = null;
 		myCreateJavaProject("Prj1");
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs15Tests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs15Tests.java
index cad4a2b..30534c0 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs15Tests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs15Tests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c)  2020, 2021 IBM Corporation and others.
+ * Copyright (c)  2020, 2022 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
@@ -1087,7 +1087,7 @@
 			int length = selection.length();
 
 			IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
-			assertTrue(elements.length ==1);
+			assertEquals("incorrect size of elements", 1, elements.length);
 			assertTrue((elements[0] instanceof LocalVariable));
 
 		}
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs16Tests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs16Tests.java
index 2c43f22..8123f78 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs16Tests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBugs16Tests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c)  2021 IBM Corporation and others.
+ * Copyright (c)  2021, 2022 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
@@ -612,6 +612,7 @@
 				int start = str.indexOf(selection);
 				int length = selection.length();
 				IJavaElement[] elements = this.workingCopies[0].codeSelect(start, length);
+				assertEquals("incorrect number of elements", 1, elements.length);
 				ILocalVariable local = (ILocalVariable) elements[0];
 				search(local, DECLARATIONS, EXACT_RULE);
 				assertSearchResults("src/X.java void X.method(Object).xvar [xvar] EXACT_MATCH");
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests12To15.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests12To15.java
index f37f336..f055515 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests12To15.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests12To15.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2019, 2020 IBM Corporation and others.
+ * Copyright (c) 2019, 2022 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 @@
 	ICompilationUnit wc = null;
 
 static {
-//	 TESTS_NAMES = new String[] { "test018" };
+//	 TESTS_NAMES = new String[] { "testBug577508_4" };
 	// TESTS_NUMBERS = new int[] { 124 };
 	// TESTS_RANGE = new int[] { 16, -1 };
 }
@@ -803,4 +803,117 @@
 			"s2 [in <anonymous #1> [in test() [in Test2 [in [Working copy] Test2.java [in <default> [in src [in Resolve]]]]]]]",
 			elements);
 }
+public void testBug577508_1() throws JavaModelException {
+	this.wc = getWorkingCopy("/Resolve15/src/X.java",
+			"public class X {\n"
+					+ "    public X () {\n"
+					+ "		new Runnable() {\n"
+					+ "			public void run () {\n"
+					+ "				Object object = null;\n"
+					+ "				if (object instanceof Thread thread) thread.start();\n"
+					+ "				tryToOpenDeclarationOnThisMethod();\n"
+					+ "			}\n"
+					+ "		};\n"
+					+ "	}\n"
+					+ "	public void tryToOpenDeclarationOnThisMethod () {\n"
+					+ "	}\n"
+					+ "}");
+	String str = this.wc.getSource();
+	String selection = "tryToOpenDeclarationOnThisMethod";
+	int start = str.indexOf(selection);
+	int length = selection.length();
+	IJavaElement[] elements = this.wc.codeSelect(start, length);
+	assertElementsEqual(
+		"Unexpected elements",
+		"tryToOpenDeclarationOnThisMethod() [in X [in [Working copy] X.java [in <default> [in src [in Resolve15]]]]]",
+		elements
+	);
+}
+public void testBug577508_2() throws JavaModelException {
+	this.wc = getWorkingCopy("/Resolve15/src/X.java",
+			"public class X {\n"
+					+ "    public X () {\n"
+					+ "		for (Object object : new Object[] {\"test\"}) {\n"
+					+ "			if (object instanceof String string) {\n"
+					+ "				System.out.println(string);\n"
+					+ "				tryToOpenDeclarationOnThisMethod();\n"
+					+ "			}\n"
+					+ "		}\n"
+					+ "	}\n"
+					+ "	static public void tryToOpenDeclarationOnThisMethod () {\n"
+					+ "	}\n"
+					+ "}");
+	String str = this.wc.getSource();
+	String selection = "tryToOpenDeclarationOnThisMethod";
+	int start = str.indexOf(selection);
+	int length = selection.length();
+	IJavaElement[] elements = this.wc.codeSelect(start, length);
+	assertElementsEqual(
+		"Unexpected elements",
+		"tryToOpenDeclarationOnThisMethod() [in X [in [Working copy] X.java [in <default> [in src [in Resolve15]]]]]",
+		elements
+	);
+}
+public void testBug577508_3() throws JavaModelException {
+	this.wc = getWorkingCopy("/Resolve15/src/X.java",
+			"public class X {\n"
+			+ "  public static void main(String[] args) {\n"
+			+ "    Set<Foo> foos = Set.of(new Foo(), new Bar());\n"
+			+ "    for (Foo foo : foos) {\n"
+			+ "      String string;\n"
+			+ "      if (foo instanceof Bar bar) {\n"
+			+ "        string = \"__\";\n"
+			+ "      }\n"
+			+ "    }\n"
+			+ "    String[] names = new String[] {};\n"
+			+ "    for (String name : names) {\n"
+			+ "      int size = name.length();\n"
+			+ "    }\n"
+			+ "  }\n"
+			+ "  static class Foo {}\n"
+			+ "  static class Bar extends Foo {}\n"
+			+ "}");
+	String str = this.wc.getSource();
+	String selection = "length";
+	int start = str.indexOf(selection);
+	int length = "length".length();
+	IJavaElement[] elements = this.wc.codeSelect(start, length);
+	assertElementsEqual(
+		"Unexpected elements",
+		"length() [in String [in String.class [in java.lang [in "+ getExternalPath() + "jclMin14.jar]]]]",
+		elements
+	);
+}
+public void testBug577508_4() throws JavaModelException {
+	this.wc = getWorkingCopy("/Resolve15/src/X.java",
+			"public class X {\n"
+			+ "  static public void main (String[] args) {\n"
+			+ "	Object[] objects = new Object[3];\n"
+			+ "	for (Object object : objects) \n"
+			+ "		if (object instanceof String string && !(object instanceof Runnable)) \n"
+			+ "			System.out.println(); // Open Declaration fails here if you remove the braces from the for loop.\n"
+			+ "	System.out.println(); // Open Declaration always fails here.\n"
+			+ "}\n"
+			+ "}");
+	String str = this.wc.getSource();
+	String selection = "println";
+	int start = str.indexOf(selection);
+	int length = selection.length();
+	IJavaElement[] elements = this.wc.codeSelect(start, length);
+	assertElementsEqual(
+		"Unexpected elements",
+		"println(java.lang.String) [in PrintStream [in PrintStream.class [in java.io [in "+ getExternalPath() + "jclMin14.jar]]]]",
+		elements
+	);
+
+	str = this.wc.getSource();
+	start = str.lastIndexOf(selection);
+	length = selection.length();
+	elements = this.wc.codeSelect(start, length);
+	assertElementsEqual(
+		"Unexpected elements",
+		"println(java.lang.String) [in PrintStream [in PrintStream.class [in java.io [in "+ getExternalPath() + "jclMin14.jar]]]]",
+		elements
+	);
+}
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SubwordCompletionTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SubwordCompletionTests.java
index a6e8043..da222e9 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SubwordCompletionTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SubwordCompletionTests.java
@@ -25,6 +25,8 @@
 
 public class SubwordCompletionTests extends AbstractJavaModelCompletionTests {
 
+private Hashtable<String, String> defaultOptions;
+
 public static Test suite() {
 	return buildModelTestSuite(SubwordCompletionTests.class, BYTECODE_DECLARATION_ORDER);
 }
@@ -40,6 +42,7 @@
 	super.setUpSuite();
 	Hashtable<String, String> options = new Hashtable<>(this.oldOptions);
 	options.put(JavaCore.CODEASSIST_SUBWORD_MATCH, JavaCore.ENABLED);
+	this.defaultOptions = options;
 	JavaCore.setOptions(options);
 }
 public void tearDownSuite() throws Exception {
@@ -57,6 +60,12 @@
 	}
 	super.tearDownSuite();
 }
+
+@Override
+protected Hashtable<String, String> getDefaultJavaCoreOptions() {
+	return this.defaultOptions;
+}
+
 private CompletionTestsRequestor2 createFilteredRequestor() {
 	CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
 	Predicate<CompletionProposal> javaTypeRef = p -> p.getKind() == CompletionProposal.TYPE_REF && new String(p.getSignature()).startsWith("Ljava.");
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SuiteOfTestCases.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SuiteOfTestCases.java
index c832840..2876fcd 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SuiteOfTestCases.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/SuiteOfTestCases.java
@@ -129,6 +129,9 @@
 	public void setUpSuite() throws Exception {
 		// Indexer is disabled for tests by defailt, see
 		// org.eclipse.jdt.core.tests.junit.extension.TestCase.isIndexDisabledForTest()
+
+		// The first individual setup() call will also call done()
+		FreezeMonitor.expectCompletionIn(FROZEN_TEST_TIMEOUT_MS);
 	}
 
 	/**
@@ -137,6 +140,10 @@
 	public void tearDownSuite() throws Exception {
 		// Indexer is disabled for tests by defailt, see
 		// org.eclipse.jdt.core.tests.junit.extension.TestCase.isIndexDisabledForTest()
+
+		// Just to be symmetrical to setup(), actually this shouldn't be needed
+		// if we have at least one test
+		FreezeMonitor.done();
 	}
 
 	@Override
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/modifying/ASTRewritingModifyingTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/modifying/ASTRewritingModifyingTest.java
index e284701..26fc735 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/modifying/ASTRewritingModifyingTest.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/rewrite/modifying/ASTRewritingModifyingTest.java
@@ -55,7 +55,8 @@
 	protected IJavaProject javaProject;
 	protected IPackageFragmentRoot sourceFolder;
 
-	private Hashtable oldOptions;
+	private Hashtable<String, String> oldOptions;
+	private Hashtable<String, String> defaultOptions;
 
 	public ASTRewritingModifyingTest(String name) {
 		super(name);
@@ -79,20 +80,28 @@
 		this.javaProject = createJavaProject("P", new String[] {"src"}, null, "bin", "1.5");
 		this.sourceFolder = getPackageFragmentRoot("P", "src");
 
-		Hashtable options = JavaCore.getOptions();
+		Hashtable<String, String> options = JavaCore.getOptions();
 		this.oldOptions = (Hashtable)options.clone();
 		options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, JavaCore.SPACE);
 		options.put(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, "4");
+		this.defaultOptions = options;
 		JavaCore.setOptions(options);
 
 		waitUntilIndexesReady();
 	}
+
 	@Override
 	public void tearDownSuite() throws Exception {
 		deleteProject("P");
 		JavaCore.setOptions(this.oldOptions);
 		super.tearDownSuite();
 	}
+
+	@Override
+	protected Hashtable<String, String> getDefaultJavaCoreOptions() {
+		return this.defaultOptions;
+	}
+
 	public CompilationUnit createCU(
 		ICompilationUnit unit,
 		boolean resolveBindings,
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 9f96ac8..9296681 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
@@ -52,6 +52,7 @@
 import org.eclipse.jdt.internal.compiler.ast.Statement;
 import org.eclipse.jdt.internal.compiler.ast.SuperReference;
 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
+import org.eclipse.jdt.internal.compiler.ast.TypePattern;
 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.lookup.Binding;
@@ -384,6 +385,41 @@
 			this.lastCheckPoint = importRef.declarationSourceEnd + 1;
 		}
 	}
+	// This is  copy of the code that processes astStack early in this method
+	for (int i = 0; i <= this.patternPtr; i++, lastNode = node) {
+		node = this.patternStack[i];
+		/* check for intermediate block creation, so recovery can properly close them afterwards */
+		int nodeStart = node.sourceStart;
+		for (int j = blockIndex; j <= this.realBlockPtr; j++){
+			if (this.blockStarts[j] >= 0) {
+				if (this.blockStarts[j] > nodeStart){
+					blockIndex = j; // shift the index to the new block
+					break;
+				}
+				if (this.blockStarts[j] != lastStart){ // avoid multiple block if at same position
+					block = new Block(0);
+					block.sourceStart = lastStart = this.blockStarts[j];
+					element = element.add(block, 1);
+				}
+			} else {
+				if (-this.blockStarts[j] > nodeStart){
+					blockIndex = j; // shift the index to the new block
+					break;
+				}
+				block = new Block(0);
+				block.sourceStart = lastStart = -this.blockStarts[j];
+				element = element.add(block, 1);
+			}
+			blockIndex = j+1; // shift the index to the new block
+		}
+
+		if (node instanceof TypePattern){
+			TypePattern pattern = (TypePattern) node;
+			LocalDeclaration local = pattern.getPatternVariableIntroduced();
+			element = element.add(local, 0);
+			continue;
+		}
+	}
 	if (this.currentToken == TokenNameRBRACE) {
 		 if (isIndirectlyInsideLambdaExpression())
 			 this.ignoreNextClosingBrace = true;
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 4cce843..b6f8f41 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, 2021 IBM Corporation and others.
+ * Copyright (c) 2000, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -851,6 +851,10 @@
 			}
 			if (local != null) {
 				pushOnAstStack(local);
+				if (!this.diet) {
+					this.restartRecovery	= true;
+					this.lastIgnoredToken = -1;
+				}
 			}
 		}
 	} else {
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 4ba8b83..2218b08 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
@@ -5638,7 +5638,7 @@
 		exp.sourceEnd = this.scanner.startPosition - 1;
 	}
 }
-private Expression consumePatternInsideInstanceof(Pattern pattern) {
+protected Expression consumePatternInsideInstanceof(Pattern pattern) {
 	Expression exp;
 	if (pattern instanceof GuardedPattern) {
 		// This is a workaround as InstanceOfExpression doesn't handle a guarded pattern
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
index fbae13a..9c43b41 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
@@ -388,6 +388,8 @@
 		} catch (JavaModelException e) {
 			//do nothing
 		}
+		if(resolvedClasspath == null)
+			return srcClassPath;
 
 		for (IClasspathEntry entry : resolvedClasspath) {
 		    if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
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 afea0a4..65853de 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
@@ -77,6 +77,23 @@
 			.compile("&(#x[0-9a-fA-F]+)?(#[0-9]+)?(lt)?(gt)?(nbsp)?(amp)?(circ)?(tilde)?(quot)?;"); //$NON-NLS-1$
 	private final static String HTML_ENTITY_REPLACE = "   <> &^~\""; //$NON-NLS-1$
 
+	private final static Pattern SNIPPET_ATTRIBUTE_PATTERN;
+	private final static Pattern SNIPPET_ATTRIBUTES_PATTERN;
+	private final static Pattern SNIPPET_MARKUP_TAG_PATTERN;
+	private final static Pattern SNIPPET_MARKUP_TAG_ARGUMENT_PATTERN;
+	static {
+		String attributeNames = "(class|file|id|lang|region)"; //$NON-NLS-1$
+		String markupTagNames = "(@start|@end|@highlight|@replace|@link)"; //$NON-NLS-1$
+		String ws = "(?>[ \\t]++|[\\r\\n]++[ \\t]*+\\*?)"; // whitespace or line break with optional asterisk //$NON-NLS-1$
+		String attributeValue = "(?>\"[^\"]*\")|(?>\'[^\']*\')|[\\S&&[^\"':]]++"; //$NON-NLS-1$
+		String snippetAttribute = "(?>" + ws + "*" + attributeNames + ws + "*(=)" + ws + "*(" + attributeValue  + "))"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+		String markupTagArgument = "(?>[ \\t]*\\w+(?>[ \\t]*(=)[ \\t]*(" + attributeValue  + "))?)"; //$NON-NLS-1$ //$NON-NLS-2$
+		SNIPPET_ATTRIBUTE_PATTERN = Pattern.compile(snippetAttribute);
+		SNIPPET_ATTRIBUTES_PATTERN = Pattern.compile(snippetAttribute + "*" + ws + "*(?<colon>:?)"); //$NON-NLS-1$ //$NON-NLS-2$
+		SNIPPET_MARKUP_TAG_ARGUMENT_PATTERN = Pattern.compile(markupTagArgument);
+		SNIPPET_MARKUP_TAG_PATTERN = Pattern.compile(markupTagNames + markupTagArgument + "*"); //$NON-NLS-1$
+	}
+
 	// Param tags list copied from IJavaDocTagConstants in legacy formatter for compatibility.
 	// There were the following comments:
 	// TODO (frederic) should have another name than 'param' for the following tags
@@ -110,7 +127,8 @@
 	private int formatCodeOpenTagEndIndex = -1;
 	private int lastFormatCodeClosingTagIndex = -1;
 	private ArrayList<Integer> commonAttributeAnnotations = new ArrayList<Integer>();
-	private DefaultCodeFormatter commentCodeFormatter;
+	private DefaultCodeFormatter preTagCodeFormatter;
+	private DefaultCodeFormatter snippetCodeFormatter;
 
 	public CommentsPreparator(TokenManager tm, DefaultCodeFormatterOptions options, String sourceLevel) {
 		this.tm = tm;
@@ -204,6 +222,7 @@
 		} else {
 			commentToken.setInternalStructure(structure);
 			handleCompilerTags(commentToken, commentIndex);
+			handleSnippetMarkupTags(commentToken);
 			preserveWhitespace(commentToken, commentIndex);
 			this.lastLineComment = commentToken;
 			this.lastLineCommentPosition = positionInLine;
@@ -312,6 +331,25 @@
 		}
 	}
 
+	private void handleSnippetMarkupTags(Token commentToken) {
+		String commentText = this.tm.toString(commentToken);
+
+		Matcher m = SNIPPET_MARKUP_TAG_PATTERN.matcher(commentText);
+		while (m.find()) {
+			Matcher m2 = SNIPPET_MARKUP_TAG_ARGUMENT_PATTERN.matcher(m.group());
+			if (!m2.find())
+				continue;
+			this.commentStructure = commentToken.getInternalStructure();
+			this.ctm = new TokenManager(this.commentStructure, this.tm);
+			if (commentToken.tokenType != TokenNameCOMMENT_LINE)
+				continue;
+			do {
+				handleFoundAssignment(m2, 1, commentToken.originalStart + m.start());
+				handleFoundStringLiteral(m2, 2, commentToken.originalStart + m.start());
+			} while (m2.find());
+		}
+	}
+
 	private List<Token> findStringLiteralsInLine(int lastTokenIndex) {
 		List<Token> stringLiterals = new ArrayList<>();
 		Token previous = this.tm.get(lastTokenIndex);
@@ -583,30 +621,32 @@
 	@Override
 	public boolean visit(TagElement node) {
 		String tagName = node.getTagName();
-		if (tagName == null || tagName.length() <= 1)
+		if (tagName == null || tagName.length() <= 1 || !node.tagProperties().isEmpty() /*snippet markup tags*/)
 			return true;
 
 		int startIndex = tokenStartingAt(node.getStartPosition());
-		int nodeEnd = node.getStartPosition() + node.getLength() - 1;
-		while (ScannerHelper.isWhitespace(this.ctm.charAt(nodeEnd)))
-			nodeEnd--;
-		int endIndex = tokenEndingAt(nodeEnd);
-
 		this.ctm.get(startIndex + 1).setWrapPolicy(WrapPolicy.DISABLE_WRAP);
 
 		if (node.getParent() instanceof Javadoc) {
 			assert this.ctm.toString(startIndex).startsWith(tagName);
 
-			Token startTokeen = this.ctm.get(startIndex);
-			if (startIndex > 1)
-				startTokeen.breakBefore();
+			if (startIndex > 1) {
+				this.ctm.get(startIndex).breakBefore();
+			}
 
 			handleHtml(node);
 			this.ctm.get(tokenStartingAt(node.getStartPosition())).setToEscape(false);
-		}
 
-		if (node.isNested() && IMMUTABLE_TAGS.contains(tagName) && startIndex < endIndex) {
-			disableFormatting(startIndex, endIndex, false);
+		} else if (node.isNested() && (IMMUTABLE_TAGS.contains(tagName) || TagElement.TAG_SNIPPET.equals(tagName))) {
+			int endPos = node.getStartPosition() + node.getLength() - 1;
+			int endIndex = this.ctm.findIndex(endPos, -1, false);
+			if (this.ctm.get(endIndex).originalEnd > endPos)
+				endIndex = tokenEndingAt(endPos);
+			if (TagElement.TAG_SNIPPET.equals(tagName)) {
+				handleSnippet(node, startIndex, endIndex);
+			} else {
+				disableFormatting(startIndex, endIndex, false);
+			}
 		}
 		return true;
 	}
@@ -836,16 +876,42 @@
 	private void handleStringLiterals(String text, int textStartPosition) {
 		Matcher matcher = STRING_LITERAL_PATTERN.matcher(text);
 		while (matcher.find()) {
-			int startPosition = textStartPosition + matcher.start();
-			int startIndex = this.ctm.findIndex(startPosition, -1, false);
-			int endPosition = textStartPosition + matcher.end() - 1;
-			int endIndex = this.ctm.findIndex(endPosition, -1, false);
-			if (startIndex != endIndex) {
-				startIndex = tokenStartingAt(startPosition);
-				endIndex = tokenEndingAt(endPosition);
-				disableFormatting(startIndex, endIndex, false);
-			}
+			handleFoundStringLiteral(matcher, 0, textStartPosition);
+		}
+	}
+
+	private void handleFoundStringLiteral(Matcher matcher, int group, int textStartPosition) {
+		if (matcher.start(group) == matcher.end(group))
+			return;
+		int startPosition = textStartPosition + matcher.start(group);
+		int startIndex = this.ctm.findIndex(startPosition, -1, false);
+		int endPosition = textStartPosition + matcher.end(group) - 1;
+		int endIndex = this.ctm.findIndex(endPosition, -1, false);
+		if (startIndex != endIndex) {
+			startIndex = tokenStartingAt(startPosition);
+			endIndex = tokenEndingAt(endPosition);
+			disableFormatting(startIndex, endIndex, false);
+		}
+		if (this.ctm.get(0).tokenType != TokenNameCOMMENT_LINE)
 			noSubstituteWrapping(startPosition, endPosition);
+	}
+
+	private void handleFoundAssignment(Matcher matcher, int group, int textStartPosition) {
+		if (matcher.start(group) == matcher.end(group))
+			return;
+		int equalsPosition = textStartPosition + matcher.start(group);
+		int equalsIndex = tokenStartingAt(equalsPosition);
+		equalsIndex = tokenEndingAt(equalsPosition);
+		assert this.ctm.toString(equalsIndex).equals("="); //$NON-NLS-1$
+		if (this.options.insert_space_before_assignment_operator) {
+			this.ctm.get(equalsIndex).spaceBefore();
+		} else {
+			this.ctm.get(equalsIndex).clearSpaceBefore();
+		}
+		if (this.options.insert_space_after_assignment_operator) {
+			this.ctm.get(equalsIndex + 1).spaceBefore();
+		} else {
+			this.ctm.get(equalsIndex + 1).clearSpaceBefore();
 		}
 	}
 
@@ -938,7 +1004,7 @@
 						}
 						closingBracePos--;
 
-						if (formatCode(tokenEndingAt(nameEndPos), tokenStartingAt(closingBracePos))) {
+						if (formatCode(tokenEndingAt(nameEndPos), tokenStartingAt(closingBracePos), false)) {
 							int closingIndex = tokenStartingAt(closingBracePos);
 							Token t = this.ctm.get(closingIndex);
 							this.commentStructure.set(closingIndex,
@@ -961,7 +1027,7 @@
 					}
 				}
 			} else if (this.formatCodeOpenTagEndIndex >= startIndex - 1
-					|| !formatCode(this.formatCodeOpenTagEndIndex, startIndex)) {
+					|| !formatCode(this.formatCodeOpenTagEndIndex, startIndex, false)) {
 				disableFormattingExclusively(this.formatCodeOpenTagEndIndex, startIndex);
 			}
 			this.formatCodeOpenTagEndIndex = -1;
@@ -969,6 +1035,39 @@
 		}
 	}
 
+	private void handleSnippet(TagElement node, int startIndex, int endIndex) {
+		Token startToken = this.ctm.get(startIndex), endToken = this.ctm.get(endIndex);
+		startToken.breakBefore();
+		endToken.breakAfter();
+
+		String lang = null;
+		boolean isInline = false;
+		int snippetTextStartPos = startToken.originalEnd + 1;
+		String snippetText = this.ctm.getSource().substring(snippetTextStartPos, endToken.originalEnd + 1);
+		Matcher m = SNIPPET_ATTRIBUTES_PATTERN.matcher(snippetText);
+		if (m.find() && m.start() == 0) {
+			isInline = !m.group("colon").isEmpty(); //$NON-NLS-1$
+			Matcher m2 = SNIPPET_ATTRIBUTE_PATTERN.matcher(snippetText);
+			while (m2.find()) {
+				handleFoundAssignment(m2, 2, snippetTextStartPos);
+				handleFoundStringLiteral(m2, 3, snippetTextStartPos);
+				if (m2.group(1).equals("lang")) //$NON-NLS-1$
+					lang = m2.group(3);
+			}
+		}
+
+		List<ASTNode> fragments = node.fragments();
+		if (isInline && !fragments.isEmpty()) {
+			int openingIndex = this.ctm.firstIndexBefore(fragments.get(0), -1);
+			int closingIndex = tokenStartingAt(endToken.originalEnd);
+			this.ctm.get(closingIndex).breakBefore();
+			boolean formatted = (lang == null || lang.matches("['\"]?java['\"]?")) //$NON-NLS-1$
+					&& formatCode(openingIndex, closingIndex, true);
+			if (!formatted)
+				disableFormattingExclusively(openingIndex, closingIndex);
+		}
+	}
+
 	private void fixJavadocTagAlign(Token baseToken, int fixFirstIndex) {
 		for (int i = fixFirstIndex; i < this.ctm.size() - 1; i++) {
 			Token token = this.ctm.get(i);
@@ -1213,7 +1312,7 @@
 		}
 	}
 
-	private boolean formatCode(int openingIndex, int closingIndex) {
+	private boolean formatCode(int openingIndex, int closingIndex, boolean snippetTag) {
 		int codeStartPosition = this.ctm.get(openingIndex).originalEnd + 1;
 		int codeEndPosition = this.ctm.get(closingIndex).originalStart - 1;
 		StringBuilder codeBuilder = new StringBuilder(codeEndPosition - codeStartPosition + 1);
@@ -1221,7 +1320,8 @@
 		// ^ index: original source position (minus startPosition), value: position in code string
 		getCodeToFormat(codeStartPosition, codeEndPosition, codeBuilder, positionMapping);
 
-		List<Token> formattedTokens = getCommentCodeFormatter().prepareFormattedCode(codeBuilder.toString());
+		DefaultCodeFormatter formatter = snippetTag ? getSnippetCodeFormatter() : getPreTagCodeFormatter();
+		List<Token> formattedTokens = formatter.prepareFormattedCode(codeBuilder.toString());
 
 		if (formattedTokens == null) {
 			return false;
@@ -1248,18 +1348,35 @@
 		return true;
 	}
 
-	private DefaultCodeFormatter getCommentCodeFormatter() {
-		if (this.commentCodeFormatter == null) {
+	private DefaultCodeFormatter getPreTagCodeFormatter() {
+		if (this.preTagCodeFormatter == null) {
 			Map<String, String> options2 = this.options.getMap();
 			options2.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_LINE_LENGTH,
 					String.valueOf(this.options.comment_line_length - this.commentIndent
 							- COMMENT_LINE_SEPARATOR_LENGTH));
+
 			options2.put(DefaultCodeFormatterConstants.FORMATTER_LINE_SPLIT,
 					String.valueOf(this.options.page_width - this.commentIndent - COMMENT_LINE_SEPARATOR_LENGTH));
 			options2.put(CompilerOptions.OPTION_Source, this.sourceLevel);
-			this.commentCodeFormatter = new DefaultCodeFormatter(options2);
+			this.preTagCodeFormatter = new DefaultCodeFormatter(options2);
 		}
-		return this.commentCodeFormatter;
+		return this.preTagCodeFormatter;
+	}
+
+	private DefaultCodeFormatter getSnippetCodeFormatter() {
+		if (this.snippetCodeFormatter == null) {
+			Map<String, String> options2 = this.options.getMap();
+			options2.put(
+					DefaultCodeFormatterConstants.FORMATTER_COMMENT_PRESERVE_WHITE_SPACE_BETWEEN_CODE_AND_LINE_COMMENT,
+					DefaultCodeFormatterConstants.TRUE);
+			options2.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_LINE_LENGTH, String.valueOf(10000));
+
+			options2.put(DefaultCodeFormatterConstants.FORMATTER_LINE_SPLIT,
+					String.valueOf(this.options.page_width - this.commentIndent - COMMENT_LINE_SEPARATOR_LENGTH));
+			options2.put(CompilerOptions.OPTION_Source, this.sourceLevel);
+			this.snippetCodeFormatter = new DefaultCodeFormatter(options2);
+		}
+		return this.snippetCodeFormatter;
 	}
 
 	private void getCodeToFormat(int startPos, int endPos, StringBuilder sb, int[] posMapping) {
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 cc13438..2edf8cc 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
@@ -13,6 +13,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.core;
 
+import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IPath;
 
 /**
@@ -507,4 +508,24 @@
 		}
 		return false;
 	}
+
+	/**
+	 * Answer the path for external annotations (for null analysis) associated with this classpath entry.
+	 * Five shapes of paths are supported:
+	 * <ol>
+	 * <li>relative, variable (VAR/relpath): resolve classpath variable VAR and append relpath</li>
+	 * <li>relative, container (CON/relpath): locate relpath among the elements within container CON</li>
+	 * <li>relative, project (relpath): interpret relpath as a relative path within the given project</li>
+	 * <li>absolute, workspace (/Proj/relpath): an absolute path in the workspace</li>
+	 * <li>absolute, filesystem (/abspath): an absolute path in the filesystem</li>
+	 * </ol>
+	 * In case of ambiguity, workspace lookup has higher priority than filesystem lookup
+	 * (in fact filesystem paths are never validated).
+	 *
+	 * @param project project whose classpath we are analysing
+	 * @param resolve if true, any workspace-relative paths will be resolved to filesystem paths.
+	 * @return a path (in the workspace or filesystem-absolute) or null
+	 * @since 3.30
+	 */
+	IPath getExternalAnnotationPath(IProject project, boolean resolve);
 }
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 a9bdd4e..764c7f9 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
@@ -41,7 +41,6 @@
 import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider;
 import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
 import org.eclipse.jdt.internal.compiler.lookup.SignatureWrapper;
-import org.eclipse.jdt.internal.core.ClasspathEntry;
 import org.eclipse.jdt.internal.core.util.KeyToSignature;
 
 /**
@@ -207,7 +206,7 @@
 
 		IPackageFragmentRoot packageRoot = (IPackageFragmentRoot) targetType.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 		IClasspathEntry entry = packageRoot.getResolvedClasspathEntry();
-		IPath annotationPath = ClasspathEntry.getExternalAnnotationPath(entry, project.getProject(), false);
+		IPath annotationPath = entry.getExternalAnnotationPath(project.getProject(), false);
 
 		if (annotationPath == null)
 			return null;
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 bc5bc7e..0b4d6d1 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
@@ -282,7 +282,7 @@
 			entryName = new String(Util.concat(
 					BinaryTypeFactory.fieldDescriptorToBinaryName(descriptor.fieldDescriptor), SuffixConstants.SUFFIX_CLASS));
 			IProject project = javaProject.getProject();
-			IPath externalAnnotationPath = ClasspathEntry.getExternalAnnotationPath(entry, project, false); // unresolved for use in ExternalAnnotationTracker
+			IPath externalAnnotationPath = entry.getExternalAnnotationPath(project, false); // unresolved for use in ExternalAnnotationTracker
 			if (externalAnnotationPath != null) {
 				result = setupExternalAnnotationProvider(project, externalAnnotationPath, result,
 						entryName.substring(0, entryName.length() - SuffixConstants.SUFFIX_CLASS.length));
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 2bc5c30..8d4cdb8 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
@@ -1312,26 +1312,9 @@
 		return this.sourceAttachmentRootPath;
 	}
 
-	/**
-	 * Internal API: answer the path for external annotations (for null analysis) associated with
-	 * the given classpath entry.
-	 * Four shapes of paths are supported:
-	 * <ol>
-	 * <li>relative, variable (VAR/relpath): resolve classpath variable VAR and append relpath</li>
-	 * <li>relative, project (relpath): interpret relpath as a relative path within the given project</li>
-	 * <li>absolute, workspace (/Proj/relpath): an absolute path in the workspace</li>
-	 * <li>absolute, filesystem (/abspath): an absolute path in the filesystem</li>
-	 * </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.
-	 * @return a path (in the workspace or filesystem-absolute) or null
-	 */
-	public static IPath getExternalAnnotationPath(IClasspathEntry entry, IProject project, boolean resolve) {
-		String rawAnnotationPath = getRawExternalAnnotationPath(entry);
+	@Override
+	public IPath getExternalAnnotationPath(IProject project, boolean resolve) {
+		String rawAnnotationPath = getRawExternalAnnotationPath(this);
 		if (rawAnnotationPath != null) {
 			IPath annotationPath = new Path(rawAnnotationPath);
 			if (annotationPath.isAbsolute()) {
@@ -1358,6 +1341,13 @@
 						IResource member = project.findMember(annotationPath);
 						if (member != null)
 							return member.getLocation();
+					}
+					// try container relative:
+					IPath containerMemberPath = findAnnotationPathViaContainer(project, rawAnnotationPath, resolve);
+					if (containerMemberPath != null)
+						return containerMemberPath;
+
+					if (resolve) {
 						invalidExternalAnnotationPath(project);
 					} else {
 						return new Path(project.getName()).append(annotationPath).makeAbsolute();
@@ -1368,6 +1358,62 @@
 		return null;
 	}
 
+	public static IPath findAnnotationPathViaContainer(IProject project, String rawAnnotationPath, boolean resolve) {
+		if (rawAnnotationPath.indexOf('/') == -1)
+			return null;
+		IJavaProject jProject = JavaCore.create(project);
+		try {
+			IClasspathContainer container = null;
+			String relative = null;
+			// scan containers:
+			for (IClasspathEntry rawEntry : jProject.getRawClasspath()) {
+				if (rawEntry.getEntryKind() == IClasspathEntry.CPE_CONTAINER) {
+					String containerName = rawEntry.getPath().toString()+'/';
+					if (rawAnnotationPath.startsWith(containerName)) {
+						// this is the container referenced in the annotation path
+						container = JavaCore.getClasspathContainer(rawEntry.getPath(), jProject);
+						relative = rawAnnotationPath.substring(containerName.length());
+						break;
+					}
+				}
+			}
+			if (container != null) {
+				// now search container entries for the one matching the tail 'relative':
+				for (IClasspathEntry containerEntry : container.getClasspathEntries()) {
+					IPath path = containerEntry.getPath();
+					String entryName = path.lastSegment();
+					if (entryName.startsWith(relative)) {
+						// found a prefix match, check if the prefix ends at some kind of "boundary":
+						int endPos = relative.length();
+						if (endPos >= entryName.length() || !Character.isLetterOrDigit(entryName.charAt(endPos))) {
+							if (path.isAbsolute() && path.segmentCount() == 1) {
+								// resolved entry could point to a workspace project
+								IWorkspaceRoot wsRoot = project.getWorkspace().getRoot();
+								IProject tgtProject = wsRoot.getProject(path.toString());
+								IJavaProject tgtJProject = JavaCore.create(tgtProject);
+								if (tgtJProject.exists()) {
+									if (resolve) {
+										// resolve the project's output location:
+										return wsRoot.getLocation().append(tgtJProject.getOutputLocation());
+									}
+									// in non-resolving scenarii return the unresolved source folder path
+									for (IClasspathEntry classpathEntry : tgtJProject.getRawClasspath()) {
+										if (classpathEntry.getEntryKind() == CPE_SOURCE && classpathEntry.getOutputLocation() == null)
+											return classpathEntry.getPath();
+									}
+								}
+							}
+							return path; // assumed to be a file system path
+						}
+					}
+				}
+			}
+		} catch (JavaModelException e) {
+			Util.log(e);
+		}
+		return null;
+	}
+
 	/**
 	 * Answer the raw external annotation path as specified in .classpath, or null.
 	 * @param entry where to look
@@ -1405,6 +1451,9 @@
 			{
 				return null;
 			}
+			if (findAnnotationPathViaContainer(project, annotationPath.toString(), false) != null) {
+				return null;
+			}
 		}
 		return new JavaModelStatus(IJavaModelStatusConstants.CP_INVALID_EXTERNAL_ANNOTATION_PATH,
 				javaProject,
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 c8bada7..eb74445 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
@@ -223,7 +223,7 @@
 	private String getExternalAnnotationPath(IClasspathEntry entry) {
 		if (entry == null)
 			return null;
-		IPath path = ClasspathEntry.getExternalAnnotationPath(entry, this.project.getProject(), true);
+		IPath path = entry.getExternalAnnotationPath(this.project.getProject(), true);
 		if (path == null)
 			return null;
 		return path.toOSString();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildNotifier.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildNotifier.java
index b0c7db7..65ca983 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildNotifier.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BuildNotifier.java
@@ -13,6 +13,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.builder;
 
+import java.util.function.BooleanSupplier;
+
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
 
@@ -40,6 +42,14 @@
 public static int NewWarningCount = 0;
 public static int FixedWarningCount = 0;
 
+private static final int millisecondsBeforeCancelAutoBuild = Integer
+		.getInteger("org.eclipse.jdt.MillisecondsBeforeCancelAutoBuild", 1000); //$NON-NLS-1$
+private static final int millisecondsBeforeInterruptAutoBuild = Integer
+		.getInteger("org.eclipse.jdt.MillisecondsBeforeInterruptAutoBuild", 3000); //$NON-NLS-1$
+private BooleanSupplier interruptSupplier;
+private long startTimeNanos;
+private int buildKind;
+
 public static void resetProblemCounters() {
 	NewErrorCount = 0;
 	FixedErrorCount = 0;
@@ -47,8 +57,10 @@
 	FixedWarningCount = 0;
 }
 
-public BuildNotifier(IProgressMonitor monitor, IProject project) {
+public BuildNotifier(IProgressMonitor monitor, int buildKind, BooleanSupplier interruptSupplier) {
 	this.monitor = monitor;
+	this.buildKind = buildKind;
+	this.interruptSupplier = interruptSupplier;
 	this.cancelling = false;
 	this.newErrorCount = NewErrorCount;
 	this.fixedErrorCount = FixedErrorCount;
@@ -56,6 +68,7 @@
 	this.fixedWarningCount = FixedWarningCount;
 	this.workDone = 0;
 	this.totalWork = 1000000;
+	this.startTimeNanos = System.nanoTime();
 }
 
 /**
@@ -76,8 +89,32 @@
  * Check whether the build has been canceled.
  */
 public void checkCancel() {
-	if (this.monitor != null && this.monitor.isCanceled())
-		throw new OperationCanceledException();
+	if (this.monitor != null && this.monitor.isCanceled()) {
+		// User requested cancel.
+		if (this.buildKind == IncrementalProjectBuilder.AUTO_BUILD) {
+			// Since jdt can not resume the incremental build we follow that request only after a period of grace
+			// to increase the chance the cancel happens between project builds and not during a project build
+			if (getBuildDurationInMs() > millisecondsBeforeCancelAutoBuild) {
+				throw new OperationCanceledException();
+			}
+		} else {
+			// non autobuild will be canceled immediately.
+			throw new OperationCanceledException();
+		}
+	}
+	if (this.interruptSupplier.getAsBoolean()) {
+		// Automatic request to interrupt build due to a conflicting user action.
+		// Since jdt can not resume the incremental build we follow that request only after a period of grace:
+		if (getBuildDurationInMs() > millisecondsBeforeInterruptAutoBuild) {
+			// This is a trade off between UI responsiveness and additional work to restart autobuild.
+			// We cancel autobuild to avoid possible UI freeze where the user can not manually cancel.
+			throw new OperationCanceledException();
+		}
+	}
+}
+
+private long getBuildDurationInMs() {
+	return ((System.nanoTime() - this.startTimeNanos) / 1_000_000);
 }
 
 /**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
index 649f978..c9b6319 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
@@ -176,7 +176,8 @@
 	if (DEBUG)
 		System.out.println("\nJavaBuilder: Starting build of " + this.currentProject.getName() //$NON-NLS-1$
 			+ " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
-	this.notifier = new BuildNotifier(monitor, this.currentProject);
+	this.notifier = new BuildNotifier(monitor,kind,
+			kind == IncrementalProjectBuilder.AUTO_BUILD ? this::isInterrupted : ()->false);
 	this.notifier.begin();
 	boolean ok = false;
 	try {
@@ -321,7 +322,7 @@
 	if (DEBUG)
 		System.out.println("\nJavaBuilder: Cleaning " + this.currentProject.getName() //$NON-NLS-1$
 			+ " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
-	this.notifier = new BuildNotifier(monitor, this.currentProject);
+	this.notifier = new BuildNotifier(monitor,CLEAN_BUILD, ()->false);
 	this.notifier.begin();
 	try {
 		this.notifier.checkCancel();
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 03a261d..2540c33 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
@@ -141,7 +141,7 @@
 		ClasspathEntry entry = (ClasspathEntry) classpathEntries[i];
 		IPath path = entry.getPath();
 		Object target = JavaModel.getTarget(path, true);
-		IPath externalAnnotationPath = ClasspathEntry.getExternalAnnotationPath(entry, javaProject.getProject(), true);
+		IPath externalAnnotationPath = entry.getExternalAnnotationPath(javaProject.getProject(), true);
 		if (target == null) continue nextEntry;
 		boolean isOnModulePath = isOnModulePath(entry);
 
@@ -208,7 +208,7 @@
 							continue nextPrereqEntry;
 						IPath srcExtAnnotPath = (externalAnnotationPath != null)
 							? externalAnnotationPath
-							: ClasspathEntry.getExternalAnnotationPath(prereqEntry, javaProject.getProject(), true);
+							: prereqEntry.getExternalAnnotationPath(javaProject.getProject(), true);
 						Object prereqTarget = JavaModel.getTarget(prereqEntry.getPath(), true);
 						if (!(prereqTarget instanceof IContainer)) continue nextPrereqEntry;
 						if (srcExtAnnotPath == null) {
@@ -219,7 +219,7 @@
 								if (other.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
 									IPath otherOutput = other.getOutputLocation();
 									if ((outputLoc == null) ? otherOutput == null : outputLoc.equals(otherOutput)) {
-										srcExtAnnotPath = ClasspathEntry.getExternalAnnotationPath(other, javaProject.getProject(),  true);
+										srcExtAnnotPath = other.getExternalAnnotationPath(javaProject.getProject(),  true);
 										if (srcExtAnnotPath != null)
 											break; // TODO: merging of several .eea?
 									}
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 06d34b8..286edf7 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
@@ -265,10 +265,9 @@
 			String compliance = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
 			cp = (root instanceof JrtPackageFragmentRoot) ?
 					ClasspathLocation.forJrtSystem(path.toOSString(), rawClasspathEntry.getAccessRuleSet(),
-							ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, project.getProject(), true), compliance) :
+							rawClasspathEntry.getExternalAnnotationPath(project.getProject(), true), compliance) :
 									ClasspathLocation.forLibrary(manager.getZipFile(path), rawClasspathEntry.getAccessRuleSet(),
-												ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry,
-														((IJavaProject) root.getParent()).getProject(), true),
+												rawClasspathEntry.getExternalAnnotationPath(((IJavaProject) root.getParent()).getProject(), true),
 												rawClasspathEntry.isModular(), compliance) ;
 		} else {
 			Object target = JavaModel.getTarget(path, true);
@@ -278,7 +277,7 @@
 				} else {
 					ClasspathEntry rawClasspathEntry = (ClasspathEntry) root.getRawClasspathEntry();
 					cp = ClasspathLocation.forBinaryFolder((IContainer) target, false, rawClasspathEntry.getAccessRuleSet(),
-														ClasspathEntry.getExternalAnnotationPath(rawClasspathEntry, ((IJavaProject)root.getParent()).getProject(), true),
+														rawClasspathEntry.getExternalAnnotationPath(((IJavaProject)root.getParent()).getProject(), true),
 														rawClasspathEntry.isModular());
 				}
 			}