update jdt.core to I20211111-0910
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTests17.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTests17.java
index 4e28565..95e3ea4 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTests17.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/NullAnnotationTests17.java
@@ -366,13 +366,12 @@
 				  "	}\n" +
 				  "}\n"
 			};
-		// demonstrate that null case cannot leak into a type pattern:
 		runner.expectedCompilerLog =
 				"----------\n" +
 				"1. ERROR in X.java (at line 5)\n" +
 				"	case null, Integer i -> consumeInt(i);\n" +
-				"	           ^^^^^^^^^\n" +
-				"Illegal fall-through to a pattern\n" +
+				"	                                   ^\n" +
+				"Null type mismatch: required \'@NonNull Integer\' but the provided value is inferred as @Nullable\n" +
 				"----------\n";
 		runner.runNegativeTest();
 	}
@@ -492,4 +491,54 @@
 		runner.expectedOutputString = "null";
 		runner.runConformTest();
 	}
+
+	public void test_defaultDoesNotApplyToNull_field2() {
+		Runner runner = getDefaultRunner();
+		runner.customOptions.put(CompilerOptions.OPTION_SyntacticNullAnalysisForFields, CompilerOptions.ENABLED);
+		runner.testFiles = new String[] {
+				"X.java",
+				  "import org.eclipse.jdt.annotation.*;\n" +
+				  "public class X {\n" +
+				  "	@Nullable Object o;\n" +
+				  "	void foo(X x) {\n" +
+				  "		switch (x.o) {\n" +
+				  "			case Integer i -> consumeInt(i);\n" +
+				  "			default -> System.out.println(x.o.toString());\n" +
+				  "			case null -> System.out.print(\"null\");\n" +
+				  "		};\n" +
+				  "	}\n" +
+				  "	void consumeInt(@NonNull Integer i) {\n" +
+				  "	}\n" +
+				  "	public static void main(String... args) {\n" +
+				  "		new X().foo(new X());\n" +
+				  "	}\n" +
+				  "}\n"
+			};
+		runner.expectedCompilerLog = "";
+		runner.expectedOutputString = "null";
+		runner.runConformTest();
+	}
+
+	public void testBug576329() {
+		Runner runner = getDefaultRunner();
+		runner.customOptions.put(CompilerOptions.OPTION_SyntacticNullAnalysisForFields, CompilerOptions.ENABLED);
+		runner.testFiles = new String[] {
+				"Main.java",
+				"public class Main {\n" +
+				"    int length;\n" +
+				"    public String switchOnArray(Object argv[]) {\n" +
+				"        return switch(argv.length) {\n" +
+				"        case 0 -> \"0\";\n" +
+				"        default -> \"x\";\n" +
+				"        };\n" +
+				"    }\n" +
+				"	public static void main(String... args) {\n" +
+				"		System.out.print(new Main().switchOnArray(args));\n" +
+				"	}\n" +
+				"}\n"
+			};
+		runner.expectedCompilerLog = "";
+		runner.expectedOutputString = "0";
+		runner.runConformTest();
+	}
 }
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java
index 9bfd9e1..eb15476 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/SwitchExpressionsYieldTest.java
@@ -6115,4 +6115,25 @@
 				},
 				"Success");
 	}
+	public void testBug576861_001() {
+		this.runConformTest(
+				new String[] {
+				"X.java",
+				"import java.util.Comparator;\n"+
+				"\n"+
+				"public class X {\n"+
+				" public static void foo(Comparator<? super Long> comparator) {}\n"+
+				"\n"+
+				" public static void main(String[] args) {\n"+
+				"   int someSwitchCondition = 10;\n"+
+				"   X.foo(switch (someSwitchCondition) {\n"+
+				"   case 10 -> Comparator.comparingLong(Long::longValue);\n"+
+				"   default -> throw new IllegalArgumentException(\"Unsupported\");\n"+
+				" });\n"+
+				"   System.out.println(\"hello\");\n"+
+				" }\n"+
+				"}"
+				},
+				"hello");
+	}
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests16_2.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests16_2.java
index 30272c2..bc781a9 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests16_2.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests16_2.java
@@ -393,4 +393,44 @@
 				requestor.getResults());
 
 	}
+
+	public void bug575599() throws Exception {
+		this.workingCopies = new ICompilationUnit[1];
+		this.workingCopies[0] = getWorkingCopy(
+				"/Completion/src/Bug_575599.java",
+				"class Bug_575599 {\n" +
+				"	void sample(CharSequence param1, CharSequence param2) {\n" +
+				"		if (param1 instanceof String s1 && param2 instanceof String s2) {\n" +
+				"			// s1.| completion doesn't work here: `No Default Proposals`\n" +
+				"			// ; <- adding `;` here makes completion above work (similar to bug 574267)\n" +
+				"			s1.toUpperCase();\n" +
+				"			// s1.| completion works here, showing expected options\n" +
+				"			if (s1.strip().equals(\"FOO\")) {\n" +
+				"				s1.\n" +
+				"			}\n" +
+				"		}\n" +
+				"	}\n" +
+				"}");
+		this.workingCopies[0].getJavaProject(); // assuming single project for all working copies
+		CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+		requestor.allowAllRequiredProposals();
+		String str = this.workingCopies[0].getSource();
+		String completeBehind = "s1.";
+		int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length();
+		this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+		assertResults("clone[METHOD_REF]{clone(), Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 60}\n" +
+				"codePointAt[METHOD_REF]{codePointAt(), Ljava.lang.String;, (I)I, codePointAt, (index), 60}\n" +
+				"equals[METHOD_REF]{equals(), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 60}\n" +
+				"finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 60}\n" +
+				"getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<+Ljava.lang.Object;>;, getClass, null, 60}\n" +
+				"hashCode[METHOD_REF]{hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 60}\n" +
+				"length[METHOD_REF]{length(), Ljava.lang.String;, ()I, length, null, 60}\n" +
+				"notify[METHOD_REF]{notify(), Ljava.lang.Object;, ()V, notify, null, 60}\n" +
+				"notifyAll[METHOD_REF]{notifyAll(), Ljava.lang.Object;, ()V, notifyAll, null, 60}\n" +
+				"toString[METHOD_REF]{toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 60}\n" +
+				"wait[METHOD_REF]{wait(), Ljava.lang.Object;, ()V, wait, null, 60}\n" +
+				"wait[METHOD_REF]{wait(), Ljava.lang.Object;, (J)V, wait, (millis), 60}\n" +
+				"wait[METHOD_REF]{wait(), Ljava.lang.Object;, (JI)V, wait, (millis, nanos), 60}",
+				requestor.getResults());
+	}
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
index a3c593d..0f42fbe 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java
@@ -6185,4 +6185,51 @@
 			+ "[LAMBDA_EXPRESSION]{->, Ljava.util.function.Consumer<Ljava.lang.Integer;>;, (Ljava.lang.Integer;)V, accept, (t), 89}",
 			result);
 }
+public void testBug576068() throws JavaModelException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy(
+			"Completion/src/Bug576068.java",
+			"public class Bug576068 {\n" +
+			"\n" +
+			"	// Type a new member here and content assist won't find anything.\n" +
+			"\n" +
+			"	public void methodA(){\n" +
+			"		switch( 1 ){\n" +
+			"			case 0:\n" +
+			"		}\n" +
+			"	}\n" +
+			"	public void methodB(){\n" +
+			"		Runnable r = ()->{};\n" +
+			"	}\n" +
+			"}");
+	CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true);
+	requestor.allowAllRequiredProposals();
+	String str = this.workingCopies[0].getSource();
+	String completeBefore = "// Type";
+	int cursorLocation = str.indexOf(completeBefore);
+	this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner);
+	String result = requestor.getResults();
+	assertResults("[POTENTIAL_METHOD_DECLARATION]{, LBug576068;, ()V, , null, 39}\n" +
+			"abstract[KEYWORD]{abstract, null, null, abstract, null, 49}\n" +
+			"class[KEYWORD]{class, null, null, class, null, 49}\n" +
+			"enum[KEYWORD]{enum, null, null, enum, null, 49}\n" +
+			"final[KEYWORD]{final, null, null, final, null, 49}\n" +
+			"interface[KEYWORD]{interface, null, null, interface, null, 49}\n" +
+			"native[KEYWORD]{native, null, null, native, null, 49}\n" +
+			"private[KEYWORD]{private, null, null, private, null, 49}\n" +
+			"protected[KEYWORD]{protected, null, null, protected, null, 49}\n" +
+			"public[KEYWORD]{public, null, null, public, null, 49}\n" +
+			"static[KEYWORD]{static, null, null, static, null, 49}\n" +
+			"strictfp[KEYWORD]{strictfp, null, null, strictfp, null, 49}\n" +
+			"synchronized[KEYWORD]{synchronized, null, null, synchronized, null, 49}\n" +
+			"transient[KEYWORD]{transient, null, null, transient, null, 49}\n" +
+			"volatile[KEYWORD]{volatile, null, null, volatile, null, 49}\n" +
+			"Bug576068[TYPE_REF]{Bug576068, , LBug576068;, null, null, 52}\n" +
+			"clone[METHOD_DECLARATION]{protected Object clone() throws CloneNotSupportedException, Ljava.lang.Object;, ()Ljava.lang.Object;, clone, null, 52}\n" +
+			"equals[METHOD_DECLARATION]{public boolean equals(Object obj), Ljava.lang.Object;, (Ljava.lang.Object;)Z, equals, (obj), 52}\n" +
+			"finalize[METHOD_DECLARATION]{protected void finalize() throws Throwable, Ljava.lang.Object;, ()V, finalize, null, 52}\n" +
+			"hashCode[METHOD_DECLARATION]{public int hashCode(), Ljava.lang.Object;, ()I, hashCode, null, 52}\n" +
+			"toString[METHOD_DECLARATION]{public String toString(), Ljava.lang.Object;, ()Ljava.lang.String;, toString, null, 52}",
+			result);
+}
 }
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBug565512Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBug565512Test.java
new file mode 100644
index 0000000..6159c67
--- /dev/null
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaSearchBug565512Test.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2021 SSI Schaefer.
+ *
+ * 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:
+ *     SSI Schaefer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.tests.model;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.search.IJavaSearchConstants;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchEngine;
+
+import junit.framework.Test;
+
+public class JavaSearchBug565512Test extends AbstractJavaSearchTests {
+
+	public String getProjectName() {
+		return "JavaSearchBug565512lib";
+	}
+
+	public JavaSearchBug565512Test(String name) {
+		super(name);
+		this.endChar = "";
+	}
+
+	public static Test suite() {
+		return buildModelTestSuite(JavaSearchBug565512Test.class, BYTECODE_DECLARATION_ORDER);
+	}
+
+	@Override
+	public void setUpSuite() throws Exception {
+		super.setUpSuite();
+		JAVA_PROJECT = setUpJavaProject(getProjectName(), "9");
+		// Prevent ComparisonFailure on tearDown which checks that "Workspace options should be back to their default":
+		JavaCore.setOptions(JavaCore.getDefaultOptions());
+	}
+
+	@Override
+	public void tearDownSuite() throws Exception {
+		deleteProject(getProjectName());
+		super.tearDownSuite();
+		JAVA_PROJECT = null;
+	}
+
+	@Override
+	IJavaSearchScope getJavaSearchScope() {
+		IJavaElement[] elements = new IJavaProject[] { getJavaProject(getProjectName()) };
+		boolean excludeTestCode = false;
+		int includeMask = IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES
+				| IJavaSearchScope.REFERENCED_PROJECTS;
+		return SearchEngine.createJavaSearchScope(excludeTestCode, elements, includeMask);
+	}
+
+	/** Bug 576433 - inner Type not found in .class file. */
+	public void testBug576433() throws CoreException {
+		search("lib565512.Class565512.InnerClass.InnerClass2", IJavaSearchConstants.TYPE,
+				IJavaSearchConstants.DECLARATIONS, getJavaSearchScope());
+		assertSearchResults("lib/bug565512.jar lib565512.Class565512$InnerClass$InnerClass2 [No source]");
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java
index 4d71f79..aa2a00c 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/RunJavaSearchTests.java
@@ -76,6 +76,7 @@
 		allClasses.add(MatchingRegionsTest.class);
 		allClasses.add(JavaIndexTests.class);
 		allClasses.add(Bug376673Test.class);
+		allClasses.add(JavaSearchBug565512Test.class);
 		allClasses.add(JavaSearchNameEnvironmentTest.class);
 
 		// Reset forgotten subsets of tests
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeResolveTests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeResolveTests.java
index 12ca893..d9d9e55 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeResolveTests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/TypeResolveTests.java
@@ -17,8 +17,6 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import junit.framework.Test;
-
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.core.Flags;
@@ -46,6 +44,8 @@
 import org.eclipse.jdt.internal.core.NameLookup.Answer;
 import org.eclipse.jdt.internal.core.SourceType;
 
+import junit.framework.Test;
+
 @SuppressWarnings({"rawtypes", "unchecked"})
 public class TypeResolveTests extends ModifyingResourceTests {
 	ICompilationUnit cu;
@@ -1670,4 +1670,31 @@
 		deleteProject("P");
 	}
 }
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=576778
+public void testBug576778() throws Exception {
+	try {
+		createJava11Project("P", new String[] {"src"});
+		String source =    "package p;\n\n"
+				+"public class X {\n"
+				+ "  public static void main(String[] args) {\n"
+				+ "   var runnable = new Runnable() {\n"
+				+ "     public void run() {}\n"
+				+ "   };\n"
+				+ "   runnable.run();\n"
+				+ "  }\n"
+				+ "}\n";
+		createFolder("/P/src/p");
+		createFile("/P/src/p/X.java", source);
+		waitForAutoBuild();
+		ICompilationUnit unit = getCompilationUnit("/P/src/p/X.java");
+		String select = "runnable";
+		IJavaElement[] elements = unit.codeSelect(source.indexOf(select), select.length());
+		assertEquals("should not be empty", 1, elements.length);
+		ILocalVariable variable = (ILocalVariable) elements[0];
+		String signature= variable.getTypeSignature();
+		assertEquals("incorrect type", "Qvar;", signature);
+	} finally {
+		deleteProject("P");
+	}
+}
 }
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 a2480d0..16748f7 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
@@ -1275,8 +1275,8 @@
 	// collect all if statements with instanceof expressions that enclose the completion node
 	// https://bugs.eclipse.org/bugs/show_bug.cgi?id=304006
 	while (index >= 0) {
-		if (this.elementInfoStack[index] == IF && this.elementObjectInfoStack[index] instanceof InstanceOfExpression) {
-			InstanceOfExpression condition = (InstanceOfExpression)this.elementObjectInfoStack[index];
+		if (this.elementInfoStack[index] == IF && isInstanceOfGuard(this.elementObjectInfoStack[index])) {
+			Expression condition = (Expression)this.elementObjectInfoStack[index];
 			ifStatement =
 				new IfStatement(
 						condition,
@@ -1290,6 +1290,15 @@
 	this.enclosingNode = ifStatement;
 	return ifStatement;
 }
+private boolean isInstanceOfGuard(Object object) {
+	if (object instanceof InstanceOfExpression)
+		return true;
+	if (object instanceof AND_AND_Expression) {
+		AND_AND_Expression expression = (AND_AND_Expression) object;
+		return isInstanceOfGuard(expression.left) || isInstanceOfGuard(expression.right);
+	}
+	return false;
+}
 private void buildMoreGenericsCompletionContext(ASTNode node, boolean consumeTypeArguments) {
 	int kind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
 	if(kind != 0) {
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 d3eb821..c274b97 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
@@ -82,6 +82,11 @@
 					currentScope.problemReporter().IllegalFallThroughToPattern(e);
 			}
 			analyseConstantExpression(currentScope, flowContext, flowInfo, e);
+			if (nullPatternCount > 0 && e instanceof TypePattern) {
+				LocalVariableBinding binding = ((TypePattern) e).local.binding;
+				if (binding != null)
+					flowInfo.markNullStatus(binding, FlowInfo.POTENTIALLY_NULL);
+			}
 		}
 	}
 	return flowInfo;
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 806abac..f9801a9 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
@@ -53,6 +53,8 @@
 	private boolean isPolyExpression = false;
 	private TypeBinding[] originalValueResultExpressionTypes;
 	private TypeBinding[] finalValueResultExpressionTypes;
+	/* package */ Map<Expression, TypeBinding> originalTypeMap;
+
 
 	private int nullStatus = FlowInfo.UNKNOWN;
 	public List<Expression> resultExpressions;
@@ -473,6 +475,8 @@
 					}
 				}
 
+				if (this.originalTypeMap == null)
+					this.originalTypeMap = new HashMap<>();
 				resolve(upperScope);
 
 				if (this.statements == null || this.statements.length == 0) {
@@ -512,7 +516,8 @@
 					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) {
+					TypeBinding origType = this.originalTypeMap.get(resultExpr);
+					if (origType == null || origType.kind() == Binding.POLY_TYPE) {
 						this.finalValueResultExpressionTypes[i] = this.originalValueResultExpressionTypes[i] =
 							resultExpr.resolveTypeExpecting(upperScope, this.expectedType);
 					}
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 baf9700..f8c5377 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
@@ -186,14 +186,19 @@
 							this.scope.problemReporter().possibleFallThroughCase(this.scope.enclosingCase);
 						}
 						caseInits = caseInits.mergedWith(flowInfo.unconditionalInits());
-						if ((this.switchBits & LabeledRules) != 0 && this.expression instanceof NameReference) {
-							// default case does not apply to null => mark the variable being switched over as nonnull:
-							NameReference reference = (NameReference) this.expression;
-							if (reference.localVariableBinding() != null) {
-								caseInits.markAsDefinitelyNonNull(reference.localVariableBinding());
-							} else if (reference.lastFieldBinding() != null) {
+						if ((this.switchBits & LabeledRules) != 0 && this.expression.resolvedType instanceof ReferenceBinding) {
+							if (this.expression instanceof NameReference) {
+								// default case does not apply to null => mark the variable being switched over as nonnull:
+								NameReference reference = (NameReference) this.expression;
+								if (reference.localVariableBinding() != null) {
+									caseInits.markAsDefinitelyNonNull(reference.localVariableBinding());
+								} else if (reference.lastFieldBinding() != null) {
+									if (this.scope.compilerOptions().enableSyntacticNullAnalysisForFields)
+										switchContext.recordNullCheckedFieldReference(reference, 2); // survive this case statement and into the next
+								}
+							} else if (this.expression instanceof FieldReference) {
 								if (this.scope.compilerOptions().enableSyntacticNullAnalysisForFields)
-									switchContext.recordNullCheckedFieldReference(reference, 2); // survive this case statement and into the next
+									switchContext.recordNullCheckedFieldReference((FieldReference) this.expression, 2); // survive this case statement and into the next
 							}
 						}
 						complaintLevel = initialComplaintLevel; // reset complaint
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 f626942..e750fd5 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
@@ -245,7 +245,9 @@
 			this.scope.problemReporter().switchExpressionsYieldOutsideSwitchExpression(this);
 		}
 	}
-	this.expression.resolveType(this.scope);
+	TypeBinding type = this.expression.resolveType(this.scope);
+	if (this.switchExpression != null && type != null)
+		this.switchExpression.originalTypeMap.put(this.expression, type);
 }
 
 @Override
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 e314ed9..4e29559 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
@@ -116,7 +116,7 @@
 	private RecordComponentInfo[] recordComponents;
 
 private static String printTypeModifiers(int modifiers) {
-	java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream();
+	java.io.StringWriter out = new java.io.StringWriter();
 	java.io.PrintWriter print = new java.io.PrintWriter(out);
 
 	if ((modifiers & ClassFileConstants.AccPublic) != 0) print.print("public "); //$NON-NLS-1$
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 6cb5e97..14da02e 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
@@ -12078,6 +12078,7 @@
 	if (length == 0 && !containsComment(switchStatement.blockStart, switchStatement.sourceEnd)) {
 		switchStatement.bits |= ASTNode.UndocumentedEmptyBlock;
 	}
+	this.scanner.caseStartPosition = -1; // safety: at the end of a switch we definitely leave the scope of this value
 	return switchStatement;
 }
 protected void consumeStatementSwitch() {
@@ -12321,6 +12322,7 @@
 protected void consumeSwitchLabelCaseLhs() {
 	if (this.scanner.lookBack[1] == TerminalTokens.TokenNameCOLON) // kludge for yield :(
 		this.scanner.yieldColons = 1;
+	this.scanner.caseStartPosition = -1; // value has expired
 }
 protected void consumeCaseLabelExpr() {
 //	SwitchLabelExpr ::= SwitchLabelCaseLhs BeginCaseExpr '->'
@@ -17681,6 +17683,8 @@
 	if (this.lastPosistion < this.scanner.currentPosition) {
 		this.lastPosistion = this.scanner.currentPosition;
 		this.scanner.lastPosition = this.scanner.currentPosition;
+		if (this.scanner.startPosition <= this.scanner.caseStartPosition)
+			this.scanner.caseStartPosition = -1;
 	}
 
 	/* attempt to reset state in order to resume to parse loop */
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
index 9bda423..5bea2fd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/Scanner.java
@@ -18,6 +18,7 @@
 package org.eclipse.jdt.internal.compiler.parser;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -298,7 +299,7 @@
 	public boolean wasAcr = false;
 
 	public boolean fakeInModule = false;
-	int caseStartPosition = -1;
+	public int caseStartPosition = -1;
 	boolean inCondition = false;
 	/* package */ int yieldColons = -1;
 	boolean breakPreviewAllowed = false;
@@ -6303,13 +6304,10 @@
 // SH}
 			this.caseStartPosition < this.startPosition) {
 		// this.caseStartPosition > this.startPositionpossible on recovery - bother only about correct ones.
-		int nSz = scanner.startPosition - scanner.caseStartPosition;
 		// add fake token of TokenNameCOLON, call vanguard on this modified source
 		// TODO: Inefficient method due to redoing of the same source, investigate alternate
 		// Can we do a dup of parsing/check the transition of the state?
-		String s = new String(scanner.source, scanner.caseStartPosition, nSz);
-		String modSource = s.concat(new String(new char[] {':'}));
-		char[] nSource = modSource.toCharArray();
+		char[] nSource = CharOperation.append(Arrays.copyOfRange(scanner.source, scanner.caseStartPosition, scanner.startPosition), ':');
 		VanguardParser vp = getNewVanguardParser(nSource);
 		if (vp.parse(Goal.SwitchLabelCaseLhsGoal) == VanguardParser.SUCCESS) {
 			scanner.nextToken = TokenNameARROW;
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 a7ae6cc..4a443f0 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
@@ -23,12 +23,10 @@
 import static org.eclipse.jdt.internal.compiler.util.Util.UTF_8;
 import static org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsCharArray;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
+import java.io.StringWriter;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.nio.file.Paths;
@@ -505,18 +503,12 @@
 	}
 
 	private static void decodeUnknownNode(Node node, StringBuffer buffer, IJavaProject project) {
-		ByteArrayOutputStream s = new ByteArrayOutputStream();
-		OutputStreamWriter writer;
-		try {
-			writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
-			XMLWriter xmlWriter = new XMLWriter(writer, project, false/*don't print XML version*/);
-			decodeUnknownNode(node, xmlWriter, true/*insert new line*/);
-			xmlWriter.flush();
-			xmlWriter.close();
-			buffer.append(s.toString("UTF8")); //$NON-NLS-1$
-		} catch (UnsupportedEncodingException e) {
-			// ignore (UTF8 is always supported)
-		}
+		StringWriter writer = new StringWriter();
+		XMLWriter xmlWriter = new XMLWriter(writer, project, false/*don't print XML version*/);
+		decodeUnknownNode(node, xmlWriter, true/*insert new line*/);
+		xmlWriter.flush();
+		xmlWriter.close();
+		buffer.append(writer.toString());
 	}
 
 	private static void decodeUnknownNode(Node node, XMLWriter xmlWriter, boolean insertNewLine) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java
index 70d6bf8..04957b9 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessingState.java
@@ -595,9 +595,7 @@
 		}
 
 		File timestamps = getTimeStampsFile();
-		DataOutputStream out = null;
-		try {
-			out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(timestamps)));
+		try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(timestamps)))){
 			out.writeInt(this.externalTimeStamps.size() - toRemove.size());
 			Iterator<Entry<IPath, Long>> entries = this.externalTimeStamps.entrySet().iterator();
 			while (entries.hasNext()) {
@@ -612,14 +610,6 @@
 		} catch (IOException e) {
 			IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, "Problems while saving timestamps", e); //$NON-NLS-1$
 			throw new CoreException(status);
-		} finally {
-			if (out != null) {
-				try {
-					out.close();
-				} catch (IOException e) {
-					// nothing we can do: ignore
-				}
-			}
 		}
 	}
 
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 72da45e..0cc5501 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
@@ -3408,17 +3408,18 @@
 		long now = System.currentTimeMillis();
 
 		// If the TTL for this cache entry has expired, directly check whether the archive is still invalid.
-		// If it transitioned to being valid, remove it from the cache and force an update to project caches.
 		if (now > invalidArchiveInfo.evictionTimestamp) {
 			try {
 				ZipFile zipFile = getZipFile(path, false);
 				closeZipFile(zipFile);
 				removeFromInvalidArchiveCache(path);
+				addInvalidArchive(path, ArchiveValidity.VALID); // update TTL
+				return ArchiveValidity.VALID;
 			} catch (CoreException e) {
 				// Archive is still invalid, fall through to reporting it is invalid.
 			}
-			// Retry the test from the start, now that we have an up-to-date result
-			return getArchiveValidity(path);
+			addInvalidArchive(path, ArchiveValidity.INVALID); // update TTL
+			return ArchiveValidity.INVALID;
 		}
 		if (DEBUG_INVALID_ARCHIVES) {
 			System.out.println("JAR cache: " + invalidArchiveInfo.reason + " " + path);  //$NON-NLS-1$ //$NON-NLS-2$
@@ -3435,6 +3436,7 @@
 				}
 				return; // do not remove the VALID information
 			}
+			// If it transitioned to being valid then force an update to project caches.
 			if (this.invalidArchives.remove(path) != null) {
 				if (DEBUG_INVALID_ARCHIVES) {
 					System.out.println("JAR cache: removed INVALID " + path);  //$NON-NLS-1$
@@ -4367,9 +4369,7 @@
 
 	private void saveClasspathListCache(String cacheName) throws CoreException {
 		File file = getClasspathListFile(cacheName);
-		DataOutputStream out = null;
-		try {
-			out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
+		try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))){
 			Set<IPath> pathCache = getClasspathListCache(cacheName);
 			synchronized (pathCache) {
 				out.writeInt(pathCache.size());
@@ -4382,35 +4382,17 @@
 		} catch (IOException e) {
 			IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, "Problems while saving non-chaining jar cache", e); //$NON-NLS-1$
 			throw new CoreException(status);
-		} finally {
-			if (out != null) {
-				try {
-					out.close();
-				} catch (IOException e) {
-					// nothing we can do: ignore
-				}
-			}
 		}
 	}
 
 	private void saveVariablesAndContainers(ISaveContext context) throws CoreException {
 		File file = getVariableAndContainersFile();
-		DataOutputStream out = null;
-		try {
-			out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
+		try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
 			out.writeInt(VARIABLES_AND_CONTAINERS_FILE_VERSION);
 			new VariablesAndContainersSaveHelper(out).save(context);
 		} catch (IOException e) {
 			IStatus status = new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, IStatus.ERROR, "Problems while saving variables and containers", e); //$NON-NLS-1$
 			throw new CoreException(status);
-		} finally {
-			if (out != null) {
-				try {
-					out.close();
-				} catch (IOException e) {
-					// nothing we can do: ignore
-				}
-			}
 		}
 	}
 
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 514596a..ba02f41 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
@@ -1438,8 +1438,7 @@
 	 */
 	protected String encodeClasspath(IClasspathEntry[] classpath, IClasspathEntry[] referencedEntries, IPath outputLocation, boolean indent, Map unknownElements) throws JavaModelException {
 		try {
-			ByteArrayOutputStream s = new ByteArrayOutputStream();
-			OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
+			StringWriter writer = new StringWriter();
 			XMLWriter xmlWriter = new XMLWriter(writer, this, true/*print XML version*/);
 
 			xmlWriter.startTag(ClasspathEntry.TAG_CLASSPATH, indent);
@@ -1465,7 +1464,7 @@
 			xmlWriter.endTag(ClasspathEntry.TAG_CLASSPATH, indent, true/*insert new line*/);
 			writer.flush();
 			writer.close();
-			return s.toString("UTF8");//$NON-NLS-1$
+			return writer.toString();
 		} catch (IOException e) {
 			throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
 		}
@@ -1474,15 +1473,14 @@
 	@Override
 	public String encodeClasspathEntry(IClasspathEntry classpathEntry) {
 		try {
-			ByteArrayOutputStream s = new ByteArrayOutputStream();
-			OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
+			StringWriter writer = new StringWriter();
 			XMLWriter xmlWriter = new XMLWriter(writer, this, false/*don't print XML version*/);
 
 			((ClasspathEntry)classpathEntry).elementEncode(xmlWriter, this.project.getFullPath(), true/*indent*/, true/*insert new line*/, null/*not interested in unknown elements*/, (classpathEntry.getReferencingEntry() != null));
 
 			writer.flush();
 			writer.close();
-			return s.toString("UTF8");//$NON-NLS-1$
+			return writer.toString();
 		} catch (IOException e) {
 			return null; // never happens since all is done in memory
 		}
@@ -2895,18 +2893,9 @@
 		if (projectMetaLocation != null) {
 			File prefFile = projectMetaLocation.append(PREF_FILENAME).toFile();
 			if (prefFile.exists()) { // load preferences from file
-				InputStream in = null;
-				try {
-					in = new BufferedInputStream(new FileInputStream(prefFile));
+				try (InputStream in = new BufferedInputStream(new FileInputStream(prefFile))){
 					preferences = Platform.getPreferencesService().readPreferences(in);
 				} catch (CoreException | IOException e) { // problems loading preference store - quietly ignore
-				} finally {
-					if (in != null) {
-						try {
-							in.close();
-						} catch (IOException e) { // ignore problems with close
-						}
-					}
 				}
 				// one shot read, delete old preferences
 				prefFile.delete();
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 2f8344c..d7cd766 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
@@ -494,7 +494,7 @@
 			parent = ((IOTJavaElement)parent).getCorrespondingJavaElement();
 // SH}
 		String typeSig = null;
-		if (local.type == null || local.type.isTypeNameVar(binding.declaringScope)) {
+		if (local.type == null || (local.type.isTypeNameVar(binding.declaringScope) && !binding.type.isAnonymousType())) {
 			if (local.initialization instanceof CastExpression) {
 				typeSig = Util.typeSignature(((CastExpression) local.initialization).type);
 			} else {
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 17216a3..5eeeb03 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
@@ -14,10 +14,9 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.core;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.OutputStreamWriter;
 import java.io.Reader;
+import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
 import javax.xml.parsers.DocumentBuilder;
@@ -101,8 +100,7 @@
 	}
 
 	public static String serialize(IClasspathEntry[] entries, boolean isSystemLibrary) throws IOException {
-		ByteArrayOutputStream s = new ByteArrayOutputStream();
-		OutputStreamWriter writer = new OutputStreamWriter(s, "UTF8"); //$NON-NLS-1$
+		StringWriter writer = new StringWriter();
 		XMLWriter xmlWriter = new XMLWriter(writer, null/*use the workspace line delimiter*/, true/*print XML version*/);
 
 		HashMap library = new HashMap();
@@ -144,7 +142,7 @@
 		xmlWriter.endTag(TAG_USERLIBRARY, true/*insert tab*/, true/*insert new line*/);
 		writer.flush();
 		writer.close();
-		return s.toString("UTF8");//$NON-NLS-1$
+		return writer.toString();
 	}
 
 	public static UserLibrary createFromString(Reader reader) throws IOException {
diff --git a/org.eclipse.jdt.core/pom.xml b/org.eclipse.jdt.core/pom.xml
index c04798d..f7ea5ae 100644
--- a/org.eclipse.jdt.core/pom.xml
+++ b/org.eclipse.jdt.core/pom.xml
@@ -153,6 +153,13 @@
                     <include>scripts/binary/**</include>
                   </includes>
                 </fileSet>
+                <!-- Include API stubs required for building ECJ on Java 11 -->
+                <fileSet>
+                  <directory>${project.basedir}/../org.eclipse.jdt.compiler.tool/lib</directory>
+                  <includes>
+                    <include>*.jar</include>
+                  </includes>
+                </fileSet>
               </fileSets>
             </configuration>
           </execution>
diff --git a/org.eclipse.jdt.core/scripts/build.xml b/org.eclipse.jdt.core/scripts/build.xml
index 229bec2..c68cc37 100644
--- a/org.eclipse.jdt.core/scripts/build.xml
+++ b/org.eclipse.jdt.core/scripts/build.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-    Copyright (c) 2007, 2015 IBM Corporation and others.
+    Copyright (c) 2007, 2021 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 @@
 
 		<javac srcdir="${basedir}" destdir="${output}"
 					debuglevel="lines,source"
-					source="1.8"
-					target="1.8">
-			<compilerarg line="-Xlint:none"/>
+					debug="true"
+					release="11">
+			<compilerarg line="-Xlint:none --patch-module java.compiler=javax17api.jar"/>
 		</javac>
 
 		<delete file="${basedir}/META-INF/MANIFEST.MF" failonerror="false"/>
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 200095e..496057e 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
@@ -40,10 +40,67 @@
 	TagBits.AnnotationForModule |
 	TagBits.AnnotationForRecordComponent;
 private static final char[] JAVA_LANG_ANNOTATION_ELEMENTTYPE = CharOperation.concatWith(TypeConstants.JAVA_LANG_ANNOTATION_ELEMENTTYPE, '.');
+
+/**
+ * Convert binary name internally used in class files to binary name as specified by jls-13.1.
+ * <p/>
+ * Examples:
+ * <ul>
+ * <li>"java/lang/String" -> "java.lang.String",</li>
+ * <li>"java/util/Map$Entry" -> "java.util.Map$Entry"</li>
+ * </ul>
+ *
+ * @param name
+ *            class files internal form of binary name
+ * @return binary name as specified by
+ *         <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-6.html#jls-6.7">jls-13.1</a>
+ * @see Class#getName()
+ * @see IBinaryType#getName()
+ */
 public static char[] convertClassFileFormat(char[] name) {
 	return CharOperation.replaceOnCopy(name, '/', '.');
 }
 
+/**
+ * Returns null or a qualified name suitable for search. Unlike "qualified name" as specified by
+ * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-6.html#jls-6.7">jls-6.7</a> (which defines that a
+ * local class or anonymous class does not have a full qualified name) this will return a name for local classes.
+ *
+ * <p>
+ * Note that the returned name could contain a "$" for a class or package that has a "$" in its simple name.
+ * </p>
+ *
+ * @param type
+ *            the IBinaryType to get the name from.
+ * @return full qualified name suitable for search or null for anonymous classes.<br>
+ *         Examples:
+ *         <ul>
+ *         <li>returns null for anonymous class like <code>new Object(){}</code>,</li>
+ *         <li>returns "java.lang.String" for String,</li>
+ *         <li>returns "java.util.Map.Entry" for the inner type java.util.Map$Entry,</li>
+ *         <li>returns "mypackage.MyLocal" for local class inside a block statement like <code>{class MyLocal{}}</code>,</li>
+ *         <li>should return "$.$.$1" (XXX currently does return ".....1") for $1 from <br>
+ *         <code>package $;<br> class $ {class $1{}}</code></li>
+ *         </ul>
+ * @see Class#getPackageName()
+ * @see Class#getSimpleName()
+ * @see Class#getCanonicalName()
+ **/
+static char[] getSearchFullQualifiedSearchName(IBinaryType type) {
+	if (type.isAnonymous()) {
+		return null;
+	}
+	char[] binaryName = convertClassFileFormat(type.getName());
+	// XXX textual replacement of "$" is not sufficient for classes/packages which contain "$" in their simple name:
+	// nevertheless this at least solves finding normal named inner Types in .class files
+	// "$" is rarely used since jls-3.8 states:
+	// "the $ sign should be used only in mechanically generated source code or, rarely, to access pre-existing names on legacy systems"
+	char[] qualifiedName = CharOperation.replaceOnCopy(binaryName, '$', '.');
+	// Note on how a type name is calculated for the UI:
+	// @see org.eclipse.jdt.internal.core.manipulation.BindingLabelProviderCore#getTypeLabel(ITypeBinding, long, StringBuffer)
+	return qualifiedName;
+}
+
 private  boolean checkAnnotation(IBinaryAnnotation annotation, TypeReferencePattern pattern) {
 	if (checkTypeName(pattern.simpleName, pattern.qualification, convertClassFileFormat(Signature.toCharArray(annotation.getTypeName())), pattern.isCaseSensitive, pattern.isCamelCase)) {
 		return true;
@@ -495,7 +552,7 @@
 	if (!(binaryInfo instanceof IBinaryType)) return false;
 
 	IBinaryType type = (IBinaryType) binaryInfo;
-	char[] fullyQualifiedTypeName = convertClassFileFormat(type.getName());
+	char[] fullyQualifiedTypeName = getSearchFullQualifiedSearchName(type);
 	boolean qualifiedPattern = pattern instanceof QualifiedTypeDeclarationPattern;
 	if (pattern.enclosingTypeNames == null || qualifiedPattern) {
 		char[] simpleName = (pattern.getMatchMode() == SearchPattern.R_PREFIX_MATCH)