Bug 578794 - [18] Merge from master to BETA_JAVA18 Periodically
diff --git a/org.eclipse.jdt.astview.feature/feature.xml b/org.eclipse.jdt.astview.feature/feature.xml
index 7ecc462..a04a52c 100644
--- a/org.eclipse.jdt.astview.feature/feature.xml
+++ b/org.eclipse.jdt.astview.feature/feature.xml
@@ -2,13 +2,13 @@
 <feature
       id="org.eclipse.jdt.astview.feature"
       label="AST View"
-      version="1.1.13.qualifier"
+      version="1.1.14.qualifier"
       provider-name="Eclipse.org"
       license-feature="org.eclipse.license"
       license-feature-version="0.0.0">
 
    <description>
-      AST View for Eclipse 2020-12 and later (jdt.core 3.24)
+      AST View for Eclipse 2021-12 and later (jdt.core 3.28)
    </description>
 
    <license url="%licenseURL">
@@ -20,8 +20,8 @@
    </url>
 
    <requires>
-      <import plugin="org.eclipse.jdt.core" version="3.24.0" match="compatible"/>
-      <import plugin="org.eclipse.jdt.ui" version="3.22.0" match="compatible"/>
+      <import plugin="org.eclipse.jdt.core" version="3.28.0" match="compatible"/>
+      <import plugin="org.eclipse.jdt.ui" version="3.25.0" match="compatible"/>
       <import plugin="org.eclipse.core.runtime"/>
       <import plugin="org.eclipse.ui.ide"/>
       <import plugin="org.eclipse.ui.views"/>
diff --git a/org.eclipse.jdt.astview.feature/pom.xml b/org.eclipse.jdt.astview.feature/pom.xml
index c58d5e9..dd517a8 100644
--- a/org.eclipse.jdt.astview.feature/pom.xml
+++ b/org.eclipse.jdt.astview.feature/pom.xml
@@ -18,6 +18,6 @@
   </parent>
   <groupId>org.eclipse.jdt.feature</groupId>
   <artifactId>org.eclipse.jdt.astview.feature</artifactId>
-  <version>1.1.13-SNAPSHOT</version>
+  <version>1.1.14-SNAPSHOT</version>
   <packaging>eclipse-feature</packaging>
 </project>
diff --git a/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
index ab82233..80822d5 100644
--- a/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.core.manipulation; singleton:=true
-Bundle-Version: 1.15.200.qualifier
+Bundle-Version: 1.16.0.qualifier
 Bundle-Vendor: %providerName
 Bundle-Activator: org.eclipse.jdt.internal.core.manipulation.JavaManipulationPlugin
 Bundle-Localization: plugin
@@ -12,7 +12,7 @@
  org.eclipse.ltk.core.refactoring;bundle-version="[3.6.0,4.0.0)",
  org.eclipse.jdt.core;bundle-version="[3.28.0,4.0.0)",
  org.eclipse.core.expressions;bundle-version="[3.4.100,4.0.0)",
- org.eclipse.text;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.text;bundle-version="[3.12.0,4.0.0)",
  org.eclipse.jdt.launching;bundle-version="3.19.400",
  org.eclipse.core.filesystem;bundle-version="1.7.200",
  org.eclipse.core.filebuffers;bundle-version="3.6.300"
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/CoreASTProvider.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/CoreASTProvider.java
index bb444b6..fc77b79 100644
--- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/CoreASTProvider.java
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/core/manipulation/CoreASTProvider.java
@@ -62,6 +62,7 @@
 	private Object fReconcileLock= new Object();
 	private Object fWaitLock= new Object();
 	private volatile boolean fIsReconciling;
+	private volatile Runnable fFinishReconciling;
 
 	/**
 	 * Wait flag class.
@@ -166,6 +167,7 @@
 
 		if (isReconciling) {
 			try {
+				notifyReconciler();
 				// Wait for AST
 				synchronized (fWaitLock) {
 					if (isReconciling(input)) {
@@ -215,6 +217,13 @@
 		return ast;
 	}
 
+	private void notifyReconciler() {
+		Runnable finishReconciling= fFinishReconciling;
+		if (finishReconciling!=null) {
+			finishReconciling.run();
+		}
+	}
+
 	/**
 	 * Informs that reconciling for the given element is about to be started.
 	 *
@@ -222,6 +231,18 @@
 	 * See org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener#aboutToBeReconciled()
 	 */
 	public void aboutToBeReconciled(ITypeRoot javaElement) {
+		aboutToBeReconciled(javaElement, null);
+	}
+
+	/**
+	 * Informs that reconciling for the given element is about to be started.
+	 *
+	 * @param javaElement the Java element
+	 * @param finishReconciling Runnable to be run.
+	 * see org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener#aboutToBeReconciled(JavaReconciler)
+	 * @since 1.16
+	 */
+	public void aboutToBeReconciled(ITypeRoot javaElement, Runnable finishReconciling) {
 
 		if (javaElement == null)
 			return;
@@ -232,6 +253,7 @@
 		synchronized (fReconcileLock) {
 			fReconcilingJavaElement= javaElement;
 			fIsReconciling= true;
+			this.fFinishReconciling = finishReconciling;
 		}
 		cache(null, javaElement);
 	}
@@ -302,6 +324,7 @@
 
 		synchronized (fReconcileLock) {
 			fIsReconciling= false;
+			fFinishReconciling= null;
 			if (javaElement == null || !javaElement.equals(fReconcilingJavaElement)) {
 
 				if (JavaManipulationPlugin.DEBUG_AST_PROVIDER)
@@ -498,6 +521,7 @@
 		synchronized (fReconcileLock) {
 			fIsReconciling = false;
 			fReconcilingJavaElement = null;
+			fFinishReconciling = null;
 		}
 	}
 
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/SubstringCleanUpCore.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/SubstringCleanUpCore.java
new file mode 100644
index 0000000..b7fe61a
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/SubstringCleanUpCore.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *     Red Hat - moved here from jdt.ui project
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.text.edits.TextEditGroup;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.manipulation.CleanUpRequirementsCore;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
+import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFixCore;
+import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation;
+import org.eclipse.jdt.internal.corext.fix.LinkedProposalModelCore;
+import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
+
+import org.eclipse.jdt.internal.ui.text.correction.IProblemLocationCore;
+
+/**
+ * A fix that removes the second <code>substring()</code> parameter if this parameter is the length of the string:
+ * <ul>
+ * <li>It must reference the same expression,</li>
+ * <li>The expression must be passive.</li>
+ * </ul>
+ */
+public class SubstringCleanUpCore extends AbstractMultiFixCore {
+	public SubstringCleanUpCore() {
+		this(Collections.emptyMap());
+	}
+
+	public SubstringCleanUpCore(final Map<String, String> options) {
+		super(options);
+	}
+
+	@Override
+	public CleanUpRequirementsCore getRequirementsCore() {
+		boolean requireAST= isEnabled(CleanUpConstants.SUBSTRING);
+		return new CleanUpRequirementsCore(requireAST, false, false, null);
+	}
+
+	@Override
+	public String[] getStepDescriptions() {
+		if (isEnabled(CleanUpConstants.SUBSTRING)) {
+			return new String[] { MultiFixMessages.SubstringCleanUp_description };
+		}
+
+		return new String[0];
+	}
+
+	@Override
+	public String getPreview() {
+		if (isEnabled(CleanUpConstants.SUBSTRING)) {
+			return "String shortenedText = text.substring(2);\n"; //$NON-NLS-1$
+		}
+
+		return "String shortenedText = text.substring(2, text.length());\n"; //$NON-NLS-1$
+	}
+
+	@Override
+	public ICleanUpFixCore createFix(final CompilationUnit unit) throws CoreException {
+		if (!isEnabled(CleanUpConstants.SUBSTRING)) {
+			return null;
+		}
+
+		final List<CompilationUnitRewriteOperation> rewriteOperations= new ArrayList<>();
+
+		unit.accept(new ASTVisitor() {
+			@Override
+			public boolean visit(final MethodInvocation visited) {
+				if (ASTNodes.usesGivenSignature(visited, String.class.getCanonicalName(), "substring", int.class.getCanonicalName(), int.class.getCanonicalName())) { //$NON-NLS-1$
+					MethodInvocation endIndex= ASTNodes.as((Expression) visited.arguments().get(1), MethodInvocation.class);
+
+					if (endIndex != null
+							&& endIndex.getExpression() != null
+							&& ASTNodes.usesGivenSignature(endIndex, String.class.getCanonicalName(), "length") //$NON-NLS-1$
+							&& ASTNodes.match(visited.getExpression(), endIndex.getExpression())
+							&& ASTNodes.isPassive(visited.getExpression())) {
+				rewriteOperations.add(new SubstringOperation(visited));
+						return false;
+					}
+				}
+
+				return true;
+			}
+		});
+
+		if (rewriteOperations.isEmpty()) {
+			return null;
+		}
+
+		return new CompilationUnitRewriteOperationsFixCore(MultiFixMessages.SubstringCleanUp_description, unit,
+				rewriteOperations.toArray(new CompilationUnitRewriteOperation[0]));
+	}
+	@Override
+	public ICleanUpFixCore createFix(CompilationUnit unit, IProblemLocationCore[] problems) throws CoreException {
+		return createFix(unit);
+	}
+
+
+	@Override
+	public boolean canFix(final ICompilationUnit compilationUnit, final IProblemLocationCore problem) {
+		return false;
+	}
+
+	private static class SubstringOperation extends CompilationUnitRewriteOperation {
+		private final MethodInvocation visited;
+
+		public SubstringOperation(final MethodInvocation visited) {
+			this.visited= visited;
+		}
+
+		@Override
+		public void rewriteAST(final CompilationUnitRewrite cuRewrite, final LinkedProposalModelCore linkedModel) throws CoreException {
+			ASTRewrite rewrite= cuRewrite.getASTRewrite();
+			TextEditGroup group= createTextEditGroup(MultiFixMessages.SubstringCleanUp_description, cuRewrite);
+
+			rewrite.remove((ASTNode) visited.arguments().get(1), group);
+		}
+	}
+}
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/preferences/formatter/ProfileVersionerCore.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/preferences/formatter/ProfileVersionerCore.java
index d17bd71..a017fda 100644
--- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/preferences/formatter/ProfileVersionerCore.java
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/preferences/formatter/ProfileVersionerCore.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2020 IBM Corporation and others.
+ * Copyright (c) 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -23,7 +23,7 @@
 
 public class ProfileVersionerCore {
 
-	private static final int CURRENT_VERSION= 21;
+	private static final int CURRENT_VERSION= 22;
 
 	public static int getFirstVersion() {
 		return 1;
@@ -94,6 +94,9 @@
 		case 20:
 			version20to21(oldSettings);
 			//$FALL-THROUGH$
+		case 21:
+			version21to22(oldSettings);
+			//$FALL-THROUGH$
 		default:
 			for (Map.Entry<String, String> entry : oldSettings.entrySet()) {
 				final String key= entry.getKey();
@@ -733,6 +736,16 @@
 			}
 		}
 
+		private static void version21to22(Map<String, String> oldSettings) {
+			oldSettings.put(DefaultCodeFormatterConstants.FORMATTER_ALIGN_SELECTOR_IN_METHOD_INVOCATION_ON_EXPRESSION_FIRST_LINE, DefaultCodeFormatterConstants.FALSE);
+			oldSettings.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SWITCH_CASE_WITH_ARROW,
+					DefaultCodeFormatterConstants.createAlignmentValue(false, DefaultCodeFormatterConstants.WRAP_NO_SPLIT, DefaultCodeFormatterConstants.INDENT_DEFAULT));
+			oldSettings.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_SWITCH_CASE_WITH_ARROW,
+					DefaultCodeFormatterConstants.createAlignmentValue(false, DefaultCodeFormatterConstants.WRAP_NO_SPLIT, DefaultCodeFormatterConstants.INDENT_DEFAULT));
+			oldSettings.put(DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_SWITCH_CASE_WITH_COLON,
+					DefaultCodeFormatterConstants.createAlignmentValue(false, DefaultCodeFormatterConstants.WRAP_NO_SPLIT, DefaultCodeFormatterConstants.INDENT_DEFAULT));
+		}
+
 		/* old format constant values */
 
 	    private static final String FORMATTER_METHOD_DECLARATION_ARGUMENTS_ALIGNMENT = JavaCore.PLUGIN_ID + ".formatter.method_declaration_arguments_alignment"; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/correction/CorrectionMessages.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/correction/CorrectionMessages.java
index 8d5fc9d..8e2d05e 100644
--- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/correction/CorrectionMessages.java
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/correction/CorrectionMessages.java
@@ -429,6 +429,7 @@
 	public static String QuickAssistProcessor_extract_to_local_all_description;
 	public static String QuickAssistProcessor_extract_to_local_description;
 	public static String QuickAssistProcessor_extractmethod_description;
+	public static String QuickAssistProcessor_extractmethod_from_lambda_description;
 	public static String QuickAssistProcessor_move_exception_to_separate_catch_block;
 	public static String QuickAssistProcessor_move_exceptions_to_separate_catch_block;
 	public static String QuickAssistProcessor_create_new_junit_test_case;
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/correction/CorrectionMessages.properties b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/correction/CorrectionMessages.properties
index 137a21d..b3f27f7 100644
--- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/correction/CorrectionMessages.properties
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/correction/CorrectionMessages.properties
@@ -389,6 +389,7 @@
 QuickAssistProcessor_extract_to_local_all_description=Extract to local variable (replace all occurrences)
 QuickAssistProcessor_extract_to_local_description=Extract to local variable
 QuickAssistProcessor_extractmethod_description=Extract to method
+QuickAssistProcessor_extractmethod_from_lambda_description=Extract lambda body to method
 QuickAssistProcessor_extract_to_constant_description=Extract to constant
 QuickAssistProcessor_joindeclaration_description=Join variable declaration
 QuickAssistProcessor_add_inferred_lambda_parameter_types=Add inferred lambda parameter types
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/NecessaryParenthesesChecker.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/NecessaryParenthesesChecker.java
index 889ad82..3a3ba4e 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/NecessaryParenthesesChecker.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/NecessaryParenthesesChecker.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2019 IBM Corporation and others.
+ * Copyright (c) 2011, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -21,6 +21,7 @@
 import org.eclipse.jdt.core.dom.ArrayAccess;
 import org.eclipse.jdt.core.dom.ArrayCreation;
 import org.eclipse.jdt.core.dom.AssertStatement;
+import org.eclipse.jdt.core.dom.CastExpression;
 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
 import org.eclipse.jdt.core.dom.ConditionalExpression;
 import org.eclipse.jdt.core.dom.DoStatement;
@@ -40,6 +41,7 @@
 import org.eclipse.jdt.core.dom.SwitchStatement;
 import org.eclipse.jdt.core.dom.SynchronizedStatement;
 import org.eclipse.jdt.core.dom.ThrowStatement;
+import org.eclipse.jdt.core.dom.Type;
 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
 import org.eclipse.jdt.core.dom.WhileStatement;
 
@@ -60,6 +62,7 @@
 				|| type == ASTNode.POSTFIX_EXPRESSION
 				|| type == ASTNode.CAST_EXPRESSION
 				|| type == ASTNode.INSTANCEOF_EXPRESSION
+				|| type == ASTNode.PATTERN_INSTANCEOF_EXPRESSION
 				|| type == ASTNode.ARRAY_CREATION
 				|| type == ASTNode.ASSIGNMENT;
 	}
@@ -404,6 +407,13 @@
 					(expressionOperator == PrefixExpression.Operator.MINUS || expressionOperator == PrefixExpression.Operator.DECREMENT)) {
 				return true;
 			}
+		} else if (parentExpression instanceof CastExpression) {
+			CastExpression castExp= (CastExpression) parentExpression;
+			Type type= castExp.getType();
+			if (type != null && type.isPrimitiveType()) {
+				return false;
+			}
+			return true;
 		}
 		return false;
 	}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/OperatorPrecedence.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/OperatorPrecedence.java
index 065da72..d245dd8 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/OperatorPrecedence.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/OperatorPrecedence.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -24,6 +24,7 @@
 import org.eclipse.jdt.core.dom.InfixExpression.Operator;
 import org.eclipse.jdt.core.dom.InstanceofExpression;
 import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.PatternInstanceofExpression;
 import org.eclipse.jdt.core.dom.PostfixExpression;
 import org.eclipse.jdt.core.dom.PrefixExpression;
 
@@ -73,7 +74,7 @@
 			return ASSIGNMENT;
 		} else if (expression instanceof ConditionalExpression) {
 			return CONDITIONAL;
-		} else if (expression instanceof InstanceofExpression) {
+		} else if (expression instanceof InstanceofExpression || expression instanceof PatternInstanceofExpression) {
 			return RELATIONAL;
 		} else if (expression instanceof CastExpression) {
 			return TYPEGENERATION;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/BreakContinueTargetFinder.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/BreakContinueTargetFinder.java
similarity index 97%
rename from org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/BreakContinueTargetFinder.java
rename to org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/BreakContinueTargetFinder.java
index d01cb81..44f34dc 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/BreakContinueTargetFinder.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/BreakContinueTargetFinder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 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
@@ -11,7 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
-package org.eclipse.jdt.internal.ui.search;
+package org.eclipse.jdt.internal.core.manipulation.search;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -36,13 +36,11 @@
 import org.eclipse.jdt.core.dom.SwitchStatement;
 import org.eclipse.jdt.core.dom.WhileStatement;
 
-import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder;
+import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
 import org.eclipse.jdt.internal.corext.dom.TokenScanner;
 import org.eclipse.jdt.internal.corext.util.Messages;
 
-import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
-
 
 /**
  * Class used to find the target for a break or continue statement according
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/ExceptionOccurrencesFinder.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/ExceptionOccurrencesFinder.java
similarity index 98%
rename from org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/ExceptionOccurrencesFinder.java
rename to org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/ExceptionOccurrencesFinder.java
index 46c0b9f..c190689 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/ExceptionOccurrencesFinder.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/ExceptionOccurrencesFinder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 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
@@ -11,7 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
-package org.eclipse.jdt.internal.ui.search;
+package org.eclipse.jdt.internal.core.manipulation.search;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -48,7 +48,6 @@
 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
 
 import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving;
-import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder;
 import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
 import org.eclipse.jdt.internal.corext.dom.Bindings;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/ImplementOccurrencesFinder.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/ImplementOccurrencesFinder.java
similarity index 96%
rename from org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/ImplementOccurrencesFinder.java
rename to org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/ImplementOccurrencesFinder.java
index 3a45e1d..01c999f 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/ImplementOccurrencesFinder.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/ImplementOccurrencesFinder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 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
@@ -11,7 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
-package org.eclipse.jdt.internal.ui.search;
+package org.eclipse.jdt.internal.core.manipulation.search;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -33,13 +33,11 @@
 import org.eclipse.jdt.core.dom.TypeDeclaration;
 import org.eclipse.jdt.core.dom.TypeDeclarationStatement;
 
-import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder;
+import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
 import org.eclipse.jdt.internal.corext.dom.Bindings;
 import org.eclipse.jdt.internal.corext.util.Messages;
 
-import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
-
 
 /**
  * Finds all implement occurrences of an extended class or an implemented interface.
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/MethodExitsFinder.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/MethodExitsFinder.java
similarity index 98%
rename from org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/MethodExitsFinder.java
rename to org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/MethodExitsFinder.java
index ea2c9a7..f1f2473 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/MethodExitsFinder.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/MethodExitsFinder.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
@@ -11,7 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
-package org.eclipse.jdt.internal.ui.search;
+package org.eclipse.jdt.internal.core.manipulation.search;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -48,7 +48,6 @@
 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
 
 import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving;
-import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder;
 import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
 import org.eclipse.jdt.internal.corext.dom.Bindings;
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/SearchMessages.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/SearchMessages.java
index c7bb826..5236acc 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/SearchMessages.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/SearchMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 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
@@ -35,4 +35,35 @@
 	public static String OccurrencesFinder_occurrence_description;
 	public static String OccurrencesFinder_occurrence_write_description;
 	public static String OccurrencesSearchLabelProvider_line_number;
+
+	public static String ExceptionOccurrencesFinder_no_exception;
+	public static String ExceptionOccurrencesFinder_searchfor;
+	public static String ExceptionOccurrencesFinder_label_singular;
+	public static String ExceptionOccurrencesFinder_label_plural;
+	public static String ExceptionOccurrencesFinder_occurrence_description;
+	public static String ExceptionOccurrencesFinder_occurrence_implicit_close_description;
+
+	public static String ImplementOccurrencesFinder_invalidTarget;
+	public static String ImplementOccurrencesFinder_searchfor;
+	public static String ImplementOccurrencesFinder_label_singular;
+	public static String ImplementOccurrencesFinder_label_plural;
+	public static String ImplementOccurrencesFinder_occurrence_description;
+
+	public static String MethodExitsFinder_job_label;
+	public static String MethodExitsFinder_label_plural;
+	public static String MethodExitsFinder_label_singular;
+	public static String MethodExitsFinder_no_return_type_selected;
+	public static String MethodExitsFinder_occurrence_exit_description;
+	public static String MethodExitsFinder_occurrence_exit_impclict_close_description;
+	public static String MethodExitsFinder_occurrence_return_description;
+
+	public static String BreakContinueTargetFinder_break_label_plural;
+	public static String BreakContinueTargetFinder_break_label_singular;
+	public static String BreakContinueTargetFinder_cannot_highlight;
+	public static String BreakContinueTargetFinder_continue_label_plural;
+	public static String BreakContinueTargetFinder_continue_label_singular;
+	public static String BreakContinueTargetFinder_job_label;
+	public static String BreakContinueTargetFinder_no_break_or_continue_selected;
+	public static String BreakContinueTargetFinder_occurrence_description;
+
 }
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/SearchMessages.properties b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/SearchMessages.properties
index 7a76fa7..2a5452d 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/SearchMessages.properties
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/search/SearchMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2016 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
@@ -21,3 +21,39 @@
 OccurrencesFinder_occurrence_description=Occurrence of ''{0}''
 OccurrencesFinder_occurrence_write_description=Write occurrence of ''{0}''
 OccurrencesSearchLabelProvider_line_number={0}: 
+
+ExceptionOccurrencesFinder_no_exception= Cannot search for current selection. Please select an exception.
+ExceptionOccurrencesFinder_searchfor= Search for Exception Occurrences
+
+# The first argument will be replaced by the element name and the second one by the file name
+ExceptionOccurrencesFinder_label_singular=''{0}'' - 1 exception occurrence in ''{1}''
+# The first argument will be replaced by the element name, the second by the count and the last by the file name
+ExceptionOccurrencesFinder_label_plural=''{0}'' - {1} exception occurrences in ''{2}''
+ExceptionOccurrencesFinder_occurrence_description=Occurrences throwing ''{0}''
+ExceptionOccurrencesFinder_occurrence_implicit_close_description=''{0}'' is thrown from implicit close() methods of highlighted resources.
+
+ImplementOccurrencesFinder_invalidTarget= Cannot search for current selection. Please select a type behind 'implements' or 'extends'.
+ImplementOccurrencesFinder_searchfor= Search for Implement Occurrences
+
+# The first argument will be replaced by the element name and the second one by the file name
+ImplementOccurrencesFinder_label_singular=''{0}'' - 1 implement occurrence in ''{1}''
+# The first argument will be replaced by the element name, the second by the count and the last by the file name
+ImplementOccurrencesFinder_label_plural=''{0}'' - {1} implement occurrences in ''{2}''
+ImplementOccurrencesFinder_occurrence_description=Implementors of methods in ''{0}''
+
+MethodExitsFinder_job_label=Search for Method Exit Occurrences
+MethodExitsFinder_label_plural=''{0}(...)'' - {1} method exit occurrence in ''{2}''
+MethodExitsFinder_label_singular=''{0}(...)'' - 1 method exit occurrence in ''{1}''
+MethodExitsFinder_no_return_type_selected=No return type selected
+MethodExitsFinder_occurrence_exit_description=Exit point of ''{0}()''
+MethodExitsFinder_occurrence_exit_impclict_close_description=Exit point of ''{0}()'': Exception is thrown from implicit close() methods of highlighted resources.
+MethodExitsFinder_occurrence_return_description=Return type of ''{0}()''
+
+BreakContinueTargetFinder_break_label_plural=''{0}'' - {1} break target occurrences in ''{2}''
+BreakContinueTargetFinder_break_label_singular=''{0}'' - 1 break target occurrence in ''{1}''
+BreakContinueTargetFinder_cannot_highlight=Occurrences in this element cannot be highlighted
+BreakContinueTargetFinder_continue_label_plural=''{0}'' - {1} continue target occurrences in ''{2}''
+BreakContinueTargetFinder_continue_label_singular=''{0}'' - 1 continue target occurrence in ''{1}''
+BreakContinueTargetFinder_job_label=Search for Break/Continue Target Occurrences
+BreakContinueTargetFinder_no_break_or_continue_selected=No break or continue selected
+BreakContinueTargetFinder_occurrence_description=Target of ''{0}''
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CallSearchResultCollector.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CallSearchResultCollector.java
index c792b19..2ab3af7 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CallSearchResultCollector.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CallSearchResultCollector.java
@@ -43,21 +43,23 @@
     }
 
     protected void addMember(IMember member, IMember calledMember, int start, int end) {
-        addMember(member, calledMember, start, end, CallLocation.UNKNOWN_LINE_NUMBER);
+        addMember(member, calledMember, start, end, CallLocation.UNKNOWN_LINE_NUMBER, false);
     }
 
-    protected void addMember(IMember member, IMember calledMember, int start, int end, int lineNumber) {
+    protected void addMember(IMember member, IMember calledMember, int start, int end, int lineNumber, boolean potential) {
         if ((member != null) && (calledMember != null)) {
             if (!isIgnored(calledMember)) {
                 MethodCall methodCall = fCalledMembers.get(calledMember.getHandleIdentifier());
 
                 if (methodCall == null) {
-                    methodCall = new MethodCall(calledMember);
+                    methodCall = new MethodCall(calledMember, potential);
                     fCalledMembers.put(calledMember.getHandleIdentifier(), methodCall);
                 }
 
-                methodCall.addCallLocation(new CallLocation(member, calledMember, start,
-                        end, lineNumber));
+                if(start > -1 && end > -1) {
+                    methodCall.addCallLocation(new CallLocation(member, calledMember, start,
+                            end, lineNumber));
+                }
             }
         }
     }
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CalleeAnalyzerVisitor.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CalleeAnalyzerVisitor.java
index 61493d9..ec46c45 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CalleeAnalyzerVisitor.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CalleeAnalyzerVisitor.java
@@ -15,13 +15,16 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.callhierarchy;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
 
+import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IMember;
 import org.eclipse.jdt.core.IMethod;
@@ -39,8 +42,10 @@
 import org.eclipse.jdt.core.dom.ITypeBinding;
 import org.eclipse.jdt.core.dom.MethodDeclaration;
 import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.Modifier;
 import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
+import org.eclipse.jdt.core.dom.TypeDeclaration;
 import org.eclipse.jdt.core.search.IJavaSearchScope;
 
 import org.eclipse.jdt.internal.core.manipulation.JavaManipulationPlugin;
@@ -55,9 +60,11 @@
     private final IProgressMonitor fProgressMonitor;
     private int fMethodEndPosition;
     private int fMethodStartPosition;
+	private CallLocation fCalledAt;
 
-    CalleeAnalyzerVisitor(IMember member, CompilationUnit compilationUnit, IProgressMonitor progressMonitor) {
-        fSearchResults = new CallSearchResultCollector();
+    CalleeAnalyzerVisitor(CallLocation calledAt, IMember member, CompilationUnit compilationUnit, IProgressMonitor progressMonitor) {
+		fSearchResults = new CallSearchResultCollector();
+        this.fCalledAt= calledAt;
         this.fMember = member;
         this.fCompilationUnit= compilationUnit;
         this.fProgressMonitor = progressMonitor;
@@ -145,6 +152,10 @@
     @Override
 	public boolean visit(MethodDeclaration node) {
         progressMonitorWorked(1);
+        if(Modifier.isAbstract(node.getModifiers()) ||
+        		((node.getParent() instanceof TypeDeclaration) && ((TypeDeclaration)node.getParent()).isInterface())) {
+    		addMethodCall(node.resolveBinding(), node);
+        }
         return isFurtherTraversalNecessary(node);
     }
 
@@ -253,23 +264,41 @@
                 IMethod calledMethod = findIncludingSupertypes(calledMethodBinding,
                         calledType, fProgressMonitor);
 
-                IMember referencedMember= null;
+                List<IMember> referencedMembers= new ArrayList<>();
+                boolean implementationResults = false;
                 if (calledMethod == null) {
                     if (calledMethodBinding.isConstructor() && calledMethodBinding.getParameterTypes().length == 0) {
-                        referencedMember= calledType;
+                    	referencedMembers.add(calledType);
                     }
                 } else {
-                    if (calledType.isInterface()) {
-                        calledMethod = findImplementingMethods(calledMethod);
-                    }
-
-                    if (!isIgnoredBySearchScope(calledMethod)) {
-                        referencedMember= calledMethod;
+                	// only find implementations if we are handling a method declaration.
+                    if (node instanceof MethodDeclaration && (calledType.isInterface() || Flags.isAbstract(calledType.getFlags()))) {
+                        Collection<IJavaElement> implementingMethods= CallHierarchyCore.getDefault().getImplementingMethods(calledMethod);
+                        implementationResults = true;
+                        for (IJavaElement element : implementingMethods) {
+							if(element instanceof IMethod) {
+								if(!isIgnoredBySearchScope((IMethod) element)) {
+									referencedMembers.add((IMethod) element);
+								}
+							} else if(element instanceof IMember) {
+								referencedMembers.add((IMember) element);
+							}
+						}
+                    } else {
+                    	referencedMembers.add(calledMethod);
                     }
                 }
-                final int position= node.getStartPosition();
-				final int number= fCompilationUnit.getLineNumber(position);
-				fSearchResults.addMember(fMember, referencedMember, position, position + node.getLength(), number < 1 ? 1 : number);
+
+                Optional<CallLocation> calledAt= Optional.ofNullable(fCalledAt);
+                Integer ignore = Integer.valueOf(-1);
+				final int position= implementationResults ? calledAt.map(CallLocation::getStart).orElse(ignore).intValue() : node.getStartPosition();
+				final int number= implementationResults ? calledAt.map(CallLocation::getLineNumber).orElse(ignore).intValue() : fCompilationUnit.getLineNumber(position);
+				final int length = implementationResults ? calledAt.map(c -> Integer.valueOf(c.getEnd() - position)).orElse(ignore).intValue() : node.getLength();
+				final IMember member = implementationResults ? calledAt.map(CallLocation::getMember).orElse(fMember) : fMember;
+				final boolean potential = implementationResults;
+				referencedMembers.forEach(m -> {
+					fSearchResults.addMember(member, m, position, position + length, number < 1 ? 1 : number, potential);
+				});
             }
         } catch (JavaModelException jme) {
             JavaManipulationPlugin.log(jme);
@@ -330,17 +359,6 @@
         return isNodeWithinMethod(node) || isNodeEnclosingMethod(node);
     }
 
-    private IMethod findImplementingMethods(IMethod calledMethod) {
-        Collection<IJavaElement> implementingMethods = CallHierarchyCore.getDefault()
-                                                        .getImplementingMethods(calledMethod);
-
-        if ((implementingMethods.isEmpty()) || (implementingMethods.size() > 1)) {
-            return calledMethod;
-        } else {
-            return (IMethod) implementingMethods.iterator().next();
-        }
-    }
-
     private void progressMonitorWorked(int work) {
         if (fProgressMonitor != null) {
             fProgressMonitor.worked(work);
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CalleeMethodWrapper.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CalleeMethodWrapper.java
index b6c7585..4f89554 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CalleeMethodWrapper.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CalleeMethodWrapper.java
@@ -96,7 +96,7 @@
 		    }
 
 			if (cu != null) {
-				CalleeAnalyzerVisitor visitor = new CalleeAnalyzerVisitor(member, cu, progressMonitor);
+				CalleeAnalyzerVisitor visitor = new CalleeAnalyzerVisitor(this.getMethodCall().getFirstCallLocation(), member, cu, progressMonitor);
 
 				cu.accept(visitor);
 				return visitor.getCallees();
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/Implementors.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/Implementors.java
index b59e1f1..a0b358b 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/Implementors.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/Implementors.java
@@ -22,6 +22,7 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.SubProgressMonitor;
 
+import org.eclipse.jdt.core.Flags;
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IMember;
 import org.eclipse.jdt.core.IMethod;
@@ -68,7 +69,7 @@
                     IMember member = (IMember) element;
                     IType type = member.getDeclaringType();
 
-                    if (type.isInterface()) {
+                    if (type.isInterface() || Flags.isAbstract(type.getFlags())) {
                         IType[] implementingTypes = findImplementingTypes(type,
                                 progressMonitor);
 
@@ -181,6 +182,12 @@
 
         try {
             for (IType type : types) {
+            	// we don't want the type we start the searched on be searched again. This happens when
+            	// searching for abstract method implementations on abstract classes.
+            	if(method.getDeclaringType().equals(type)) {
+            		continue;
+            	}
+
                 IMethod[] methods = type.findMethods(method);
 
                 if (methods != null) {
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/MethodCall.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/MethodCall.java
index 147d25c..a04e797 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/MethodCall.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/callhierarchy/MethodCall.java
@@ -23,14 +23,27 @@
 public class MethodCall {
     private IMember fMember;
     private List<CallLocation> fCallLocations;
+    private boolean potential;
 
     /**
      * @param enclosingElement
      */
     public MethodCall(IMember enclosingElement) {
-        this.fMember = enclosingElement;
+    	this(enclosingElement, false);
     }
 
+	/**
+	 * @param enclosingElement enclosing member of this call object
+	 * @param potential indicate whether this call object is a potential item in the hierarchy. A
+	 *            item is considered as potential when there is no direct reference, like methods on
+	 *            a implementation class which are referred through the interface in actual code.
+	 */
+	public MethodCall(IMember enclosingElement, boolean potential) {
+		this.fMember= enclosingElement;
+		this.potential = potential;
+	}
+
+
     /**
      *
      */
@@ -75,6 +88,16 @@
         fCallLocations.add(location);
     }
 
+	/**
+	 * Returns if this is a potential call object.
+	 *
+	 * @return <code>true</code> if its potential.
+	 * @see #MethodCall(IMember, boolean)
+	 */
+	public boolean isPotential() {
+		return potential;
+	}
+
 	@Override
 	public String toString() {
 		StringBuilder builder= new StringBuilder();
@@ -82,6 +105,7 @@
 		if (fMember != null) {
 			builder.append(fMember);
 		}
+		builder.append(',').append(potential);
 		builder.append("]"); //$NON-NLS-1$
 		return builder.toString();
 	}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java
index f709e8f..642bd88 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java
@@ -33,6 +33,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.regex.Pattern;
 
@@ -94,9 +95,11 @@
 import org.eclipse.jdt.core.dom.IBinding;
 import org.eclipse.jdt.core.dom.IExtendedModifier;
 import org.eclipse.jdt.core.dom.IMethodBinding;
+import org.eclipse.jdt.core.dom.IPackageBinding;
 import org.eclipse.jdt.core.dom.ITypeBinding;
 import org.eclipse.jdt.core.dom.IVariableBinding;
 import org.eclipse.jdt.core.dom.IfStatement;
+import org.eclipse.jdt.core.dom.ImportDeclaration;
 import org.eclipse.jdt.core.dom.InfixExpression;
 import org.eclipse.jdt.core.dom.LabeledStatement;
 import org.eclipse.jdt.core.dom.LambdaExpression;
@@ -3278,6 +3281,187 @@
 	}
 
 	/**
+	 * Returns if another method or constructor has the given signature.
+	 * It is useful to know if a refactoring of the given method or constructor is possible without conflict.
+	 * The method or constructor in parameter does not need to match this signature (usually not).
+	 *
+	 * @param methodOrConstructor A method, super method, constructor or super constructor
+	 * @param methodOrConstructorBinding The associated binding
+	 * @param expectedArgumentTypes The argument types that should match
+	 * @return True if another method or constructor has the given signature
+	 */
+	public static boolean hasConflictingMethodOrConstructor(
+			final ASTNode methodOrConstructor,
+			final IMethodBinding methodOrConstructorBinding,
+			final ITypeBinding[] expectedArgumentTypes) {
+		TypeDeclaration typeDeclaration= getTypedAncestor(methodOrConstructor, TypeDeclaration.class);
+
+		if (typeDeclaration == null) {
+			return true;
+		}
+
+		ITypeBinding type= typeDeclaration.resolveBinding();
+
+		if (type == null) {
+			return true;
+		}
+
+		boolean inSameClass= true;
+		// Figure out the type where we need to start looking at methods in the hierarchy.
+		// If we have a new class instance or super method call or this expression or
+		// we have a static call that is qualified, we use the referenced class as the starting point.
+		// If we have a non-qualified method call, we use the class containing the call.
+		// Otherwise, we bail on the clean-up.
+		if (methodOrConstructor instanceof ClassInstanceCreation) {
+			type= ((ClassInstanceCreation) methodOrConstructor).resolveTypeBinding();
+			inSameClass= type.isNested();
+		} else if (methodOrConstructor instanceof MethodInvocation) {
+			MethodInvocation methodInvocation= (MethodInvocation) methodOrConstructor;
+			Expression expression= methodInvocation.getExpression();
+
+			if (expression == null) {
+				ASTNode root= methodOrConstructor.getRoot();
+
+				if (root instanceof CompilationUnit) {
+					CompilationUnit compilationUnit= (CompilationUnit) root;
+					List<ImportDeclaration> imports= compilationUnit.imports();
+					String localPackage= null;
+
+					if (compilationUnit.getPackage() != null && compilationUnit.getPackage().getName() != null) {
+						localPackage= compilationUnit.getPackage().getName().getFullyQualifiedName();
+					}
+
+					for (ImportDeclaration oneImport : imports) {
+						if (oneImport.isStatic()
+								&& !oneImport.isOnDemand()
+								&& oneImport.getName() instanceof QualifiedName) {
+							QualifiedName methodName= (QualifiedName) oneImport.getName();
+							String methodIdentifier= methodName.getName().getIdentifier();
+							ITypeBinding conflictingType= methodName.getQualifier().resolveTypeBinding();
+
+							if (conflictingType == null) {
+								return true; // Error on side of caution
+							}
+
+							String importPackage= null;
+
+							if (conflictingType.getPackage() != null) {
+								importPackage= conflictingType.getPackage().getName();
+							}
+
+							boolean inSamePackage= Objects.equals(localPackage, importPackage);
+
+							for (IMethodBinding declaredMethod : conflictingType.getDeclaredMethods()) {
+								if (methodIdentifier.equals(declaredMethod.getName())
+										&& isMethodMatching(expectedArgumentTypes, methodOrConstructorBinding, false, inSamePackage, declaredMethod)) {
+									return true;
+								}
+							}
+						}
+					}
+				}
+
+				if (Modifier.isStatic(methodOrConstructorBinding.getModifiers())) {
+					inSameClass= methodOrConstructorBinding.getDeclaringClass().isEqualTo(type);
+					type= methodOrConstructorBinding.getDeclaringClass();
+				}
+			} else if (!(expression instanceof ThisExpression)) {
+				inSameClass= methodOrConstructorBinding.getDeclaringClass().isEqualTo(type);
+				type= expression.resolveTypeBinding();
+			}
+		} else if (methodOrConstructor instanceof SuperMethodInvocation) {
+			inSameClass= type.isNested();
+			type= type.getSuperclass();
+		} else {
+			return true; // Error on side of caution
+		}
+
+		if (type == null) {
+			return true;
+		}
+
+		return hasEquivalentMethodForInheritedTypes(expectedArgumentTypes, methodOrConstructorBinding, type, type, inSameClass);
+	}
+
+	private static boolean hasEquivalentMethodForInheritedTypes(
+			final ITypeBinding[] parameterTypesForConflictingMethod,
+			final IMethodBinding binding,
+			final ITypeBinding type,
+			final ITypeBinding origType,
+			final boolean wasInSameClass) {
+		ITypeBinding superType= type;
+		boolean inSameClass= wasInSameClass;
+
+		while (superType != null) {
+			IPackageBinding packageBinding= superType.getPackage();
+			boolean inSamePackage= packageBinding.isEqualTo(origType.getPackage());
+
+			if (hasEquivalentMethodForOneType(parameterTypesForConflictingMethod, binding, superType, inSameClass, inSamePackage)) {
+				return true;
+			}
+
+			if (superType.isNested()) {
+				if (hasEquivalentMethodForInheritedTypes(parameterTypesForConflictingMethod, binding, superType.getDeclaringClass(), origType, inSameClass)) {
+					return true;
+				}
+
+				superType= superType.getSuperclass();
+				inSameClass&= superType.isNested();
+			} else {
+				superType= superType.getSuperclass();
+				inSameClass= false;
+			}
+		}
+
+		return false;
+	}
+
+	private static boolean hasEquivalentMethodForOneType(
+			final ITypeBinding[] parameterTypesForConflictingMethod,
+			final IMethodBinding binding,
+			final ITypeBinding type,
+			final boolean inSameClass,
+			final boolean inSamePackage) {
+		for (IMethodBinding method : type.getDeclaredMethods()) {
+			if (isMethodMatching(parameterTypesForConflictingMethod, binding, inSameClass, inSamePackage, method)) {
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	private static boolean isMethodMatching(
+			final ITypeBinding[] parameterTypesForConflictingMethod,
+			final IMethodBinding binding,
+			final boolean inSameClass,
+			final boolean inSamePackage,
+			final IMethodBinding testedMethod) {
+		int methodModifiers= testedMethod.getModifiers();
+		ITypeBinding[] parameterTypes= testedMethod.getParameterTypes();
+
+		if (!binding.isEqualTo(testedMethod)
+				&& parameterTypesForConflictingMethod.length == parameterTypes.length
+				&& binding.getName().equals(testedMethod.getName())
+				&& (inSameClass || Modifier.isPublic(methodModifiers) || Modifier.isProtected(methodModifiers)
+						|| (inSamePackage && !Modifier.isPrivate(methodModifiers)))) {
+			for (int i= 0; i < parameterTypesForConflictingMethod.length; i++) {
+				if (parameterTypesForConflictingMethod[i] == null || parameterTypes[i] == null) {
+					return true;
+				}
+
+				if (!parameterTypesForConflictingMethod[i].isAssignmentCompatible(parameterTypes[i])) {
+					return false;
+				}
+			}
+
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
 	 * Returns whether the provided method invocation invokes a method with the
 	 * provided method signature. The method signature is compared against the
 	 * erasure of the invoked method.
@@ -3997,5 +4181,4 @@
 		}
 		return comments;
 	}
-
 }
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/LinkedNodeFinder.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/LinkedNodeFinder.java
index 6073904..73db53b 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/LinkedNodeFinder.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/LinkedNodeFinder.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
@@ -28,6 +28,8 @@
 import org.eclipse.jdt.core.dom.ITypeBinding;
 import org.eclipse.jdt.core.dom.IVariableBinding;
 import org.eclipse.jdt.core.dom.LabeledStatement;
+import org.eclipse.jdt.core.dom.ModuleDeclaration;
+import org.eclipse.jdt.core.dom.Name;
 import org.eclipse.jdt.core.dom.NodeFinder;
 import org.eclipse.jdt.core.dom.RecordDeclaration;
 import org.eclipse.jdt.core.dom.SimpleName;
@@ -226,6 +228,21 @@
 		return new SimpleName[] { name };
 	}
 
+	public static Name[] findByNode(ASTNode root, Name name) {
+		Name[] names= findByProblems(root, name);
+		if (names != null) {
+			return names;
+		}
+		int parentKind= name.getParent().getNodeType();
+		if (parentKind == ASTNode.LABELED_STATEMENT || parentKind == ASTNode.BREAK_STATEMENT || parentKind == ASTNode.CONTINUE_STATEMENT) {
+			ArrayList<Name> res= new ArrayList<>();
+			QLabelFinder nodeFinder= new QLabelFinder(name, res);
+			root.accept(nodeFinder);
+			return res.toArray(new Name[res.size()]);
+		}
+		return new Name[] { name };
+	}
+
 
 
 	private static final int FIELD= 1;
@@ -266,6 +283,21 @@
 		return 0;
 	}
 
+	private static int getNameNodeProblemKind(IProblem[] problems, Name nameNode) {
+		int nameOffset= nameNode.getStartPosition();
+		int nameInclEnd= nameOffset + nameNode.getLength() - 1;
+
+		for (IProblem curr : problems) {
+			if (curr.getSourceStart() == nameOffset && curr.getSourceEnd() == nameInclEnd) {
+				int kind= getProblemKind(curr);
+				if (kind != 0) {
+					return kind;
+				}
+			}
+		}
+		return 0;
+	}
+
 
 	public static SimpleName[] findByProblems(ASTNode parent, SimpleName nameNode) {
 		if (nameNode.getAST().apiLevel() >= ASTHelper.JLS10 && nameNode.isVar()) {
@@ -308,6 +340,42 @@
 		return res.toArray(new SimpleName[res.size()]);
 	}
 
+	public static Name[] findByProblems(ASTNode parent, Name nameNode) {
+		ArrayList<Name> res= new ArrayList<>();
+
+		ASTNode astRoot = parent.getRoot();
+		if (!(astRoot instanceof CompilationUnit)) {
+			return null;
+		}
+
+		IProblem[] problems= ((CompilationUnit) astRoot).getProblems();
+		int nameNodeKind= getNameNodeProblemKind(problems, nameNode);
+		if (nameNodeKind == 0) { // no problem on node
+			return null;
+		}
+
+		int bodyStart= parent.getStartPosition();
+		int bodyEnd= bodyStart + parent.getLength();
+
+		String name= nameNode.getFullyQualifiedName();
+
+		for (IProblem curr : problems) {
+			int probStart= curr.getSourceStart();
+			int probEnd= curr.getSourceEnd() + 1;
+
+			if (probStart > bodyStart && probEnd < bodyEnd) {
+				int currKind= getProblemKind(curr);
+				if ((nameNodeKind & currKind) != 0) {
+					ASTNode node= NodeFinder.perform(parent, probStart, (probEnd - probStart));
+					if (node instanceof Name && name.equals(((Name) node).getFullyQualifiedName())) {
+						res.add((Name) node);
+					}
+				}
+			}
+		}
+		return res.toArray(new Name[res.size()]);
+	}
+
 	private static class LabelFinder extends ASTVisitor {
 
 		private SimpleName fLabel;
@@ -357,6 +425,37 @@
 		}
 	}
 
+	private static class QLabelFinder extends ASTVisitor {
+
+		private Name fLabel;
+		private ASTNode fDefiningLabel;
+		private ArrayList<Name> fResult;
+
+		public QLabelFinder(Name label, ArrayList<Name> result) {
+			super(true);
+			fLabel= label;
+			fResult= result;
+			fDefiningLabel= null;
+		}
+
+		private boolean isSameLabel(Name label) {
+			return label != null && fLabel.getFullyQualifiedName().equals(label.getFullyQualifiedName());
+		}
+
+		@Override
+		public boolean visit(ModuleDeclaration node) {
+			if (fDefiningLabel == null) {
+				Name label= node.getName();
+				if (fLabel == label || isSameLabel(label) && ASTNodes.isParent(fLabel, node)) {
+					fDefiningLabel= node;
+					fResult.add(label);
+				}
+			}
+			node.getName().accept(this);
+			return false;
+		}
+	}
+
 	private static class BindingFinder extends ASTVisitor {
 
 		private IBinding fBinding;
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AbstractSerialVersionOperationCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AbstractSerialVersionOperationCore.java
index 13792b4..20a7ac5 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AbstractSerialVersionOperationCore.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AbstractSerialVersionOperationCore.java
@@ -125,7 +125,7 @@
 			}
 
 			final String comment= CodeGeneration.getFieldComment(fUnit, declaration.getType().toString(), NAME_FIELD, StubUtility.getLineDelimiterUsed(fUnit));
-			if (comment != null && comment.length() > 0 && !"/**\n *\n */\n".equals(comment)) { //$NON-NLS-1$
+			if (comment != null && comment.length() > 0 && !comment.matches("[/\\* \t\n]*")) { //$NON-NLS-1$
 				final Javadoc doc= (Javadoc) rewrite.createStringPlaceholder(comment, ASTNode.JAVADOC);
 				declaration.setJavadoc(doc);
 			}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchExpressionsFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchExpressionsFixCore.java
index dc4e17f..4f01bc7 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchExpressionsFixCore.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchExpressionsFixCore.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2020, 2021 Red Hat Inc. and others.
+ * Copyright (c) 2020, 2022 Red Hat Inc. and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -199,6 +199,8 @@
 					if (exp instanceof Name) {
 						commonAssignmentName= ((Name)exp).getFullyQualifiedName();
 						assignmentBinding= ((Name) exp).resolveBinding();
+					} else {
+						return null;
 					}
 				} else {
 					Expression exp= assignment.getLeftHandSide();
@@ -207,6 +209,8 @@
 						if (!name.getFullyQualifiedName().equals(commonAssignmentName)) {
 							return null;
 						}
+					} else {
+						return null;
 					}
 				}
 			}
@@ -260,91 +264,107 @@
 			Expression newSwitchExpressionExpression= (Expression)rewrite.createCopyTarget(switchStatement.getExpression());
 			newSwitchExpression.setExpression(newSwitchExpressionExpression);
 			SwitchCase lastSwitchCase= null;
+
+			boolean forceOldStyle= false;
+			// if there are comments at end of case statements, we have to use old style cases
+			for (Map.Entry<SwitchCase, List<Statement>> entry : caseMap.entrySet()) {
+				SwitchCase oldSwitchCase= entry.getKey();
+				List<Comment> trailingComments= ASTNodes.getTrailingComments(oldSwitchCase);
+				if (trailingComments != null && !trailingComments.isEmpty()) {
+					forceOldStyle= true;
+					break;
+				}
+			}
+
 			// build switch expression
 			for (Map.Entry<SwitchCase, List<Statement>> entry : caseMap.entrySet()) {
 				SwitchCase oldSwitchCase= entry.getKey();
 				List<Statement> oldStatements= entry.getValue();
 				if (oldStatements.isEmpty()) {
-					// fall-through, want all fall-through labels in single case
-					if (lastSwitchCase == null) {
-						lastSwitchCase= ast.newSwitchCase();
-						lastSwitchCase.setSwitchLabeledRule(true);
-						newSwitchExpression.statements().add(lastSwitchCase);
-					}
-					for (Object obj : oldSwitchCase.expressions()) {
-						Expression oldExpression= (Expression)obj;
-						Expression newExpression= (Expression)rewrite.createCopyTarget(oldExpression);
-						lastSwitchCase.expressions().add(newExpression);
+					if (forceOldStyle) {
+						SwitchCase newSwitchCase= (SwitchCase)rewrite.createCopyTarget(oldSwitchCase);
+						newSwitchExpression.statements().add(newSwitchCase);
+					} else {
+						// fall-through, want all fall-through labels in single case
+						if (lastSwitchCase == null) {
+							lastSwitchCase= ast.newSwitchCase();
+							lastSwitchCase.setSwitchLabeledRule(true);
+							newSwitchExpression.statements().add(lastSwitchCase);
+						}
+						for (Object obj : oldSwitchCase.expressions()) {
+							Expression oldExpression= (Expression)obj;
+							Expression newExpression= (Expression)rewrite.createCopyTarget(oldExpression);
+							lastSwitchCase.expressions().add(newExpression);
+						}
 					}
 					continue;
 				}
 				SwitchCase switchCase= null;
-				if (lastSwitchCase == null) {
-					SwitchCase newSwitchCase= ast.newSwitchCase();
+				boolean needDuplicateDefault= false;
+				if (forceOldStyle) {
+					SwitchCase newSwitchCase= (SwitchCase)rewrite.createCopyTarget(oldSwitchCase);
 					newSwitchExpression.statements().add(newSwitchCase);
-					newSwitchCase.setSwitchLabeledRule(true);
-					switchCase= newSwitchCase;
 				} else {
-					switchCase= lastSwitchCase;
-				}
-				lastSwitchCase= null;
-				for (Object obj : oldSwitchCase.expressions()) {
-					Expression oldExpression= (Expression)obj;
-					Expression newExpression= (Expression)rewrite.createCopyTarget(oldExpression);
-					switchCase.expressions().add(newExpression);
-				}
-				if (oldStatements.size() == 1 && oldStatements.get(0) instanceof Block) {
-					oldStatements= ((Block)oldStatements.get(0)).statements();
-				}
-				if (oldStatements.size() == 1) {
-					Statement oldStatement= oldStatements.get(0);
-					Statement newStatement= null;
-					if (oldStatement instanceof ThrowStatement) {
-						ThrowStatement throwStatement= (ThrowStatement)oldStatement;
-						newStatement= (Statement)rewrite.createCopyTarget(throwStatement);
+					if (lastSwitchCase == null) {
+						SwitchCase newSwitchCase= ast.newSwitchCase();
+						newSwitchExpression.statements().add(newSwitchCase);
+						newSwitchCase.setSwitchLabeledRule(true);
+						switchCase= newSwitchCase;
 					} else {
-						ExpressionStatement oldExpStatement= (ExpressionStatement)oldStatement;
-						Assignment oldAssignment= (Assignment)oldExpStatement.getExpression();
-						Expression rhs= oldAssignment.getRightHandSide();
-						// Ugly hack to tack on trailing comments
-						IBuffer buffer= cuRewrite.getCu().getBuffer();
-						StringBuilder b= new StringBuilder();
-						b.append(buffer.getText(rhs.getStartPosition(), rhs.getLength()) + ";"); //$NON-NLS-1$
-						List<Comment> trailingComments= ASTNodes.getTrailingComments(oldExpStatement);
-						for (Comment comment : trailingComments) {
-							b.append(" " + buffer.getText(comment.getStartPosition(), comment.getLength())); //$NON-NLS-1$
-						}
-						newStatement= (Statement) rewrite.createStringPlaceholder(b.toString(), ASTNode.EXPRESSION_STATEMENT);
+						switchCase= lastSwitchCase;
 					}
-					newSwitchExpression.statements().add(newStatement);
-				} else {
-					Block newBlock= ast.newBlock();
-					int statementsLen= oldStatements.size();
-					for (int i= 0; i < statementsLen - 1; ++i) {
-						Statement oldSwitchCaseStatement= oldStatements.get(i);
-						newBlock.statements().add(rewrite.createCopyTarget(oldSwitchCaseStatement));
+					if (lastSwitchCase != null
+							&& oldSwitchCase.expressions().isEmpty()) {
+						// Original switch had fall-through into default case so
+						// we will need to duplicate the statements from the default case
+						// to a new case statement that has all fall-through expressions
+						// and to a new default case that uses new syntax
+						needDuplicateDefault= true;
 					}
-					ExpressionStatement oldExpStatement= (ExpressionStatement)oldStatements.get(statementsLen - 1);
-					Assignment oldAssignment= (Assignment)oldExpStatement.getExpression();
-					Expression rhs= oldAssignment.getRightHandSide();
-					IBuffer buffer= cuRewrite.getCu().getBuffer();
-					StringBuilder b= new StringBuilder();
-					List<Comment> leadingComments= ASTNodes.getLeadingComments(oldExpStatement);
-					for (Comment comment : leadingComments) {
-						b.append(buffer.getText(comment.getStartPosition(), comment.getLength()) + "\n"); //$NON-NLS-1$
+					lastSwitchCase= null;
+					for (Object obj : oldSwitchCase.expressions()) {
+						Expression oldExpression= (Expression)obj;
+						Expression newExpression= (Expression)rewrite.createCopyTarget(oldExpression);
+						switchCase.expressions().add(newExpression);
 					}
-					b.append("yield "); //$NON-NLS-1$
-					List<Comment> trailingComments= ASTNodes.getTrailingComments(oldExpStatement);
-					b.append(buffer.getText(rhs.getStartPosition(), rhs.getLength()) + ";"); //$NON-NLS-1$
-					for (Comment comment : trailingComments) {
-						b.append(" " + buffer.getText(comment.getStartPosition(), comment.getLength())); //$NON-NLS-1$
-					}
+				}
 
-					YieldStatement newYield = (YieldStatement)rewrite.createStringPlaceholder(b.toString(), ASTNode.YIELD_STATEMENT);
-					Expression newYieldExpression= (Expression) rewrite.createStringPlaceholder(b.toString(), rhs.getNodeType());
-					newYield.setExpression(newYieldExpression);
-					newBlock.statements().add(newYield);
-					newSwitchExpression.statements().add(newBlock);
+				while (true) {
+					if (oldStatements.size() == 1 && oldStatements.get(0) instanceof Block) {
+						oldStatements= ((Block)oldStatements.get(0)).statements();
+					}
+					if (oldStatements.size() == 1) {
+						Statement oldStatement= oldStatements.get(0);
+						Statement newStatement= null;
+						if (oldStatement instanceof ThrowStatement) {
+							ThrowStatement throwStatement= (ThrowStatement)oldStatement;
+							newStatement= (Statement)rewrite.createCopyTarget(throwStatement);
+						} else if (forceOldStyle) {
+							newStatement= getNewYieldStatement(cuRewrite, rewrite, (ExpressionStatement)oldStatement);
+						} else {
+							newStatement= getNewStatementForCase(cuRewrite, rewrite, oldStatement);
+						}
+						newSwitchExpression.statements().add(newStatement);
+					} else {
+						Block newBlock= ast.newBlock();
+						int statementsLen= oldStatements.size();
+						for (int i= 0; i < statementsLen - 1; ++i) {
+							Statement oldSwitchCaseStatement= oldStatements.get(i);
+							newBlock.statements().add(rewrite.createCopyTarget(oldSwitchCaseStatement));
+						}
+						YieldStatement newYield= getNewYieldStatement(cuRewrite, rewrite, (ExpressionStatement)oldStatements.get(statementsLen-1));
+						newBlock.statements().add(newYield);
+						newSwitchExpression.statements().add(newBlock);
+					}
+					if (needDuplicateDefault) {
+						needDuplicateDefault= false;
+						SwitchCase newSwitchCase= ast.newSwitchCase();
+						newSwitchExpression.statements().add(newSwitchCase);
+						newSwitchCase.setSwitchLabeledRule(true);
+						switchCase= newSwitchCase;
+					} else {
+						break;
+					}
 				}
 			}
 
@@ -413,6 +433,45 @@
 			}
 		}
 
+		private Statement getNewStatementForCase(CompilationUnitRewrite cuRewrite, final ASTRewrite rewrite, Statement oldStatement) throws JavaModelException {
+			Statement newStatement;
+			ExpressionStatement oldExpStatement= (ExpressionStatement)oldStatement;
+			Assignment oldAssignment= (Assignment)oldExpStatement.getExpression();
+			Expression rhs= oldAssignment.getRightHandSide();
+			// Ugly hack to tack on trailing comments
+			IBuffer buffer= cuRewrite.getCu().getBuffer();
+			StringBuilder b= new StringBuilder();
+			b.append(buffer.getText(rhs.getStartPosition(), rhs.getLength()) + ";"); //$NON-NLS-1$
+			List<Comment> trailingComments= ASTNodes.getTrailingComments(oldExpStatement);
+			for (Comment comment : trailingComments) {
+				b.append(" " + buffer.getText(comment.getStartPosition(), comment.getLength())); //$NON-NLS-1$
+			}
+			newStatement= (Statement) rewrite.createStringPlaceholder(b.toString(), ASTNode.EXPRESSION_STATEMENT);
+			return newStatement;
+		}
+
+		private YieldStatement getNewYieldStatement(CompilationUnitRewrite cuRewrite, final ASTRewrite rewrite, ExpressionStatement oldExpStatement) throws JavaModelException {
+			Assignment oldAssignment= (Assignment)oldExpStatement.getExpression();
+			Expression rhs= oldAssignment.getRightHandSide();
+			IBuffer buffer= cuRewrite.getCu().getBuffer();
+			StringBuilder b= new StringBuilder();
+			List<Comment> leadingComments= ASTNodes.getLeadingComments(oldExpStatement);
+			for (Comment comment : leadingComments) {
+				b.append(buffer.getText(comment.getStartPosition(), comment.getLength()) + "\n"); //$NON-NLS-1$
+			}
+			b.append("yield "); //$NON-NLS-1$
+			List<Comment> trailingComments= ASTNodes.getTrailingComments(oldExpStatement);
+			b.append(buffer.getText(rhs.getStartPosition(), rhs.getLength()) + ";"); //$NON-NLS-1$
+			for (Comment comment : trailingComments) {
+				b.append(" " + buffer.getText(comment.getStartPosition(), comment.getLength())); //$NON-NLS-1$
+			}
+
+			YieldStatement newYield = (YieldStatement)rewrite.createStringPlaceholder(b.toString(), ASTNode.YIELD_STATEMENT);
+			Expression newYieldExpression= (Expression) rewrite.createStringPlaceholder(b.toString(), rhs.getNodeType());
+			newYield.setExpression(newYieldExpression);
+			return newYield;
+		}
+
 		private void replaceWithLeadingComments(CompilationUnitRewrite cuRewrite, ListRewrite listRewrite,
 				ASTNode oldNode, TextEditGroup group, ASTNode newNode) throws JavaModelException {
 			ASTRewrite rewrite= cuRewrite.getASTRewrite();
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchFixCore.java
index d21c76c..068b04a 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchFixCore.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/SwitchFixCore.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ * Copyright (c) 2021, 2022 Fabrice TIERCELIN and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -18,7 +18,6 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Objects;
 import java.util.Set;
 
 import org.eclipse.core.runtime.CoreException;
@@ -39,11 +38,11 @@
 import org.eclipse.jdt.core.dom.IfStatement;
 import org.eclipse.jdt.core.dom.InfixExpression;
 import org.eclipse.jdt.core.dom.Name;
-import org.eclipse.jdt.core.dom.SimpleName;
 import org.eclipse.jdt.core.dom.Statement;
 import org.eclipse.jdt.core.dom.SuperFieldAccess;
 import org.eclipse.jdt.core.dom.SwitchCase;
 import org.eclipse.jdt.core.dom.SwitchStatement;
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
 import org.eclipse.jdt.core.dom.WhileStatement;
 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
 import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer;
@@ -160,7 +159,6 @@
 				List<SwitchCaseSection> cases= new ArrayList<>();
 				Statement remainingStatement= null;
 
-				Set<SimpleName> variableDeclarationIds= new HashSet<>();
 				IfStatement ifStatement= visited;
 				boolean isFallingThrough= true;
 
@@ -168,11 +166,6 @@
 					IfStatement currentNode= ifStatement;
 
 					while (ASTNodes.isSameVariable(switchExpression, variable.name)) {
-						if (detectDeclarationConflicts(currentNode.getThenStatement(), variableDeclarationIds)) {
-							// Cannot declare two variables with the same name in two cases
-							return true;
-						}
-
 						cases.add(new SwitchCaseSection(variable.constantValues,
 								ASTNodes.asList(currentNode.getThenStatement())));
 
@@ -226,25 +219,6 @@
 				return hasUnlabeledBreakVisitor.hasUnlabeledBreak;
 			}
 
-			private boolean detectDeclarationConflicts(final Statement statement, final Set<SimpleName> variableDeclarationIds) {
-				Set<SimpleName> varNames= ASTNodes.getLocalVariableIdentifiers(statement, false);
-				boolean hasConflict= containsAny(variableDeclarationIds, varNames);
-				variableDeclarationIds.addAll(varNames);
-				return hasConflict;
-			}
-
-			private boolean containsAny(final Set<SimpleName> variableDeclarations, final Set<SimpleName> varNames) {
-				for (SimpleName varName : varNames) {
-					for (SimpleName variableDeclaration : variableDeclarations) {
-						if (varName.getIdentifier() != null && Objects.equals(varName.getIdentifier(), variableDeclaration.getIdentifier())) {
-							return true;
-						}
-					}
-				}
-
-				return false;
-			}
-
 			/**
 			 * Side-effect: removes the dead branches in a chain of if-elseif.
 			 *
@@ -406,12 +380,19 @@
 				switchStatements.add(ast.newSwitchCase());
 			}
 
+			List<Statement> statementsList= switchStatement.statements();
 			boolean isBreakNeeded= true;
+			boolean needBlock= checkForLocalDeclarations(innerStatements);
+			Block block= null;
+			if (needBlock) {
+				block= ast.newBlock();
+				statementsList= block.statements();
+			}
 
 			// Add the statement(s) for this case(s)
 			if (!innerStatements.isEmpty()) {
 				for (Statement statement : innerStatements) {
-					switchStatements.add(ASTNodes.createMoveTarget(rewrite, statement));
+					statementsList.add(ASTNodes.createMoveTarget(rewrite, statement));
 				}
 
 				isBreakNeeded= !ASTNodes.fallsThrough(innerStatements.get(innerStatements.size() - 1));
@@ -419,8 +400,21 @@
 
 			// When required: end with a break
 			if (isBreakNeeded) {
-				switchStatements.add(ast.newBreakStatement());
+				statementsList.add(ast.newBreakStatement());
 			}
+
+			if (needBlock) {
+				switchStatements.add(block);
+			}
+		}
+
+		private boolean checkForLocalDeclarations(final List<Statement> statements) {
+			for (Statement statement : statements) {
+				if (statement instanceof VariableDeclarationStatement) {
+					return true;
+				}
+			}
+			return false;
 		}
 	}
 
@@ -468,5 +462,6 @@
 			this.literalExpressions= literalExpressions;
 			this.statements= statements;
 		}
+
 	}
 }
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/UnusedCodeFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/UnusedCodeFixCore.java
index cfe292e..1f10265 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/UnusedCodeFixCore.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/UnusedCodeFixCore.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2019 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
@@ -487,7 +487,12 @@
 				removeStatement(rewrite, statementNode, group);
 				fRemovedAssignmentsCount++;
 			} else {
-				ASTNode initNode = rewrite.createMoveTarget(initializerNode);
+				// Can't create a field access expression statement so remove right-hand field accesses
+				ASTNode nodeToMove= initializerNode;
+				while (nodeToMove instanceof FieldAccess) {
+					nodeToMove= ((FieldAccess)nodeToMove).getExpression();
+				}
+				ASTNode initNode = rewrite.createMoveTarget(nodeToMove);
 				ExpressionStatement statement = rewrite.getAST().newExpressionStatement((Expression) initNode);
 				rewrite.replace(statementNode, statement, null);
 				fAlteredAssignmentsCount++;
diff --git a/org.eclipse.jdt.core.manipulation/pom.xml b/org.eclipse.jdt.core.manipulation/pom.xml
index f47dcba..17129c2 100644
--- a/org.eclipse.jdt.core.manipulation/pom.xml
+++ b/org.eclipse.jdt.core.manipulation/pom.xml
@@ -18,6 +18,6 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.core.manipulation</artifactId>
-  <version>1.15.200-SNAPSHOT</version>
+  <version>1.16.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>
diff --git a/org.eclipse.jdt.jeview.feature/feature.xml b/org.eclipse.jdt.jeview.feature/feature.xml
index be17dab..56e0b06 100644
--- a/org.eclipse.jdt.jeview.feature/feature.xml
+++ b/org.eclipse.jdt.jeview.feature/feature.xml
@@ -2,13 +2,13 @@
 <feature
       id="org.eclipse.jdt.jeview.feature"
       label="JavaElement View"
-      version="1.0.12.qualifier"
+      version="1.0.13.qualifier"
       provider-name="Eclipse.org"
       license-feature="org.eclipse.license"
       license-feature-version="0.0.0">
 
    <description>
-      JavaElement View for Eclipse 2020-12 and later (jdt.core 3.24)
+      JavaElement View for Eclipse 2021-12 and later (jdt.core 3.28)
    </description>
 
    <license url="%licenseURL">
@@ -20,8 +20,8 @@
    </url>
 
    <requires>
-      <import plugin="org.eclipse.jdt.core" version="3.24.0" match="compatible"/>
-      <import plugin="org.eclipse.jdt.ui" version="3.22.0" match="compatible"/>
+      <import plugin="org.eclipse.jdt.core" version="3.28.0" match="compatible"/>
+      <import plugin="org.eclipse.jdt.ui" version="3.25.0" match="compatible"/>
       <import plugin="org.eclipse.ui"/>
       <import plugin="org.eclipse.core.runtime"/>
       <import plugin="org.eclipse.core.resources"/>
@@ -29,7 +29,7 @@
       <import plugin="org.eclipse.ui.ide"/>
       <import plugin="org.eclipse.ui.views"/>
       <import plugin="org.eclipse.ui.workbench.texteditor"/>
-      <import plugin="org.eclipse.ui.workbench" version="3.122" match="compatible"/>
+      <import plugin="org.eclipse.ui.workbench" version="3.124" match="compatible"/>
    </requires>
 
    <plugin
diff --git a/org.eclipse.jdt.jeview.feature/pom.xml b/org.eclipse.jdt.jeview.feature/pom.xml
index 2be1fba..5cee192 100644
--- a/org.eclipse.jdt.jeview.feature/pom.xml
+++ b/org.eclipse.jdt.jeview.feature/pom.xml
@@ -18,6 +18,6 @@
   </parent>
   <groupId>org.eclipse.jdt.feature</groupId>
   <artifactId>org.eclipse.jdt.jeview.feature</artifactId>
-  <version>1.0.12-SNAPSHOT</version>
+  <version>1.0.13-SNAPSHOT</version>
   <packaging>eclipse-feature</packaging>
 </project>
diff --git a/org.eclipse.jdt.junit.core/META-INF/MANIFEST.MF b/org.eclipse.jdt.junit.core/META-INF/MANIFEST.MF
index 063390e..9e2082d 100644
--- a/org.eclipse.jdt.junit.core/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.junit.core/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.junit.core;singleton:=true
-Bundle-Version: 3.11.100.qualifier
+Bundle-Version: 3.11.200.qualifier
 Bundle-Activator: org.eclipse.jdt.internal.junit.JUnitCorePlugin
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %providerName
diff --git a/org.eclipse.jdt.junit.core/pom.xml b/org.eclipse.jdt.junit.core/pom.xml
index 08482db..ba1ab1f 100644
--- a/org.eclipse.jdt.junit.core/pom.xml
+++ b/org.eclipse.jdt.junit.core/pom.xml
@@ -18,6 +18,6 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.junit.core</artifactId>
-  <version>3.11.100-SNAPSHOT</version>
+  <version>3.11.200-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitPreferencesConstants.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitPreferencesConstants.java
index 37ec38c..18cffe1 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitPreferencesConstants.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JUnitPreferencesConstants.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
@@ -15,7 +15,6 @@
 package org.eclipse.jdt.internal.junit;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.StringTokenizer;
 
@@ -174,8 +173,8 @@
 	 *
 	 * @return list
 	 */
-	public static List<String> createDefaultStackFiltersList() {
-		return Arrays.asList(fgDefaultFilterPatterns);
+	public static String[] createDefaultStackFiltersList() {
+		return fgDefaultFilterPatterns;
 	}
 
 	/**
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JunitPreferenceInitializer.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JunitPreferenceInitializer.java
index 45a1f53..f8f1271 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JunitPreferenceInitializer.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/internal/junit/JunitPreferenceInitializer.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
@@ -14,8 +14,6 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.junit;
 
-import java.util.List;
-
 import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
 import org.eclipse.core.runtime.preferences.DefaultScope;
 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
@@ -35,8 +33,7 @@
 		prefs.putBoolean(JUnitPreferencesConstants.SHOW_ON_ERROR_ONLY, false);
 		prefs.putBoolean(JUnitPreferencesConstants.ENABLE_ASSERTIONS, JUnitPreferencesConstants.ENABLE_ASSERTIONS_DEFAULT);
 
-		List<String> defaults= JUnitPreferencesConstants.createDefaultStackFiltersList();
-		String[] filters= defaults.toArray(new String[defaults.size()]);
+		String[] filters= JUnitPreferencesConstants.createDefaultStackFiltersList();
 		String active= JUnitPreferencesConstants.serializeList(filters);
 		prefs.put(JUnitPreferencesConstants.PREF_ACTIVE_FILTERS_LIST, active);
 		prefs.put(JUnitPreferencesConstants.PREF_INACTIVE_FILTERS_LIST, ""); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.java b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.java
index 4c051b2..8000929 100644
--- a/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.java
+++ b/org.eclipse.jdt.junit.core/src/org/eclipse/jdt/junit/launcher/JUnitLaunchConfigurationDelegate.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
@@ -213,7 +213,7 @@
 					if (!Arrays.stream(classpath).anyMatch(s -> s.contains("junit-jupiter-engine") || s.contains("org.junit.jupiter.engine"))) { //$NON-NLS-1$ //$NON-NLS-2$
 						try {
 							JUnitRuntimeClasspathEntry x= new JUnitRuntimeClasspathEntry("org.junit.jupiter.engine", null); //$NON-NLS-1$
-							String entryString= new ClasspathLocalizer(Platform.inDevelopmentMode()).entryString(x);
+							String entryString= new ClasspathLocalizer(false).entryString(x);
 							int length= classpath.length;
 							System.arraycopy(classpath, 0, classpath= new String[length + 1], 0, length);
 							classpath[length]= entryString;
@@ -221,7 +221,18 @@
 							throw new CoreException(new Status(IStatus.ERROR, JUnitCorePlugin.CORE_PLUGIN_ID, IStatus.ERROR, "", e)); //$NON-NLS-1$
 						}
 					}
-			}
+					if (!Arrays.stream(classpath).anyMatch(s -> s.contains("junit-jupiter-api") || s.contains("org.junit.jupiter.api"))) { //$NON-NLS-1$ //$NON-NLS-2$
+						try {
+							JUnitRuntimeClasspathEntry x= new JUnitRuntimeClasspathEntry("org.junit.jupiter.api", null); //$NON-NLS-1$
+							String entryString= new ClasspathLocalizer(false).entryString(x);
+							int length= classpath.length;
+							System.arraycopy(classpath, 0, classpath= new String[length + 1], 0, length);
+							classpath[length]= entryString;
+						} catch (IOException | URISyntaxException e) {
+							throw new CoreException(new Status(IStatus.ERROR, JUnitCorePlugin.CORE_PLUGIN_ID, IStatus.ERROR, "", e)); //$NON-NLS-1$
+						}
+					}
+				}
 			}
 
 			// Create VM config
diff --git a/org.eclipse.jdt.junit/META-INF/MANIFEST.MF b/org.eclipse.jdt.junit/META-INF/MANIFEST.MF
index e486afe..3572aea 100644
--- a/org.eclipse.jdt.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.junit/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.junit;singleton:=true
-Bundle-Version: 3.13.0.qualifier
+Bundle-Version: 3.14.0.qualifier
 Bundle-Activator: org.eclipse.jdt.internal.junit.ui.JUnitPlugin
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %providerName
@@ -28,7 +28,7 @@
  org.eclipse.debug.core;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.debug.ui;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.jdt.core;bundle-version="[3.18.0,4.0.0)",
- org.eclipse.jdt.ui;bundle-version="[3.17.100,4.0.0)",
+ org.eclipse.jdt.ui;bundle-version="[3.26.0,4.0.0)",
  org.eclipse.core.runtime;bundle-version="[3.11.0,4.0.0)",
  org.eclipse.jdt.launching;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.jdt.debug.ui;bundle-version="[3.3.0,4.0.0)",
@@ -37,7 +37,7 @@
  org.eclipse.ltk.core.refactoring;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.core.variables;bundle-version="[3.2.200,4.0.0)",
  org.eclipse.ltk.ui.refactoring;bundle-version="[3.5.0,4.0.0)",
- org.eclipse.jdt.junit.core;bundle-version="[3.6.0,4.0.0)";visibility:=reexport,
+ org.eclipse.jdt.junit.core;bundle-version="[3.11.200,4.0.0)";visibility:=reexport,
  com.ibm.icu;bundle-version="4.4.2",
  org.eclipse.jdt.core.manipulation;bundle-version="1.9.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-11
diff --git a/org.eclipse.jdt.junit/pom.xml b/org.eclipse.jdt.junit/pom.xml
index b7af641..b774c48 100644
--- a/org.eclipse.jdt.junit/pom.xml
+++ b/org.eclipse.jdt.junit/pom.xml
@@ -18,6 +18,6 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.junit</artifactId>
-  <version>3.13.0-SNAPSHOT</version>
+  <version>3.14.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>
diff --git a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitPreferencePage.java b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitPreferencePage.java
index 1d9a8c8..d5ab5ce 100644
--- a/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitPreferencePage.java
+++ b/org.eclipse.jdt.junit/src/org/eclipse/jdt/internal/junit/ui/JUnitPreferencePage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 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
@@ -14,77 +14,37 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.junit.ui;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-
-import org.eclipse.osgi.util.TextProcessor;
 
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.TableEditor;
-import org.eclipse.swt.events.FocusAdapter;
-import org.eclipse.swt.events.FocusEvent;
-import org.eclipse.swt.events.KeyAdapter;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.TableColumn;
-import org.eclipse.swt.widgets.TableItem;
-import org.eclipse.swt.widgets.Text;
 
 import org.eclipse.core.runtime.preferences.DefaultScope;
 import org.eclipse.core.runtime.preferences.InstanceScope;
 
 import org.eclipse.jface.dialogs.Dialog;
 import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.preference.PreferencePage;
-import org.eclipse.jface.resource.JFaceResources;
-import org.eclipse.jface.viewers.CheckboxTableViewer;
-import org.eclipse.jface.viewers.ColumnWeightData;
-import org.eclipse.jface.viewers.ContentViewer;
-import org.eclipse.jface.viewers.ILabelProvider;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.viewers.ITableLabelProvider;
-import org.eclipse.jface.viewers.LabelProvider;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerComparator;
-import org.eclipse.jface.window.Window;
 
 import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.IWorkbenchPreferencePage;
 import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.dialogs.SelectionDialog;
 import org.eclipse.ui.preferences.ScopedPreferenceStore;
-import org.eclipse.ui.progress.IProgressService;
-
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchEngine;
 
 import org.eclipse.jdt.internal.junit.JUnitCorePlugin;
 import org.eclipse.jdt.internal.junit.JUnitPreferencesConstants;
 import org.eclipse.jdt.internal.junit.launcher.AssertionVMArg;
-import org.eclipse.jdt.internal.junit.util.ExceptionHandler;
-import org.eclipse.jdt.internal.junit.util.LayoutUtil;
 
-import org.eclipse.jdt.ui.IJavaElementSearchConstants;
-import org.eclipse.jdt.ui.ISharedImages;
-import org.eclipse.jdt.ui.JavaUI;
-
+import org.eclipse.jdt.internal.ui.filtertable.FilterManager;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.ButtonLabel;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.DialogLabels;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.FilterTableConfig;
 import org.eclipse.jdt.internal.ui.util.SWTUtil;
-import org.eclipse.jdt.internal.ui.util.TableLayoutComposite;
 
 /**
  * Preference page for JUnit settings. Supports to define the failure
@@ -92,241 +52,38 @@
  */
 public class JUnitPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
 
-	private static final String DEFAULT_NEW_FILTER_TEXT= ""; //$NON-NLS-1$
-	private static final Image IMG_CUNIT= JavaUI.getSharedImages().getImage(ISharedImages.IMG_OBJS_CLASS);
-	private static final Image IMG_PKG= JavaUI.getSharedImages().getImage(ISharedImages.IMG_OBJS_PACKAGE);
+	final static FilterManager FILTER_MANAGER = new FilterManager(JUnitPreferencesConstants.PREF_ACTIVE_FILTERS_LIST, JUnitPreferencesConstants.PREF_INACTIVE_FILTERS_LIST) {
+		@Override
+		protected String[] getDefaultActiveFilters(IPreferenceStore store) {
+			return JUnitPreferencesConstants.createDefaultStackFiltersList();
+		}
 
+		@Override
+		protected String[] getDefaultInactiveFilters(IPreferenceStore store) {
+			return new String[0];
+		}
+	};
+
+	private final JavaFilterTable fJavaFilterTable;
 	private Button fEnableAssertionsCheckBox;
 	private Button fShowInAllViewsCheckBox;
 
-	// Step filter widgets
-	private Label fFilterViewerLabel;
-	private CheckboxTableViewer fFilterViewer;
-	private Table fFilterTable;
-
-	private Button fAddPackageButton;
-	private Button fAddTypeButton;
-	private Button fRemoveFilterButton;
-	private Button fAddFilterButton;
-
-	private Button fEnableAllButton;
-	private Button fDisableAllButton;
-
-	private Text fEditorText;
-	private String fInvalidEditorText= null;
-	private TableEditor fTableEditor;
-	private TableItem fNewTableItem;
-	private Filter fNewStackFilter;
-
-	private StackFilterContentProvider fStackFilterContentProvider;
-
-	/**
-	 * Model object that represents a single entry in the filter table.
-	 */
-	private static class Filter {
-
-		private String fName;
-		private boolean fChecked;
-
-		public Filter(String name, boolean checked) {
-			setName(name);
-			setChecked(checked);
-		}
-
-		public String getName() {
-			return fName;
-		}
-
-		public void setName(String name) {
-			fName= name;
-		}
-
-		public boolean isChecked() {
-			return fChecked;
-		}
-
-		public void setChecked(boolean checked) {
-			fChecked= checked;
-		}
-
-		@Override
-		public boolean equals(Object o) {
-			if (!(o instanceof Filter))
-				return false;
-
-			Filter other= (Filter) o;
-			return (getName().equals(other.getName()));
-		}
-
-		@Override
-		public int hashCode() {
-			return fName.hashCode();
-		}
-	}
-
-	/**
-	 * Sorter for the filter table; sorts alphabetically ascending.
-	 */
-	private static class FilterViewerSorter extends ViewerComparator {
-		@Override
-		public int compare(Viewer viewer, Object e1, Object e2) {
-			ILabelProvider lprov= (ILabelProvider) ((ContentViewer) viewer).getLabelProvider();
-			String name1= lprov.getText(e1);
-			String name2= lprov.getText(e2);
-			if (name1 == null)
-				name1= ""; //$NON-NLS-1$
-
-			if (name2 == null)
-				name2= ""; //$NON-NLS-1$
-
-			if (name1.length() > 0 && name2.length() > 0) {
-				boolean isPackage1= name1.indexOf('*') != -1;
-				boolean isPackage2= name2.indexOf('*') != -1;
-				if (isPackage1 && !isPackage2)
-					return -1;
-
-				if (isPackage2 && !isPackage1)
-					return 1;
-			}
-			return getComparator().compare(name1, name2);
-		}
-	}
-
-	/**
-	 * Label provider for Filter model objects
-	 */
-	private static class FilterLabelProvider extends LabelProvider implements ITableLabelProvider {
-
-		@Override
-		public String getColumnText(Object object, int column) {
-			return (column == 0) ? getText(object) : ""; //$NON-NLS-1$
-		}
-
-		@Override
-		public String getText(Object element) {
-			return TextProcessor.process(((Filter) element).getName());
-		}
-
-		@Override
-		public Image getColumnImage(Object object, int column) {
-			String name= ((Filter) object).getName();
-			if (name.contains(".*") || name.equals(JUnitMessages.JUnitMainTab_label_defaultpackage)) {  //$NON-NLS-1$
-				//package
-				return IMG_PKG;
-			} else if ("".equals(name)) { //$NON-NLS-1$
-				//needed for the in-place editor
-				return null;
-			} else if ((Character.isUpperCase(name.charAt(0))) && (name.indexOf('.') < 0)) {
-				//class in default package
-				return IMG_CUNIT;
-			} else {
-				//fully-qualified class or other filter
-				final int lastDotIndex= name.lastIndexOf('.');
-				if ((-1 != lastDotIndex) && ((name.length() - 1) != lastDotIndex) && Character.isUpperCase(name.charAt(lastDotIndex + 1)))
-					return IMG_CUNIT;
-			}
-			//other filter
-			return null;
-		}
-	}
-
-	/**
-	 * Content provider for the filter table.  Content consists of instances of
-	 * Filter.
-	 */
-	private class StackFilterContentProvider implements IStructuredContentProvider {
-
-		private List<Filter> fFilters;
-
-		public StackFilterContentProvider() {
-			List<String> active= createActiveStackFiltersList();
-			List<String> inactive= createInactiveStackFiltersList();
-			populateFilters(active, inactive);
-		}
-
-		public void setDefaults() {
-			fFilterViewer.remove(fFilters.toArray());
-			List<String> active= JUnitPreferencesConstants.createDefaultStackFiltersList();
-			List<String> inactive= new ArrayList<>();
-			populateFilters(active, inactive);
-		}
-
-		protected void populateFilters(List<String> activeList, List<String> inactiveList) {
-			fFilters= new ArrayList<>(activeList.size() + inactiveList.size());
-			populateList(activeList, true);
-			if (!inactiveList.isEmpty())
-				populateList(inactiveList, false);
-		}
-
-		protected void populateList(List<String> list, boolean checked) {
-			Iterator<String> iterator= list.iterator();
-
-			while (iterator.hasNext()) {
-				String name= iterator.next();
-				addFilter(name, checked);
-			}
-		}
-
-		public Filter addFilter(String name, boolean checked) {
-			Filter filter= new Filter(name, checked);
-			if (!fFilters.contains(filter)) {
-				fFilters.add(filter);
-				fFilterViewer.add(filter);
-				fFilterViewer.setChecked(filter, checked);
-			}
-			updateActions();
-			return filter;
-		}
-
-		public void saveFilters() {
-			List<String> active= new ArrayList<>(fFilters.size());
-			List<String> inactive= new ArrayList<>(fFilters.size());
-			Iterator<Filter> iterator= fFilters.iterator();
-			while (iterator.hasNext()) {
-				Filter filter= iterator.next();
-				String name= filter.getName();
-				if (filter.isChecked())
-					active.add(name);
-				else
-					inactive.add(name);
-			}
-			String pref= JUnitPreferencesConstants.serializeList(active.toArray(new String[active.size()]));
-			getPreferenceStore().setValue(JUnitPreferencesConstants.PREF_ACTIVE_FILTERS_LIST, pref);
-			pref= JUnitPreferencesConstants.serializeList(inactive.toArray(new String[inactive.size()]));
-			getPreferenceStore().setValue(JUnitPreferencesConstants.PREF_INACTIVE_FILTERS_LIST, pref);
-		}
-
-		public void removeFilters(Object[] filters) {
-			for (int i= (filters.length - 1); i >= 0; --i) {
-				Filter filter= (Filter) filters[i];
-				fFilters.remove(filter);
-			}
-			fFilterViewer.remove(filters);
-			updateActions();
-		}
-
-		public void toggleFilter(Filter filter) {
-			boolean newState= !filter.isChecked();
-			filter.setChecked(newState);
-			fFilterViewer.setChecked(filter, newState);
-		}
-
-		@Override
-		public Object[] getElements(Object inputElement) {
-			return fFilters.toArray();
-		}
-
-		@Override
-		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
-		@Override
-		public void dispose() {}
-
-	}
-
 	public JUnitPreferencePage() {
 		super();
 		setDescription(JUnitMessages.JUnitPreferencePage_description);
-		setPreferenceStore(new ScopedPreferenceStore(InstanceScope.INSTANCE,JUnitCorePlugin.CORE_PLUGIN_ID));
+		setPreferenceStore(new ScopedPreferenceStore(InstanceScope.INSTANCE, JUnitCorePlugin.CORE_PLUGIN_ID));
+		fJavaFilterTable = new JavaFilterTable(this, FILTER_MANAGER,
+				new FilterTableConfig()
+					.setLabelText(JUnitMessages.JUnitPreferencePage_filter_label)
+					.setAddFilter(new ButtonLabel(JUnitMessages.JUnitPreferencePage_addfilterbutton_label))
+					.setAddType(new ButtonLabel(JUnitMessages.JUnitPreferencePage_addtypebutton_label))
+					.setAddTypeDialog(new DialogLabels(JUnitMessages.JUnitPreferencePage_addtypedialog_title, JUnitMessages.JUnitPreferencePage_addtypedialog_message))
+					.setAddPackage(new ButtonLabel(JUnitMessages.JUnitPreferencePage_addpackagebutton_label))
+					.setAddPackageDialog(new DialogLabels(JUnitMessages.JUnitPreferencePage_addpackagedialog_title, JUnitMessages.JUnitPreferencePage_addpackagedialog_message))
+					.setRemove(new ButtonLabel(JUnitMessages.JUnitPreferencePage_removefilterbutton_label))
+					.setSelectAll(new ButtonLabel(JUnitMessages.JUnitPreferencePage_enableallbutton_label))
+					.setDeselectAll(new ButtonLabel(JUnitMessages.JUnitPreferencePage_disableallbutton_label))
+					.setHelpContextId(IJUnitHelpContextIds.JUNIT_PREFERENCE_PAGE));
 	}
 
 	@Override
@@ -346,11 +103,24 @@
 
 		createEnableAssertionsCheckbox(composite);
 		createShowInAllViewsCheckbox(composite);
-		createStackFilterPreferences(composite);
+		createJavaFilterTable(composite);
 		Dialog.applyDialogFont(composite);
 		return composite;
 	}
 
+	private void createJavaFilterTable(Composite parent) {
+		Composite container= new Composite(parent, SWT.NONE);
+		GridLayout layout= new GridLayout();
+		layout.numColumns= 2;
+		layout.marginHeight= 0;
+		layout.marginWidth= 0;
+		container.setLayout(layout);
+		GridData gd= new GridData(GridData.FILL_BOTH);
+		container.setLayoutData(gd);
+
+		fJavaFilterTable.createTable(container);
+	}
+
 	private void createEnableAssertionsCheckbox(Composite container) {
 		fEnableAssertionsCheckBox= new Button(container, SWT.CHECK | SWT.WRAP);
 		fEnableAssertionsCheckBox.setText(JUnitMessages.JUnitPreferencePage_enableassertionscheckbox_label);
@@ -389,108 +159,6 @@
 		fShowInAllViewsCheckBox.setSelection(selected);
 	}
 
-	/*
-	 * Create a group to contain the step filter related widgets
-	 */
-	private void createStackFilterPreferences(Composite composite) {
-		fFilterViewerLabel= new Label(composite, SWT.SINGLE | SWT.LEFT);
-		fFilterViewerLabel.setText(JUnitMessages.JUnitPreferencePage_filter_label);
-
-		Composite container= new Composite(composite, SWT.NONE);
-		GridLayout layout= new GridLayout();
-		layout.numColumns= 2;
-		layout.marginHeight= 0;
-		layout.marginWidth= 0;
-		container.setLayout(layout);
-		GridData gd= new GridData(GridData.FILL_BOTH);
-		container.setLayoutData(gd);
-
-		createFilterTable(container);
-		createStepFilterButtons(container);
-	}
-
-	private void createFilterTable(Composite container) {
-		TableLayoutComposite layouter= new TableLayoutComposite(container, SWT.NONE);
-		layouter.addColumnData(new ColumnWeightData(100));
-		layouter.setLayoutData(new GridData(GridData.FILL_BOTH));
-
-		fFilterTable= new Table(layouter, SWT.CHECK | SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
-
-		@SuppressWarnings("unused")
-		TableColumn tableColumn= new TableColumn(fFilterTable, SWT.NONE);
-		fFilterViewer= new CheckboxTableViewer(fFilterTable);
-		fTableEditor= new TableEditor(fFilterTable);
-		fFilterViewer.setLabelProvider(new FilterLabelProvider());
-		fFilterViewer.setComparator(new FilterViewerSorter());
-		fStackFilterContentProvider= new StackFilterContentProvider();
-		fFilterViewer.setContentProvider(fStackFilterContentProvider);
-		// input just needs to be non-null
-		fFilterViewer.setInput(this);
-		fFilterViewer.addCheckStateListener(event -> {
-			Filter filter= (Filter) event.getElement();
-			fStackFilterContentProvider.toggleFilter(filter);
-		});
-		fFilterViewer.addSelectionChangedListener(event -> {
-			ISelection selection= event.getSelection();
-			fRemoveFilterButton.setEnabled(!selection.isEmpty());
-		});
-	}
-
-	private void createStepFilterButtons(Composite container) {
-		Composite buttonContainer= new Composite(container, SWT.NONE);
-		GridData gd= new GridData(GridData.FILL_VERTICAL);
-		buttonContainer.setLayoutData(gd);
-		GridLayout buttonLayout= new GridLayout();
-		buttonLayout.numColumns= 1;
-		buttonLayout.marginHeight= 0;
-		buttonLayout.marginWidth= 0;
-		buttonContainer.setLayout(buttonLayout);
-
-		fAddFilterButton= new Button(buttonContainer, SWT.PUSH);
-		fAddFilterButton.setText(JUnitMessages.JUnitPreferencePage_addfilterbutton_label);
-		gd= new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING);
-		fAddFilterButton.setLayoutData(gd);
-		LayoutUtil.setButtonDimensionHint(fAddFilterButton);
-		fAddFilterButton.addListener(SWT.Selection, event -> editFilter());
-
-		fAddTypeButton= new Button(buttonContainer, SWT.PUSH);
-		fAddTypeButton.setText(JUnitMessages.JUnitPreferencePage_addtypebutton_label);
-		gd= getButtonGridData(fAddTypeButton);
-		fAddTypeButton.setLayoutData(gd);
-		LayoutUtil.setButtonDimensionHint(fAddTypeButton);
-		fAddTypeButton.addListener(SWT.Selection, event -> addType());
-
-		fAddPackageButton= new Button(buttonContainer, SWT.PUSH);
-		fAddPackageButton.setText(JUnitMessages.JUnitPreferencePage_addpackagebutton_label);
-		gd= getButtonGridData(fAddPackageButton);
-		fAddPackageButton.setLayoutData(gd);
-		SWTUtil.setButtonDimensionHint(fAddPackageButton);
-		fAddPackageButton.addListener(SWT.Selection, event -> addPackage());
-
-		fRemoveFilterButton= new Button(buttonContainer, SWT.PUSH);
-		fRemoveFilterButton.setText(JUnitMessages.JUnitPreferencePage_removefilterbutton_label);
-		gd= getButtonGridData(fRemoveFilterButton);
-		fRemoveFilterButton.setLayoutData(gd);
-		SWTUtil.setButtonDimensionHint(fRemoveFilterButton);
-		fRemoveFilterButton.addListener(SWT.Selection, event -> removeFilters());
-		fRemoveFilterButton.setEnabled(false);
-
-		fEnableAllButton= new Button(buttonContainer, SWT.PUSH);
-		fEnableAllButton.setText(JUnitMessages.JUnitPreferencePage_enableallbutton_label);
-		gd= getButtonGridData(fEnableAllButton);
-		fEnableAllButton.setLayoutData(gd);
-		SWTUtil.setButtonDimensionHint(fEnableAllButton);
-		fEnableAllButton.addListener(SWT.Selection, event -> checkAllFilters(true));
-
-		fDisableAllButton= new Button(buttonContainer, SWT.PUSH);
-		fDisableAllButton.setText(JUnitMessages.JUnitPreferencePage_disableallbutton_label);
-		gd= getButtonGridData(fDisableAllButton);
-		fDisableAllButton.setLayoutData(gd);
-		SWTUtil.setButtonDimensionHint(fDisableAllButton);
-		fDisableAllButton.addListener(SWT.Selection, event -> checkAllFilters(false));
-
-	}
-
 	private GridData getButtonGridData(Button button) {
 		GridData gd= new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING);
 		int widthHint= convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
@@ -501,229 +169,11 @@
 	@Override
 	public void init(IWorkbench workbench) {}
 
-	/**
-	 * Create a new filter in the table (with the default 'new filter' value),
-	 * then open up an in-place editor on it.
-	 */
-	private void editFilter() {
-		// if a previous edit is still in progress, finish it
-		if (fEditorText != null)
-			validateChangeAndCleanup();
-
-		fNewStackFilter= fStackFilterContentProvider.addFilter(DEFAULT_NEW_FILTER_TEXT, true);
-		fNewTableItem= fFilterTable.getItem(0);
-		int textStyles= SWT.SINGLE | SWT.LEFT;
-
-		/*
-		 * Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=218193
-		 * which won't get fixed (advice is to not use border). We still use a
-		 * border on platforms where it looks OK and nicer with a border.
-		 */
-		String platform= SWT.getPlatform();
-		if ("win32".equals(platform) || "gtk".equals(platform)) //$NON-NLS-1$ //$NON-NLS-2$
-			textStyles|= SWT.BORDER;
-
-		fEditorText= new Text(fFilterTable, textStyles);
-		fEditorText.setFont(JFaceResources.getDialogFont());
-		GridData gd= new GridData(GridData.FILL_BOTH);
-		fEditorText.setLayoutData(gd);
-
-		// set the editor
-		fTableEditor.horizontalAlignment= SWT.LEFT;
-		fTableEditor.grabHorizontal= true;
-		fTableEditor.setEditor(fEditorText, fNewTableItem, 0);
-
-		// get the editor ready to use
-		fEditorText.setText(fNewStackFilter.getName());
-		fEditorText.selectAll();
-		setEditorListeners(fEditorText);
-		fEditorText.setFocus();
-	}
-
-	private void setEditorListeners(Text text) {
-		// CR means commit the changes, ESC means abort and don't commit
-		text.addKeyListener(new KeyAdapter() {
-			@Override
-			public void keyReleased(KeyEvent event) {
-				if (event.character == SWT.CR) {
-					if (fInvalidEditorText != null) {
-						fEditorText.setText(fInvalidEditorText);
-						fInvalidEditorText= null;
-					} else
-						validateChangeAndCleanup();
-				} else if (event.character == SWT.ESC) {
-					removeNewFilter();
-					cleanupEditor();
-				}
-			}
-		});
-		// Consider loss of focus on the editor to mean the same as CR
-		text.addFocusListener(new FocusAdapter() {
-			@Override
-			public void focusLost(FocusEvent event) {
-				if (fInvalidEditorText != null) {
-					fEditorText.setText(fInvalidEditorText);
-					fInvalidEditorText= null;
-				} else
-					validateChangeAndCleanup();
-			}
-		});
-		// Consume traversal events from the text widget so that CR doesn't
-		// traverse away to dialog's default button.  Without this, hitting
-		// CR in the text field closes the entire dialog.
-		text.addListener(SWT.Traverse, event -> event.doit= false);
-	}
-
-	private void validateChangeAndCleanup() {
-		String trimmedValue= fEditorText.getText().trim();
-		// if the new value is blank, remove the filter
-		if (trimmedValue.length() < 1)
-			removeNewFilter();
-
-		// if it's invalid, beep and leave sitting in the editor
-		else if (!validateEditorInput(trimmedValue)) {
-			fInvalidEditorText= trimmedValue;
-			fEditorText.setText(JUnitMessages.JUnitPreferencePage_invalidstepfilterreturnescape);
-			getShell().getDisplay().beep();
-			return;
-			// otherwise, commit the new value if not a duplicate
-		} else {
-			Object[] filters= fStackFilterContentProvider.getElements(null);
-			for (Object filter2 : filters) {
-				Filter filter= (Filter) filter2;
-				if (filter.getName().equals(trimmedValue)) {
-					removeNewFilter();
-					cleanupEditor();
-					return;
-				}
-			}
-			fNewTableItem.setText(trimmedValue);
-			fNewStackFilter.setName(trimmedValue);
-			fFilterViewer.refresh();
-		}
-		cleanupEditor();
-	}
-
-	/*
-	 * Cleanup all widgets & resources used by the in-place editing
-	 */
-	private void cleanupEditor() {
-		if (fEditorText == null)
-			return;
-
-		fNewStackFilter= null;
-		fNewTableItem= null;
-		fTableEditor.setEditor(null, null, 0);
-		fEditorText.dispose();
-		fEditorText= null;
-	}
-
-	private void removeNewFilter() {
-		fStackFilterContentProvider.removeFilters(new Object[] { fNewStackFilter });
-	}
-
-	/*
-	 * A valid step filter is simply one that is a valid Java identifier.
-	 * and, as defined in the JDI spec, the regular expressions used for
-	 * step filtering must be limited to exact matches or patterns that
-	 * begin with '*' or end with '*'. Beyond this, a string cannot be validated
-	 * as corresponding to an existing type or package (and this is probably not
-	 * even desirable).
-	 */
-	private boolean validateEditorInput(String trimmedValue) {
-		char firstChar= trimmedValue.charAt(0);
-		if ((!(Character.isJavaIdentifierStart(firstChar)) || (firstChar == '*')))
-			return false;
-
-		int length= trimmedValue.length();
-		for (int i= 1; i < length; i++) {
-			char c= trimmedValue.charAt(i);
-			if (!Character.isJavaIdentifierPart(c)) {
-				if (c == '.' && i != (length - 1))
-					continue;
-				if (c == '*' && i == (length - 1))
-					continue;
-
-				return false;
-			}
-		}
-		return true;
-	}
-
-	private void addType() {
-		Shell shell= getShell();
-		SelectionDialog dialog= null;
-		try {
-			dialog=
-				JavaUI.createTypeDialog(
-					shell,
-					PlatformUI.getWorkbench().getProgressService(),
-					SearchEngine.createWorkspaceScope(),
-					IJavaElementSearchConstants.CONSIDER_CLASSES,
-					false);
-		} catch (JavaModelException jme) {
-			String title= JUnitMessages.JUnitPreferencePage_addtypedialog_title;
-			String message= JUnitMessages.JUnitPreferencePage_addtypedialog_error_message;
-			ExceptionHandler.handle(jme, shell, title, message);
-			return;
-		}
-
-		dialog.setTitle(JUnitMessages.JUnitPreferencePage_addtypedialog_title);
-		dialog.setMessage(JUnitMessages.JUnitPreferencePage_addtypedialog_message);
-		if (dialog.open() == IDialogConstants.CANCEL_ID)
-			return;
-
-		Object[] types= dialog.getResult();
-		if (types != null && types.length > 0) {
-			IType type= (IType) types[0];
-			fStackFilterContentProvider.addFilter(type.getFullyQualifiedName('.'), true);
-		}
-	}
-
-	private void addPackage() {
-		Shell shell= getShell();
-		IProgressService context= PlatformUI.getWorkbench().getProgressService();
-		IJavaSearchScope createWorkspaceScope= SearchEngine.createWorkspaceScope();
-		SelectionDialog dialog= JavaUI.createPackageDialog(shell, context, createWorkspaceScope, true, true, ""); //$NON-NLS-1$
-		dialog.setTitle(JUnitMessages.JUnitPreferencePage_addpackagedialog_title);
-		dialog.setMessage(JUnitMessages.JUnitPreferencePage_addpackagedialog_message);
-		if (dialog.open() != Window.OK)
-			return;
-
-		Object[] packages= dialog.getResult();
-		if (packages == null)
-			return;
-
-		for (Object package1 : packages) {
-			IJavaElement pkg= (IJavaElement) package1;
-
-			String filter= pkg.getElementName();
-			if (filter.length() < 1)
-				filter= JUnitMessages.JUnitMainTab_label_defaultpackage;
-			else
-				filter += ".*"; //$NON-NLS-1$
-
-			fStackFilterContentProvider.addFilter(filter, true);
-		}
-	}
-	private void removeFilters() {
-		IStructuredSelection selection= (IStructuredSelection) fFilterViewer.getSelection();
-		fStackFilterContentProvider.removeFilters(selection.toArray());
-	}
-
-	private void checkAllFilters(boolean check) {
-		Object[] filters= fStackFilterContentProvider.getElements(null);
-		for (int i= (filters.length - 1); i >= 0; --i)
-			 ((Filter) filters[i]).setChecked(check);
-
-		fFilterViewer.setAllChecked(check);
-	}
-
 	@Override
 	public boolean performOk() {
 		AssertionVMArg.setEnableAssertionsPreference(getAssertionCheckBoxSelection());
 		JUnitUIPreferencesConstants.setShowInAllViews(getShowInAllViewsCheckBoxSelection());
-		fStackFilterContentProvider.saveFilters();
+		fJavaFilterTable.performOk(getPreferenceStore());
 		return true;
 	}
 
@@ -738,35 +188,7 @@
 				.getBoolean(JUnitPreferencesConstants.ENABLE_ASSERTIONS, JUnitPreferencesConstants.ENABLE_ASSERTIONS_DEFAULT));
 		fShowInAllViewsCheckBox.setSelection(DefaultScope.INSTANCE.getNode(JUnitPlugin.PLUGIN_ID)
 				.getBoolean(JUnitUIPreferencesConstants.SHOW_IN_ALL_VIEWS, JUnitUIPreferencesConstants.SHOW_IN_ALL_VIEWS_DEFAULT));
-		fStackFilterContentProvider.setDefaults();
+		fJavaFilterTable.performDefaults();
 	}
 
-	/**
-	 * Returns a list of active stack filters.
-	 *
-	 * @return list
-	 */
-	protected List<String> createActiveStackFiltersList() {
-		return Arrays.asList(JUnitPreferencesConstants.getFilterPatterns());
-	}
-
-	/**
-	 * Returns a list of active stack filters.
-	 *
-	 * @return list
-	 */
-	protected List<String> createInactiveStackFiltersList() {
-		String[] strings=
-			JUnitPreferencesConstants.parseList(getPreferenceStore().getString(JUnitPreferencesConstants.PREF_INACTIVE_FILTERS_LIST));
-		return Arrays.asList(strings);
-	}
-
-	protected void updateActions() {
-		if (fEnableAllButton == null)
-			return;
-
-		boolean enabled= fFilterViewer.getTable().getItemCount() > 0;
-		fEnableAllButton.setEnabled(enabled);
-		fDisableAllButton.setEnabled(enabled);
-	}
 }
diff --git a/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF b/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF
index bf2029e..3bee31e 100644
--- a/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.text.tests/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %Plugin.name
 Bundle-SymbolicName: org.eclipse.jdt.text.tests;singleton:=true
-Bundle-Version: 3.13.1500.qualifier
+Bundle-Version: 3.13.1600.qualifier
 Bundle-Activator: org.eclipse.jdt.text.tests.JdtTextTestPlugin
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %Plugin.providerName
diff --git a/org.eclipse.jdt.text.tests/pom.xml b/org.eclipse.jdt.text.tests/pom.xml
index 2087329..eb51642 100644
--- a/org.eclipse.jdt.text.tests/pom.xml
+++ b/org.eclipse.jdt.text.tests/pom.xml
@@ -20,7 +20,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.text.tests</artifactId>
-  <version>3.13.1500-SNAPSHOT</version>
+  <version>3.13.1600-SNAPSHOT</version>
   <packaging>eclipse-test-plugin</packaging>
 
   <properties>
diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/BreakContinueTargetFinderTest.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/BreakContinueTargetFinderTest.java
index bf19d32..2dd2803 100644
--- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/BreakContinueTargetFinderTest.java
+++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/BreakContinueTargetFinderTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2020 IBM Corporation and others.
+ * Copyright (c) 2005, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -34,12 +34,11 @@
 import org.eclipse.jdt.core.dom.ASTParser;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 
+import org.eclipse.jdt.internal.core.manipulation.search.BreakContinueTargetFinder;
 import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder.OccurrenceLocation;
 
 import org.eclipse.jdt.ui.tests.core.rules.ProjectTestSetup;
 
-import org.eclipse.jdt.internal.ui.search.BreakContinueTargetFinder;
-
 /**
  * Tests for the BreakContinueTargerFinder class.
  *
diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/EnumConstructorTargetFinderTest.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/EnumConstructorTargetFinderTest.java
index d137201..380712a 100644
--- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/EnumConstructorTargetFinderTest.java
+++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/EnumConstructorTargetFinderTest.java
@@ -283,12 +283,108 @@
 		{
 			int offset= s.indexOf("A1(\"\")");
 			int targetOffset= s.indexOf("A(String s)");
-			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1 /* 'A' */, 0, "A(String s)"));
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(String s)"));
 		}
 		{
 			int offset= s.indexOf("A2(\"\",\"\")");
-			int targetOffset= s.indexOf("A2(\"\",\"\")");
-			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 2 /* 'A2' */, 0, "A2(\"\",\"\")"));
+			int targetOffset= s.indexOf("A(String ... strings)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(String ... strings)"));
+		}
+	}
+
+	@Test
+	public void testEnumConstructorFinder_6() throws Exception {
+		String s= "" +
+				"package test1;\n" +
+				"class E {\n" +
+
+				"   public enum A {\n" +
+				"      A1(\"\"),\n" +
+				"      A2(new Object());\n" +
+				"      A(String s) {\n" +
+				"      }\n" +
+				"      A(Object o) {\n" +
+				"      }\n" +
+				"   }\n" +
+
+				"}\n";
+
+		CompilationUnit root= createCompilationUnit(s);
+
+		{
+			int offset= s.indexOf("A1");
+			int targetOffset= s.indexOf("A(String");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1 /* 'A' */, 0, "A(String"));
+		}
+		{
+			int offset= s.indexOf("A2");
+			int targetOffset= s.indexOf("A(Object");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1 /* 'A' */, 0, "A(Object"));
+		}
+	}
+
+	@Test
+	public void testEnumConstructorFinder_7() throws Exception {
+		String s= "" +
+				"package test1;\n" +
+				"class E {\n" +
+
+				"   public enum A {\n" +
+				"      A1(1L),\n" +
+				"      A2(new Long(1)),\n" +
+				"      A3(new Long(1), 1L),\n" +
+				"      A4(Long.valueOf(1)),\n" +
+				"      A5(Long.parseLong(\"1\")),\n" +
+				"      A6(1L, 2.0),\n" +
+				"      A7(Long.valueOf(1), Double.valueOf(2.0));\n" +
+				"      A(long l) {\n" +
+				"      }\n" +
+				"      A(Long l) {\n" +
+				"      }\n" +
+				"      A(long l, double d) {\n" +
+				"      }\n" +
+				"      A(Long l, Double d) {\n" +
+				"      }\n" +
+				"   }\n" +
+
+				"}\n";
+
+		CompilationUnit root= createCompilationUnit(s);
+
+		{
+			int offset= s.indexOf("A1");
+			int targetOffset= s.indexOf("A(long l)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(long l)"));
+		}
+		{
+			int offset= s.indexOf("A2");
+			int targetOffset= s.indexOf("A(Long l)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(Long l)"));
+		}
+		{
+			int offset= s.indexOf("A3");
+			int targetOffset= s.indexOf("A(long l, double d)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(long l, double d)"));
+		}
+		{
+			int offset= s.indexOf("A4");
+			int targetOffset= s.indexOf("A(Long l)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(Long l)"));
+		}
+		{
+			int offset= s.indexOf("A5");
+			int targetOffset= s.indexOf("A(long l)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(long l)"));
+		}
+		{
+			int offset= s.indexOf("A6");
+			int targetOffset= s.indexOf("A(long l, double d)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(long l, double d)"));
+		}
+		{
+			int offset= s.indexOf("A7");
+			int targetOffset= s.indexOf("A(Long l, Double d)");
+			checkSelection(root, offset, 0, new OccurrenceLocation(targetOffset, 1, 0, "A(Long l, Double d)"));
 		}
 	}
 }
diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/MarkOccurrenceTest1d7.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/MarkOccurrenceTest1d7.java
index a5a75eb..515a8bb 100644
--- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/MarkOccurrenceTest1d7.java
+++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/MarkOccurrenceTest1d7.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2020 IBM Corporation and others.
+ * Copyright (c) 2011, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -34,15 +34,15 @@
 import org.eclipse.jdt.core.dom.ASTParser;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 
+import org.eclipse.jdt.internal.core.manipulation.search.ExceptionOccurrencesFinder;
 import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder;
 import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder.OccurrenceLocation;
+import org.eclipse.jdt.internal.core.manipulation.search.MethodExitsFinder;
 
 import org.eclipse.jdt.ui.PreferenceConstants;
 import org.eclipse.jdt.ui.tests.core.rules.Java1d7ProjectTestSetup;
 
 import org.eclipse.jdt.internal.ui.JavaPlugin;
-import org.eclipse.jdt.internal.ui.search.ExceptionOccurrencesFinder;
-import org.eclipse.jdt.internal.ui.search.MethodExitsFinder;
 
 /**
  * Tests the Java Editor's occurrence marking feature.
diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/MarkOccurrenceTest1d8.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/MarkOccurrenceTest1d8.java
index dd74b76..1bfed0d 100644
--- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/MarkOccurrenceTest1d8.java
+++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/MarkOccurrenceTest1d8.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2020 IBM Corporation and others.
+ * Copyright (c) 2011, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -34,15 +34,15 @@
 import org.eclipse.jdt.core.dom.ASTParser;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 
+import org.eclipse.jdt.internal.core.manipulation.search.ExceptionOccurrencesFinder;
 import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder;
 import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder.OccurrenceLocation;
+import org.eclipse.jdt.internal.core.manipulation.search.MethodExitsFinder;
 
 import org.eclipse.jdt.ui.PreferenceConstants;
 import org.eclipse.jdt.ui.tests.core.rules.Java1d8ProjectTestSetup;
 
 import org.eclipse.jdt.internal.ui.JavaPlugin;
-import org.eclipse.jdt.internal.ui.search.ExceptionOccurrencesFinder;
-import org.eclipse.jdt.internal.ui.search.MethodExitsFinder;
 
 /**
  * Those tests are made to run on Java Spider 1.8 .
diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/PluginsNotLoadedTest.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/PluginsNotLoadedTest.java
index d013a18..599421f 100644
--- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/PluginsNotLoadedTest.java
+++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/PluginsNotLoadedTest.java
@@ -78,7 +78,7 @@
 			"org.eclipse.core.filesystem.win32.x86",
 			"org.eclipse.core.resources.compatibility",
 			"org.eclipse.core.resources.win32",
-			"org.eclipse.debug.ui",
+//			"org.eclipse.debug.ui", bug 507546: debug code minings
 			"org.eclipse.equinox.http.jetty",
 			"org.eclipse.equinox.http.registry",
 			"org.eclipse.equinox.http.servlet",
@@ -92,8 +92,8 @@
 			"org.eclipse.jdt.apt.ui",
 			"org.eclipse.jdt.compiler.apt",
 			"org.eclipse.jdt.compiler.tool",
-			"org.eclipse.jdt.debug",
-			"org.eclipse.jdt.debug.ui",
+//			"org.eclipse.jdt.debug", bug 507546: debug code minings
+//			"org.eclipse.jdt.debug.ui", bug 507546: debug code minings
 			"org.eclipse.jdt.doc.isv",
 			"org.eclipse.jdt.doc.user",
 			"org.eclipse.jdt.junit",
@@ -130,7 +130,7 @@
 			"org.eclipse.text",
 			"org.eclipse.text.tests",
 			"org.eclipse.ui.cheatsheets",
-			"org.eclipse.ui.console",
+//			"org.eclipse.ui.console", bug 507546: debug code minings
 			"org.eclipse.ui.editors.tests",
 			"org.eclipse.ui.examples.javaeditor",
 			"org.eclipse.ui.examples.rcp.texteditor",
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/p/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/p/A.java
new file mode 100644
index 0000000..611171d
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/p/A.java
@@ -0,0 +1,10 @@
+package p;
+
+import q.Asuper;
+
+public class A extends Asuper {
+
+	void m() {
+		C c = null;
+	}
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/p/C.java b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/p/C.java
new file mode 100644
index 0000000..cca21a2
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/p/C.java
@@ -0,0 +1,4 @@
+package p;
+
+public class C {
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/q/Asuper.java b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/q/Asuper.java
new file mode 100644
index 0000000..4eb74a4
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/q/Asuper.java
@@ -0,0 +1,7 @@
+package q;
+
+public class Asuper {
+
+	C cc;
+
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/q/C.java b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/q/C.java
new file mode 100644
index 0000000..ebc356e
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/in/q/C.java
@@ -0,0 +1,4 @@
+package q;
+
+public class C {
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/p/A.java b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/p/A.java
new file mode 100644
index 0000000..e23c2a3
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/p/A.java
@@ -0,0 +1,6 @@
+package p;
+
+import q.Asuper;
+
+public class A extends Asuper {
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/p/C.java b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/p/C.java
new file mode 100644
index 0000000..cca21a2
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/p/C.java
@@ -0,0 +1,4 @@
+package p;
+
+public class C {
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/q/Asuper.java b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/q/Asuper.java
new file mode 100644
index 0000000..54bdf29
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/q/Asuper.java
@@ -0,0 +1,11 @@
+package q;
+
+public class Asuper {
+
+	C cc;
+
+	void m() {
+		p.C c = null;
+	}
+
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/q/C.java b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/q/C.java
new file mode 100644
index 0000000..ebc356e
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/PullUp/testFieldMethod5/out/q/C.java
@@ -0,0 +1,4 @@
+package q;
+
+public class C {
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/PullUpTests.java b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/PullUpTests.java
index e3ad5d5..dfc677e 100644
--- a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/PullUpTests.java
+++ b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/PullUpTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2020 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -1589,6 +1589,11 @@
 		fieldMethodHelper2(new String[] { "c" }, new String[] {}, new String[][] { new String[0] }, true, false);
 	}
 
+	@Test
+	public void testFieldMethod5() throws Exception {
+		fieldMethodHelper2(new String[] {}, new String[] {"m"}, new String[][] { new String[0] }, true, false);
+	}
+
 	//----
 	@Test
 	public void testAddingRequiredMembers0() throws Exception {
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/callhierarchy/CallHierarchyTestHelper.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/callhierarchy/CallHierarchyTestHelper.java
index 1a75643..1156113 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/callhierarchy/CallHierarchyTestHelper.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/callhierarchy/CallHierarchyTestHelper.java
@@ -52,6 +52,13 @@
     private IJavaProject fJavaProject3;
     private IType fType1;
     private IType fType2;
+    private IType fTypeP;
+	private IType fFooImplAType;
+	private IType fFooImplBType;
+	private IType fFooType;
+	private IType fAbsType;
+	private IType fAbsI1Type;
+	private IType fAbsI2Type;
     private IPackageFragment fPack1;
     private IPackageFragment fPack2;
     private IPackageFragment fPack3;
@@ -62,6 +69,14 @@
     private IMethod fMethod4;
     private IMethod fRecursiveMethod1;
     private IMethod fRecursiveMethod2;
+	private IMethod fCalleeMethod;
+	private IMethod fAbsCalleeMethod;
+	private IMethod fFooMethod;
+	private IMethod fFooImplMethod_A;
+	private IMethod fFooImplMethod_B;
+	private IMethod fAbsFooMethod;
+	private IMethod fAbsI1FooMethod;
+	private IMethod fAbsI2FooMethod;
 
     public void setUp() throws Exception {
         fJavaProject1= JavaProjectHelper.createJavaProject("TestProject1", "bin");
@@ -72,6 +87,13 @@
         assertBuildWithoutErrors(fJavaProject3);
         fType1= null;
         fType2= null;
+        fTypeP= null;
+        fFooImplAType= null;
+        fFooImplBType= null;
+        fAbsI1Type= null;
+        fAbsI2Type= null;
+        fAbsType= null;
+        fFooType= null;
         fPack1= null;
         fPack2= null;
         fPack3= null;
@@ -359,6 +381,81 @@
         assertBuildWithoutErrors(fJavaProject3);
     }
 
+    public void createCalleeClasses() throws Exception {
+        createPackages();
+
+        ICompilationUnit cu3= fPack2.getCompilationUnit("P.java");
+        fTypeP=
+        		cu3.createType(
+                    "public class P {\n"
+                    + "  private A handler;\n"
+                    + "  private Abs absHandler;\n"
+                    + "\n"
+                    + "  public void callFoo() {\n"
+                    + "     handler.foo();\n"
+                    + "  }\n"
+                    + "  public void callAbsFoo() {\n"
+                    + "     absHandler.absFoo();\n"
+                    + "  }\n"
+                    + "\n"
+                    + "}",
+                    null,
+                    true,
+                    null);
+
+        ICompilationUnit cu4= fPack2.getCompilationUnit("A.java");
+        fFooType= cu4.createType(
+        		"public interface A {\n"
+                + "   void foo();\n"
+                + "}\n"
+                , null, true, null);
+
+
+        ICompilationUnit cu5= fPack2.getCompilationUnit("AImpl.java");
+        fFooImplAType= cu5.createType(
+                "public class AImpl implements A {\n"
+                + "  public void foo() {\n"
+                + "      System.out.println();\n"
+                + "  }\n"
+                + "}\n"
+                , null, true, null);
+
+        ICompilationUnit cu6= fPack2.getCompilationUnit("BImpl.java");
+        fFooImplBType= cu6.createType(
+                "public class BImpl implements A {\n"
+                + "  public void foo() {\n"
+                + "      System.out.printf(\"\");\n"
+                + "  }\n"
+                + "}\n"
+                , null, true, null);
+
+
+        ICompilationUnit cu7= fPack2.getCompilationUnit("Abs.java");
+        fAbsType= cu7.createType(
+        		"public abstract class Abs {\n"
+                + "   abstract void absFoo();\n"
+                + "}\n"
+                , null, true, null);
+
+        ICompilationUnit cu8= fPack2.getCompilationUnit("AbsI1.java");
+        fAbsI1Type= cu8.createType(
+        		"public class AbsI1 extends Abs {\n"
+                + "   void absFoo() {}\n"
+                + "}\n"
+                , null, true, null);
+
+        ICompilationUnit cu9= fPack2.getCompilationUnit("AbsI2.java");
+        fAbsI2Type= cu9.createType(
+        		"public class AbsI2 extends Abs {\n"
+                + "   void absFoo() {}\n"
+                + "}\n"
+                , null, true, null);
+
+        assertBuildWithoutErrors(fJavaProject1);
+        assertBuildWithoutErrors(fJavaProject2);
+
+    }
+
     /**
      * Creates two packages (pack1 and pack2) in different projects. Sets the
      * instance fields fPack1 and fPack2.
@@ -508,6 +605,34 @@
         return fType2;
     }
 
+    public IType getTypeP() {
+    	return fTypeP;
+    }
+
+    public IType getFooImplAType() {
+		return fFooImplAType;
+	}
+
+    public IType getFooImplBType() {
+		return fFooImplBType;
+	}
+
+    public IType getFooType() {
+		return fFooType;
+	}
+
+    public IType getAbsType() {
+		return fAbsType;
+	}
+
+    public IType getAbsI1Type() {
+		return fAbsI1Type;
+	}
+
+    public IType getAbsI2Type() {
+		return fAbsI2Type;
+	}
+
     public IMethod getMethod1() {
         if (fMethod1 == null) {
             fMethod1= getType1().getMethod("method1", EMPTY);
@@ -549,4 +674,60 @@
         }
         return fRecursiveMethod2;
     }
+
+    public IMethod getCalleeMethod() {
+        if (fCalleeMethod == null) {
+            fCalleeMethod= getTypeP().getMethod("callFoo", EMPTY);
+        }
+        return fCalleeMethod;
+    }
+
+    public IMethod getAbsCalleeMethod() {
+        if (fAbsCalleeMethod == null) {
+        	fAbsCalleeMethod= getTypeP().getMethod("callAbsFoo", EMPTY);
+        }
+        return fAbsCalleeMethod;
+    }
+
+	public IMethod getFooImplMethod_A() {
+        if (fFooImplMethod_A == null) {
+        	fFooImplMethod_A= getFooImplAType().getMethod("foo", EMPTY);
+        }
+        return fFooImplMethod_A;
+	}
+
+	public IMethod getFooImplMethod_B() {
+        if (fFooImplMethod_B == null) {
+        	fFooImplMethod_B= getFooImplBType().getMethod("foo", EMPTY);
+        }
+        return fFooImplMethod_B;
+	}
+
+	public IMethod getFooMethod() {
+        if (fFooMethod == null) {
+        	fFooMethod= getFooType().getMethod("foo", EMPTY);
+        }
+        return fFooMethod;
+	}
+
+	public IMethod getAbsFooMethod() {
+        if (fAbsFooMethod == null) {
+        	fAbsFooMethod= getAbsType().getMethod("absFoo", EMPTY);
+        }
+        return fAbsFooMethod;
+	}
+
+	public IMethod getAbsI1FooMethod() {
+        if (fAbsI1FooMethod == null) {
+        	fAbsI1FooMethod= getAbsI1Type().getMethod("absFoo", EMPTY);
+        }
+        return fAbsI1FooMethod;
+	}
+
+	public IMethod getAbsI2FooMethod() {
+        if (fAbsI2FooMethod == null) {
+        	fAbsI2FooMethod= getAbsI2Type().getMethod("absFoo", EMPTY);
+        }
+        return fAbsI2FooMethod;
+	}
 }
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/CallHierarchyTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/CallHierarchyTest.java
index 6ce77e4..ef397d1 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/CallHierarchyTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/CallHierarchyTest.java
@@ -16,9 +16,11 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
@@ -38,6 +40,8 @@
 
 import org.eclipse.jdt.ui.tests.callhierarchy.CallHierarchyTestHelper;
 
+import org.eclipse.jdt.internal.ui.JavaPlugin;
+
 public class CallHierarchyTest {
     private static final String[] EMPTY= new String[0];
 
@@ -477,6 +481,46 @@
         checkCalls(helper.getType1().getType("OneRecord").getMethod("OneRecord", EMPTY), helper.getMethod2());
     }
 
+    @Test
+    public void implementingCallees_onInterfaces() throws Exception {
+    	JavaPlugin.getDefault().getPreferenceStore().setValue("PREF_USE_IMPLEMENTORS", true);
+    	helper.createCalleeClasses();
+
+        IMethod method= helper.getCalleeMethod();
+
+        MethodWrapper wrapper= getSingleCalleeRoot(method);
+
+        MethodWrapper[] firstLevel= wrapper.getCalls(new NullProgressMonitor());
+        assertNotNull(firstLevel);
+        assertEquals(1, firstLevel.length);
+        helper.assertCalls(Arrays.asList(helper.getFooMethod()), firstLevel);
+
+        MethodWrapper[] secondLevel= firstLevel[0].getCalls(new NullProgressMonitor());
+        assertNotNull(secondLevel);
+        assertEquals(2, secondLevel.length);
+        helper.assertCalls(Arrays.asList(helper.getFooImplMethod_A(), helper.getFooImplMethod_B()), secondLevel);
+    }
+
+    @Test
+    public void implementingCallees_onAbstractMethods() throws Exception {
+    	JavaPlugin.getDefault().getPreferenceStore().setValue("PREF_USE_IMPLEMENTORS", true);
+        helper.createCalleeClasses();
+
+        IMethod method= helper.getAbsCalleeMethod();
+
+        MethodWrapper wrapper= getSingleCalleeRoot(method);
+
+        MethodWrapper[] firstLevel= wrapper.getCalls(new NullProgressMonitor());
+        assertNotNull(firstLevel);
+        assertEquals(1, firstLevel.length);
+        helper.assertCalls(Arrays.asList(helper.getAbsFooMethod()), firstLevel);
+
+        MethodWrapper[] secondLevel= firstLevel[0].getCalls(new NullProgressMonitor());
+        assertNotNull(secondLevel);
+        assertEquals(2, secondLevel.length);
+        helper.assertCalls(Arrays.asList(helper.getAbsI1FooMethod(), helper.getAbsI2FooMethod()), secondLevel);
+    }
+
     private void checkCalls(IMember memberToCheck, IMethod... expectedCallers) {
         MethodWrapper[] methodWrappers = CallHierarchy.getDefault().getCallerRoots(new IMember[] { memberToCheck });
         MethodWrapper[] callers = methodWrappers[0].getCalls(new NullProgressMonitor());
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/TypeInfoTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/TypeInfoTest.java
index c039d42..5e0b677 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/TypeInfoTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/TypeInfoTest.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
@@ -243,6 +243,9 @@
 		assertEquals("java.lang.Throwable", TypeInfoFilter.simplifySearchText(" at java.lang.Throwable.fillInStackTrace ()"));
 		assertEquals("java.io.FileOutputStream", TypeInfoFilter.simplifySearchText(" at java.io.FileOutputStream.<init> ()"));
 		assertEquals("java.util.Map.Entry", TypeInfoFilter.simplifySearchText(" at java.util.Map$Entry.anything() (x.java:1)"));
+		assertEquals("*.Map.Entry", TypeInfoFilter.simplifySearchText("Map$Entry"));
+		assertEquals("org.eclipse.jdt.ui.tests.core.Main.Runner.Executor", TypeInfoFilter.simplifySearchText("org.eclipse.jdt.ui.tests.core.Main$Runner$Executor.exec(Main.java:10)"));
+		assertEquals("*.Main.Runner.Executor", TypeInfoFilter.simplifySearchText("Main$Runner$Executor.exec(Main.java:10)"));
 		assertEquals("java.io.FileOutputStream", TypeInfoFilter.simplifySearchText(" at java.io.FileOutputStream$1.close ()"));
 		assertEquals("org.eclipse.swt.internal.win32.OS", TypeInfoFilter.simplifySearchText(" at org.eclipse.swt.internal.win32.OS.WaitMessage(Native Method)"));
 
@@ -266,10 +269,35 @@
 		// convert inner types to qualified name:
 		assertEquals("java.lang.ref.ReferenceQueue.Lock", TypeInfoFilter.simplifySearchText(" at java.lang.ref.ReferenceQueue$Lock "));
 		assertEquals("java.util.concurrent.ThreadPoolExecutor.Worker", TypeInfoFilter.simplifySearchText(" at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@16.0.2/ThreadPoolExecutor.java:630) "));
+		assertEquals("*.DebugPlugin.EventDispatchJob",TypeInfoFilter.simplifySearchText("\"C:\\org.eclipse.debug.core\\bin\\org\\eclipse\\debug\\core\\DebugPlugin$EventDispatchJob.class\""));
+
 
 		/** possible future features if useful: **/
 //		// locks from thread dumps:
 //		assertEquals("sun.nio.ch.WindowsSelectorImpl", TypeInfoFilter.simplifySearchText(" - locked <0x0000000087428348> (a sun.nio.ch.WindowsSelectorImpl) "));
 		// "- waiting to re-lock in wait() <0x00000007005919b0> (a java.lang.ref.ReferenceQueue$Lock)"
 	}
-}
+
+    @Test
+    public void testBug578547() {
+    	IJavaElement[] elements= new IJavaElement[] { fJProject1 };
+		IJavaSearchScope scope= SearchEngine.createJavaSearchScope(elements);
+
+		TypeInfoFilter filter= new TypeInfoFilter("TestInner1.TestInner2", scope, 0, null);
+		assertEquals("TestInner2", filter.getNamePattern());
+		assertEquals("*TestInner1*", filter.getPackagePattern());
+
+		filter= new TypeInfoFilter("TestInner1.TestInner2.TestInner3", scope, 0, null);
+		assertEquals("TestInner3", filter.getNamePattern());
+		assertEquals("*TestInner1.TestInner2*", filter.getPackagePattern());
+
+		filter= new TypeInfoFilter("org.eclipse.jdt.IProblemInfo", scope, 0, null);
+		assertEquals("IProblemInfo", filter.getNamePattern());
+		assertEquals("org*.eclipse*.jdt*", filter.getPackagePattern());
+
+		filter= new TypeInfoFilter("Test", scope, 0, null);
+		assertEquals("Test", filter.getNamePattern());
+		assertEquals(null, filter.getPackagePattern());
+   }
+
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java
index bbb9f1e..a14c7c1 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest.java
@@ -10939,4 +10939,100 @@
 		}
 	}
 
+	@Test
+	public void testDoesntRemoveImportWhenClassReferenceIsPresent() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuffer buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("public class T {\n");
+		buf.append("    public static void foo() { };\n");
+		buf.append("}\n");
+		pack1.createCompilationUnit("T.java", buf.toString(), false, null);
+		IPackageFragment pack2= fSourceFolder.createPackageFragment("test2", false, null);
+		buf= new StringBuffer();
+		buf.append("package test2;\n");
+		buf.append("\n");
+		buf.append("import test1.T;\n");
+		buf.append("\n");
+		buf.append("public class S {\n");
+		buf.append("    public S() {\n");
+		buf.append("        T.foo();\n");
+		buf.append("        System.out.println(T.class);\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack2.createCompilationUnit("S.java", buf.toString(), false, null);
+		String selection= "foo";
+		int offset= buf.toString().indexOf(selection);
+		AssistContext context= getCorrectionContext(cu, offset, selection.length());
+		ArrayList<IJavaCompletionProposal> proposals= collectAssists(context, false);
+		assertCorrectLabels(proposals);
+		assertNumberOfProposals(proposals, 2);
+		StringBuffer expectation= new StringBuffer();
+		expectation.append("package test2;\n");
+		expectation.append("\n");
+		expectation.append("import static test1.T.foo;\n");
+		expectation.append("\n");
+		expectation.append("import test1.T;\n");
+		expectation.append("\n");
+		expectation.append("public class S {\n");
+		expectation.append("    public S() {\n");
+		expectation.append("        foo();\n");
+		expectation.append("        System.out.println(T.class);\n");
+		expectation.append("    }\n");
+		expectation.append("}\n");
+		assertProposalPreviewEquals(expectation.toString(), "Convert to static import", proposals);
+		assertProposalPreviewEquals(expectation.toString(), "Convert to static import (replace all occurrences)", proposals);
+	}
+
+	@Test
+	public void testDoesntRemoveImportWithClassReferenceInSeparateClass() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuffer buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("public class T {\n");
+		buf.append("    public static void foo() { };\n");
+		buf.append("}\n");
+		pack1.createCompilationUnit("T.java", buf.toString(), false, null);
+		IPackageFragment pack2= fSourceFolder.createPackageFragment("test2", false, null);
+		buf= new StringBuffer();
+		buf.append("package test2;\n");
+		buf.append("\n");
+		buf.append("import test1.T;\n");
+		buf.append("\n");
+		buf.append("public class S {\n");
+		buf.append("    public S() {\n");
+		buf.append("        T.foo();\n");
+		buf.append("    }\n");
+		buf.append("class C {\n");
+		buf.append("    {\n");
+		buf.append("        System.out.println(T.class);\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack2.createCompilationUnit("S.java", buf.toString(), false, null);
+		String selection= "foo";
+		int offset= buf.toString().indexOf(selection);
+		AssistContext context= getCorrectionContext(cu, offset, selection.length());
+		ArrayList<IJavaCompletionProposal> proposals= collectAssists(context, false);
+		assertCorrectLabels(proposals);
+		assertNumberOfProposals(proposals, 2);
+		StringBuffer expectation= new StringBuffer();
+		expectation.append("package test2;\n");
+		expectation.append("\n");
+		expectation.append("import static test1.T.foo;\n");
+		expectation.append("\n");
+		expectation.append("import test1.T;\n");
+		expectation.append("\n");
+		expectation.append("public class S {\n");
+		expectation.append("    public S() {\n");
+		expectation.append("        foo();\n");
+		expectation.append("    }\n");
+		expectation.append("class C {\n");
+		expectation.append("    {\n");
+		expectation.append("        System.out.println(T.class);\n");
+		expectation.append("    }\n");
+		expectation.append("}\n");
+		assertProposalPreviewEquals(expectation.toString(), "Convert to static import", proposals);
+		assertProposalPreviewEquals(expectation.toString(), "Convert to static import (replace all occurrences)", proposals);
+	}
+
 }
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java
index 2ab494c..f033d58 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java
@@ -947,7 +947,7 @@
 		assertNoErrors(context);
 		List<IJavaCompletionProposal> proposals= collectAssists(context, false);
 
-		assertNumberOfProposals(proposals, 2);
+		assertNumberOfProposals(proposals, 3);
 		assertCorrectLabels(proposals);
 
 		buf= new StringBuilder();
@@ -2618,6 +2618,202 @@
 	}
 
 	@Test
+	public void testExtractLambdaBodyToMethod1() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuilder buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E {\n");
+		buf.append("	public void foo1(int a) {\n");
+		buf.append("		FI2 k = (e) -> {\n");
+		buf.append("			int x = e + 3;\n");
+		buf.append("			if (x > 3) {\n");
+		buf.append("				return a;\n");
+		buf.append("			}\n");
+		buf.append("			return x;\n");
+		buf.append("		};\n");
+		buf.append("		k.foo(3);\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		buf.append("\n");
+		buf.append("@FunctionalInterface\n");
+		buf.append("interface FI2 {\n");
+		buf.append("    int foo(int x);\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+		int offset= buf.toString().indexOf("+");
+		AssistContext context= getCorrectionContext(cu, offset, 0);
+		assertNoErrors(context);
+		List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+		assertCorrectLabels(proposals);
+		assertProposalDoesNotExist(proposals, CorrectionMessages.QuickAssistProcessor_extractmethod_description);
+		buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E {\n");
+		buf.append("	public void foo1(int a) {\n");
+		buf.append("		FI2 k = (e) -> extracted(a, e);\n");
+		buf.append("		k.foo(3);\n");
+		buf.append("	}\n");
+		buf.append("\n");
+		buf.append("    private int extracted(int a, int e) {\n");
+		buf.append("        int x = e + 3;\n");
+		buf.append("        if (x > 3) {\n");
+		buf.append("        	return a;\n");
+		buf.append("        }\n");
+		buf.append("        return x;\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("\n");
+		buf.append("@FunctionalInterface\n");
+		buf.append("interface FI2 {\n");
+		buf.append("    int foo(int x);\n");
+		buf.append("}\n");
+
+		String expected1= buf.toString();
+
+		assertExpectedExistInProposals(proposals, new String[] { expected1 });
+	}
+
+	@Test
+	public void testExtractLambdaBodyToMethod2() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuilder buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E {\n");
+		buf.append("	public void foo1(int a) {\n");
+		buf.append("		FI2 k = (e) -> {\n");
+		buf.append("			int x = e + 3;\n");
+		buf.append("			if (x > 3) {\n");
+		buf.append("				return a;\n");
+		buf.append("			}\n");
+		buf.append("			return x;\n");
+		buf.append("		};\n");
+		buf.append("		k.foo(3);\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		buf.append("\n");
+		buf.append("@FunctionalInterface\n");
+		buf.append("interface FI2 {\n");
+		buf.append("    int foo(int x);\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+		int offset= buf.toString().indexOf("e + 3");
+		AssistContext context= getCorrectionContext(cu, offset, 5);
+		assertNoErrors(context);
+		List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+		assertCorrectLabels(proposals);
+		buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E {\n");
+		buf.append("	public void foo1(int a) {\n");
+		buf.append("		FI2 k = (e) -> extracted(a, e);\n");
+		buf.append("		k.foo(3);\n");
+		buf.append("	}\n");
+		buf.append("\n");
+		buf.append("    private int extracted(int a, int e) {\n");
+		buf.append("        int x = e + 3;\n");
+		buf.append("        if (x > 3) {\n");
+		buf.append("        	return a;\n");
+		buf.append("        }\n");
+		buf.append("        return x;\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("\n");
+		buf.append("@FunctionalInterface\n");
+		buf.append("interface FI2 {\n");
+		buf.append("    int foo(int x);\n");
+		buf.append("}\n");
+
+		String expected1= buf.toString();
+
+		buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E {\n");
+		buf.append("	public void foo1(int a) {\n");
+		buf.append("		FI2 k = (e) -> {\n");
+		buf.append("			int x = extracted(e);\n");
+		buf.append("			if (x > 3) {\n");
+		buf.append("				return a;\n");
+		buf.append("			}\n");
+		buf.append("			return x;\n");
+		buf.append("		};\n");
+		buf.append("		k.foo(3);\n");
+		buf.append("	}\n");
+		buf.append("\n");
+		buf.append("    private int extracted(int e) {\n");
+		buf.append("        return e + 3;\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("\n");
+		buf.append("@FunctionalInterface\n");
+		buf.append("interface FI2 {\n");
+		buf.append("    int foo(int x);\n");
+		buf.append("}\n");
+
+		String expected2= buf.toString();
+		assertExpectedExistInProposals(proposals, new String[] { expected1, expected2 });
+	}
+
+	@Test
+	public void testExtractLambdaBodyToMethod3() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuilder buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E {\n");
+		buf.append("	public void foo1(int a) {\n");
+		buf.append("		FI2 k = (e) -> {\n");
+		buf.append("			int x = e + 3;\n");
+		buf.append("            System.out.println(\"help\");\n");
+		buf.append("			if (x > 3) {\n");
+		buf.append("				return a;\n");
+		buf.append("			}\n");
+		buf.append("			return x;\n");
+		buf.append("		};\n");
+		buf.append("		k.foo(3);\n");
+		buf.append("	}\n");
+		buf.append("}\n");
+		buf.append("\n");
+		buf.append("@FunctionalInterface\n");
+		buf.append("interface FI2 {\n");
+		buf.append("    int foo(int x);\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+		int offset= buf.toString().indexOf("elp");
+		AssistContext context= getCorrectionContext(cu, offset, 5);
+		assertNoErrors(context);
+		List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+		assertCorrectLabels(proposals);
+		buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E {\n");
+		buf.append("	public void foo1(int a) {\n");
+		buf.append("		FI2 k = (e) -> extracted(a, e);\n");
+		buf.append("		k.foo(3);\n");
+		buf.append("	}\n");
+		buf.append("\n");
+		buf.append("    private int extracted(int a, int e) {\n");
+		buf.append("        int x = e + 3;\n");
+		buf.append("        System.out.println(\"help\");\n");
+		buf.append("        if (x > 3) {\n");
+		buf.append("        	return a;\n");
+		buf.append("        }\n");
+		buf.append("        return x;\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("\n");
+		buf.append("@FunctionalInterface\n");
+		buf.append("interface FI2 {\n");
+		buf.append("    int foo(int x);\n");
+		buf.append("}\n");
+
+		String expected1= buf.toString();
+
+		assertExpectedExistInProposals(proposals, new String[] { expected1 });
+	}
+
+	@Test
 	public void testBug433754() throws Exception {
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
 		StringBuilder buf= new StringBuilder();
@@ -4477,7 +4673,7 @@
 		context= getCorrectionContext(cu, offset, 0);
 		assertNoErrors(context);
 		proposals= collectAssists(context, false);
-		assertNumberOfProposals(proposals, 1);
+		assertNumberOfProposals(proposals, 2);
 		assertCorrectLabels(proposals);
 		buf= new StringBuilder();
 		buf.append("package test1;\n");
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpStressTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpStressTest.java
index 3dbbbd1..2d608c9 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpStressTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpStressTest.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
@@ -309,7 +309,7 @@
         buf.append("     * Extract the class name from a String in VA/Java style\n");
         buf.append("     */\n");
         buf.append("    public String extractClassName(final String className) {\n");
-        buf.append("        if (className.startsWith(\"Default package for\")) {\n");
+        buf.append("        if (className.startsWith(\"Default package for\")) { // $NON-NLS-1$\n");
         buf.append("            return className.substring(className.lastIndexOf(\".\") + 1); //$NON-NLS-1$\n");
         buf.append("        }\n");
         buf.append("        return className;\n");
@@ -1797,7 +1797,7 @@
         buf.append("            if (key.startsWith(\"excluded.\")) { //$NON-NLS-1$\n");
         buf.append("                String path = p.getProperty(key);\n");
         buf.append("                path = path.trim();\n");
-        buf.append("                if (path.endsWith(\"*\")) {\n");
+        buf.append("                if (path.endsWith(\"*\")) { //$NON-NLS-1$\n");
         buf.append("                    path = path.substring(0, path.length() - 1);\n");
         buf.append("                }\n");
         buf.append("                if (path.length() > 0) {\n");
@@ -2439,7 +2439,10 @@
         buf.append("                Assert.failNotEquals(message, new Double(expected),\n");
         buf.append("                        new Double(actual));\n");
         buf.append("            }\n");
-        buf.append("        } else if (!(Math.abs(expected - actual) <= delta)) {\n");
+        buf.append("        } else if (!(Math.abs(expected - actual) <= delta)) { // Because\n");
+        buf.append("                                                              // comparison with\n");
+        buf.append("                                                              // NaN always\n");
+        buf.append("                                                              // returns false\n");
         buf.append("            Assert.failNotEquals(message, new Double(expected),\n");
         buf.append("                    new Double(actual));\n");
         buf.append("        }\n");
@@ -2698,7 +2701,7 @@
         buf.append("        final String s = classFileName.substring(0,\n");
         buf.append("                classFileName.length() - ClassPathTestCollector.SUFFIX_LENGTH);\n");
         buf.append("        final String s2 = s.replace(File.separatorChar, '.');\n");
-        buf.append("        if (s2.startsWith(\".\")) {\n");
+        buf.append("        if (s2.startsWith(\".\")) { //$NON-NLS-1$\n");
         buf.append("            return s2.substring(1);\n");
         buf.append("        }\n");
         buf.append("        return s2;\n");
@@ -3081,19 +3084,19 @@
         buf.append("        boolean wait = false;\n");
         buf.append("\n");
         buf.append("        for (int i = 0; i < args.length; i++) {\n");
-        buf.append("            if (args[i].equals(\"-wait\")) {\n");
+        buf.append("            if (args[i].equals(\"-wait\")) { //$NON-NLS-1$\n");
         buf.append("                wait = true;\n");
-        buf.append("            } else if (args[i].equals(\"-c\")) {\n");
+        buf.append("            } else if (args[i].equals(\"-c\")) { //$NON-NLS-1$\n");
         buf.append("                testCase = this.extractClassName(args[++i]);\n");
-        buf.append("            } else if (args[i].equals(\"-v\")) {\n");
+        buf.append("            } else if (args[i].equals(\"-v\")) { //$NON-NLS-1$\n");
         buf.append("                System.err.println(\"JUnit \" + Version.id() //$NON-NLS-1$\n");
         buf.append("                        + \" by Kent Beck and Erich Gamma\"); //$NON-NLS-1$\n");
-        buf.append("            } else {\n");
+        buf.append("            } else { // $NON-NLS-1$\n");
         buf.append("                testCase = args[i];\n");
         buf.append("            }\n");
         buf.append("        }\n");
         buf.append("\n");
-        buf.append("        if (testCase.equals(\"\")) {\n");
+        buf.append("        if (testCase.equals(\"\")) { // $NON-NLS-1$\n");
         buf.append("            throw new Exception(\n");
         buf.append("                    \"Usage: TestRunner [-wait] testCaseName, where name is the name of the TestCase class\"); //$NON-NLS-1$\n");
         buf.append("        }\n");
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java
index de10c84..6566f92 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.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
@@ -864,6 +864,84 @@
 	}
 
 	@Test
+	public void testUnusedCodeBug578169() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		String sample= "" //
+				+ "package test1;\n" //
+				+ "public class E1 {\n" //
+				+ "    static class Point {\n" //
+				+ "        int x, y;\n" //
+		        + "        public int getX() {\n" //
+		        + "            return x;\n" //
+		        + "        }\n" //
+		        + "    }\n" //
+		        + "\n" //
+		        + "    static class Rect {\n" //
+		        + "        Point loc;\n" //
+		        + "        int w, h;\n" //
+		        + "        public Point getLoc() {\n" //
+		        + "            return loc;\n" //
+		        + "        }\n" //
+		        + "    }\n" //
+		        + "\n" //
+		        + "    Rect getRect() {\n" //
+		        + "        return new Rect();\n" //
+		        + "    }\n" //
+		        + "\n" //
+		        + "    void test() {\n" //
+		        + "        int x;\n" //
+		        + "        int y;\n" //
+		        + "        int z;\n" //
+		        + "        int k = getRect().loc.getX();\n" //
+		        + "        x = getRect().getLoc().x;\n" //
+		        + "        y = getRect().loc.y;\n" //
+		        + "        System.out.println(y);\n" //
+		        + "        z = getRect().loc.x;\n" //
+		        + "        k = getRect().loc.getX();\n" //
+		        + "    }\n" //
+				+ "}\n";
+		ICompilationUnit cu1= pack1.createCompilationUnit("E1.java", sample, false, null);
+
+		enable(CleanUpConstants.REMOVE_UNUSED_CODE_LOCAL_VARIABLES);
+
+		sample= "" //
+				+ "package test1;\n" //
+				+ "public class E1 {\n" //
+				+ "    static class Point {\n" //
+				+ "        int x, y;\n" //
+		        + "        public int getX() {\n" //
+		        + "            return x;\n" //
+		        + "        }\n" //
+		        + "    }\n" //
+		        + "\n" //
+		        + "    static class Rect {\n" //
+		        + "        Point loc;\n" //
+		        + "        int w, h;\n" //
+		        + "        public Point getLoc() {\n" //
+		        + "            return loc;\n" //
+		        + "        }\n" //
+		        + "    }\n" //
+		        + "\n" //
+		        + "    Rect getRect() {\n" //
+		        + "        return new Rect();\n" //
+		        + "    }\n" //
+		        + "\n" //
+		        + "    void test() {\n" //
+		        + "        int y;\n" //
+		        + "        getRect().loc.getX();\n" //
+		        + "        getRect().getLoc();\n" //
+		        + "        y = getRect().loc.y;\n" //
+		        + "        System.out.println(y);\n" //
+		        + "        getRect();\n" //
+		        + "        getRect().loc.getX();\n" //
+		        + "    }\n" //
+				+ "}\n";
+		String expected1= sample;
+
+		assertRefactoringResultAsExpected(new ICompilationUnit[] {cu1}, new String[] {expected1}, null);
+	}
+
+	@Test
 	public void testUnusedCodeBug123766() throws Exception {
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
 		String sample= "" //
@@ -11647,6 +11725,7 @@
 				+ "        boolean newBoolean2 = (i1 == i2) && (i3 <= i4) || !(i1 == i2) && !(i4 >= i3);\n" //
 				+ "        boolean newBoolean3 = (i1 == i2) && (i3 != i4) || (i2 != i1) && (i3 == i4);\n" //
 				+ "        boolean newBoolean4 = (i1 == i2) && (i3 < i4) || (i1 != i2) && (i4 <= i3);\n" //
+				+ "        boolean newBoolean5 = (i1 == i2 && i3 != i4) || (i2 != i1 && i3 == i4);\n" //
 				+ "    }\n" //
 				+ "\n" //
 				+ "    public void replaceDuplicateConditionsWithFields() {\n" //
@@ -11715,6 +11794,7 @@
 				+ "        boolean newBoolean2 = (i1 == i2) == (i3 <= i4);\n" //
 				+ "        boolean newBoolean3 = (i1 == i2) == (i3 != i4);\n" //
 				+ "        boolean newBoolean4 = (i1 == i2) == (i3 < i4);\n" //
+				+ "        boolean newBoolean5 = (i1 == i2) == (i3 != i4);\n" //
 				+ "    }\n" //
 				+ "\n" //
 				+ "    public void replaceDuplicateConditionsWithFields() {\n" //
@@ -18562,6 +18642,58 @@
 	}
 
 	@Test
+	public void testAddParenthesesBug578081() throws Exception {
+
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		String sample= "" //
+				+ "package test1;\n" //
+				+ "public class E {\n" //
+				+ "    void foo(int i) {\n" //
+				+ "        if (i == 0 || i == 1 /* i is 0 or 1 */) // if comment\n" //
+				+ "            /* additional if comment */\n"
+				+ "            System.out.println(i);\n" //
+				+ "        \n" //
+				+ "        while (i > 0 && i < 10 /* i gt 0 and lt 10 */) // while comment\n" //
+				+ "            /* additional while comment */\n"
+				+ "            System.out.println(1);\n" //
+				+ "        \n" //
+				+ "        boolean b= i != -1 && i > 10 && i < 100 || i > 20;\n" //
+				+ "        \n" //
+				+ "        do ; while (i > 5 && b || i < 100 && i > 90);\n" //
+				+ "    }\n" //
+				+ "}\n";
+		ICompilationUnit cu1= pack1.createCompilationUnit("E.java", sample, false, null);
+
+		enable(CleanUpConstants.CONTROL_STATEMENTS_USE_BLOCKS);
+		enable(CleanUpConstants.CONTROL_STATEMENTS_USE_BLOCKS_ALWAYS);
+
+		sample= "" //
+				+ "package test1;\n" //
+				+ "public class E {\n" //
+				+ "    void foo(int i) {\n" //
+				+ "        if (i == 0 || i == 1 /* i is 0 or 1 */) { // if comment\n" //
+				+ "        \t/* additional if comment */\n"
+				+ "        \tSystem.out.println(i);\n" //
+				+ "        }\n" //
+				+ "        \n" //
+				+ "        while (i > 0 && i < 10 /* i gt 0 and lt 10 */) { // while comment\n" //
+				+ "        \t/* additional while comment */\n"
+				+ "        \tSystem.out.println(1);\n" //
+				+ "        }\n" //
+				+ "        \n" //
+				+ "        boolean b= i != -1 && i > 10 && i < 100 || i > 20;\n" //
+				+ "        \n" //
+				+ "        do {\n" //
+				+ "            ;\n" //
+				+ "        } while (i > 5 && b || i < 100 && i > 90);\n" //
+				+ "    }\n" //
+				+ "}\n";
+		String expected1= sample;
+
+		assertRefactoringResultAsExpected(new ICompilationUnit[] {cu1}, new String[] {expected1}, null);
+	}
+
+	@Test
 	public void testRemoveParentheses01() throws Exception {
 
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
@@ -27826,4 +27958,55 @@
 						Messages.format(FixMessages.CodeStyleFix_QualifyWithThis_description, new Object[] {"field", "this"})
 				})));
 	}
+
+	@Test
+	public void testRemoveParenthesesBug438266_1() throws Exception {
+
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		String sample= ""
+				+ "package test1;\n" //
+				+ "public class E {\n"
+				+ "    public static void main(String[] args) {\n"
+				+ "        Integer b = (Integer) (-1);\n"
+				+ "        System.out.println(b);\n"
+				+ "    }\n"
+				+ "}";
+		ICompilationUnit cu1= pack1.createCompilationUnit("E.java", sample, false, null);
+
+		enable(CleanUpConstants.EXPRESSIONS_USE_PARENTHESES);
+		enable(CleanUpConstants.EXPRESSIONS_USE_PARENTHESES_NEVER);
+
+		String expected= sample;
+
+		assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected }, null);
+	}
+
+	@Test
+	public void testRemoveParenthesesBug438266_2() throws Exception {
+
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		String sample= ""
+				+ "package test1;\n" //
+				+ "public class E {\n"
+				+ "    public static void main(String[] args) {\n"
+				+ "        Integer b = (int) (-1);\n"
+				+ "        System.out.println(b);\n"
+				+ "    }\n"
+				+ "}";
+		ICompilationUnit cu1= pack1.createCompilationUnit("E.java", sample, false, null);
+
+		enable(CleanUpConstants.EXPRESSIONS_USE_PARENTHESES);
+		enable(CleanUpConstants.EXPRESSIONS_USE_PARENTHESES_NEVER);
+
+		String expected= ""
+				+ "package test1;\n" //
+				+ "public class E {\n"
+				+ "    public static void main(String[] args) {\n"
+				+ "        Integer b = (int) -1;\n"
+				+ "        System.out.println(b);\n"
+				+ "    }\n"
+				+ "}";
+
+		assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected }, null);
+	}
 }
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest12.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest12.java
index 45ad938..86a861b 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest12.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest12.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2020 Red Hat Inc. and others.
+ * Copyright (c) 2020, 2022 Red Hat Inc. and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -453,6 +453,23 @@
 				+ "        return 155;\n" //
 				+ "    }\n" //
 				+ "\n" //
+				+ "    public void replaceWhenVariableTypesConflict(int i1) {\n" //
+				+ "        int i = 0;\n" //
+				+ "        if (i1 == 0) {\n" //
+				+ "            int integer1 = 0;\n" //
+				+ "            i = integer1;\n" //
+				+ "        } else if (i1 == 2) {\n" //
+				+ "            char integer1 = 'a';\n" //
+				+ "            i = integer1;\n" //
+				+ "        } else if (i1 == 3) {\n" //
+				+ "            char c = 'a';\n" //
+				+ "            i = c;\n" //
+				+ "        } else {\n" //
+				+ "            char c = 'b';\n" //
+				+ "            i = c;\n" //
+				+ "        }\n" //
+				+ "    }\n" //
+				+ "\n" //
 				+ "    public int replaceMeltCases(int i1) {\n" //
 				+ "        // Keep this comment\n" //
 				+ "        if (i1 == 0) {\n" //
@@ -760,7 +777,7 @@
 				+ "            case 0 :\n" //
 				+ "                j = 0;\n" //
 				+ "                break;\n" //
-				+ "            case 1 :\n" //
+				+ "            case 1 : {\n" //
 				+ "                j = 10;\n" //
 				+ "                short k = 0;\n" //
 				+ "                do {\n" //
@@ -770,6 +787,7 @@
 				+ "                    k++;\n" //
 				+ "                } while (k < j);\n" //
 				+ "                break;\n" //
+				+ "            }\n" //
 				+ "            case 2 :\n" //
 				+ "                j = 20;\n" //
 				+ "                for (short l = 0; l < j; l++) {\n" //
@@ -778,7 +796,7 @@
 				+ "                    }\n" //
 				+ "                }\n" //
 				+ "                break;\n" //
-				+ "            case 3 :\n" //
+				+ "            case 3 : {\n" //
 				+ "                j = 25;\n" //
 				+ "                j = 30;\n" //
 				+ "                short m = 0;\n" //
@@ -789,6 +807,7 @@
 				+ "                    m++;\n" //
 				+ "                }\n" //
 				+ "                break;\n" //
+				+ "            }\n" //
 				+ "            case 4 :\n" //
 				+ "                j = 40;\n" //
 				+ "                for (short o : new short[] { 1, 2, 3 }) {\n" //
@@ -816,18 +835,21 @@
 				+ "    public void replaceIfWhenNoVariableNameConflictExists(int i1) {\n" //
 				+ "        int i = 0;\n" //
 				+ "        switch (i1) {\n" //
-				+ "            case 0 :\n" //
+				+ "            case 0 : {\n" //
 				+ "                int newVariable1 = 0;\n" //
 				+ "                i = newVariable1;\n" //
 				+ "                break;\n" //
-				+ "            case 1 :\n" //
+				+ "            }\n" //
+				+ "            case 1 : {\n" //
 				+ "                int newVariable2 = 10;\n" //
 				+ "                i = newVariable2;\n" //
 				+ "                break;\n" //
-				+ "            case 2 :\n" //
+				+ "            }\n" //
+				+ "            case 2 : {\n" //
 				+ "                char newVariable3 = 'a';\n" //
 				+ "                i = newVariable3;\n" //
 				+ "                break;\n" //
+				+ "            }\n" //
 				+ "            default :\n" //
 				+ "                break;\n" //
 				+ "        }\n" //
@@ -842,14 +864,16 @@
 				+ "                    i = integer1;\n" //
 				+ "                }\n" //
 				+ "                break;\n" //
-				+ "            case 1 :\n" //
+				+ "            case 1 : {\n" //
 				+ "                int integer1 = 10;\n" //
 				+ "                i = integer1;\n" //
 				+ "                break;\n" //
-				+ "            case 2 :\n" //
+				+ "            }\n" //
+				+ "            case 2 : {\n" //
 				+ "                int i2 = 20;\n" //
 				+ "                i = i2;\n" //
 				+ "                break;\n" //
+				+ "            }\n" //
 				+ "            default :\n" //
 				+ "                break;\n" //
 				+ "        }\n" //
@@ -978,6 +1002,32 @@
 				+ "        return 155;\n" //
 				+ "    }\n" //
 				+ "\n" //
+				+ "    public void replaceWhenVariableTypesConflict(int i1) {\n" //
+				+ "        int i = 0;\n" //
+				+ "        switch (i1) {\n" //
+				+ "            case 0 : {\n" //
+				+ "                int integer1 = 0;\n" //
+				+ "                i = integer1;\n" //
+				+ "                break;\n" //
+				+ "            }\n" //
+				+ "            case 2 : {\n" //
+				+ "                char integer1 = 'a';\n" //
+				+ "                i = integer1;\n" //
+				+ "                break;\n" //
+				+ "            }\n" //
+				+ "            case 3 : {\n" //
+				+ "                char c = 'a';\n" //
+				+ "                i = c;\n" //
+				+ "                break;\n" //
+				+ "            }\n" //
+				+ "            default : {\n" //
+				+ "                char c = 'b';\n" //
+				+ "                i = c;\n" //
+				+ "                break;\n" //
+				+ "            }\n" //
+				+ "        }\n" //
+				+ "    }\n" //
+				+ "\n" //
 				+ "    public int replaceMeltCases(int i1) {\n" //
 				+ "        // Keep this comment\n" //
 				+ "        switch (i1) {\n" //
@@ -1051,34 +1101,6 @@
 				+ "        }\n" //
 				+ "    }\n" //
 				+ "\n" //
-				+ "    public void doNotReplaceWhenVariableNameConflicts(int number) {\n" //
-				+ "        int i = 0;\n" //
-				+ "        if (number == 0) {\n" //
-				+ "            int integer1 = 0;\n" //
-				+ "            i = integer1;\n" //
-				+ "        } else if (number == 1) {\n" //
-				+ "            int integer1 = 10;\n" //
-				+ "            i = integer1;\n" //
-				+ "        } else if (number == 2) {\n" //
-				+ "            int i2 = 20;\n" //
-				+ "            i = i2;\n" //
-				+ "        }\n" //
-				+ "    }\n" //
-				+ "\n" //
-				+ "    public void doNotReplaceWhenVariableTypesConflict(int i1) {\n" //
-				+ "        int i = 0;\n" //
-				+ "        if (i1 == 0) {\n" //
-				+ "            int integer1 = 0;\n" //
-				+ "            i = integer1;\n" //
-				+ "        } else if (i1 == 2) {\n" //
-				+ "            char integer1 = 'a';\n" //
-				+ "            i = integer1;\n" //
-				+ "        } else if (i1 == 3) {\n" //
-				+ "            char c = 'a';\n" //
-				+ "            i = c;\n" //
-				+ "        }\n" //
-				+ "    }\n" //
-				+ "\n" //
 				+ "    public void doNotReplaceIfWithoutElseIf(int i1) {\n" //
 				+ "        int i = 0;\n" //
 				+ "        if (i1 == 0) {\n" //
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest14.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest14.java
index 910ade9..f096aba 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest14.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest14.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2020, 2021 Red Hat Inc. and others.
+ * Copyright (c) 2020, 2022 Red Hat Inc. and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -259,6 +259,7 @@
 
 		assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected1 }, null);
 	}
+
 	@Test
 	public void testConvertToSwitchExpressionBug574824() throws Exception {
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
@@ -310,6 +311,188 @@
 	}
 
 	@Test
+	public void testConvertToSwitchExpressionBug578130() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		String sample= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "import java.io.File;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+			    + "    public void foo(String[] args) throws Exception {\n" //
+			    + "        boolean isWhiteSpace;\n" //
+			    + "        switch (args[0].charAt(0)) {\n" //
+			    + "            case 10: /* \\ u000a: LINE FEED */\n" //
+			    + "            case 12: /* \\ u000c: FORM FEED */\n" //
+			    + "            case 13: /* \\ u000d: CARRIAGE RETURN */\n" //
+			    + "            case 32: /* \\ u0020: SPACE */\n" //
+			    + "            case 9: /* \\ u0009: HORIZONTAL TABULATION */\n" //
+			    + "                isWhiteSpace = true; /* comment x */\n" //
+			    + "                break;\n" //
+			    + "            case 0:\n" //
+			    + "            	   throw new Exception(\"invalid char\"); //$NON-NLS-1$\n" //
+			    + "            case 95:\n" //
+			    + "            {\n" //
+			    + "                System.out.println(\"here\"); //$NON-NLS-1$\n" //
+			    + "            	   isWhiteSpace = false;\n" //
+			    + "            }\n" //
+			    + "            break;\n" //
+			    + "            default:\n" //
+			    + "                isWhiteSpace = false;\n" //
+			    + "        }\n" //
+			    + "        System.out.println(isWhiteSpace);\n" //
+			    + "    }\n" //
+				+ "}\n";
+		ICompilationUnit cu1= pack1.createCompilationUnit("E.java", sample, false, null);
+
+		enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS);
+
+		sample= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "import java.io.File;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+			    + "    public void foo(String[] args) throws Exception {\n" //
+			    + "        boolean isWhiteSpace = switch (args[0].charAt(0)) {\n" //
+			    + "            case 10: /* \\ u000a: LINE FEED */\n" //
+			    + "            case 12: /* \\ u000c: FORM FEED */\n" //
+			    + "            case 13: /* \\ u000d: CARRIAGE RETURN */\n" //
+			    + "            case 32: /* \\ u0020: SPACE */\n" //
+			    + "            case 9: /* \\ u0009: HORIZONTAL TABULATION */\n" //
+			    + "                yield true; /* comment x */\n" //
+			    + "            case 0:\n" //
+			    + "                throw new Exception(\"invalid char\"); //$NON-NLS-1$\n" //
+			    + "            case 95: {\n" //
+			    + "                System.out.println(\"here\"); //$NON-NLS-1$\n" //
+			    + "                yield false;\n" //
+			    + "            }\n" //
+			    + "            default:\n" //
+			    + "                yield false;\n" //
+			    + "        };\n" //
+			    + "        System.out.println(isWhiteSpace);\n" //
+			    + "    }\n" //
+				+ "}\n";
+		String expected1= sample;
+
+		assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected1 }, null);
+	}
+
+	@Test
+	public void testConvertToSwitchExpressionBug578129_1() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		String sample= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "import java.io.File;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+			    + "    public void foo(String[] args) throws Exception {\n" //
+			    + "        boolean isWhiteSpace;\n" //
+			    + "        switch (args[0].charAt(0)) {\n" //
+			    + "            case 10:\n" //
+			    + "            case 12:\n" //
+			    + "            case 13:\n" //
+			    + "            case 32:\n" //
+			    + "            case 9:\n" //
+			    + "                isWhiteSpace = true; /* comment x */\n" //
+			    + "                break;\n" //
+			    + "            case 0:\n" //
+			    + "            	   throw new Exception(\"invalid char\"); //$NON-NLS-1$\n" //
+			    + "            case 95:\n" //
+			    + "            default:\n" //
+			    + "                isWhiteSpace = false;\n" //
+			    + "        }\n" //
+			    + "        System.out.println(isWhiteSpace);\n" //
+			    + "    }\n" //
+				+ "}\n";
+		ICompilationUnit cu1= pack1.createCompilationUnit("E.java", sample, false, null);
+
+		enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS);
+
+		sample= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "import java.io.File;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+			    + "    public void foo(String[] args) throws Exception {\n" //
+			    + "        boolean isWhiteSpace = switch (args[0].charAt(0)) {\n" //
+			    + "            case 10, 12, 13, 32, 9 -> true; /* comment x */\n" //
+			    + "            case 0 -> throw new Exception(\"invalid char\"); //$NON-NLS-1$\n" //
+			    + "            case 95 -> false;\n" //
+			    + "            default -> false;\n" //
+			    + "        };\n" //
+			    + "        System.out.println(isWhiteSpace);\n" //
+			    + "    }\n" //
+				+ "}\n";
+		String expected1= sample;
+
+		assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected1 }, null);
+	}
+
+	@Test
+	public void testConvertToSwitchExpressionBug578129_2() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		String sample= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "import java.io.File;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+			    + "    public void foo(String[] args) throws Exception {\n" //
+			    + "        boolean isWhiteSpace;\n" //
+			    + "        switch (args[0].charAt(0)) {\n" //
+			    + "            case 10:\n" //
+			    + "            case 12:\n" //
+			    + "            case 13:\n" //
+			    + "            case 32:\n" //
+			    + "            case 9:\n" //
+			    + "                isWhiteSpace = true; /* comment x */\n" //
+			    + "                break;\n" //
+			    + "            case 0:\n" //
+			    + "            	   throw new Exception(\"invalid char\"); //$NON-NLS-1$\n" //
+			    + "            case 95:\n" //
+			    + "            default: {\n" //
+			    + "                System.out.println(\"non-whitespace\");\n" //
+			    + "                isWhiteSpace = false;\n" //
+			    + "            }\n" //
+			    + "        }\n" //
+			    + "        System.out.println(isWhiteSpace);\n" //
+			    + "    }\n" //
+				+ "}\n";
+		ICompilationUnit cu1= pack1.createCompilationUnit("E.java", sample, false, null);
+
+		enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS);
+
+		sample= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "import java.io.File;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+			    + "    public void foo(String[] args) throws Exception {\n" //
+			    + "        boolean isWhiteSpace = switch (args[0].charAt(0)) {\n" //
+			    + "            case 10, 12, 13, 32, 9 -> true; /* comment x */\n" //
+			    + "            case 0 -> throw new Exception(\"invalid char\"); //$NON-NLS-1$\n" //
+			    + "            case 95 -> {\n" //
+			    + "                System.out.println(\"non-whitespace\");\n" //
+			    + "                yield false;\n" //
+			    + "            }\n" //
+			    + "            default -> {\n" //
+			    + "                System.out.println(\"non-whitespace\");\n" //
+			    + "                yield false;\n" //
+			    + "            }\n" //
+			    + "        };\n" //
+			    + "        System.out.println(isWhiteSpace);\n" //
+			    + "    }\n" //
+				+ "}\n";
+		String expected1= sample;
+
+		assertRefactoringResultAsExpected(new ICompilationUnit[] { cu1 }, new String[] { expected1 }, null);
+	}
+
+	@Test
 	public void testDoNotConvertToSwitchExpressionNoBreak() throws Exception {
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
 		String sample= "" //
@@ -532,4 +715,39 @@
 		assertRefactoringHasNoChange(new ICompilationUnit[] { cu1 });
 	}
 
+	@Test
+	public void testDoNotConvertToSwitchExpressionBug578128() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		String sample= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "public class E1 {\n" //
+			    + "    public static void main(String[] args) {\n" //
+			    + "        boolean rulesOK = true;\n" //
+			    + "        switch (args[0].charAt(0)) {\n" //
+			    + "            case '+':\n" //
+			    + "                args[0] = \"+\";\n" //
+			    + "                break;\n" //
+			    + "            case '~':\n" //
+			    + "                args[0] = \"~\";\n" //
+			    + "                break;\n" //
+			    + "            case '-':\n" //
+			    + "                args[0] = \"-\";\n" //
+			    + "                break;\n" //
+			    + "            case '?':\n" //
+			    + "                args[0] = \"?\";\n" //
+			    + "                break;\n" //
+			    + "            default:\n" //
+			    + "                rulesOK = false;\n" //
+			    + "        }\n" //
+			    + "        System.out.println(rulesOK);\n" //
+			    + "    }\n" //
+				+ "}\n";
+		ICompilationUnit cu1= pack1.createCompilationUnit("E1.java", sample, false, null);
+
+		enable(CleanUpConstants.CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS);
+
+		assertRefactoringHasNoChange(new ICompilationUnit[] { cu1 });
+	}
+
 }
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest16.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest16.java
index 6f64edb..a887787 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest16.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest16.java
@@ -630,4 +630,32 @@
 		assertRefactoringResultAsExpected(new ICompilationUnit[] { cu0, cu1 }, new String[] { expected0, expected1 }, null);
 	}
 
+	@Test
+	public void testDoNotRemoveParenthesesFromPatternInstanceof() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+
+		String sample= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "public class TestParenthesesRemoval {\n" //
+				+ "        public static void doNotChangeParenthesesForInstanceof(Object o) {\n" //
+				+ "            if (!(o instanceof String)) {\n" //
+				+ "                System.out.println(\"not a String\");\n" //
+				+ "            }\n" //
+				+ "        }\n" //
+				+ "        public static void doNotChangeParenthesesForPatternInstanceof(Object o) {\n" //
+				+ "            if (!(o instanceof String s)) {\n" //
+				+ "                System.out.println(\"not a String\");\n" //
+				+ "            } else {\n" //
+				+ "                System.out.println(\"String length is \" + s.length());\n" //
+				+ "        }\n" //
+				+ "    }\n" //
+				+ "}\n";
+		ICompilationUnit cu1= pack1.createCompilationUnit("TestParenthesesRemoval.java", sample, false, null);
+
+		enable(CleanUpConstants.EXPRESSIONS_USE_PARENTHESES_NEVER);
+
+		assertRefactoringHasNoChange(new ICompilationUnit[] { cu1 });
+	}
+
 }
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d5.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d5.java
index f944e5b..4716910 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d5.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d5.java
@@ -2343,12 +2343,30 @@
 	}
 
 	@Test
-	public void testDoNotUseAutoboxingOnString() throws Exception {
+	public void testDoNotUseAutoboxing() throws Exception {
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
 		String sample= "" //
 				+ "package test1;\n" //
 				+ "\n" //
+				+ "import java.util.List;\n" //
+				+ "\n" //
 				+ "public class E1 {\n" //
+				+ "    public static int dummyMethod(Byte byObject) {\n" //
+				+ "        return 1;\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public static int dummyMethod(byte byPrimitive) {\n" //
+				+ "        return 2;\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public static void doNotCleanupOnConflictingMethod(byte byPrimitive) {\n" //
+				+ "        dummyMethod(Byte.valueOf(byPrimitive));\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public static void doNotCleanupOnOverloadedMethod(List<Integer> integers, int notAnIndex) {\n" //
+				+ "        integers.remove(Integer.valueOf(notAnIndex));\n" //
+				+ "    }\n" //
+				+ "\n" //
 				+ "    public static void doNotUseAutoboxingOnString() {\n" //
 				+ "        Integer i = Integer.valueOf(\"1\");\n" //
 				+ "        Long l = Long.valueOf(\"1\");\n" //
@@ -2612,6 +2630,22 @@
 				+ "package test1;\n" //
 				+ "\n" //
 				+ "public class E1 {\n" //
+				+ "    public static int dummyMethod(Byte byObject) {\n" //
+				+ "        return 1;\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public static int dummyMethod(byte byPrimitive) {\n" //
+				+ "        return 2;\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public static void doNotCleanupOnConflictingMethod(Byte byObject) {\n" //
+				+ "        dummyMethod(byObject.byteValue());\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public static void doNotCleanupOnOverloadedMethod(StringBuilder builder, Character optimizedObject) {\n" //
+				+ "        builder.append(optimizedObject.charValue());\n" //
+				+ "    }\n" //
+				+ "\n" //
 				+ "    public static void doNotUseUnboxingOnNarrowingType(Character cObject, Byte byObject,\n" //
 				+ "            Integer iObject, Short sObject, Float fObject) {\n" //
 				+ "        int c = cObject.charValue();\n" //
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/LocalCorrectionsQuickFixTest1d8.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/LocalCorrectionsQuickFixTest1d8.java
index 498ce03..7412975 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/LocalCorrectionsQuickFixTest1d8.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/LocalCorrectionsQuickFixTest1d8.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014, 2020 IBM Corporation and others.
+ * Copyright (c) 2014, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -1217,6 +1217,204 @@
 	}
 
 	@Test
+	public void testCreateMethodInSuperTypeQuickFix1() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuilder buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    void foo(int... i) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+		CompilationUnit astRoot= getASTRoot(cu);
+		ArrayList<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
+		assertNumberOfProposals(proposals, 2);
+		assertCorrectLabels(proposals);
+
+		buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    void foo(int... i) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("\n");
+		buf.append("    void foo(int... i);\n");
+		buf.append("}\n");
+		assertExpectedExistInProposals(proposals, new String[] { buf.toString() });
+	}
+
+	@Test
+	public void testCreateMethodInSuperTypeQuickFix2() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuilder buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    void foo(int[]... i) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+		CompilationUnit astRoot= getASTRoot(cu);
+		ArrayList<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
+		assertNumberOfProposals(proposals, 2);
+		assertCorrectLabels(proposals);
+
+		buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    void foo(int[]... i) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("\n");
+		buf.append("    void foo(int[]... i);\n");
+		buf.append("}\n");
+		assertExpectedExistInProposals(proposals, new String[] { buf.toString() });
+	}
+
+	@Test
+	public void testCreateMethodInSuperTypeQuickFix3() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuilder buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    void foo(double d, int[]... i) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+		CompilationUnit astRoot= getASTRoot(cu);
+		ArrayList<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
+		assertNumberOfProposals(proposals, 2);
+		assertCorrectLabels(proposals);
+
+		buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    void foo(double d, int[]... i) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("\n");
+		buf.append("    void foo(double d, int[]... i);\n");
+		buf.append("}\n");
+		assertExpectedExistInProposals(proposals, new String[] { buf.toString() });
+	}
+
+	@Test
+	public void testCreateMethodInSuperTypeQuickFix4() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuilder buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    <T> void foo(T t) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+		CompilationUnit astRoot= getASTRoot(cu);
+		ArrayList<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
+		assertNumberOfProposals(proposals, 2);
+		assertCorrectLabels(proposals);
+
+		buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    <T> void foo(T t) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("\n");
+		buf.append("    <T> void foo(T t);\n");
+		buf.append("}\n");
+		assertExpectedExistInProposals(proposals, new String[] { buf.toString() });
+	}
+
+	@Test
+	public void testCreateMethodInSuperTypeQuickFix5() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuilder buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    <T> void foo(T... t) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+		CompilationUnit astRoot= getASTRoot(cu);
+		ArrayList<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
+		assertNumberOfProposals(proposals, 2);
+		assertCorrectLabels(proposals);
+
+		buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    <T> void foo(T... t) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("\n");
+		buf.append("    <T> void foo(T... t);\n");
+		buf.append("}\n");
+		assertExpectedExistInProposals(proposals, new String[] { buf.toString() });
+	}
+
+	@Test
+	public void testCreateMethodInSuperTypeQuickFix6() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		StringBuilder buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    <T> void foo(T[]... t) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("}\n");
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", buf.toString(), false, null);
+
+		CompilationUnit astRoot= getASTRoot(cu);
+		ArrayList<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
+		assertNumberOfProposals(proposals, 2);
+		assertCorrectLabels(proposals);
+
+		buf= new StringBuilder();
+		buf.append("package test1;\n");
+		buf.append("class E implements I {\n");
+		buf.append("    @Override\n");
+		buf.append("    <T> void foo(T[]... t) {\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("interface I {\n");
+		buf.append("\n");
+		buf.append("    <T> void foo(T[]... t);\n");
+		buf.append("}\n");
+		assertExpectedExistInProposals(proposals, new String[] { buf.toString() });
+	}
+
+	@Test
 	public void testOverrideDefaultMethod_noParam() throws Exception {
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
 		StringBuilder buf= new StringBuilder();
diff --git a/org.eclipse.jdt.ui.unittest.junit.feature/feature.xml b/org.eclipse.jdt.ui.unittest.junit.feature/feature.xml
index f0b1976..76df38a 100644
--- a/org.eclipse.jdt.ui.unittest.junit.feature/feature.xml
+++ b/org.eclipse.jdt.ui.unittest.junit.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.jdt.ui.unittest.junit.feature"
       label="%featureName"
-      version="1.0.100.qualifier"
+      version="1.0.200.qualifier"
       provider-name="%provider"
       license-feature="org.eclipse.license"
       license-feature-version="0.0.0">
diff --git a/org.eclipse.jdt.ui.unittest.junit.feature/pom.xml b/org.eclipse.jdt.ui.unittest.junit.feature/pom.xml
index dab5bba..2c71a7c 100644
--- a/org.eclipse.jdt.ui.unittest.junit.feature/pom.xml
+++ b/org.eclipse.jdt.ui.unittest.junit.feature/pom.xml
@@ -20,7 +20,7 @@
   </parent>
   <groupId>org.eclipse.jdt.feature</groupId>
   <artifactId>org.eclipse.jdt.ui.unittest.junit.feature</artifactId>
-  <version>1.0.100-SNAPSHOT</version>
+  <version>1.0.200-SNAPSHOT</version>
   <packaging>eclipse-feature</packaging>
   <build>
      <plugins>
diff --git a/org.eclipse.jdt.ui.unittest.junit/META-INF/MANIFEST.MF b/org.eclipse.jdt.ui.unittest.junit/META-INF/MANIFEST.MF
index 11ec513..fe83769 100644
--- a/org.eclipse.jdt.ui.unittest.junit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.ui.unittest.junit/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.ui.unittest.junit;singleton:=true
-Bundle-Version: 1.0.200.qualifier
+Bundle-Version: 1.0.300.qualifier
 Bundle-Activator: org.eclipse.jdt.ui.unittest.junit.JUnitTestPlugin
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %providerName
@@ -22,9 +22,9 @@
  org.eclipse.core.runtime;bundle-version="[3.11.0,4.0.0)",
  org.eclipse.jdt.launching;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.jdt.debug.ui;bundle-version="[3.3.0,4.0.0)",
- org.eclipse.jdt.junit.core;bundle-version="[3.10.800,4.0.0]",
+ org.eclipse.jdt.junit.core;bundle-version="[3.11.200,4.0.0]",
  org.eclipse.jdt.junit.runtime;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.core.variables;bundle-version="[3.2.200,4.0.0)",
  org.eclipse.jdt.core.manipulation;bundle-version="1.9.0",
- org.eclipse.jdt.junit;bundle-version="3.11.0"
+ org.eclipse.jdt.junit;bundle-version="3.14.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-11
diff --git a/org.eclipse.jdt.ui.unittest.junit/pom.xml b/org.eclipse.jdt.ui.unittest.junit/pom.xml
index a2dad83..f0c4a57 100644
--- a/org.eclipse.jdt.ui.unittest.junit/pom.xml
+++ b/org.eclipse.jdt.ui.unittest.junit/pom.xml
@@ -18,7 +18,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.ui.unittest.junit</artifactId>
-  <version>1.0.200-SNAPSHOT</version>
+  <version>1.0.300-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
   <properties>
       <skipAPIAnalysis>true</skipAPIAnalysis>
diff --git a/org.eclipse.jdt.ui.unittest.junit/src/org/eclipse/jdt/ui/unittest/junit/launcher/JUnitLaunchConfigurationDelegate.java b/org.eclipse.jdt.ui.unittest.junit/src/org/eclipse/jdt/ui/unittest/junit/launcher/JUnitLaunchConfigurationDelegate.java
index ea343f2..aa61037 100644
--- a/org.eclipse.jdt.ui.unittest.junit/src/org/eclipse/jdt/ui/unittest/junit/launcher/JUnitLaunchConfigurationDelegate.java
+++ b/org.eclipse.jdt.ui.unittest.junit/src/org/eclipse/jdt/ui/unittest/junit/launcher/JUnitLaunchConfigurationDelegate.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
@@ -228,6 +228,34 @@
 									new Status(IStatus.ERROR, JUnitTestPlugin.PLUGIN_ID, IStatus.ERROR, "", e)); //$NON-NLS-1$
 						}
 					}
+					if (!Arrays.stream(classpath).anyMatch(
+							s -> s.contains("junit-jupiter-engine") || s.contains("org.junit.jupiter.engine"))) { //$NON-NLS-1$ //$NON-NLS-2$
+						try {
+							JUnitRuntimeClasspathEntry x = new JUnitRuntimeClasspathEntry("org.junit.jupiter.engine", //$NON-NLS-1$
+									null);
+							String entryString = new ClasspathLocalizer(false).entryString(x);
+							int length = classpath.length;
+							System.arraycopy(classpath, 0, classpath = new String[length + 1], 0, length);
+							classpath[length] = entryString;
+						} catch (IOException | URISyntaxException e) {
+							throw new CoreException(
+									new Status(IStatus.ERROR, JUnitCorePlugin.CORE_PLUGIN_ID, IStatus.ERROR, "", e)); //$NON-NLS-1$
+						}
+					}
+					if (!Arrays.stream(classpath)
+							.anyMatch(s -> s.contains("junit-jupiter-api") || s.contains("org.junit.jupiter.api"))) { //$NON-NLS-1$ //$NON-NLS-2$
+						try {
+							JUnitRuntimeClasspathEntry x = new JUnitRuntimeClasspathEntry("org.junit.jupiter.api", //$NON-NLS-1$
+									null);
+							String entryString = new ClasspathLocalizer(false).entryString(x);
+							int length = classpath.length;
+							System.arraycopy(classpath, 0, classpath = new String[length + 1], 0, length);
+							classpath[length] = entryString;
+						} catch (IOException | URISyntaxException e) {
+							throw new CoreException(
+									new Status(IStatus.ERROR, JUnitCorePlugin.CORE_PLUGIN_ID, IStatus.ERROR, "", e)); //$NON-NLS-1$
+						}
+					}
 				}
 			}
 
diff --git a/org.eclipse.jdt.ui/META-INF/MANIFEST.MF b/org.eclipse.jdt.ui/META-INF/MANIFEST.MF
index 6ffb6dd..f5453ec 100644
--- a/org.eclipse.jdt.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.ui/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.ui; singleton:=true
-Bundle-Version: 3.25.100.qualifier
+Bundle-Version: 3.26.0.qualifier
 Bundle-Activator: org.eclipse.jdt.internal.ui.JavaPlugin
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %providerName
@@ -45,6 +45,7 @@
  org.eclipse.jdt.internal.ui.dialogs;x-friends:="org.eclipse.jdt.apt.ui,org.eclipse.jdt.junit",
  org.eclipse.jdt.internal.ui.dnd;x-internal:=true,
  org.eclipse.jdt.internal.ui.filters;x-internal:=true,
+ org.eclipse.jdt.internal.ui.filtertable;x-friends:="org.eclipse.jdt.junit,org.eclipse.jdt.debug.ui",
  org.eclipse.jdt.internal.ui.fix;x-internal:=true,
  org.eclipse.jdt.internal.ui.infoviews;x-internal:=true,
  org.eclipse.jdt.internal.ui.jarimport;x-internal:=true,
@@ -120,7 +121,7 @@
  org.eclipse.compare;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.team.ui;bundle-version="[3.4.100,4.0.0)",
  org.eclipse.team.core;bundle-version="[3.4.100,4.0.0)",
- org.eclipse.jface.text;bundle-version="[3.16.0,4.0.0)",
+ org.eclipse.jface.text;bundle-version="[3.20.0,4.0.0)",
  org.eclipse.ui;bundle-version="[3.117.0,4.0.0)",
  org.eclipse.ui.console;bundle-version="[3.4.0,4.0.0)",
  org.eclipse.ui.workbench.texteditor;bundle-version="[3.10.0,4.0.0)",
@@ -133,7 +134,7 @@
  org.eclipse.ui.forms;bundle-version="[3.4.0,4.0.0)",
  org.eclipse.ui.navigator;bundle-version="[3.3.200,4.0.0)",
  org.eclipse.ui.navigator.resources;bundle-version="[3.4.0,4.0.0)",
- org.eclipse.jdt.core.manipulation;bundle-version="[1.15.100,2.0.0)",
+ org.eclipse.jdt.core.manipulation;bundle-version="[1.15.200,2.0.0)",
  com.ibm.icu;bundle-version="4.4.2",
  org.eclipse.equinox.bidi;bundle-version="[0.10.0,2.0.0)"
 Bundle-RequiredExecutionEnvironment: JavaSE-11
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CallHierarchy.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CallHierarchy.java
index b1f04d7..8a8cd72 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CallHierarchy.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/callhierarchy/CallHierarchy.java
@@ -63,7 +63,7 @@
         return settings.getBoolean(PREF_USE_IMPLEMENTORS);
     }
 
-    public void setSearchUsingImplementorsEnabled(boolean enabled) {
+    public static void setSearchUsingImplementorsEnabled(boolean enabled) {
         IPreferenceStore settings = JavaPlugin.getDefault().getPreferenceStore();
 
         settings.setValue(PREF_USE_IMPLEMENTORS, enabled);
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ControlStatementsFix.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ControlStatementsFix.java
index 282de9f..4a517db 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ControlStatementsFix.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/ControlStatementsFix.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2011 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
@@ -20,9 +20,12 @@
 
 import org.eclipse.text.edits.TextEditGroup;
 
+import org.eclipse.jdt.core.IBuffer;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.Block;
 import org.eclipse.jdt.core.dom.ChildPropertyDescriptor;
+import org.eclipse.jdt.core.dom.Comment;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.core.dom.DoStatement;
 import org.eclipse.jdt.core.dom.EnhancedForStatement;
@@ -33,6 +36,7 @@
 import org.eclipse.jdt.core.dom.ThrowStatement;
 import org.eclipse.jdt.core.dom.WhileStatement;
 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
 
 import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
@@ -181,18 +185,82 @@
 		public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
 			ASTRewrite rewrite= cuRewrite.getASTRewrite();
 			String label;
+			ASTNode expression= null;
+			int statementType= -1;
 			if (fBodyProperty == IfStatement.THEN_STATEMENT_PROPERTY) {
 				label = FixMessages.CodeStyleFix_ChangeIfToBlock_desription;
+				expression= ((IfStatement)fControlStatement).getExpression();
+				if (((IfStatement)fControlStatement).getElseStatement() == null) {
+					statementType= ASTNode.IF_STATEMENT;
+				}
 			} else if (fBodyProperty == IfStatement.ELSE_STATEMENT_PROPERTY) {
 				label = FixMessages.CodeStyleFix_ChangeElseToBlock_description;
+				expression= ((IfStatement)fControlStatement).getExpression();
 			} else {
 				label = FixMessages.CodeStyleFix_ChangeControlToBlock_description;
+				if (fBodyProperty == WhileStatement.BODY_PROPERTY) {
+					expression= ((WhileStatement)fControlStatement).getExpression();
+					statementType= ASTNode.WHILE_STATEMENT;
+				} else if (fBodyProperty == ForStatement.BODY_PROPERTY) {
+					expression= ((ForStatement)fControlStatement).getExpression();
+					statementType= ASTNode.FOR_STATEMENT;
+				} else if (fBodyProperty == EnhancedForStatement.BODY_PROPERTY) {
+					expression= ((EnhancedForStatement)fControlStatement).getExpression();
+					statementType= ASTNode.ENHANCED_FOR_STATEMENT;
+				}
 			}
 
 			TextEditGroup group= createTextEditGroup(label, cuRewrite);
-			ASTNode moveTarget= rewrite.createMoveTarget(fBody);
-			Block replacingBody= cuRewrite.getRoot().getAST().newBlock();
-			replacingBody.statements().add(moveTarget);
+			List<Comment> commentsToPreserve= new ArrayList<>();
+			CompilationUnit cuRoot= cuRewrite.getRoot();
+			int controlStatementLine= cuRoot.getLineNumber(fControlStatement.getStartPosition());
+			int bodyLine= cuRoot.getLineNumber(fBody.getStartPosition());
+			// If single body statement is on next line, we need to preserve any comments pertaining to the
+			// control statement (e.g. NLS comment for if expression)
+			if (controlStatementLine != bodyLine) {
+				int startPosition= expression == null ? fControlStatement.getStartPosition() : (expression.getStartPosition() + cuRoot.getExtendedLength(expression));
+				List<Comment> comments= cuRoot.getCommentList();
+				for (Comment comment : comments) {
+					int commentLine= cuRoot.getLineNumber(comment.getStartPosition());
+					if (commentLine == controlStatementLine && comment.getStartPosition() > startPosition &&
+							comment.getStartPosition() < fBody.getStartPosition()) {
+						commentsToPreserve.add(comment);
+					}
+				}
+			}
+			String blockString= "{"; //$NON-NLS-1$
+			IBuffer cuBuffer= cuRewrite.getCu().getBuffer();
+			Block replacingBody= null;
+			String blockPosition= JavaCore.getOption(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_BLOCK);
+			boolean blockEndOfLine= blockPosition.equals(DefaultCodeFormatterConstants.END_OF_LINE);
+			if (!commentsToPreserve.isEmpty()) {
+				// Get extended body text and convert multiple indent tabs to be just one tab as they will be relative to control statement
+				String bodyString= cuBuffer.getText(cuRoot.getExtendedStartPosition(fBody), cuRoot.getExtendedLength(fBody))
+						.replaceAll("\\r\\n|\\r|\\n(\\t|\\s)*", System.lineSeparator() + "\t"); //$NON-NLS-1$ //$NON-NLS-2$
+				if (blockEndOfLine || statementType == -1) {
+					// To ensure the comments to preserve end up on same line as the control statement, we need
+					// to build the block manually as a string and then create a Block placeholder from it
+					for (Comment comment : commentsToPreserve) {
+						String commentString= cuBuffer.getText(comment.getStartPosition(), comment.getLength());
+						blockString += " " + commentString; //$NON-NLS-1$
+					}
+					blockString += System.lineSeparator() + "\t" + bodyString + System.lineSeparator() + "}"; //$NON-NLS-1$ //$NON-NLS-2$
+					replacingBody= (Block)rewrite.createStringPlaceholder(blockString, ASTNode.BLOCK);
+				} else {
+					Comment lastComment= commentsToPreserve.get(commentsToPreserve.size()-1);
+					String newControlStatement= cuBuffer.getText(cuRoot.getExtendedStartPosition(fControlStatement),
+							lastComment.getStartPosition() + lastComment.getLength() - cuRoot.getExtendedStartPosition(fControlStatement));
+					newControlStatement += System.lineSeparator() + "{" + System.lineSeparator(); //$NON-NLS-1$
+					newControlStatement += "\t" + bodyString + System.lineSeparator() + "}"; //$NON-NLS-1$ //$NON-NLS-2$
+					Statement newStatement= (Statement)rewrite.createStringPlaceholder(newControlStatement, statementType);
+					rewrite.replace(fControlStatement, newStatement, group);
+					return;
+				}
+			} else {
+				ASTNode moveTarget= rewrite.createMoveTarget(fBody);
+				replacingBody= cuRewrite.getRoot().getAST().newBlock();
+				replacingBody.statements().add(moveTarget);
+			}
 			rewrite.set(fControlStatement, fBodyProperty, replacingBody, group);
 		}
 
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/UnnecessaryArrayCreationFix.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/UnnecessaryArrayCreationFix.java
index b8b68d5..fb9034e 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/UnnecessaryArrayCreationFix.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/UnnecessaryArrayCreationFix.java
@@ -18,8 +18,8 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Stream;
 
 import org.eclipse.core.runtime.IStatus;
 
@@ -30,16 +30,10 @@
 import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.core.dom.Expression;
 import org.eclipse.jdt.core.dom.IMethodBinding;
-import org.eclipse.jdt.core.dom.IPackageBinding;
 import org.eclipse.jdt.core.dom.ITypeBinding;
-import org.eclipse.jdt.core.dom.ImportDeclaration;
 import org.eclipse.jdt.core.dom.MethodInvocation;
-import org.eclipse.jdt.core.dom.Modifier;
 import org.eclipse.jdt.core.dom.NullLiteral;
-import org.eclipse.jdt.core.dom.QualifiedName;
 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
-import org.eclipse.jdt.core.dom.ThisExpression;
-import org.eclipse.jdt.core.dom.TypeDeclaration;
 
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
 import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
@@ -50,9 +44,10 @@
 public class UnnecessaryArrayCreationFix extends CompilationUnitRewriteOperationsFix {
 
 	public final static class UnnecessaryArrayCreationFinder extends GenericVisitor {
+		private static final Set<String> fInvalidTypes= new HashSet<>(Arrays.asList("byte", "char", "short")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
 		private final List<CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation> fResult;
 		private final boolean fRemoveUnnecessaryArrayCreation;
-		private final Set<String> fInvalidTypes= new HashSet<>(Arrays.asList("byte", "char", "short")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 
 		public UnnecessaryArrayCreationFinder(boolean removeUnnecessaryArrayCreation, List<CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation> resultingCollection) {
 			fRemoveUnnecessaryArrayCreation= removeUnnecessaryArrayCreation;
@@ -60,62 +55,64 @@
 		}
 
 		@Override
-		public boolean visit(ArrayCreation node) {
+		public boolean visit(ArrayCreation visited) {
 			if (!fRemoveUnnecessaryArrayCreation
-					|| node.getType().getDimensions() != 1) {
+					|| visited.getType().getDimensions() != 1) {
 				return true;
 			}
 
-			ArrayInitializer initializer= node.getInitializer();
+			ArrayInitializer initializer= visited.getInitializer();
 
 			if (initializer != null
 					&& initializer.expressions() != null
 					&& initializer.expressions().size() == 1) {
 				List<Expression> expressions= initializer.expressions();
 				ITypeBinding singleElement= expressions.get(0).resolveTypeBinding();
-				NullLiteral nullLiteral= ASTNodes.as(expressions.get(0), NullLiteral.class);
 
-				if (nullLiteral != null
+				if (ASTNodes.is(expressions.get(0), NullLiteral.class)
 						|| singleElement == null
 						|| singleElement.isArray()) {
 					return true;
 				}
 			}
 
-			ASTNode parent= node.getParent();
+			ASTNode parent= visited.getParent();
 
-			if (parent instanceof ClassInstanceCreation) {
+			if (parent instanceof ClassInstanceCreation
+					&& visited.getLocationInParent() == ClassInstanceCreation.ARGUMENTS_PROPERTY) {
 				ClassInstanceCreation cic= (ClassInstanceCreation) parent;
 
-				if (canArrayBeRemoved(node, cic.arguments(), cic.resolveConstructorBinding())) {
-					fResult.add(new UnwrapNewArrayOperation(node, cic));
+				if (canArrayBeRemoved(visited, cic.arguments(), cic.resolveConstructorBinding())) {
+					fResult.add(new UnwrapNewArrayOperation(visited, cic));
 				}
-			} else if (parent instanceof MethodInvocation) {
+			} else if (parent instanceof MethodInvocation
+					&& visited.getLocationInParent() == MethodInvocation.ARGUMENTS_PROPERTY) {
 				MethodInvocation m= (MethodInvocation) parent;
 
-				if (canArrayBeRemoved(node, m.arguments(), m.resolveMethodBinding())) {
-					fResult.add(new UnwrapNewArrayOperation(node, m));
+				if (canArrayBeRemoved(visited, m.arguments(), m.resolveMethodBinding())) {
+					fResult.add(new UnwrapNewArrayOperation(visited, m));
 				}
-			} else if (parent instanceof SuperMethodInvocation) {
+			} else if (parent instanceof SuperMethodInvocation
+					&& visited.getLocationInParent() == SuperMethodInvocation.ARGUMENTS_PROPERTY) {
 				SuperMethodInvocation sm= (SuperMethodInvocation) parent;
 
-				if (canArrayBeRemoved(node, sm.arguments(), sm.resolveMethodBinding())) {
-					fResult.add(new UnwrapNewArrayOperation(node, sm));
+				if (canArrayBeRemoved(visited, sm.arguments(), sm.resolveMethodBinding())) {
+					fResult.add(new UnwrapNewArrayOperation(visited, sm));
 				}
 			}
 
 			return true;
 		}
 
-		private boolean canArrayBeRemoved(ArrayCreation node, List<Expression> arguments, IMethodBinding binding) {
-			return isUselessArrayCreation(node, arguments, binding)
-					&& !hasEquivalentMethod(node, arguments, binding);
+		private boolean canArrayBeRemoved(ArrayCreation visited, List<Expression> arguments, IMethodBinding binding) {
+			return isUselessArrayCreation(visited, arguments, binding)
+					&& !ASTNodes.hasConflictingMethodOrConstructor(visited.getParent(), binding, getParameterTypesForConflictingMethod(arguments, visited));
 		}
 
-		private boolean isUselessArrayCreation(ArrayCreation node, List<Expression> arguments, IMethodBinding binding) {
-			return (node.getInitializer() != null || (node.dimensions().size() == 1 && Long.valueOf(0L).equals(ASTNodes.getIntegerLiteral((Expression) node.dimensions().get(0)))))
+		private boolean isUselessArrayCreation(ArrayCreation visited, List<Expression> arguments, IMethodBinding binding) {
+			return (visited.getInitializer() != null || (visited.dimensions().size() == 1 && Long.valueOf(0L).equals(ASTNodes.getIntegerLiteral((Expression) visited.dimensions().get(0)))))
 					&& !arguments.isEmpty()
-					&& arguments.get(arguments.size() - 1) == node
+					&& arguments.get(arguments.size() - 1) == visited
 					&& binding != null
 					&& binding.isVarargs()
 					&& binding.getParameterTypes().length == arguments.size()
@@ -123,103 +120,8 @@
 					&& !fInvalidTypes.contains(binding.getParameterTypes()[arguments.size() - 1].getElementType().getName());
 		}
 
-		private boolean hasEquivalentMethod(ArrayCreation node, List<Expression> arguments, IMethodBinding binding) {
-			TypeDeclaration typeDeclaration= ASTNodes.getTypedAncestor(node, TypeDeclaration.class);
-
-			if (typeDeclaration == null) {
-				return true;
-			}
-
-			ITypeBinding type= typeDeclaration.resolveBinding();
-
-			if (type == null) {
-				return true;
-			}
-
-			boolean inSameClass= true;
-			ASTNode parent= node.getParent();
-			ITypeBinding[] parameterTypesForConflictingMethod= getParameterTypesForConflictingMethod(arguments, node);
-
-			// Figure out the type where we need to start looking at methods in the hierarchy.
-			// If we have a new class instance or super method call or this expression or
-			// we have a static call that is qualified, we use the referenced class as the starting point.
-			// If we have a non-qualified method call, we use the class containing the call.
-			// Otherwise, we bail on the clean-up.
-			if (parent instanceof ClassInstanceCreation) {
-				type= ((ClassInstanceCreation) parent).resolveTypeBinding();
-				inSameClass= type.isNested();
-			} else if (parent instanceof MethodInvocation) {
-				MethodInvocation methodInvocation= (MethodInvocation) parent;
-				Expression expression= methodInvocation.getExpression();
-
-				if (expression != null) {
-					if (!(expression instanceof ThisExpression)) {
-						inSameClass= binding.getDeclaringClass().isEqualTo(type);
-						type= expression.resolveTypeBinding();
-					}
-				} else {
-					ASTNode root= node.getRoot();
-
-					if (root instanceof CompilationUnit) {
-						CompilationUnit compilationUnit= (CompilationUnit) root;
-						List<ImportDeclaration> imports= compilationUnit.imports();
-						String localPackage= null;
-
-						if (compilationUnit.getPackage() != null && compilationUnit.getPackage().getName() != null) {
-							localPackage= compilationUnit.getPackage().getName().getFullyQualifiedName();
-						}
-
-						for (ImportDeclaration oneImport : imports) {
-							if (oneImport.isStatic()
-									&& !oneImport.isOnDemand()
-									&& oneImport.getName() instanceof QualifiedName) {
-								QualifiedName methodName= (QualifiedName) oneImport.getName();
-								String methodIdentifier= methodName.getName().getIdentifier();
-								ITypeBinding conflictingType= methodName.getQualifier().resolveTypeBinding();
-
-								if (conflictingType == null) {
-									return true; // Error on side of caution
-								}
-
-								String importPackage= null;
-
-								if (conflictingType.getPackage() != null) {
-									importPackage= conflictingType.getPackage().getName();
-								}
-
-								boolean inSamePackage= Objects.equals(localPackage, importPackage);
-
-								for (IMethodBinding declaredMethod : conflictingType.getDeclaredMethods()) {
-									if (methodIdentifier.equals(declaredMethod.getName())
-											&& isMethodMatching(parameterTypesForConflictingMethod, binding, false, inSamePackage, declaredMethod)) {
-										return true;
-									}
-								}
-							}
-						}
-					}
-
-					if (Modifier.isStatic(binding.getModifiers())) {
-						inSameClass= binding.getDeclaringClass().isEqualTo(type);
-						type= binding.getDeclaringClass();
-					}
-				}
-			} else if (parent instanceof SuperMethodInvocation) {
-				inSameClass= type.isNested();
-				type= type.getSuperclass();
-			} else {
-				return true; // Error on side of caution
-			}
-
-			if (type == null) {
-				return true;
-			}
-
-			return hasEquivalentMethodForInheritedTypes(parameterTypesForConflictingMethod, binding, type, type, inSameClass);
-		}
-
-		private ITypeBinding[] getParameterTypesForConflictingMethod(List<Expression> arguments, ArrayCreation node) {
-			ArrayInitializer initializer= node.getInitializer();
+		private ITypeBinding[] getParameterTypesForConflictingMethod(List<Expression> arguments, ArrayCreation visited) {
+			ArrayInitializer initializer= visited.getInitializer();
 
 			List<Expression> initializerExpressions;
 			if (initializer != null) {
@@ -228,79 +130,7 @@
 				initializerExpressions= Collections.EMPTY_LIST;
 			}
 
-			ITypeBinding[] parameterTypesForConflictingMethod= new ITypeBinding[arguments.size() - 1 + initializerExpressions.size()];
-
-			for (int i= 0; i < arguments.size() - 1; i++) {
-				parameterTypesForConflictingMethod[i]= arguments.get(i).resolveTypeBinding();
-			}
-
-			for (int i= 0; i < initializerExpressions.size(); i++) {
-				parameterTypesForConflictingMethod[arguments.size() - 1 + i]= initializerExpressions.get(i).resolveTypeBinding();
-			}
-
-			return parameterTypesForConflictingMethod;
-		}
-
-		private boolean hasEquivalentMethodForInheritedTypes(ITypeBinding[] parameterTypesForConflictingMethod, IMethodBinding binding, ITypeBinding type,
-				ITypeBinding origType, boolean inSameClass) {
-			while (type != null) {
-				IPackageBinding packageBinding= type.getPackage();
-				boolean inSamePackage= packageBinding.isEqualTo(origType.getPackage());
-
-				if (hasEquivalentMethodForOneType(parameterTypesForConflictingMethod, binding, type, inSameClass, inSamePackage)) {
-					return true;
-				}
-
-				if (type.isNested()) {
-					if (hasEquivalentMethodForInheritedTypes(parameterTypesForConflictingMethod, binding, type.getDeclaringClass(), origType, inSameClass)) {
-						return true;
-					}
-
-					type= type.getSuperclass();
-					inSameClass&= type.isNested();
-				} else {
-					type= type.getSuperclass();
-					inSameClass= false;
-				}
-			}
-
-			return false;
-		}
-
-		private boolean hasEquivalentMethodForOneType(ITypeBinding[] parameterTypesForConflictingMethod, IMethodBinding binding,
-				ITypeBinding type, boolean inSameClass, boolean inSamePackage) {
-			for (IMethodBinding method : type.getDeclaredMethods()) {
-				if (isMethodMatching(parameterTypesForConflictingMethod, binding, inSameClass, inSamePackage, method)) {
-					return true;
-				}
-			}
-
-			return false;
-		}
-
-		private boolean isMethodMatching(ITypeBinding[] parameterTypesForConflictingMethod, IMethodBinding binding, boolean inSameClass, boolean inSamePackage, IMethodBinding testedMethod) {
-			int methodModifiers= testedMethod.getModifiers();
-			ITypeBinding[] parameterTypes= testedMethod.getParameterTypes();
-
-			if (!binding.isEqualTo(testedMethod)
-					&& parameterTypesForConflictingMethod.length == parameterTypes.length
-					&& binding.getName().equals(testedMethod.getName())
-					&& (inSameClass || Modifier.isPublic(methodModifiers) || Modifier.isProtected(methodModifiers)
-							|| (inSamePackage && !Modifier.isPrivate(methodModifiers)))) {
-				for (int i= 0; i < parameterTypesForConflictingMethod.length; i++) {
-					if (parameterTypesForConflictingMethod[i] == null || parameterTypes[i] == null) {
-						return true;
-					}
-
-					if (!parameterTypesForConflictingMethod[i].isAssignmentCompatible(parameterTypes[i])) {
-						return false;
-					}
-				}
-
-				return true;
-			}
-
-			return false;
+			return Stream.concat(arguments.stream().limit(arguments.size() - 1), initializerExpressions.stream()).map(Expression::resolveTypeBinding).toArray(ITypeBinding[]::new);
 		}
 	}
 
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/javadoc/JavaDocLocations.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/javadoc/JavaDocLocations.java
index a1acd97..cbed5ce 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/javadoc/JavaDocLocations.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/javadoc/JavaDocLocations.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
@@ -60,6 +60,10 @@
 import org.eclipse.jdt.internal.corext.CorextMessages;
 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
 
+import org.eclipse.jdt.launching.AbstractVMInstall;
+import org.eclipse.jdt.launching.IVMInstall;
+import org.eclipse.jdt.launching.JavaRuntime;
+
 import org.eclipse.jdt.ui.JavaUI;
 
 import org.eclipse.jdt.internal.ui.JavaPlugin;
@@ -378,10 +382,10 @@
 		IModuleDescription moduleDescription= null;
 		/*
 		 * The Javadoc tool for Java SE 11 uses module name in the created URL.
-		 * We can't know what format is required, so we just guess by the project's compiler compliance.
+		 * We can't know what format is required, so we just guess by the project's execution environment or compiler compliance.
 		 */
 		IJavaProject javaProject= pack.getJavaProject();
-		if (javaProject != null && JavaModelUtil.is11OrHigher(javaProject)) {
+		if (javaProject != null && is11OrHigher(javaProject)) {
 			if (pack.isReadOnly()) {
 				IPackageFragmentRoot root= (IPackageFragmentRoot) pack.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
 				if (root != null) {
@@ -398,6 +402,79 @@
 		return moduleDescription;
 	}
 
+	/**
+	 * This function finds out which jvm/source compliance is being used to see if its version 11 or higher.
+	 * @param javaProject the java project for which the version number is to be verified.
+	 * @return <i>true</i> if the jvm used is version 11 or higher (If no jvm is found then the source compliance is used)
+	 * else returns <i>false</i>
+	 */
+	private static boolean is11OrHigher(IJavaProject javaProject) {
+		boolean is11orHigher= false;
+		if (javaProject != null) {
+			try {
+				IVMInstall install= JavaRuntime.getVMInstall(javaProject);
+				if (install instanceof AbstractVMInstall) {
+					String vmver = ((AbstractVMInstall)install).getJavaVersion();
+					is11orHigher= JavaModelUtil.is11OrHigher(vmver);
+				} else {
+					is11orHigher= JavaModelUtil.is11OrHigher(javaProject);
+				}
+			} catch (CoreException e) {
+				is11orHigher= JavaModelUtil.is11OrHigher(javaProject);
+			}
+		}
+		return is11orHigher;
+	}
+
+	/**
+	 * This function finds out which jvm/source compliance is being used to see if its version 10 or higher.
+	 * @param javaProject the java project for which the version number is to be verified.
+	 * @return <i>true</i> if the jvm used is version 10 or higher (If no jvm is found then the source compliance is used)
+	 * else returns <i>false</i>
+	 */
+	private static boolean is10OrHigher(IJavaProject javaProject) {
+		boolean is10orHigher= false;
+		if (javaProject != null) {
+			try {
+				IVMInstall install= JavaRuntime.getVMInstall(javaProject);
+				if (install instanceof AbstractVMInstall) {
+					String vmver = ((AbstractVMInstall)install).getJavaVersion();
+					is10orHigher= JavaModelUtil.is10OrHigher(vmver);
+				} else {
+					is10orHigher= JavaModelUtil.is10OrHigher(javaProject);
+				}
+			} catch (CoreException e) {
+				is10orHigher= JavaModelUtil.is10OrHigher(javaProject);
+			}
+		}
+		return is10orHigher;
+	}
+
+	/**
+	 * This function finds out which jvm/source compliance is being used to see if its version 1.8 or 9.
+	 * @param javaProject the java project for which the version number is to be verified.
+	 * @return <i>true</i> if the jvm used is 1.8 or 9 (If no jvm is found then the source compliance is used)
+	 * else returns <i>false</i>
+	 */
+	private static boolean is1d8Or9(IJavaProject javaProject) {
+		boolean is1d8Or9= false;
+		String compliance= JavaModelUtil.getSourceCompliance(javaProject);
+		if (javaProject != null) {
+			try {
+				IVMInstall install= JavaRuntime.getVMInstall(javaProject);
+				if (install instanceof AbstractVMInstall) {
+					String vmver = ((AbstractVMInstall)install).getJavaVersion();
+					is1d8Or9 = JavaModelUtil.is1d8OrHigher(vmver) && !JavaModelUtil.is10OrHigher(vmver);
+				} else {
+					is1d8Or9= JavaCore.compareJavaVersions(compliance, JavaCore.VERSION_1_8) == 0 || JavaCore.compareJavaVersions(compliance, JavaCore.VERSION_9) == 0;
+				}
+			} catch (CoreException e) {
+				is1d8Or9= JavaCore.compareJavaVersions(compliance, JavaCore.VERSION_1_8) == 0 || JavaCore.compareJavaVersions(compliance, JavaCore.VERSION_9) == 0;
+			}
+		}
+		return is1d8Or9;
+	}
+
 	private static void appendFieldReference(IField field, StringBuffer buf) {
 		buf.append(field.getElementName());
 	}
@@ -411,9 +488,8 @@
 		 * We can't know what format is required, so we just guess by the project's compiler compliance.
 		 */
 		IJavaProject javaProject= meth.getJavaProject();
-		String compliance= JavaModelUtil.getSourceCompliance(javaProject);
-		boolean is1d8Or9= JavaCore.compareJavaVersions(compliance, JavaCore.VERSION_1_8) == 0 || JavaCore.compareJavaVersions(compliance, JavaCore.VERSION_9) == 0;
-		boolean is10OrHigher= JavaModelUtil.is10OrHigher(javaProject);
+		boolean is1d8Or9= is1d8Or9(javaProject);
+		boolean is10OrHigher= is10OrHigher(javaProject);
 		buf.append(is1d8Or9 ? '-' : '(');
 		String[] params= meth.getParameterTypes();
 		IType declaringType= meth.getDeclaringType();
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/util/TypeInfoFilter.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/util/TypeInfoFilter.java
index d664de2..6e6cb25 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/util/TypeInfoFilter.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/util/TypeInfoFilter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 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
@@ -84,11 +84,18 @@
 			// skip $1, $2 ... - typenames cannot start with a number
 			s= skipSynthetic(s);
 			// binary name of Inner Class to qualified name
-			s= s.replace('$', '.');
+			int inner= countContains(s, '$');
+			if (inner > 0) {
+				s= s.replace('$', '.');
+			}
 			if (s.isEmpty()) {
 				// oversimplified
 				return input;
 			}
+			// partially qualified names need a asterisk wildcard to be found by Open Type dialog:
+			if (inner > 0 && !input.trim().equals(s.trim()) && countContains(s, '.') == inner && !s.contains("*")) { //$NON-NLS-1$
+				s= "*." + s; //$NON-NLS-1$
+			}
 		} catch (Exception e) {
 			// just in case anything bad happened:
 			return input;
@@ -96,6 +103,10 @@
 		return s;
 	}
 
+	private static int countContains(String s, char c) {
+		return (int) s.chars().filter(i -> c == (char) i).count();
+	}
+
 	private static String skipBefore(String s, String skip) {
 		int i= s.lastIndexOf(skip);
 		if (i != -1) {
@@ -135,7 +146,12 @@
 			fNameMatcher= new PatternMatcher(text);
 			fPackageMatcher= null;
 		} else {
-			fPackageMatcher= new PatternMatcher(evaluatePackagePattern(text.substring(0, index)));
+			if (Character.isUpperCase(text.charAt(0))) {
+				// might be referring to class so add wild-card at front
+				fPackageMatcher= new PatternMatcher(evaluatePackagePattern("*" + text.substring(0, index))); //$NON-NLS-1$
+			} else {
+				fPackageMatcher= new PatternMatcher(evaluatePackagePattern(text.substring(0, index)));
+			}
 			String name= text.substring(index + 1);
 			if (name.length() == 0)
 				name= "*"; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/RefactoringAvailabilityTester.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/RefactoringAvailabilityTester.java
index 117bc7c..f631707 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/RefactoringAvailabilityTester.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/RefactoringAvailabilityTester.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2021 IBM Corporation and others.
+ * Copyright (c) 2005, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -1174,7 +1174,6 @@
 				case IJavaElement.LOCAL_VARIABLE:
 					return isRenameAvailable((ILocalVariable) element);
 				case IJavaElement.JAVA_MODULE: {
-					if (isTextSelection) return false;
 					return isRenameAvailable((IModuleDescription) element);
 				}
 				default:
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/IntroduceIndirectionRefactoring.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/IntroduceIndirectionRefactoring.java
index 0019c42..8ffbd94 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/IntroduceIndirectionRefactoring.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/IntroduceIndirectionRefactoring.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
@@ -424,16 +424,19 @@
 					// Allow invocation on super methods calls. makes sense as other
 					// calls or even only the declaration can be updated.
 					targetMethodBinding= ((SuperMethodInvocation) selectionNode).resolveMethodBinding();
-				} else {
+				}
+				if (targetMethodBinding != null) {
+					fTargetMethodBinding= targetMethodBinding.getMethodDeclaration(); // resolve generics
+					if (fTargetMethodBinding != null) {
+						fTargetMethod= (IMethod) fTargetMethodBinding.getJavaElement();
+						//allow single updating mode if an invocation was selected and the invocation can be updated
+						if (selectionNode instanceof MethodInvocation && fSelectionCompilationUnit != null)
+							fSelectionMethodInvocation= (MethodInvocation) selectionNode;
+					}
+				}
+				if (targetMethodBinding == null || fTargetMethodBinding == null) {
 					return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceIndirectionRefactoring_not_available_on_this_selection);
 				}
-				fTargetMethodBinding= targetMethodBinding.getMethodDeclaration(); // resolve generics
-				fTargetMethod= (IMethod) fTargetMethodBinding.getJavaElement();
-
-				//allow single updating mode if an invocation was selected and the invocation can be updated
-				if (selectionNode instanceof MethodInvocation && fSelectionCompilationUnit != null)
-					fSelectionMethodInvocation= (MethodInvocation) selectionNode;
-
 			} else {
 				// (2) invoked on an IMethod: Source may not be available
 
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PullUpRefactoringProcessor.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PullUpRefactoringProcessor.java
index a445e38..44d641f 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PullUpRefactoringProcessor.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PullUpRefactoringProcessor.java
@@ -70,6 +70,7 @@
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.ASTParser;
 import org.eclipse.jdt.core.dom.ASTRequestor;
+import org.eclipse.jdt.core.dom.ASTVisitor;
 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
 import org.eclipse.jdt.core.dom.Block;
@@ -88,6 +89,7 @@
 import org.eclipse.jdt.core.dom.Name;
 import org.eclipse.jdt.core.dom.NodeFinder;
 import org.eclipse.jdt.core.dom.QualifiedName;
+import org.eclipse.jdt.core.dom.QualifiedType;
 import org.eclipse.jdt.core.dom.ReturnStatement;
 import org.eclipse.jdt.core.dom.SimpleName;
 import org.eclipse.jdt.core.dom.SimpleType;
@@ -116,6 +118,7 @@
 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility2Core;
 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.dom.AbortSearchException;
 import org.eclipse.jdt.internal.corext.dom.Bindings;
 import org.eclipse.jdt.internal.corext.dom.BodyDeclarationRewrite;
 import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
@@ -238,6 +241,29 @@
 		}
 
 		@Override
+		public final boolean visit(final SimpleType node) {
+			if (node.getName().isSimpleName()) {
+				ITypeBinding binding= node.resolveBinding();
+				if (binding == null) {
+					return false;
+				}
+				CheckTypeNameInTarget check= new CheckTypeNameInTarget(binding);
+				try {
+					fTargetRewriter.getRoot().accept(check);
+				} catch (AbortSearchException e) {
+					// do nothing
+				}
+				if (check.isQualificationRequired() && binding.getPackage() != null && !binding.getPackage().getName().isEmpty()) {
+					String newName= binding.getPackage().getName() + "."  + node.getName().getFullyQualifiedName(); //$NON-NLS-1$
+					QualifiedType newQualifiedType= (QualifiedType)fRewrite.createStringPlaceholder(newName, ASTNode.QUALIFIED_TYPE);
+					fRewrite.replace(node, newQualifiedType, null);
+					return false;
+				}
+			}
+			return false;
+		}
+
+		@Override
 		public final boolean visit(final SuperMethodInvocation node) {
 			if (!fAnonymousClassDeclaration && !fTypeDeclarationStatement) {
 				final IBinding superBinding= node.getName().resolveBinding();
@@ -278,6 +304,35 @@
 			fTypeDeclarationStatement= true;
 			return super.visit(node);
 		}
+
+		private class CheckTypeNameInTarget extends ASTVisitor {
+
+			private final ITypeBinding fBinding;
+			private boolean fQualificationRequired;
+
+			public CheckTypeNameInTarget(ITypeBinding binding) {
+				this.fBinding= binding;
+			}
+
+			@Override
+			public boolean visit(SimpleType node) {
+				if (!node.getName().isSimpleName() || !node.getName().getFullyQualifiedName().equals(fBinding.getName())) {
+					return false;
+				}
+				ITypeBinding binding= node.resolveBinding();
+				if (binding != null) {
+					if (!binding.isEqualTo(fBinding)) {
+						fQualificationRequired= true;
+						throw new AbortSearchException();
+					}
+				}
+				return false;
+			}
+
+			public boolean isQualificationRequired() {
+				return fQualificationRequired;
+			}
+		}
 	}
 
 	protected static final String ATTRIBUTE_ABSTRACT= "abstract"; //$NON-NLS-1$
diff --git a/org.eclipse.jdt.ui/plugin.xml b/org.eclipse.jdt.ui/plugin.xml
index ef94ba8..2a297d9 100644
--- a/org.eclipse.jdt.ui/plugin.xml
+++ b/org.eclipse.jdt.ui/plugin.xml
@@ -125,6 +125,7 @@
 
             <adapter type="org.eclipse.jdt.internal.ui.IResourceLocator"/>
             <adapter type="org.eclipse.team.ui.history.IHistoryPageSource"/>
+            <adapter type="org.eclipse.core.resources.IProject"/>
 		</factory>
 
 		<factory
@@ -7798,4 +7799,11 @@
            requiresUIThread="false">
      </javaCompletionProposalComputer>
   </extension>
+  <extension
+        point="org.eclipse.core.contenttype.contentTypes">
+     <file-association
+           content-type="org.eclipse.jdt.core.javaClass"
+           file-extensions="class without source">
+     </file-association>
+  </extension>
 </plugin>
diff --git a/org.eclipse.jdt.ui/pom.xml b/org.eclipse.jdt.ui/pom.xml
index 15a3a7c..b301ba2 100644
--- a/org.eclipse.jdt.ui/pom.xml
+++ b/org.eclipse.jdt.ui/pom.xml
@@ -18,7 +18,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.ui</artifactId>
-  <version>3.25.100-SNAPSHOT</version>
+  <version>3.26.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
   <properties>
     <code.ignoredWarnings>-warn:-deprecation,unavoidableGenericProblems</code.ignoredWarnings>
diff --git a/org.eclipse.jdt.ui/preview/formatter.java b/org.eclipse.jdt.ui/preview/formatter.java
index 01705d1..23f2087 100644
--- a/org.eclipse.jdt.ui/preview/formatter.java
+++ b/org.eclipse.jdt.ui/preview/formatter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2018, 2019 Mateusz Matela and others.
+ * Copyright (c) 2018, 2022 Mateusz Matela and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -376,6 +376,8 @@
 //--PREVIEW--START--section-whitespace-declarations-classes
 class MyClass implements I0, I1, I2 {}
 
+public sealed class W permits X, Y, Z {}
+
 AnonClass object= new AnonClass() {void foo(Some s) { }};
 //--PREVIEW--END--section-whitespace-declarations-classes
 
@@ -721,6 +723,25 @@
 }
 //--PREVIEW--END--org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line
 
+//--PREVIEW--START--org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line
+//--PREVIEW--START--org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line
+class Example { void example(int empty, int tiny, int small, int notSoSmall) {
+	switch (empty) {}
+	switch (tiny) { case 1 -> {} }
+	switch (tiny) {
+		case 2 -> {
+			doSomething();
+		}
+	}
+	switch (small) { case 1 -> {} case 2 -> { doSomething(); } }
+	switch (notSoSmall) { case tiny -> { doSomething(); } case small -> { doFirstThing(); doSecondThing(); } }
+	return switch (tiny) {
+		default -> "result";
+	};
+}}
+//--PREVIEW--END--org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line
+//--PREVIEW--END--org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line
+
 //--PREVIEW--START--org.eclipse.jdt.core.formatter.keep_code_block_on_one_line
 class Example {
 	static {
@@ -882,7 +903,11 @@
 //--PREVIEW--END--org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation
 
 //--PREVIEW--START--org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation
-class Example {int foo(Some a) {return a.getFirst();}}
+class Example {
+	String foo() {
+		return new StringBuilder(Arrays.asList(11111111, 22222222, 3333333, 44444444)).append("TextTextText").append(11111111 + 2222222 + 33333333).toStrinig();
+	}
+}
 //--PREVIEW--END--org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation
 
 //--PREVIEW--START--org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call
@@ -1004,10 +1029,37 @@
 class Example {void foo() {try (FileReader reader1 = new FileReader("file1");   FileReader reader2 = new FileReader("file2")) {}}}
 //--PREVIEW--END--org.eclipse.jdt.core.formatter.alignment_for_resources_in_try
 
+//--PREVIEW--START--org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow
+//--PREVIEW--START--org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow
+//--PREVIEW--START--org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon
+class Example {
+	boolean foo(Color color) {
+		boolean b = switch (color) {
+			case RED, GREEN, BLACK, BLUE, CYAN, ORANGE, WHITE, PINK -> true;
+			default -> false;
+		};
+		switch (color) {
+			case RED, GREEN, BLACK, BLUE, CYAN, ORANGE, WHITE, PINK: return true;
+			default: return false;
+		}
+	}
+}
+//--PREVIEW--END--org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow
+//--PREVIEW--END--org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow
+//--PREVIEW--END--org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon
+
 //--PREVIEW--START--org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch
 class Example {void foo() {try {} catch (IllegalArgumentException | NullPointerException | ClassCastException e) {  e.printStackTrace();}}}
 //--PREVIEW--END--org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch
 
+//--PREVIEW--START--org.eclipse.jdt.core.formatter.alignment_for_assertion_message
+class Example {
+	void foo() {
+		assert this.field : "field does not have expected value - please investigate";
+	}
+}
+//--PREVIEW--END--org.eclipse.jdt.core.formatter.alignment_for_assertion_message
+
 //--PREVIEW--START--org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references
 class Example {
 	Map<String, ? extends java.lang.Object> map = new HashMap<String, java.lang.Object>();
@@ -1085,14 +1137,6 @@
 }
 //--PREVIEW--END--org.eclipse.jdt.core.formatter.alignment_for_module_statements
 
-//--PREVIEW--START--org.eclipse.jdt.core.formatter.alignment_for_assertion_message
-class Example {
-	void foo() {
-		assert this.field : "field does not have expected value - please investigate";
-	}
-}
-//--PREVIEW--END--org.eclipse.jdt.core.formatter.alignment_for_assertion_message
-
 }
 
 class COMMENTS {
diff --git a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameLinkedMode.java b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameLinkedMode.java
index fb878ac..6eb6ca0 100644
--- a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameLinkedMode.java
+++ b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/RenameLinkedMode.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2021 IBM Corporation and others.
+ * Copyright (c) 2005, 2022 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -71,6 +71,7 @@
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.Name;
 import org.eclipse.jdt.core.dom.NodeFinder;
 import org.eclipse.jdt.core.dom.SimpleName;
 import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
@@ -212,10 +213,25 @@
 
 			fLinkedPositionGroup= new LinkedPositionGroup();
 			ASTNode selectedNode= NodeFinder.perform(root, fOriginalSelection.x, fOriginalSelection.y);
-			if (! (selectedNode instanceof SimpleName)) {
+
+			Name nameNode= null;
+			if (! (selectedNode instanceof Name)) {
 				return; // TODO: show dialog
+			} else if (this.fJavaElement != null &&
+					this.fJavaElement.getElementType() ==  IJavaElement.JAVA_MODULE) {
+				nameNode= (Name) selectedNode;
+				ASTNode parent = nameNode.getParent();
+				while(parent instanceof Name) {
+					nameNode = (Name) parent;
+					parent = nameNode.getParent();
+				}
+				fOriginalName= nameNode.getFullyQualifiedName();
+			} else if (! (selectedNode instanceof SimpleName)) {
+				return; // TODO: show dialog
+			} else {
+				nameNode = (SimpleName)selectedNode;
+				fOriginalName= ((SimpleName)nameNode).getIdentifier();
 			}
-			SimpleName nameNode= (SimpleName) selectedNode;
 
 			if (viewer instanceof ITextViewerExtension6) {
 				IUndoManager undoManager= ((ITextViewerExtension6)viewer).getUndoManager();
@@ -227,7 +243,6 @@
 				}
 			}
 
-			fOriginalName= nameNode.getIdentifier();
 			final int pos= nameNode.getStartPosition();
 			ASTNode[] sameNodes= LinkedNodeFinder.findByNode(root, nameNode);
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaElementAdapterFactory.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaElementAdapterFactory.java
index c94c7d7..fd04a27 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaElementAdapterFactory.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/JavaElementAdapterFactory.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2015 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
@@ -22,6 +22,7 @@
 import org.eclipse.core.runtime.Platform;
 
 import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.mapping.ResourceMapping;
 
@@ -39,6 +40,7 @@
 
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
 
 import org.eclipse.jdt.internal.corext.util.JavaElementResourceMapping;
@@ -56,6 +58,7 @@
 public class JavaElementAdapterFactory implements IAdapterFactory, IContributorResourceAdapter2 {
 
 	private static Class<?>[] ADAPTER_LIST= new Class[] {
+		IProject.class,
 		IPropertySource.class,
 		IResource.class,
 		IWorkbenchAdapter.class,
@@ -91,7 +94,9 @@
 		updateLazyLoadedAdapters();
 		IJavaElement java= getJavaElement(element);
 
-		if (IPropertySource.class.equals(key)) {
+		if (IProject.class.equals(key)) {
+			return (T) getProject(java);
+		} if (IPropertySource.class.equals(key)) {
 			return (T) getProperties(java);
 		} if (IResource.class.equals(key)) {
 			return (T) getResource(java);
@@ -117,6 +122,16 @@
 		return null;
 	}
 
+	private IProject getProject(IJavaElement element) {
+		if (element != null) {
+			IJavaProject javaProject = element.getJavaProject();
+			if (javaProject != null) {
+				return javaProject.getProject();
+			}
+		}
+		return null;
+	}
+
 	private IResource getResource(IJavaElement element) {
 		// can't use IJavaElement.getResource directly as we are interested in the
 		// corresponding resource
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyLabelProvider.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyLabelProvider.java
index 09ae065..98e03fc 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyLabelProvider.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyLabelProvider.java
@@ -112,6 +112,11 @@
 				decorated = decorateLabel(decorated, nodeType);
 				styledDecorated= StyledCellLabelProvider.styleDecoratedString(decorated, ColoringLabelProvider.INHERITED_STYLER, styledDecorated);
 			}
+			if(wrapper.getMethodCall().isPotential()) {
+				decorated = Messages.format(CallHierarchyMessages.CallHierarchyLabelProvider_potential, decorated);
+				styledDecorated= StyledCellLabelProvider.styleDecoratedString(decorated,
+						StyledString.COUNTER_STYLER, styledDecorated);
+			}
 			return styledDecorated;
 		}
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyMessages.java
index d09bdaf..fe818fd 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyMessages.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyMessages.java
@@ -81,6 +81,7 @@
 	public static String CallHierarchyLabelProvider_noMethodSelected;
 	public static String CallHierarchyLabelProvider_updatePending;
 	public static String CallHierarchyLabelProvider_matches;
+	public static String CallHierarchyLabelProvider_potential;
 	public static String CallHierarchyViewPart_empty;
 	public static String CallHierarchyViewPart_callsToConstructors;
 	public static String CallHierarchyViewPart_callsToField;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyMessages.properties
index 3a17ec9..2d8d276 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyMessages.properties
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/callhierarchy/CallHierarchyMessages.properties
@@ -78,6 +78,7 @@
 CallHierarchyLabelProvider_noMethodSelected=- no method selected -
 CallHierarchyLabelProvider_updatePending=...
 CallHierarchyLabelProvider_matches={0} ({1} matches)
+CallHierarchyLabelProvider_potential= {0} (potential callee)
 CallHierarchyViewPart_empty=To display the call hierarchy, select one or more methods, classes, fields, or initializers, and select the \'Open Call Hierarchy\' menu option. Alternatively, you can drag and drop the member or members onto this view.
 CallHierarchyViewPart_callsToConstructors=Members calling constructors of ''{0}'' - in {1}
 CallHierarchyViewPart_callsToField=Members accessing ''{0}'' - in {1}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/Filter.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/Filter.java
new file mode 100644
index 0000000..be8c4ef
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/Filter.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * 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
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Note:
+ *     Moved from org.eclipse.jdt.internal.debug.ui from the eclipse.jdt.debug project
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.filtertable;
+
+
+/**
+ * Model object that represents a single entry in a filter table.
+ * @since 3.26
+ */
+public class Filter {
+
+	private String fName;
+	private boolean fChecked;
+
+	public Filter(String name, boolean checked) {
+		setName(name);
+		setChecked(checked);
+	}
+
+	public String getName() {
+		return fName;
+	}
+
+	public void setName(String name) {
+		fName = name;
+	}
+
+	public boolean isChecked() {
+		return fChecked;
+	}
+
+	public void setChecked(boolean checked) {
+		fChecked = checked;
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o instanceof Filter) {
+			Filter other = (Filter) o;
+			if (getName().equals(other.getName())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		return getName().hashCode();
+	}
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/FilterLabelProvider.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/FilterLabelProvider.java
new file mode 100644
index 0000000..59f93c1
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/FilterLabelProvider.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * 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
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Note:
+ *     The code moved from org.eclipse.jdt.internal.debug.ui from the eclipse.jdt.debug project
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.filtertable;
+
+
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+
+import org.eclipse.jdt.ui.ISharedImages;
+import org.eclipse.jdt.ui.JavaUI;
+
+/**
+ * Label provider for Filter model objects
+ * @since 3.26
+ */
+public class FilterLabelProvider extends LabelProvider implements ITableLabelProvider {
+
+	private static final Image IMG_CUNIT =
+		JavaUI.getSharedImages().getImage(ISharedImages.IMG_OBJS_CLASS);
+	private static final Image IMG_PKG =
+		JavaUI.getSharedImages().getImage(ISharedImages.IMG_OBJS_PACKAGE);
+
+	/**
+	 * @see ITableLabelProvider#getColumnText(Object, int)
+	 */
+	@Override
+	public String getColumnText(Object object, int column) {
+		if (column == 0) {
+			return ((Filter) object).getName();
+		}
+		return ""; //$NON-NLS-1$
+	}
+
+	/**
+	 * @see ILabelProvider#getText(Object)
+	 */
+	@Override
+	public String getText(Object element) {
+		return ((Filter) element).getName();
+	}
+
+	/**
+	 * @see ITableLabelProvider#getColumnImage(Object, int)
+	 */
+	@Override
+	public Image getColumnImage(Object object, int column) {
+		String name = ((Filter) object).getName();
+		if (name.endsWith("*") || name.equals("(default package)")) { //$NON-NLS-1$ //$NON-NLS-2$
+			return IMG_PKG;
+		}
+		return IMG_CUNIT;
+	}
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/FilterManager.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/FilterManager.java
new file mode 100644
index 0000000..65aae24
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/FilterManager.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Zsombor Gegesy.
+ *
+ * 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:
+ *     Zsombor Gegesy - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.filtertable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+
+/**
+ * Helper class to manage converting between active/inactive Filter lists into preference settings.
+ * @since 3.26
+ */
+public class FilterManager {
+
+	private final String activeListKey;
+	private final String inactiveListKey;
+	private final String separatorString;
+
+	public FilterManager(String activeListKey, String inactiveListKey, String separatorString) {
+		this.activeListKey = activeListKey;
+		this.inactiveListKey = inactiveListKey;
+		this.separatorString = separatorString;
+	}
+
+	public FilterManager(String activeListKey, String inactiveListKey) {
+		this(activeListKey, inactiveListKey, ","); //$NON-NLS-1$
+	}
+
+	public String[] getActiveList(IPreferenceStore store) {
+		return parseList(store.getString(activeListKey));
+	}
+
+	public String[] getInactiveList(IPreferenceStore store) {
+		return parseList(store.getString(inactiveListKey));
+	}
+
+	public Filter[] getAllStoredFilters(IPreferenceStore store, boolean defaults) {
+		Filter[] filters = null;
+		String[] activefilters, inactivefilters;
+		if (defaults) {
+			activefilters = parseList(store.getDefaultString(activeListKey));
+			inactivefilters = parseList(store.getDefaultString(inactiveListKey));
+		} else {
+			activefilters = getDefaultActiveFilters(store);
+			inactivefilters = getDefaultInactiveFilters(store);
+		}
+		filters = new Filter[activefilters.length + inactivefilters.length];
+		for (int i = 0; i < activefilters.length; i++) {
+			filters[i] = new Filter(activefilters[i], true);
+		}
+		for (int i = 0; i < inactivefilters.length; i++) {
+			filters[i + activefilters.length] = new Filter(inactivefilters[i], false);
+		}
+		return filters;
+	}
+
+	protected String[] getDefaultActiveFilters(IPreferenceStore store) {
+		return parseList(store.getDefaultString(activeListKey));
+	}
+
+	protected String[] getDefaultInactiveFilters(IPreferenceStore store) {
+		return parseList(store.getDefaultString(inactiveListKey));
+	}
+
+	public void save(IPreferenceStore store, Filter[] filters) {
+		ArrayList<String> active = new ArrayList<>();
+		ArrayList<String> inactive = new ArrayList<>();
+		String name = ""; //$NON-NLS-1$
+		for (int i = 0; i < filters.length; i++) {
+			name = filters[i].getName();
+			if (filters[i].isChecked()) {
+				active.add(name);
+			} else {
+				inactive.add(name);
+			}
+		}
+		String pref = serializeList(active.toArray(new String[active.size()]));
+		store.setValue(activeListKey, pref);
+		pref = serializeList(inactive.toArray(new String[inactive.size()]));
+		store.setValue(inactiveListKey, pref);
+	}
+
+
+	/**
+	 * Parses the comma separated string into an array of strings
+	 *
+	 * @param listString the comma separated string
+	 * @return list
+	 */
+	public String[] parseList(String listString) {
+		List<String> list = new ArrayList<>(10);
+		StringTokenizer tokenizer = new StringTokenizer(listString, separatorString);
+		while (tokenizer.hasMoreTokens()) {
+			String token = tokenizer.nextToken();
+			list.add(token);
+		}
+		return list.toArray(new String[list.size()]);
+	}
+
+	/**
+	 * Serializes the array of strings into one comma
+	 * separated string.
+	 *
+	 * @param list array of strings
+	 * @return a single string composed of the given list
+	 */
+	public String serializeList(String[] list) {
+		if (list == null) {
+			return ""; //$NON-NLS-1$
+		}
+		return String.join(separatorString, list);
+	}
+
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/FilterViewerComparator.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/FilterViewerComparator.java
new file mode 100644
index 0000000..a1d4acb
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/FilterViewerComparator.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * 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
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Note:
+ *     Moved from org.eclipse.jdt.internal.debug.ui from the eclipse.jdt.debug project
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.filtertable;
+
+import org.eclipse.jface.viewers.ContentViewer;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+import org.eclipse.ui.model.WorkbenchViewerComparator;
+
+/**
+ * Comparator for {@link Filter} objects.
+ * @since 3.26
+ *
+ */
+public class FilterViewerComparator extends WorkbenchViewerComparator {
+	@Override
+	public int compare(Viewer viewer, Object e1, Object e2) {
+		ILabelProvider lprov =
+			(ILabelProvider) ((ContentViewer) viewer).getLabelProvider();
+		String name1 = lprov.getText(e1);
+		String name2 = lprov.getText(e2);
+		if (name1 == null) {
+			name1 = ""; //$NON-NLS-1$
+		}
+		if (name2 == null) {
+			name2 = ""; //$NON-NLS-1$
+		}
+		if (name1.length() > 0 && name2.length() > 0) {
+			char char1 = name1.charAt(name1.length() - 1);
+			char char2 = name2.charAt(name2.length() - 1);
+			if (char1 == '*' && char1 != char2) {
+				return -1;
+			}
+			if (char2 == '*' && char2 != char1) {
+				return 1;
+			}
+		}
+		return name1.compareTo(name2);
+	}
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/JavaFilterTable.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/JavaFilterTable.java
new file mode 100644
index 0000000..0acd6bc
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/JavaFilterTable.java
@@ -0,0 +1,630 @@
+/*******************************************************************************
+ * 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
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *     Jesper Steen Moller - Enhancement 254677 - filter getters/setters
+ *     Zsombor Gegesy - creating a standalone component.
+ * Note:
+ *     The code was extracted from org.eclipse.jdt.internal.debug.ui.JavaStepFilterPreferencePage
+ *     from the eclipse.jdt.debug project.
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.filtertable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.TableItem;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.window.Window;
+
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.SelectionDialog;
+
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchEngine;
+
+import org.eclipse.jdt.ui.IJavaElementSearchConstants;
+import org.eclipse.jdt.ui.JavaUI;
+
+import org.eclipse.jdt.internal.ui.dialogs.PackageSelectionDialog;
+import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
+
+/**
+ * Component to manage a list of Java filters, where a filter can be a Java class name, or a package
+ * name, and every filter can be active or inactive, and they are stored in the preference store.
+ *
+ * @since 3.26
+ */
+public class JavaFilterTable {
+	/**
+	 * Content provider for the table. Content consists of instances of Filter.
+	 *
+	 * @since 3.26
+	 */
+	class FilterContentProvider implements IStructuredContentProvider {
+		public FilterContentProvider() {
+			initTableState(false);
+		}
+
+		@Override
+		public Object[] getElements(Object inputElement) {
+			return getAllFiltersFromTable();
+		}
+	}
+
+	/**
+	 * Interface for encapsulating the storage of the {@link Filter}s
+	 *
+	 * @since 3.26
+	 *
+	 */
+	public interface FilterStorage {
+		/**
+		 * Returns all of the stored filters
+		 *
+		 * @param defaults if the defaults should be returned
+		 * @return an array of stored filters
+		 */
+		Filter[] getStoredFilters(boolean defaults);
+
+		/**
+		 * Saves the filters in a persistent storage.
+		 *
+		 * @param store the current preference store, or null if not applicable.
+		 * @param filters an array of filters, what the user is configured
+		 */
+		void setStoredFilters(IPreferenceStore store, Filter[] filters);
+
+	}
+
+	public static class ButtonLabel {
+		final String label;
+
+		final String tooltip;
+
+		public ButtonLabel(String label, String tooltip) {
+			this.label= label;
+			this.tooltip= tooltip;
+		}
+
+		public ButtonLabel(String label) {
+			this(label, null);
+		}
+	}
+
+	public static class DialogLabels {
+		final String title;
+
+		final String message;
+
+		public DialogLabels(String title, String message) {
+			this.title= title;
+			this.message= message;
+		}
+	}
+
+	public static class FilterTableConfig {
+		String labelText;
+
+		ButtonLabel addFilter;
+
+		ButtonLabel addType;
+
+		ButtonLabel addPackage;
+
+		ButtonLabel editFilter;
+
+		ButtonLabel remove;
+
+		ButtonLabel selectAll;
+
+		ButtonLabel deselectAll;
+
+		DialogLabels addTypeDialog;
+
+		DialogLabels errorAddTypeDialog;
+
+		DialogLabels addPackageDialog;
+
+		String helpContextId;
+
+		boolean showDefaultPackage;
+		boolean showParents;
+		boolean considerAllTypes;
+		boolean checkable = true;
+
+		public FilterTableConfig setLabelText(String labelText) {
+			this.labelText= labelText;
+			return this;
+		}
+
+		public FilterTableConfig setAddFilter(ButtonLabel buttonLabel) {
+			this.addFilter= buttonLabel;
+			return this;
+		}
+
+		public FilterTableConfig setAddType(ButtonLabel buttonLabel) {
+			this.addType= buttonLabel;
+			return this;
+		}
+
+		public FilterTableConfig setEditFilter(ButtonLabel buttonLabel) {
+			this.editFilter= buttonLabel;
+			return this;
+		}
+
+		public FilterTableConfig setAddPackage(ButtonLabel buttonLabel) {
+			this.addPackage= buttonLabel;
+			return this;
+		}
+
+		public FilterTableConfig setRemove(ButtonLabel buttonLabel) {
+			this.remove= buttonLabel;
+			return this;
+		}
+
+		public FilterTableConfig setSelectAll(ButtonLabel buttonLabel) {
+			this.selectAll= buttonLabel;
+			return this;
+		}
+
+		public FilterTableConfig setDeselectAll(ButtonLabel buttonLabel) {
+			this.deselectAll= buttonLabel;
+			return this;
+		}
+
+		public FilterTableConfig setAddTypeDialog(DialogLabels dialog) {
+			this.addTypeDialog= dialog;
+			return this;
+		}
+
+		public FilterTableConfig setErrorAddTypeDialog(DialogLabels dialog) {
+			this.errorAddTypeDialog= dialog;
+			return this;
+		}
+
+		public FilterTableConfig setAddPackageDialog(DialogLabels dialog) {
+			this.addPackageDialog= dialog;
+			return this;
+		}
+
+		public FilterTableConfig setHelpContextId(String helpContextId) {
+			this.helpContextId= helpContextId;
+			return this;
+		}
+
+		public FilterTableConfig setShowDefaultPackage(boolean showDefaultPackage) {
+			this.showDefaultPackage= showDefaultPackage;
+			return this;
+		}
+
+		public FilterTableConfig setShowParents(boolean showParents) {
+			this.showParents= showParents;
+			return this;
+		}
+
+		public FilterTableConfig setConsiderAllTypes(boolean considerAllTypes) {
+			this.considerAllTypes= considerAllTypes;
+			return this;
+		}
+
+		public FilterTableConfig setCheckable(boolean checkable) {
+			this.checkable= checkable;
+			return this;
+		}
+	}
+
+	private final FilterStorage fFilterStorage;
+
+	private final FilterTableConfig config;
+
+	private TableViewer fTableViewer;
+
+	private Button fAddPackageButton;
+
+	private Button fAddTypeButton;
+
+	private Button fRemoveFilterButton;
+
+	private Button fAddFilterButton;
+
+	private Button fEditFilterButton;
+
+	private Button fSelectAllButton;
+
+	private Button fDeselectAllButton;
+
+	public JavaFilterTable(PreferencePage preferencePage, FilterManager filterManager, FilterTableConfig config) {
+		this(new FilterStorage() {
+			@Override
+			public Filter[] getStoredFilters(boolean defaults) {
+				return filterManager.getAllStoredFilters(preferencePage.getPreferenceStore(), defaults);
+			}
+
+			@Override
+			public void setStoredFilters(IPreferenceStore store, Filter[] filters) {
+				filterManager.save(store, filters);
+			}
+		}, config);
+		Objects.requireNonNull(filterManager);
+	}
+
+	public JavaFilterTable(FilterStorage filterStorage, FilterTableConfig config) {
+		this.fFilterStorage= Objects.requireNonNull(filterStorage);
+		this.config= config != null ? config : new FilterTableConfig();
+	}
+
+	public void createTable(Composite container) {
+		if (config.labelText != null) {
+			SWTFactory.createLabel(container, config.labelText, 2);
+		}
+		createFilterTableViewer(container);
+		createFilterButtons(container);
+	}
+
+	private void createFilterTableViewer(Composite container) {
+		if (config.checkable) {
+			fTableViewer= CheckboxTableViewer.newCheckList(container, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
+		} else {
+			fTableViewer= new TableViewer(container, SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
+		}
+		fTableViewer.getTable().setFont(container.getFont());
+		fTableViewer.setLabelProvider(new FilterLabelProvider());
+		fTableViewer.setComparator(new FilterViewerComparator());
+		fTableViewer.setContentProvider(new FilterContentProvider());
+		fTableViewer.setInput(getAllStoredFilters(false));
+		fTableViewer.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));
+		if (fTableViewer instanceof CheckboxTableViewer) {
+			CheckboxTableViewer checkableViewer = (CheckboxTableViewer) fTableViewer;
+			checkableViewer.addCheckStateListener(new ICheckStateListener() {
+				@Override
+				public void checkStateChanged(CheckStateChangedEvent event) {
+					((Filter) event.getElement()).setChecked(event.getChecked());
+				}
+			});
+		}
+		fTableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+			@Override
+			public void selectionChanged(SelectionChangedEvent event) {
+				boolean hasSelection= !event.getSelection().isEmpty();
+				setEnabled(fRemoveFilterButton, hasSelection);
+				setEnabled(fEditFilterButton, hasSelection);
+			}
+		});
+		fTableViewer.getControl().addKeyListener(new KeyAdapter() {
+			@Override
+			public void keyPressed(KeyEvent event) {
+				handleFilterViewerKeyPress(event);
+			}
+		});
+	}
+
+
+	/**
+	 * Creates the add/remove/etc buttons for the filters
+	 *
+	 * @param container the parent container
+	 */
+	private void createFilterButtons(Composite container) {
+		// button container
+		Composite buttonContainer= new Composite(container, SWT.NONE);
+		GridData gd= new GridData(GridData.FILL_VERTICAL);
+		buttonContainer.setLayoutData(gd);
+		GridLayout buttonLayout= new GridLayout();
+		buttonLayout.numColumns= 1;
+		buttonLayout.marginHeight= 0;
+		buttonLayout.marginWidth= 0;
+		buttonContainer.setLayout(buttonLayout);
+
+		//Add filter button
+		fAddFilterButton= createPushButton(buttonContainer, config.addFilter, event -> addFilter());
+		//Add type button
+		fAddTypeButton= createPushButton(buttonContainer, config.addType, event -> addType());
+		//Add package button
+		fAddPackageButton= createPushButton(buttonContainer, config.addPackage, event -> addPackage());
+		//Add edit button
+		fEditFilterButton= createPushButton(buttonContainer, config.editFilter, event -> editFilter(), false);
+		//Remove button
+		fRemoveFilterButton= createPushButton(buttonContainer, config.remove, event -> removeFilters(), false);
+
+		Label separator= new Label(buttonContainer, SWT.NONE);
+		separator.setVisible(false);
+		gd= new GridData();
+		gd.horizontalAlignment= GridData.FILL;
+		gd.verticalAlignment= GridData.BEGINNING;
+		gd.heightHint= 4;
+		separator.setLayoutData(gd);
+		if (fTableViewer instanceof CheckboxTableViewer) {
+			CheckboxTableViewer checkableViewer = (CheckboxTableViewer) fTableViewer;
+			//Select All button
+			fSelectAllButton= createPushButton(buttonContainer, config.selectAll, event -> checkableViewer.setAllChecked(true));
+
+			//De-Select All button
+			fDeselectAllButton= createPushButton(buttonContainer, config.deselectAll, event -> checkableViewer.setAllChecked(false));
+		}
+
+	}
+
+	private static Button createPushButton(Composite parent, ButtonLabel buttonLabels, Listener listener) {
+		return createPushButton(parent, buttonLabels, listener, true);
+	}
+
+	private static Button createPushButton(Composite parent, ButtonLabel buttonLabels, Listener listener, boolean enabled) {
+		if (buttonLabels != null && buttonLabels.label != null && !buttonLabels.label.isBlank()) {
+			Button button= SWTFactory.createPushButton(parent, buttonLabels.label, buttonLabels.tooltip, null);
+			button.addListener(SWT.Selection, listener);
+			button.setEnabled(enabled);
+			return button;
+		}
+		return null;
+	}
+
+	private void setEnabled(Button buttonToEnable, boolean enabled) {
+		if (buttonToEnable != null) {
+			buttonToEnable.setEnabled(enabled);
+		}
+	}
+
+	/**
+	 * handles the filter button being clicked
+	 *
+	 * @param event the clicked event
+	 */
+	private void handleFilterViewerKeyPress(KeyEvent event) {
+		if (event.character == SWT.DEL && event.stateMask == 0) {
+			removeFilters();
+		}
+	}
+
+	/**
+	 * Removes the currently selected filters.
+	 */
+	protected void removeFilters() {
+		fTableViewer.remove(((IStructuredSelection) fTableViewer.getSelection()).toArray());
+	}
+
+	/**
+	 * Allows a new filter to be added to the listing
+	 */
+	private void addFilter() {
+		List<String> existingEntries= getExistingFilters();
+		TypeFilterInputDialog dialog= new TypeFilterInputDialog(fAddFilterButton.getShell(), existingEntries, config.helpContextId);
+		if (dialog.open() == Window.OK) {
+			String res= (String) dialog.getResult();
+			addFilter(res, true);
+		}
+	}
+
+	private List<String> getExistingFilters() {
+		TableItem[] items= fTableViewer.getTable().getItems();
+		List<String> existingEntries= new ArrayList<>(items.length);
+		for (TableItem item : items) {
+			Filter data= (Filter) item.getData();
+			existingEntries.add(data.getName());
+		}
+		return existingEntries;
+	}
+
+	/**
+	 * Allows a filter to be edited
+	 */
+	private void editFilter() {
+		List<Filter> selected= ((IStructuredSelection) fTableViewer.getSelection()).toList();
+		if (selected.isEmpty()) {
+			return;
+		}
+		Filter editedEntry= selected.get(0);
+		List<String> existing= getExistingFilters();
+		existing.remove(editedEntry.getName());
+		TypeFilterInputDialog dialog= new TypeFilterInputDialog(fEditFilterButton.getShell(), existing, config.helpContextId);
+		dialog.setInitialString(editedEntry.getName());
+		if (dialog.open() == Window.OK) {
+			editedEntry.setName((String) dialog.getResult());
+			fTableViewer.refresh(editedEntry);
+		}
+	}
+
+	/**
+	 * add a new type to the listing of available filters
+	 */
+	private void addType() {
+		try {
+			int searchType = config.considerAllTypes ? IJavaElementSearchConstants.CONSIDER_ALL_TYPES : IJavaElementSearchConstants.CONSIDER_CLASSES;
+			SelectionDialog dialog= JavaUI.createTypeDialog(fAddTypeButton.getShell(),
+					PlatformUI.getWorkbench().getProgressService(),
+					getTypeSearchScope(),
+					searchType,
+					false);
+			apply(config.addTypeDialog, dialog);
+			if (dialog.open() == IDialogConstants.OK_ID) {
+				Object[] types= dialog.getResult();
+				if (types != null && types.length > 0) {
+					IType type= (IType) types[0];
+					addFilter(type.getFullyQualifiedName(), true);
+				}
+			}
+		} catch (JavaModelException jme) {
+			ExceptionHandler.handle(jme, config.errorAddTypeDialog.title, config.errorAddTypeDialog.message);
+		}
+	}
+
+	/**
+	 * add a new package to the list of all available package filters
+	 */
+	private void addPackage() {
+		int packageSelectionFlags = PackageSelectionDialog.F_REMOVE_DUPLICATES;
+		if (!config.showDefaultPackage) {
+			packageSelectionFlags |= PackageSelectionDialog.F_HIDE_DEFAULT_PACKAGE;
+		}
+		if (config.showParents) {
+			packageSelectionFlags |= PackageSelectionDialog.F_SHOW_PARENTS;
+		}
+		SelectionDialog dialog= JavaUI.createPackageDialog(
+				fAddPackageButton.getShell(),
+				true,
+				packageSelectionFlags,
+				""); //$NON-NLS-1$
+		apply(config.addPackageDialog, dialog);
+		if (dialog.open() == IDialogConstants.OK_ID) {
+			Object[] packages= dialog.getResult();
+			if (packages != null) {
+				IJavaElement pkg= null;
+				for (int i= 0; i < packages.length; i++) {
+					pkg= (IJavaElement) packages[i];
+					String filter= pkg.getElementName() + ".*"; //$NON-NLS-1$
+					addFilter(filter, true);
+				}
+			}
+		}
+	}
+
+	/**
+	 * Enables or disables the buttons and the table control
+	 *
+	 * @param enabled the new enabled status of the widgets
+	 * @since 3.24
+	 */
+	public void setEnabled(boolean enabled) {
+		fAddFilterButton.setEnabled(enabled);
+		fAddPackageButton.setEnabled(enabled);
+		fAddTypeButton.setEnabled(enabled);
+		fDeselectAllButton.setEnabled(enabled);
+		fSelectAllButton.setEnabled(enabled);
+		fTableViewer.getTable().setEnabled(enabled);
+		fRemoveFilterButton.setEnabled(enabled & !fTableViewer.getSelection().isEmpty());
+	}
+
+	/**
+	 * initializes the checked state of the filters when the dialog opens
+	 *
+	 * @param defaults if the defaults should be returned
+	 * @since 3.24
+	 */
+	private void initTableState(boolean defaults) {
+		Filter[] filters= getAllStoredFilters(defaults);
+		for (int i= 0; i < filters.length; i++) {
+			fTableViewer.add(filters[i]);
+			setChecked(filters[i], filters[i].isChecked());
+		}
+	}
+
+	private void setChecked(Object element, boolean checked) {
+		if (fTableViewer instanceof CheckboxTableViewer) {
+			((CheckboxTableViewer) fTableViewer).setChecked(element, checked);
+		}
+	}
+
+	private void apply(DialogLabels dialogLabels, SelectionDialog dialog) {
+		if (dialogLabels != null) {
+			dialog.setTitle(dialogLabels.title);
+			dialog.setMessage(dialogLabels.message);
+		}
+	}
+
+	/**
+	 * Returns all of the committed filters
+	 *
+	 * @param defaults if the defaults should be returned
+	 * @return an array of committed filters
+	 * @since 3.24
+	 */
+	private Filter[] getAllStoredFilters(boolean defaults) {
+		return fFilterStorage.getStoredFilters(defaults);
+	}
+
+	/**
+	 * adds a single filter to the viewer
+	 *
+	 * @param filter the new filter to add
+	 * @param checked the checked state of the new filter
+	 * @since 3.24
+	 */
+	protected void addFilter(String filter, boolean checked) {
+		if (filter != null) {
+			Filter filterObj = new Filter(filter, checked);
+			for (var item : fTableViewer.getTable().getItems()) {
+				var current = (Filter) item.getData();
+				if (filterObj.equals(current)) {
+					item.setChecked(checked);
+					return;
+				}
+			}
+			fTableViewer.add(filterObj);
+			setChecked(filterObj, checked);
+		}
+	}
+
+	/**
+	 * returns all of the filters from the table, this includes ones that have not yet been saved
+	 *
+	 * @return a possibly empty lits of filters fron the table
+	 * @since 3.24
+	 */
+	protected Filter[] getAllFiltersFromTable() {
+		TableItem[] items= fTableViewer.getTable().getItems();
+		Filter[] filters= new Filter[items.length];
+		for (int i= 0; i < items.length; i++) {
+			filters[i]= (Filter) items[i].getData();
+			filters[i].setChecked(items[i].getChecked());
+		}
+		return filters;
+	}
+
+	/**
+	 * @return the search scope for the types, by default it search in the whole workspace.
+	 */
+	protected IJavaSearchScope getTypeSearchScope() {
+		return SearchEngine.createWorkspaceScope();
+	}
+
+	/**
+	 * Resets the component to it's default state.
+	 */
+	public void performDefaults() {
+		fTableViewer.getTable().removeAll();
+		initTableState(true);
+	}
+
+	/**
+	 * Saves the current state of the table into the underlying {@link FilterStorage}
+	 *
+	 * @param store the current {@link IPreferenceStore} if the component is inside a preference
+	 *            page.
+	 */
+	public void performOk(IPreferenceStore store) {
+		fFilterStorage.setStoredFilters(store, getAllFiltersFromTable());
+	}
+
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/SWTFactory.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/SWTFactory.java
new file mode 100644
index 0000000..f0f59a4
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/SWTFactory.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ *  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
+ *  which accompanies this distribution, and is available at
+ *  https://www.eclipse.org/legal/epl-2.0/
+ *
+ *  SPDX-License-Identifier: EPL-2.0
+ *
+ *  Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Note:
+ *     The code extracted from org.eclipse.jdt.internal.debug.ui package from the
+ *     eclipse.jdt.debug project.
+ *******************************************************************************/
+
+package org.eclipse.jdt.internal.ui.filtertable;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+import org.eclipse.core.runtime.Assert;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.layout.PixelConverter;
+
+/**
+ * Factory class to create some SWT resources.
+ */
+class SWTFactory {
+
+	/**
+	 * Returns a width hint for a button control.
+	 */
+	private static int getButtonWidthHint(Button button) {
+		/*button.setFont(JFaceResources.getDialogFont());*/
+		PixelConverter converter= new PixelConverter(button);
+		int widthHint= converter.convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
+		return Math.max(widthHint, button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
+	}
+
+	/**
+	 * Sets width and height hint for the button control.
+	 * <b>Note:</b> This is a NOP if the button's layout data is not
+	 * an instance of <code>GridData</code>.
+	 *
+	 * @param button the button for which to set the dimension hint
+	 */
+	private static void setButtonDimensionHint(Button button) {
+		Assert.isNotNull(button);
+		Object gd= button.getLayoutData();
+		if (gd instanceof GridData) {
+			((GridData)gd).widthHint= getButtonWidthHint(button);
+			((GridData)gd).horizontalAlignment = GridData.FILL;
+		}
+	}
+
+	/**
+	 * Creates and returns a new push button with the given
+	 * label and/or image.
+	 *
+	 * @param parent parent control
+	 * @param label button label or <code>null</code>
+	 * @param image image of <code>null</code>
+	 *
+	 * @return a new push button
+	 */
+	private static Button createPushButton(Composite parent, String label, Image image) {
+		Button button = new Button(parent, SWT.PUSH);
+		button.setFont(parent.getFont());
+		if (image != null) {
+			button.setImage(image);
+		}
+		if (label != null) {
+			button.setText(label);
+		}
+		GridData gd = new GridData();
+		button.setLayoutData(gd);
+		setButtonDimensionHint(button);
+		return button;
+	}
+
+	/**
+	 * Creates and returns a new push button with the given
+	 * label, tooltip and/or image.
+	 *
+	 * @param parent parent control
+	 * @param label button label or <code>null</code>
+	 * @param tooltip the tooltip text for the button or <code>null</code>
+	 * @param image image of <code>null</code>
+	 *
+	 * @return a new push button
+	 * @since 3.25
+	 */
+	static Button createPushButton(Composite parent, String label, String tooltip, Image image) {
+		Button button = createPushButton(parent, label, image);
+		button.setToolTipText(tooltip);
+		return button;
+	}
+
+	/**
+	 * Creates a new label widget
+	 * @param parent the parent composite to add this label widget to
+	 * @param text the text for the label
+	 * @param hspan the horizontal span to take up in the parent composite
+	 * @return the new label
+	 * @since 3.25
+	 *
+	 */
+	static Label createLabel(Composite parent, String text, int hspan) {
+		Label l = new Label(parent, SWT.NONE);
+		l.setFont(parent.getFont());
+		l.setText(text);
+		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+		gd.horizontalSpan = hspan;
+		gd.grabExcessHorizontalSpace = false;
+		l.setLayoutData(gd);
+		return l;
+	}
+
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/TypeFilterInputDialog.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/TypeFilterInputDialog.java
similarity index 90%
rename from org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/TypeFilterInputDialog.java
rename to org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/TypeFilterInputDialog.java
index 5f0a5cc..9b845a2 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/TypeFilterInputDialog.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/filtertable/TypeFilterInputDialog.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 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
@@ -10,8 +10,10 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ * Note:
+ *     The class moved from the org.eclipse.jdt.internal.ui.preferences package.
  *******************************************************************************/
-package org.eclipse.jdt.internal.ui.preferences;
+package org.eclipse.jdt.internal.ui.filtertable;
 
 import java.util.List;
 
@@ -40,10 +42,10 @@
 
 import org.eclipse.jdt.internal.corext.util.Messages;
 
-import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
 import org.eclipse.jdt.internal.ui.dialogs.PackageSelectionDialog;
 import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
 import org.eclipse.jdt.internal.ui.dialogs.TextFieldNavigationHandler;
+import org.eclipse.jdt.internal.ui.preferences.PreferencesMessages;
 import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext;
 import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
 import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
@@ -54,7 +56,7 @@
 /**
  * Dialog to enter a new entry in the type filter preference page.
  */
-public class TypeFilterInputDialog extends StatusDialog {
+class TypeFilterInputDialog extends StatusDialog {
 
 	private class TypeFilterInputAdapter implements IDialogFieldListener, IStringButtonAdapter {
 		/*
@@ -75,9 +77,11 @@
 
 	private StringButtonDialogField fNameDialogField;
 	private List<String> fExistingEntries;
+	private final String helpContextId;
 
-	public TypeFilterInputDialog(Shell parent, List<String> existingEntries) {
+	public TypeFilterInputDialog(Shell parent, List<String> existingEntries, String helpContextId) {
 		super(parent);
+		this.helpContextId = helpContextId;
 
 		fExistingEntries= existingEntries;
 
@@ -133,7 +137,7 @@
 		dialog.setFilter(fNameDialogField.getText());
 		if (dialog.open() == IDialogConstants.OK_ID) {
 			IPackageFragment res= (IPackageFragment) dialog.getFirstResult();
-			fNameDialogField.setText(res.getElementName() + "*"); //$NON-NLS-1$
+			fNameDialogField.setText(res.getElementName() + ".*"); //$NON-NLS-1$
 		}
 	}
 
@@ -162,6 +166,6 @@
 	@Override
 	protected void configureShell(Shell newShell) {
 		super.configureShell(newShell);
-		PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell, IJavaHelpContextIds.TYPE_FILTER_PREFERENCE_PAGE);
+		PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell, helpContextId);
 	}
 }
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/AutoboxingCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/AutoboxingCleanUp.java
index 2812bb9..6a0766d 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/AutoboxingCleanUp.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/AutoboxingCleanUp.java
@@ -28,11 +28,15 @@
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.ASTVisitor;
 import org.eclipse.jdt.core.dom.CastExpression;
+import org.eclipse.jdt.core.dom.ClassInstanceCreation;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.IMethodBinding;
 import org.eclipse.jdt.core.dom.ITypeBinding;
 import org.eclipse.jdt.core.dom.MethodInvocation;
 import org.eclipse.jdt.core.dom.PrimitiveType;
+import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
+import org.eclipse.jdt.core.dom.SuperMethodInvocation;
 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
 
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
@@ -82,16 +86,15 @@
 
 	@Override
 	public String getPreview() {
-		StringBuilder bld= new StringBuilder();
 		if (isEnabled(CleanUpConstants.USE_AUTOBOXING)) {
-			bld.append("Integer i = 0;\n"); //$NON-NLS-1$
-			bld.append("Character c = '*';\n"); //$NON-NLS-1$
-		} else {
-			bld.append("Integer i = Integer.valueOf(0);\n"); //$NON-NLS-1$
-			bld.append("Character c = Character.valueOf('*');\n"); //$NON-NLS-1$
+			return "" //$NON-NLS-1$
+					+ "Integer i = 0;\n" //$NON-NLS-1$
+					+ "Character c = '*';\n"; //$NON-NLS-1$
 		}
 
-		return bld.toString();
+		return "" //$NON-NLS-1$
+				+ "Integer i = Integer.valueOf(0);\n" //$NON-NLS-1$
+				+ "Character c = Character.valueOf('*');\n"; //$NON-NLS-1$
 	}
 
 	@Override
@@ -104,33 +107,78 @@
 
 		unit.accept(new ASTVisitor() {
 			@Override
-			public boolean visit(MethodInvocation node) {
-				if ((ASTNodes.usesGivenSignature(node, Boolean.class.getCanonicalName(), VALUE_OF_METHOD, boolean.class.getSimpleName())
-						|| ASTNodes.usesGivenSignature(node, Byte.class.getCanonicalName(), VALUE_OF_METHOD, byte.class.getSimpleName())
-						|| ASTNodes.usesGivenSignature(node, Character.class.getCanonicalName(), VALUE_OF_METHOD, char.class.getSimpleName())
-						|| ASTNodes.usesGivenSignature(node, Short.class.getCanonicalName(), VALUE_OF_METHOD, short.class.getSimpleName())
-						|| ASTNodes.usesGivenSignature(node, Integer.class.getCanonicalName(), VALUE_OF_METHOD, int.class.getSimpleName())
-						|| ASTNodes.usesGivenSignature(node, Long.class.getCanonicalName(), VALUE_OF_METHOD, long.class.getSimpleName())
-						|| ASTNodes.usesGivenSignature(node, Float.class.getCanonicalName(), VALUE_OF_METHOD, float.class.getSimpleName())
-						|| ASTNodes.usesGivenSignature(node, Double.class.getCanonicalName(), VALUE_OF_METHOD, double.class.getSimpleName())
+			public boolean visit(MethodInvocation visited) {
+				if ((ASTNodes.usesGivenSignature(visited, Boolean.class.getCanonicalName(), VALUE_OF_METHOD, boolean.class.getSimpleName())
+						|| ASTNodes.usesGivenSignature(visited, Byte.class.getCanonicalName(), VALUE_OF_METHOD, byte.class.getSimpleName())
+						|| ASTNodes.usesGivenSignature(visited, Character.class.getCanonicalName(), VALUE_OF_METHOD, char.class.getSimpleName())
+						|| ASTNodes.usesGivenSignature(visited, Short.class.getCanonicalName(), VALUE_OF_METHOD, short.class.getSimpleName())
+						|| ASTNodes.usesGivenSignature(visited, Integer.class.getCanonicalName(), VALUE_OF_METHOD, int.class.getSimpleName())
+						|| ASTNodes.usesGivenSignature(visited, Long.class.getCanonicalName(), VALUE_OF_METHOD, long.class.getSimpleName())
+						|| ASTNodes.usesGivenSignature(visited, Float.class.getCanonicalName(), VALUE_OF_METHOD, float.class.getSimpleName())
+						|| ASTNodes.usesGivenSignature(visited, Double.class.getCanonicalName(), VALUE_OF_METHOD, double.class.getSimpleName())
 						)) {
-					final ITypeBinding primitiveType= node.resolveMethodBinding().getParameterTypes()[0];
-					final ITypeBinding wrapperClass= node.resolveMethodBinding().getDeclaringClass();
+					final ITypeBinding primitiveType= visited.resolveMethodBinding().getParameterTypes()[0];
+					final ITypeBinding wrapperClass= visited.resolveMethodBinding().getDeclaringClass();
 
-					final ITypeBinding actualResultType= ASTNodes.getTargetType(node);
-					final ITypeBinding actualParameterType= ((Expression) node.arguments().get(0)).resolveTypeBinding();
+					final ITypeBinding actualResultType= ASTNodes.getTargetType(visited);
+					final ITypeBinding actualParameterType= ((Expression) visited.arguments().get(0)).resolveTypeBinding();
 
 					if (actualParameterType != null
 							&& (actualResultType != null
 							&& (actualResultType.equals(primitiveType) || actualResultType.equals(wrapperClass)))
 							|| Objects.equals(actualParameterType, wrapperClass)) {
-						rewriteOperations.add(new AutoboxingOperation(node, primitiveType, wrapperClass, actualParameterType, actualResultType));
+						ASTNode parent= visited.getParent();
+
+						if (parent instanceof ClassInstanceCreation
+								&& visited.getLocationInParent() == ClassInstanceCreation.ARGUMENTS_PROPERTY) {
+							ClassInstanceCreation classInstanceCreation= (ClassInstanceCreation) parent;
+
+							if (hasConflictingMethodOrConstructor(visited, classInstanceCreation.resolveConstructorBinding(), classInstanceCreation.arguments())) {
+								return true;
+							}
+						} else if (parent instanceof MethodInvocation
+								&& visited.getLocationInParent() == MethodInvocation.ARGUMENTS_PROPERTY) {
+							MethodInvocation methodInvocation= (MethodInvocation) parent;
+
+							if (hasConflictingMethodOrConstructor(visited, methodInvocation.resolveMethodBinding(), methodInvocation.arguments())) {
+								return true;
+							}
+						} else if (parent instanceof SuperMethodInvocation
+								&& visited.getLocationInParent() == SuperMethodInvocation.ARGUMENTS_PROPERTY) {
+							SuperMethodInvocation superMethodInvocation= (SuperMethodInvocation) parent;
+
+							if (hasConflictingMethodOrConstructor(visited, superMethodInvocation.resolveMethodBinding(), superMethodInvocation.arguments())) {
+								return true;
+							}
+						} else if (parent instanceof SuperConstructorInvocation
+								&& visited.getLocationInParent() == SuperConstructorInvocation.ARGUMENTS_PROPERTY) {
+							SuperConstructorInvocation superConstructorInvocation= (SuperConstructorInvocation) parent;
+
+							if (hasConflictingMethodOrConstructor(visited, superConstructorInvocation.resolveConstructorBinding(), superConstructorInvocation.arguments())) {
+								return true;
+							}
+						}
+
+						rewriteOperations.add(new AutoboxingOperation(visited, primitiveType, wrapperClass, actualParameterType, actualResultType));
 						return false;
 					}
 				}
 
 				return true;
 			}
+
+			private boolean hasConflictingMethodOrConstructor(final MethodInvocation visited, final IMethodBinding binding, final List<Expression> arguments) {
+				int argumentIndex= arguments.indexOf(visited);
+
+				if (argumentIndex < 0 || binding.getParameterTypes().length <= argumentIndex) {
+					return true;
+				}
+
+				ITypeBinding[] argumentTypes= binding.getParameterTypes().clone();
+				argumentTypes[argumentIndex]= visited.getExpression().resolveTypeBinding();
+
+				return ASTNodes.hasConflictingMethodOrConstructor(visited.getParent(), binding, argumentTypes);
+			}
 		});
 
 		if (rewriteOperations.isEmpty()) {
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/StrictlyEqualOrDifferentCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/StrictlyEqualOrDifferentCleanUp.java
index 4ce2401..7c7ac17 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/StrictlyEqualOrDifferentCleanUp.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/StrictlyEqualOrDifferentCleanUp.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2020 Fabrice TIERCELIN and others.
+ * Copyright (c) 2020, 2022 Fabrice TIERCELIN and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -31,6 +31,7 @@
 import org.eclipse.jdt.core.dom.ConditionalExpression;
 import org.eclipse.jdt.core.dom.Expression;
 import org.eclipse.jdt.core.dom.InfixExpression;
+import org.eclipse.jdt.core.dom.ParenthesizedExpression;
 import org.eclipse.jdt.core.dom.PrefixExpression;
 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
 import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
@@ -227,8 +228,20 @@
 			TextEditGroup group= createTextEditGroup(MultiFixMessages.StrictlyEqualOrDifferentCleanUp_description, cuRewrite);
 
 			InfixExpression newInfixExpression= ast.newInfixExpression();
-			newInfixExpression.setLeftOperand(ASTNodes.createMoveTarget(rewrite, firstExpression));
-			newInfixExpression.setRightOperand(ASTNodes.createMoveTarget(rewrite, secondExpression));
+			if (firstExpression instanceof InfixExpression) {
+				ParenthesizedExpression pexp= ast.newParenthesizedExpression();
+				pexp.setExpression(ASTNodes.createMoveTarget(rewrite, firstExpression));
+				newInfixExpression.setLeftOperand(pexp);
+			} else {
+				newInfixExpression.setLeftOperand(ASTNodes.createMoveTarget(rewrite, firstExpression));
+			}
+			if (secondExpression instanceof InfixExpression) {
+				ParenthesizedExpression pexp= ast.newParenthesizedExpression();
+				pexp.setExpression(ASTNodes.createMoveTarget(rewrite, secondExpression));
+				newInfixExpression.setRightOperand(pexp);
+			} else {
+				newInfixExpression.setRightOperand(ASTNodes.createMoveTarget(rewrite, secondExpression));
+			}
 
 			if (isEquality) {
 				newInfixExpression.setOperator(InfixExpression.Operator.EQUALS);
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/SubstringCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/SubstringCleanUp.java
index 03c1baa..67b5f98 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/SubstringCleanUp.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/SubstringCleanUp.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ * Copyright (c) 2021, 2022 Fabrice TIERCELIN and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
  *
  * Contributors:
  *     Fabrice TIERCELIN - initial API and implementation
+ *     Red Hat - moved implementation to jdt.core.manipulation
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.fix;
 
@@ -20,27 +21,18 @@
 
 import org.eclipse.core.runtime.CoreException;
 
-import org.eclipse.text.edits.TextEditGroup;
-
 import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.dom.ASTNode;
-import org.eclipse.jdt.core.dom.ASTVisitor;
 import org.eclipse.jdt.core.dom.CompilationUnit;
-import org.eclipse.jdt.core.dom.Expression;
-import org.eclipse.jdt.core.dom.MethodInvocation;
-import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
 
-import org.eclipse.jdt.internal.corext.dom.ASTNodes;
-import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
-import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFix;
-import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFix.CompilationUnitRewriteOperation;
-import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
-import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
-
+import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
 import org.eclipse.jdt.ui.cleanup.CleanUpRequirements;
 import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
 import org.eclipse.jdt.ui.text.java.IProblemLocation;
 
+import org.eclipse.jdt.internal.ui.text.correction.IProblemLocationCore;
+import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation;
+
 /**
  * A fix that removes the second <code>substring()</code> parameter if this parameter is the length of the string:
  * <ul>
@@ -49,97 +41,66 @@
  * </ul>
  */
 public class SubstringCleanUp extends AbstractMultiFix {
-	public SubstringCleanUp() {
-		this(Collections.emptyMap());
-	}
+
+	private final SubstringCleanUpCore cleanUpCore;
 
 	public SubstringCleanUp(final Map<String, String> options) {
-		super(options);
+		this.cleanUpCore= new SubstringCleanUpCore();
+		setOptions(options);
+	}
+
+	public SubstringCleanUp() {
+		this(Collections.EMPTY_MAP);
+	}
+
+	@Override
+	public void setOptions(CleanUpOptions options) {
+		cleanUpCore.setOptions(options);
 	}
 
 	@Override
 	public CleanUpRequirements getRequirements() {
-		boolean requireAST= isEnabled(CleanUpConstants.SUBSTRING);
-		return new CleanUpRequirements(requireAST, false, false, null);
+		return new CleanUpRequirements(cleanUpCore.getRequirementsCore());
+	}
+
+	@Override
+	protected ICleanUpFix createFix(CompilationUnit compilationUnit) throws CoreException {
+		ICleanUpFixCore fix= cleanUpCore.createFix(compilationUnit);
+		return fix == null ? null : new CleanUpFixWrapper(fix);
+	}
+
+	@Override
+	protected ICleanUpFix createFix(CompilationUnit compilationUnit, IProblemLocation[] problems) throws CoreException {
+        IProblemLocationCore[] problemsCore= null;
+		if (problems != null) {
+			List<IProblemLocationCore> problemsList= new ArrayList<>();
+			for (IProblemLocation problem : problems) {
+				problemsList.add((ProblemLocation)problem);
+			}
+			problemsCore= problemsList.toArray(new IProblemLocationCore[0]);
+		}
+		ICleanUpFixCore fix= cleanUpCore.createFix(compilationUnit, problemsCore);
+		return fix == null ? null : new CleanUpFixWrapper(fix);
 	}
 
 	@Override
 	public String[] getStepDescriptions() {
-		if (isEnabled(CleanUpConstants.SUBSTRING)) {
-			return new String[] { MultiFixMessages.SubstringCleanUp_description };
-		}
-
-		return new String[0];
+		return cleanUpCore.getStepDescriptions();
 	}
 
 	@Override
 	public String getPreview() {
-		if (isEnabled(CleanUpConstants.SUBSTRING)) {
-			return "String shortenedText = text.substring(2);\n"; //$NON-NLS-1$
-		}
-
-		return "String shortenedText = text.substring(2, text.length());\n"; //$NON-NLS-1$
+		return cleanUpCore.getPreview();
 	}
 
 	@Override
-	protected ICleanUpFix createFix(final CompilationUnit unit) throws CoreException {
-		if (!isEnabled(CleanUpConstants.SUBSTRING)) {
-			return null;
-		}
-
-		final List<CompilationUnitRewriteOperation> rewriteOperations= new ArrayList<>();
-
-		unit.accept(new ASTVisitor() {
-			@Override
-			public boolean visit(final MethodInvocation visited) {
-				if (ASTNodes.usesGivenSignature(visited, String.class.getCanonicalName(), "substring", int.class.getCanonicalName(), int.class.getCanonicalName())) { //$NON-NLS-1$
-					MethodInvocation endIndex= ASTNodes.as((Expression) visited.arguments().get(1), MethodInvocation.class);
-
-					if (endIndex != null
-							&& endIndex.getExpression() != null
-							&& ASTNodes.usesGivenSignature(endIndex, String.class.getCanonicalName(), "length") //$NON-NLS-1$
-							&& ASTNodes.match(visited.getExpression(), endIndex.getExpression())
-							&& ASTNodes.isPassive(visited.getExpression())) {
-				rewriteOperations.add(new SubstringOperation(visited));
-						return false;
-					}
-				}
-
-				return true;
-			}
-		});
-
-		if (rewriteOperations.isEmpty()) {
-			return null;
-		}
-
-		return new CompilationUnitRewriteOperationsFix(MultiFixMessages.SubstringCleanUp_description, unit,
-				rewriteOperations.toArray(new CompilationUnitRewriteOperation[0]));
+	public boolean canFix(ICompilationUnit compilationUnit, IProblemLocation problem) {
+		IProblemLocationCore problemLocation= (ProblemLocation)problem;
+		return cleanUpCore.canFix(compilationUnit, problemLocation);
 	}
 
 	@Override
-	public boolean canFix(final ICompilationUnit compilationUnit, final IProblemLocation problem) {
-		return false;
-	}
-
-	@Override
-	protected ICleanUpFix createFix(final CompilationUnit unit, final IProblemLocation[] problems) throws CoreException {
-		return null;
-	}
-
-	private static class SubstringOperation extends CompilationUnitRewriteOperation {
-		private final MethodInvocation visited;
-
-		public SubstringOperation(final MethodInvocation visited) {
-			this.visited= visited;
-		}
-
-		@Override
-		public void rewriteAST(final CompilationUnitRewrite cuRewrite, final LinkedProposalModel linkedModel) throws CoreException {
-			ASTRewrite rewrite= cuRewrite.getASTRewrite();
-			TextEditGroup group= createTextEditGroup(MultiFixMessages.SubstringCleanUp_description, cuRewrite);
-
-			rewrite.remove((ASTNode) visited.arguments().get(1), group);
-		}
+	public int computeNumberOfFixes(CompilationUnit compilationUnit) {
+		return cleanUpCore.computeNumberOfFixes(compilationUnit);
 	}
 }
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UnboxingCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UnboxingCleanUp.java
index 0599eba..e1502f0 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UnboxingCleanUp.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/UnboxingCleanUp.java
@@ -23,11 +23,16 @@
 import org.eclipse.text.edits.TextEditGroup;
 
 import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.ClassInstanceCreation;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.IMethodBinding;
 import org.eclipse.jdt.core.dom.ITypeBinding;
 import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
+import org.eclipse.jdt.core.dom.SuperMethodInvocation;
 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
 
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
@@ -88,6 +93,7 @@
 		bld.append("Integer integerObject = Integer.MAX_VALUE;\n"); //$NON-NLS-1$
 		bld.append("Character cObject = Character.MAX_VALUE;\n"); //$NON-NLS-1$
 		bld.append("\n"); //$NON-NLS-1$
+
 		if (isEnabled(CleanUpConstants.USE_UNBOXING)) {
 			bld.append("int i = integerObject;\n"); //$NON-NLS-1$
 			bld.append("char c = cObject;\n"); //$NON-NLS-1$
@@ -109,28 +115,75 @@
 
 		unit.accept(new ASTVisitor() {
 			@Override
-			public boolean visit(MethodInvocation node) {
-				if (node.getExpression() != null) {
-					ITypeBinding nodeBinding= node.getExpression().resolveTypeBinding();
-					if (nodeBinding != null	&& nodeBinding.isClass()
-							&& (ASTNodes.usesGivenSignature(node, Boolean.class.getCanonicalName(), BOOLEAN_VALUE)
-									|| ASTNodes.usesGivenSignature(node, Byte.class.getCanonicalName(), BYTE_VALUE)
-									|| ASTNodes.usesGivenSignature(node, Character.class.getCanonicalName(), CHAR_VALUE)
-									|| ASTNodes.usesGivenSignature(node, Short.class.getCanonicalName(), SHORT_VALUE)
-									|| ASTNodes.usesGivenSignature(node, Integer.class.getCanonicalName(), INT_VALUE)
-									|| ASTNodes.usesGivenSignature(node, Long.class.getCanonicalName(), LONG_VALUE)
-									|| ASTNodes.usesGivenSignature(node, Float.class.getCanonicalName(), FLOAT_VALUE)
-									|| ASTNodes.usesGivenSignature(node, Double.class.getCanonicalName(), DOUBLE_VALUE))) {
-						final ITypeBinding actualResultType= ASTNodes.getTargetType(node);
+			public boolean visit(MethodInvocation visited) {
+				if (visited.getExpression() != null) {
+					ITypeBinding nodeBinding= visited.getExpression().resolveTypeBinding();
 
-						if (actualResultType != null && actualResultType.isAssignmentCompatible(node.resolveTypeBinding())) {
-							rewriteOperations.add(new UnboxingOperation(node));
+					if (nodeBinding != null	&& nodeBinding.isClass()
+							&& (ASTNodes.usesGivenSignature(visited, Boolean.class.getCanonicalName(), BOOLEAN_VALUE)
+									|| ASTNodes.usesGivenSignature(visited, Byte.class.getCanonicalName(), BYTE_VALUE)
+									|| ASTNodes.usesGivenSignature(visited, Character.class.getCanonicalName(), CHAR_VALUE)
+									|| ASTNodes.usesGivenSignature(visited, Short.class.getCanonicalName(), SHORT_VALUE)
+									|| ASTNodes.usesGivenSignature(visited, Integer.class.getCanonicalName(), INT_VALUE)
+									|| ASTNodes.usesGivenSignature(visited, Long.class.getCanonicalName(), LONG_VALUE)
+									|| ASTNodes.usesGivenSignature(visited, Float.class.getCanonicalName(), FLOAT_VALUE)
+									|| ASTNodes.usesGivenSignature(visited, Double.class.getCanonicalName(), DOUBLE_VALUE))) {
+						final ITypeBinding actualResultType= ASTNodes.getTargetType(visited);
+
+						if (actualResultType != null && actualResultType.isAssignmentCompatible(visited.resolveTypeBinding())) {
+							ASTNode parent= visited.getParent();
+
+							if (parent instanceof ClassInstanceCreation
+									&& visited.getLocationInParent() == ClassInstanceCreation.ARGUMENTS_PROPERTY) {
+								ClassInstanceCreation classInstanceCreation= (ClassInstanceCreation) parent;
+
+								if (hasConflictingMethodOrConstructor(visited, classInstanceCreation.resolveConstructorBinding(), classInstanceCreation.arguments())) {
+									return true;
+								}
+							} else if (parent instanceof MethodInvocation
+									&& visited.getLocationInParent() == MethodInvocation.ARGUMENTS_PROPERTY) {
+								MethodInvocation methodInvocation= (MethodInvocation) parent;
+
+								if (hasConflictingMethodOrConstructor(visited, methodInvocation.resolveMethodBinding(), methodInvocation.arguments())) {
+									return true;
+								}
+							} else if (parent instanceof SuperMethodInvocation
+									&& visited.getLocationInParent() == SuperMethodInvocation.ARGUMENTS_PROPERTY) {
+								SuperMethodInvocation superMethodInvocation= (SuperMethodInvocation) parent;
+
+								if (hasConflictingMethodOrConstructor(visited, superMethodInvocation.resolveMethodBinding(), superMethodInvocation.arguments())) {
+									return true;
+								}
+							} else if (parent instanceof SuperConstructorInvocation
+									&& visited.getLocationInParent() == SuperConstructorInvocation.ARGUMENTS_PROPERTY) {
+								SuperConstructorInvocation superConstructorInvocation= (SuperConstructorInvocation) parent;
+
+								if (hasConflictingMethodOrConstructor(visited, superConstructorInvocation.resolveConstructorBinding(), superConstructorInvocation.arguments())) {
+									return true;
+								}
+							}
+
+							rewriteOperations.add(new UnboxingOperation(visited));
 							return false;
 						}
 					}
 				}
+
 				return true;
 			}
+
+			private boolean hasConflictingMethodOrConstructor(final MethodInvocation visited, final IMethodBinding binding, final List<Expression> arguments) {
+				int argumentIndex= arguments.indexOf(visited);
+
+				if (argumentIndex < 0 || binding.getParameterTypes().length <= argumentIndex) {
+					return true;
+				}
+
+				ITypeBinding[] argumentTypes= binding.getParameterTypes().clone();
+				argumentTypes[argumentIndex]= visited.getExpression().resolveTypeBinding();
+
+				return ASTNodes.hasConflictingMethodOrConstructor(visited.getParent(), binding, argumentTypes);
+			}
 		});
 
 		if (rewriteOperations.isEmpty()) {
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/CompilationUnitEditor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/CompilationUnitEditor.java
index 768373b..6515601 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/CompilationUnitEditor.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/CompilationUnitEditor.java
@@ -140,6 +140,7 @@
 import org.eclipse.jdt.internal.ui.preferences.formatter.FormatterProfileManager;
 import org.eclipse.jdt.internal.ui.text.ContentAssistPreference;
 import org.eclipse.jdt.internal.ui.text.JavaHeuristicScanner;
+import org.eclipse.jdt.internal.ui.text.JavaReconciler;
 import org.eclipse.jdt.internal.ui.text.SmartBackspaceManager;
 import org.eclipse.jdt.internal.ui.text.Symbols;
 import org.eclipse.jdt.internal.ui.text.correction.CorrectionCommandInstaller;
@@ -1648,16 +1649,18 @@
 	 */
 	@Override
 	public void aboutToBeReconciled() {
-
-		// Notify AST provider
-		CoreASTProvider.getInstance().aboutToBeReconciled(getInputJavaElement());
-
 		// Notify listeners
 		for (IJavaReconcilingListener listener : fReconcilingListeners) {
 			listener.aboutToBeReconciled();
 		}
 	}
 
+	@Override
+	public void aboutToWork(JavaReconciler javaReconciler) {
+		// Notify AST provider
+		CoreASTProvider.getInstance().aboutToBeReconciled(getInputJavaElement(), javaReconciler::signalWaitForFinish);
+	}
+
 	/*
 	 * @see org.eclipse.jdt.internal.ui.text.java.IJavaReconcilingListener#reconciled(CompilationUnit, boolean, IProgressMonitor)
 	 * @since 3.0
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EnumConstructorTargetFinder.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EnumConstructorTargetFinder.java
index dfcb615..8456ca8 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EnumConstructorTargetFinder.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EnumConstructorTargetFinder.java
@@ -85,6 +85,11 @@
 		return location;
 	}
 
+	private enum CheckEnum {
+		EXACT,
+		UNBOXED,
+		ASSIGNEMENT_COMPATIBLE
+	}
 	private ASTNode findEnumConstructor(CompilationUnit cu, EnumConstantDeclaration enumNode) {
 		ASTNode enumDeclarationNode= ASTResolving.findParentType(enumNode);
 		if (enumDeclarationNode == null) {
@@ -97,6 +102,18 @@
 		List<ASTNode> enumNodeArguments= enumNode.arguments();
 		List<ASTNode> enumBodyDeclarations= enumDeclaration.bodyDeclarations();
 
+		ASTNode foundEnumDeclaration= findEnumDeclaration(cu, enumDeclaration, enumNodeArguments, enumBodyDeclarations, CheckEnum.EXACT);
+		if (foundEnumDeclaration == null) {
+			foundEnumDeclaration= findEnumDeclaration(cu, enumDeclaration, enumNodeArguments, enumBodyDeclarations, CheckEnum.UNBOXED);
+		}
+		if (foundEnumDeclaration == null) {
+			foundEnumDeclaration= findEnumDeclaration(cu, enumDeclaration, enumNodeArguments, enumBodyDeclarations, CheckEnum.ASSIGNEMENT_COMPATIBLE);
+		}
+		return foundEnumDeclaration;
+	}
+
+	private ASTNode findEnumDeclaration(CompilationUnit cu, EnumDeclaration enumDeclaration,
+			List<ASTNode> enumNodeArguments, List<ASTNode> enumBodyDeclarations, CheckEnum checkEnum) {
 		declarationLoop: for (ASTNode enumBodyDeclarationNode : enumBodyDeclarations) {
 			if (enumBodyDeclarationNode.getNodeType() != ASTNode.METHOD_DECLARATION) {
 				continue;
@@ -107,16 +124,14 @@
 			}
 
 			List<SingleVariableDeclaration> enumBodyDeclarationNodeParameters= enumMethodDeclaration.parameters();
-			if (enumBodyDeclarationNodeParameters.size() != enumNodeArguments.size()) {
+			if (!enumMethodDeclaration.isVarargs()
+					&& enumBodyDeclarationNodeParameters.size() != enumNodeArguments.size()) {
 				continue;
 			}
 
 			for (int i= 0; i < enumBodyDeclarationNodeParameters.size(); i++) {
 				ASTNode nodeArgument= enumNodeArguments.get(i);
 				SingleVariableDeclaration singleVariableDeclaration= enumBodyDeclarationNodeParameters.get(i);
-				if(singleVariableDeclaration.isVarargs()) {
-					continue declarationLoop;
-				}
 				Type parameterType= singleVariableDeclaration.getType();
 				if (parameterType == null) {
 					continue declarationLoop;
@@ -139,7 +154,11 @@
 					if (parameterTypes.length != enumBodyDeclarationNodeParameters.size()) {
 						continue declarationLoop;
 					}
-					nodeTypeArgument= parameterTypes[i];
+					if (singleVariableDeclaration.isVarargs()) {
+						nodeTypeArgument= parameterTypes[i].getElementType();
+					} else {
+						nodeTypeArgument= parameterTypes[i];
+					}
 				}
 				if (nodeTypeArgument == null) {
 					nodeTypeArgument= ASTResolving.guessBindingForReference(nodeArgument);
@@ -148,13 +167,29 @@
 					continue declarationLoop;
 				}
 
-				if (Bindings.equals(nodeTypeArgument, nodeTypeParameter)) {
-					continue;
-				}
 				ITypeBinding unboxedTypeArgument= Bindings.getUnboxedTypeBinding(nodeTypeArgument, cu.getAST());
 				ITypeBinding unboxedTypeParameter= Bindings.getUnboxedTypeBinding(nodeTypeParameter, cu.getAST());
-				if (Bindings.equals(unboxedTypeArgument, unboxedTypeParameter)) {
-					continue;
+				switch (checkEnum) {
+					case EXACT:
+						if (Bindings.equals(nodeTypeArgument, nodeTypeParameter)) {
+							continue;
+						}
+						break;
+					case UNBOXED:
+						if (Bindings.equals(unboxedTypeArgument, unboxedTypeParameter)) {
+							continue;
+						}
+						break;
+					case ASSIGNEMENT_COMPATIBLE:
+						if (nodeTypeArgument.isAssignmentCompatible(nodeTypeParameter)) {
+							continue;
+						}
+						if (unboxedTypeArgument.isAssignmentCompatible(unboxedTypeParameter)) {
+							continue;
+						}
+						break;
+					default:
+						break;
 				}
 				continue declarationLoop;
 			} // for all enum constructor parameters
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java
index abf2d7e..c618f35 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaEditor.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
@@ -189,8 +189,12 @@
 import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
 import org.eclipse.jdt.core.util.IModifierConstants;
 
+import org.eclipse.jdt.internal.core.manipulation.search.BreakContinueTargetFinder;
+import org.eclipse.jdt.internal.core.manipulation.search.ExceptionOccurrencesFinder;
 import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder;
 import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder.OccurrenceLocation;
+import org.eclipse.jdt.internal.core.manipulation.search.ImplementOccurrencesFinder;
+import org.eclipse.jdt.internal.core.manipulation.search.MethodExitsFinder;
 import org.eclipse.jdt.internal.core.manipulation.search.OccurrencesFinder;
 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
 
@@ -224,10 +228,6 @@
 import org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectNextAction;
 import org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectPreviousAction;
 import org.eclipse.jdt.internal.ui.javaeditor.selectionactions.StructureSelectionAction;
-import org.eclipse.jdt.internal.ui.search.BreakContinueTargetFinder;
-import org.eclipse.jdt.internal.ui.search.ExceptionOccurrencesFinder;
-import org.eclipse.jdt.internal.ui.search.ImplementOccurrencesFinder;
-import org.eclipse.jdt.internal.ui.search.MethodExitsFinder;
 import org.eclipse.jdt.internal.ui.text.DocumentCharacterIterator;
 import org.eclipse.jdt.internal.ui.text.JavaChangeHover;
 import org.eclipse.jdt.internal.ui.text.JavaPairMatcher;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementHyperlinkDetector.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementHyperlinkDetector.java
index 0eb6a52..6ffc3c4 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementHyperlinkDetector.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/JavaElementHyperlinkDetector.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
@@ -47,6 +47,7 @@
 import org.eclipse.jdt.core.dom.SwitchStatement;
 import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
 
+import org.eclipse.jdt.internal.core.manipulation.search.BreakContinueTargetFinder;
 import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder.OccurrenceLocation;
 import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
@@ -55,7 +56,6 @@
 
 import org.eclipse.jdt.ui.actions.SelectionDispatchAction;
 
-import org.eclipse.jdt.internal.ui.search.BreakContinueTargetFinder;
 import org.eclipse.jdt.internal.ui.search.SearchMessages;
 import org.eclipse.jdt.internal.ui.text.JavaWordFinder;
 
@@ -283,7 +283,7 @@
 			return null;
 		}
 
-		String description= Messages.format(SearchMessages.BreakContinueTargetFinder_occurrence_description, BasicElementLabels.getJavaElementName(ASTNodes.asString(caseNode)));
+		String description= Messages.format(org.eclipse.jdt.internal.core.manipulation.search.SearchMessages.BreakContinueTargetFinder_occurrence_description, BasicElementLabels.getJavaElementName(ASTNodes.asString(caseNode)));
 		return new OccurrenceLocation(switchNode.getStartPosition(), 6, 0, description); // '6' is the length of 'switch'
 	}
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/SemanticHighlightingReconciler.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/SemanticHighlightingReconciler.java
index 531c831..be6be9b 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/SemanticHighlightingReconciler.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/SemanticHighlightingReconciler.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
@@ -158,7 +158,7 @@
 						SemanticHighlighting semanticHighlighting= fJobSemanticHighlightings[i];
 						if (semanticHighlighting instanceof RestrictedIdentifiersHighlighting) {
 							addPosition(offset, length, fJobHighlightings[i]);
-							return false;
+							return true;
 						}
 					}
 				}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/packageview/ClassPathContainer.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/packageview/ClassPathContainer.java
index 57b2372..f5098b2 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/packageview/ClassPathContainer.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/packageview/ClassPathContainer.java
@@ -121,7 +121,7 @@
 		public boolean equals(Object obj) {
 			if (this == obj)
 				return true;
-			if (obj == null || obj!=this)
+			if (obj == null)
 				return false;
 			if (getClass() != obj.getClass())
 				return false;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/JavaBasePreferencePage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/JavaBasePreferencePage.java
index 5b8e58b..37243b3 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/JavaBasePreferencePage.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/JavaBasePreferencePage.java
@@ -70,6 +70,9 @@
 	private static final String DOUBLE_CLICK_GOES_INTO= PreferenceConstants.DOUBLE_CLICK_GOES_INTO;
 	private static final String DOUBLE_CLICK_EXPANDS= PreferenceConstants.DOUBLE_CLICK_EXPANDS;
 
+    private static final String OPEN_CALL_HIERARCHY_IMPLEMENTORS= "PREF_USE_IMPLEMENTORS"; //$NON-NLS-1$ //org.eclipse.jdt.internal.corext.callhierarchy.CallHierarchy.PREF_USE_IMPLEMENTORS
+
+
 	private ArrayList<Button> fCheckBoxes;
 	private ArrayList<Button> fRadioButtons;
 	private ArrayList<Text> fTextControls;
@@ -169,6 +172,12 @@
 		addRadioButton(typeHierarchyGroup, PreferencesMessages.JavaBasePreferencePage_inPerspective, OPEN_TYPE_HIERARCHY, OPEN_TYPE_HIERARCHY_IN_PERSPECTIVE);
 		addRadioButton(typeHierarchyGroup, PreferencesMessages.JavaBasePreferencePage_inView, OPEN_TYPE_HIERARCHY, OPEN_TYPE_HIERARCHY_IN_VIEW_PART);
 
+		Group callHierarchyGroup= new Group(result, SWT.NONE);
+		callHierarchyGroup.setLayout(new GridLayout());
+		callHierarchyGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		callHierarchyGroup.setText(PreferencesMessages.JavaBasePreferencePage_openCallHierarchy);
+		addCheckBox(callHierarchyGroup, PreferencesMessages.JavaBasePreferencePage_showCalleeImplementations, null, OPEN_CALL_HIERARCHY_IMPLEMENTORS);
+
 		Group refactoringGroup= new Group(result, SWT.NONE);
 		refactoringGroup.setLayout(new GridLayout());
 		refactoringGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java
index e9892b0..b8f3639 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java
@@ -223,6 +223,8 @@
 	public static String JavaEditorPreferencePage_smartAutoIndentAfterNewLine;
 	public static String JavaEditorColoringConfigurationBlock_link;
 	public static String JavaBasePreferencePage_openTypeHierarchy;
+	public static String JavaBasePreferencePage_openCallHierarchy;
+	public static String JavaBasePreferencePage_showCalleeImplementations;
 	public static String JavaBasePreferencePage_inView;
 	public static String JavaBasePreferencePage_inPerspective;
 	public static String JavaEditorPreferencePage_quickassist_lightbulb;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties
index 15bc858..fffda58 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties
@@ -215,6 +215,8 @@
 JavaBasePreferencePage_inView=Show the &Type Hierarchy View in the current perspective
 JavaBasePreferencePage_dialogs=Java dialogs
 JavaBasePreferencePage_inPerspective=Open a new Type Hierarchy &Perspective
+JavaBasePreferencePage_openCallHierarchy=When opening a Call Hierarchy
+JavaBasePreferencePage_showCalleeImplementations=Show implementations of callee
 
 JavaEditorPreferencePage_quickassist_lightbulb=L&ight bulb for quick assists
 JavaEditorPreferencePage_showJavaElementOnly= O&nly show the selected Java element
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/TypeFilterPreferencePage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/TypeFilterPreferencePage.java
index 982a190..2f08ad5 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/TypeFilterPreferencePage.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/TypeFilterPreferencePage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2011 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
@@ -13,12 +13,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.preferences;
 
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Hashtable;
-import java.util.List;
 import java.util.Map;
-import java.util.StringTokenizer;
 
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionAdapter;
@@ -31,35 +27,24 @@
 import org.eclipse.swt.widgets.Link;
 
 import org.eclipse.jface.dialogs.Dialog;
-import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.preference.PreferencePage;
-import org.eclipse.jface.viewers.LabelProvider;
-import org.eclipse.jface.viewers.ViewerComparator;
-import org.eclipse.jface.window.Window;
 
 import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.IWorkbenchPreferencePage;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.dialogs.PreferencesUtil;
 
-import org.eclipse.jdt.core.IPackageFragment;
 import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchEngine;
 
 import org.eclipse.jdt.ui.PreferenceConstants;
 
 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
 import org.eclipse.jdt.internal.ui.JavaPlugin;
-import org.eclipse.jdt.internal.ui.dialogs.PackageSelectionDialog;
-import org.eclipse.jdt.internal.ui.util.BusyIndicatorRunnableContext;
-import org.eclipse.jdt.internal.ui.wizards.dialogfields.CheckedListDialogField;
-import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
-import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
-import org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter;
-import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
-import org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField;
+import org.eclipse.jdt.internal.ui.filtertable.FilterManager;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.ButtonLabel;
+import org.eclipse.jdt.internal.ui.filtertable.JavaFilterTable.FilterTableConfig;
 import org.eclipse.jdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField;
 
 /*
@@ -72,61 +57,9 @@
 	private static final String PREF_FILTER_ENABLED= PreferenceConstants.TYPEFILTER_ENABLED;
 	private static final String PREF_FILTER_DISABLED= PreferenceConstants.TYPEFILTER_DISABLED;
 
-	private static String[] unpackOrderList(String str) {
-		StringTokenizer tok= new StringTokenizer(str, ";"); //$NON-NLS-1$
-		int nTokens= tok.countTokens();
-		String[] res= new String[nTokens];
-		for (int i= 0; i < nTokens; i++) {
-			res[i]= tok.nextToken();
-		}
-		return res;
-	}
+	private static final String ITEM_SEPARATOR = ";"; //$NON-NLS-1$
 
-	private static String packOrderList(List<String> orderList) {
-		StringBuilder buf= new StringBuilder();
-		for (String element : orderList) {
-			buf.append(element);
-			buf.append(';');
-		}
-		return buf.toString();
-	}
-
-	private class TypeFilterAdapter implements IListAdapter<String>, IDialogFieldListener {
-
-		private boolean canEdit(ListDialogField<String> field) {
-			return field.getSelectedElements().size() == 1;
-		}
-
-        @Override
-		public void customButtonPressed(ListDialogField<String> field, int index) {
-        	doButtonPressed(index);
-        }
-
-        @Override
-		public void selectionChanged(ListDialogField<String> field) {
-			fFilterListField.enableButton(IDX_EDIT, canEdit(field));
-        }
-
-        @Override
-		public void dialogFieldChanged(DialogField field) {
-        }
-
-        @Override
-		public void doubleClicked(ListDialogField<String> field) {
-        	if (canEdit(field)) {
-				doButtonPressed(IDX_EDIT);
-        	}
-        }
-	}
-
-	private static final int IDX_ADD= 0;
-	private static final int IDX_ADD_PACKAGE= 1;
-	private static final int IDX_EDIT= 2;
-	private static final int IDX_REMOVE= 3;
-	private static final int IDX_SELECT= 5;
-	private static final int IDX_DESELECT= 6;
-
-	private CheckedListDialogField<String> fFilterListField;
+	private JavaFilterTable fFilterTable;
 	private SelectionButtonDialogField fHideForbiddenField;
 	private SelectionButtonDialogField fHideDiscouragedField;
 
@@ -135,26 +68,21 @@
 		setPreferenceStore(JavaPlugin.getDefault().getPreferenceStore());
 		setDescription(PreferencesMessages.TypeFilterPreferencePage_description);
 
-		String[] buttonLabels= new String[] {
-			PreferencesMessages.TypeFilterPreferencePage_add_button,
-			PreferencesMessages.TypeFilterPreferencePage_addpackage_button,
-			PreferencesMessages.TypeFilterPreferencePage_edit_button,
-			PreferencesMessages.TypeFilterPreferencePage_remove_button,
-			/* 4 */  null,
-			PreferencesMessages.TypeFilterPreferencePage_selectall_button,
-			PreferencesMessages.TypeFilterPreferencePage_deselectall_button,
-		};
-
-		TypeFilterAdapter adapter= new TypeFilterAdapter();
-
-		fFilterListField= new CheckedListDialogField<>(adapter, buttonLabels, new LabelProvider());
-		fFilterListField.setDialogFieldListener(adapter);
-		fFilterListField.setLabelText(PreferencesMessages.TypeFilterPreferencePage_list_label);
-		fFilterListField.setCheckAllButtonIndex(IDX_SELECT);
-		fFilterListField.setUncheckAllButtonIndex(IDX_DESELECT);
-		fFilterListField.setRemoveButtonIndex(IDX_REMOVE);
-
-		fFilterListField.enableButton(IDX_EDIT, false);
+		fFilterTable= new JavaFilterTable(this,
+				new FilterManager(PREF_FILTER_ENABLED, PREF_FILTER_DISABLED, ITEM_SEPARATOR),
+				new FilterTableConfig()
+						.setLabelText(PreferencesMessages.TypeFilterPreferencePage_list_label)
+						.setAddFilter(new ButtonLabel(PreferencesMessages.TypeFilterPreferencePage_add_button))
+						.setEditFilter(new ButtonLabel(PreferencesMessages.TypeFilterPreferencePage_edit_button))
+						.setAddPackage(new ButtonLabel(PreferencesMessages.TypeFilterPreferencePage_addpackage_button))
+						.setRemove(new ButtonLabel(PreferencesMessages.TypeFilterPreferencePage_remove_button))
+						.setSelectAll(new ButtonLabel(PreferencesMessages.TypeFilterPreferencePage_selectall_button))
+						.setDeselectAll(new ButtonLabel(PreferencesMessages.TypeFilterPreferencePage_deselectall_button))
+						.setAddTypeDialog(new JavaFilterTable.DialogLabels(PreferencesMessages.TypeFilterInputDialog_title, PreferencesMessages.TypeFilterInputDialog_message))
+						.setAddPackageDialog(new JavaFilterTable.DialogLabels(PreferencesMessages.TypeFilterPreferencePage_choosepackage_label,
+								PreferencesMessages.TypeFilterPreferencePage_choosepackage_description))
+						.setHelpContextId(IJavaHelpContextIds.TYPE_FILTER_PREFERENCE_PAGE)
+						.setShowParents(true));
 
 		fHideForbiddenField= new SelectionButtonDialogField(SWT.CHECK);
 		fHideForbiddenField.setLabelText(PreferencesMessages.TypeFilterPreferencePage_hideForbidden_label);
@@ -188,12 +116,7 @@
 
 		composite.setLayout(layout);
 
-		fFilterListField.doFillIntoGrid(composite, 3);
-		LayoutUtil.setHorizontalSpan(fFilterListField.getLabelControl(null), 2);
-		LayoutUtil.setWidthHint(fFilterListField.getLabelControl(null), convertWidthInCharsToPixels(40));
-		LayoutUtil.setHorizontalGrabbing(fFilterListField.getListControl(null));
-
-		fFilterListField.getTableViewer().setComparator(new ViewerComparator());
+		fFilterTable.createTable(composite);
 
 		Label spacer= new Label(composite, SWT.LEFT );
 		GridData gd= new GridData(SWT.DEFAULT, convertHeightInCharsToPixels(1) / 2);
@@ -226,20 +149,9 @@
 	}
 
 	private void initialize(boolean fromDefault) {
-		IPreferenceStore store= getPreferenceStore();
-
-		String enabled= fromDefault ? store.getDefaultString(PREF_FILTER_ENABLED) : store.getString(PREF_FILTER_ENABLED);
-		String disabled= fromDefault ? store.getDefaultString(PREF_FILTER_DISABLED) : store.getString(PREF_FILTER_DISABLED);
-
-		ArrayList<String> res= new ArrayList<>();
-
-		String[] enabledEntries= unpackOrderList(enabled);
-		res.addAll(Arrays.asList(enabledEntries));
-		String[] disabledEntries= unpackOrderList(disabled);
-		res.addAll(Arrays.asList(disabledEntries));
-
-		fFilterListField.setElements(res);
-		fFilterListField.setCheckedElements(Arrays.asList(enabledEntries));
+		if (fromDefault) {
+			fFilterTable.performDefaults();
+		}
 
 		boolean hideForbidden= getJDTCoreOption(JavaCore.CODEASSIST_FORBIDDEN_REFERENCE_CHECK, fromDefault);
 		fHideForbiddenField.setSelection(hideForbidden);
@@ -252,67 +164,6 @@
 		return JavaCore.ENABLED.equals(value);
 	}
 
-	private void doButtonPressed(int index) {
-		switch (index) {
-			case IDX_ADD:
-				// add new
-				TypeFilterInputDialog dialog= new TypeFilterInputDialog(getShell(), fFilterListField.getElements());
-				if (dialog.open() == Window.OK) {
-					String res= (String) dialog.getResult();
-					fFilterListField.addElement(res);
-					fFilterListField.setChecked(res, true);
-				}
-				break;
-			case IDX_ADD_PACKAGE:
-				// add packages
-				String[] res= choosePackage();
-				if (res != null) {
-					fFilterListField.addElements(Arrays.asList(res));
-					for (String re : res) {
-						fFilterListField.setChecked(re, true);
-					}
-				}
-				break;
-			case IDX_EDIT:
-				// edit
-				List<String> selected= fFilterListField.getSelectedElements();
-				if (selected.isEmpty()) {
-					return;
-				}
-				String editedEntry= selected.get(0);
-				List<String> existing= fFilterListField.getElements();
-				existing.remove(editedEntry);
-				dialog= new TypeFilterInputDialog(getShell(), existing);
-				dialog.setInitialString(editedEntry);
-				if (dialog.open() == Window.OK) {
-					fFilterListField.replaceElement(editedEntry, (String) dialog.getResult());
-				}
-				break;
-			default:
-				break;
-		}
-	}
-
-	private String[] choosePackage() {
-		IJavaSearchScope scope= SearchEngine.createWorkspaceScope();
-		BusyIndicatorRunnableContext context= new BusyIndicatorRunnableContext();
-		int flags= PackageSelectionDialog.F_SHOW_PARENTS | PackageSelectionDialog.F_HIDE_DEFAULT_PACKAGE | PackageSelectionDialog.F_REMOVE_DUPLICATES;
-		PackageSelectionDialog dialog = new PackageSelectionDialog(getShell(), context, flags , scope);
-		dialog.setTitle(PreferencesMessages.TypeFilterPreferencePage_choosepackage_label);
-		dialog.setMessage(PreferencesMessages.TypeFilterPreferencePage_choosepackage_description);
-		dialog.setMultipleSelection(true);
-		if (dialog.open() == IDialogConstants.OK_ID) {
-			Object[] fragments= dialog.getResult();
-			String[] res= new String[fragments.length];
-			for (int i= 0; i < res.length; i++) {
-				res[i]= ((IPackageFragment) fragments[i]).getElementName() + ".*"; //$NON-NLS-1$
-			}
-			return res;
-		}
-		return null;
-	}
-
-
 	@Override
 	public void init(IWorkbench workbench) {
 	}
@@ -327,7 +178,6 @@
 		super.performDefaults();
     }
 
-
     /*
      * @see org.eclipse.jface.preference.IPreferencePage#performOk()
      */
@@ -335,12 +185,7 @@
 	public boolean performOk() {
   		IPreferenceStore prefs= JavaPlugin.getDefault().getPreferenceStore();
 
-  		List<String> checked= fFilterListField.getCheckedElements();
-  		List<String> unchecked= fFilterListField.getElements();
-  		unchecked.removeAll(checked);
-
-  		prefs.setValue(PREF_FILTER_ENABLED, packOrderList(checked));
-  		prefs.setValue(PREF_FILTER_DISABLED, packOrderList(unchecked));
+		fFilterTable.performOk(prefs);
 		JavaPlugin.flushInstanceScope();
 
 		Hashtable<String, String> coreOptions= JavaCore.getOptions();
@@ -353,7 +198,5 @@
         return true;
     }
 
-
 }
 
-
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterMessages.java
index e48d44a..8a43c07 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterMessages.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 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
@@ -165,6 +165,8 @@
 	public static String FormatterModifyDialog_lineWrap_pref_default_indent_array;
 	public static String FormatterModifyDialog_lineWrap_pref_default_indent_wrapped;
 	public static String FormatterModifyDialog_lineWrap_pref_explicit_constructor_invocations;
+	public static String FormatterModifyDialog_lineWrap_pref_expressions_in_switch_case_with_arrow;
+	public static String FormatterModifyDialog_lineWrap_pref_expressions_in_switch_case_with_colon;
 	public static String FormatterModifyDialog_lineWrap_pref_extends_clause;
 	public static String FormatterModifyDialog_lineWrap_pref_for;
 	public static String FormatterModifyDialog_lineWrap_pref_implements_clause;
@@ -179,12 +181,14 @@
 	public static String FormatterModifyDialog_lineWrap_pref_param_type_ref;
 	public static String FormatterModifyDialog_lineWrap_pref_parameters;
 	public static String FormatterModifyDialog_lineWrap_pref_qualified_invocations;
+	public static String FormatterModifyDialog_lineWrap_pref_qualified_invocations_indent_from_base_expression_first_line;
 	public static String FormatterModifyDialog_lineWrap_pref_qualified_object_allocation_arguments;
 	public static String FormatterModifyDialog_lineWrap_pref_record_components;
 	public static String FormatterModifyDialog_lineWrap_pref_relational_operators;
 	public static String FormatterModifyDialog_lineWrap_pref_shift_operators;
 	public static String FormatterModifyDialog_lineWrap_pref_string_concatenation;
 	public static String FormatterModifyDialog_lineWrap_pref_superinterfaces;
+	public static String FormatterModifyDialog_lineWrap_pref_switch_case_with_arrow;
 	public static String FormatterModifyDialog_lineWrap_pref_throws_clause;
 	public static String FormatterModifyDialog_lineWrap_pref_try;
 	public static String FormatterModifyDialog_lineWrap_pref_wrap_outer_expressions_when_nested;
@@ -246,6 +250,8 @@
 	public static String FormatterModifyDialog_newLines_pref_keep_record_constructor_declaration_on_one_line;
 	public static String FormatterModifyDialog_newLines_pref_keep_record_declaration_on_one_line;
 	public static String FormatterModifyDialog_newLines_pref_keep_simple_getter_setter_on_one_line;
+	public static String FormatterModifyDialog_newLines_pref_keep_switch_body_block_on_one_line;
+	public static String FormatterModifyDialog_newLines_pref_keep_switch_case_with_arrow_on_one_line;
 	public static String FormatterModifyDialog_newLines_pref_keep_type_declaration_on_one_line;
 	public static String FormatterModifyDialog_newLines_pref_local_variables;
 	public static String FormatterModifyDialog_newLines_pref_methods;
@@ -319,6 +325,7 @@
 	public static String FormatterModifyDialog_whiteSpace_pref_after_comma_in_case_expressions;
 	public static String FormatterModifyDialog_whiteSpace_pref_after_comma_in_method_args;
 	public static String FormatterModifyDialog_whiteSpace_pref_after_comma_in_params;
+	public static String FormatterModifyDialog_whiteSpace_pref_after_comma_in_permits;
 	public static String FormatterModifyDialog_whiteSpace_pref_after_comma_in_qalloc;
 	public static String FormatterModifyDialog_whiteSpace_pref_after_comma_in_record_components;
 	public static String FormatterModifyDialog_whiteSpace_pref_after_comma_in_throws;
@@ -367,6 +374,7 @@
 	public static String FormatterModifyDialog_whiteSpace_pref_before_comma_in_case_expressions;
 	public static String FormatterModifyDialog_whiteSpace_pref_before_comma_in_method_args;
 	public static String FormatterModifyDialog_whiteSpace_pref_before_comma_in_params;
+	public static String FormatterModifyDialog_whiteSpace_pref_before_comma_in_permits;
 	public static String FormatterModifyDialog_whiteSpace_pref_before_comma_in_qalloc;
 	public static String FormatterModifyDialog_whiteSpace_pref_before_comma_in_record_components;
 	public static String FormatterModifyDialog_whiteSpace_pref_before_comma_in_throws;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterMessages.properties
index be70a5f..55f1a35 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterMessages.properties
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2019 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
@@ -51,6 +51,8 @@
 FormatterModifyDialog_whiteSpace_pref_before_opening_brace_of_anon_class=Before opening brace of an anonymous class
 FormatterModifyDialog_whiteSpace_pref_before_comma_implements=Before comma in implements clause
 FormatterModifyDialog_whiteSpace_pref_after_comma_implements=After comma in implements clause
+FormatterModifyDialog_whiteSpace_pref_before_comma_in_permits=Before comma in permits clause
+FormatterModifyDialog_whiteSpace_pref_after_comma_in_permits=After comma in permits clause
 
 FormatterModifyDialog_whiteSpace_tree_methods=Methods
 FormatterModifyDialog_whiteSpace_tree_constructors=Constructors
@@ -217,6 +219,7 @@
 FormatterModifyDialog_lineWrap_pref_additive_operators=Additive operators (+, -)
 FormatterModifyDialog_lineWrap_pref_arguments=Arguments
 FormatterModifyDialog_lineWrap_pref_qualified_invocations=Qualified invocations
+FormatterModifyDialog_lineWrap_pref_qualified_invocations_indent_from_base_expression_first_line=Indent from the base expression's first line
 FormatterModifyDialog_lineWrap_pref_for='for'
 FormatterModifyDialog_lineWrap_pref_throws_clause='throws' clause
 FormatterModifyDialog_lineWrap_pref_try='try-with-resources'
@@ -224,6 +227,8 @@
 FormatterModifyDialog_lineWrap_pref_qualified_object_allocation_arguments=Qualified object allocation arguments
 FormatterModifyDialog_lineWrap_pref_array_init=Array initializers
 FormatterModifyDialog_lineWrap_pref_explicit_constructor_invocations=Explicit constructor invocations
+FormatterModifyDialog_lineWrap_pref_expressions_in_switch_case_with_arrow=Expressions in 'switch' case wtih arrow
+FormatterModifyDialog_lineWrap_pref_expressions_in_switch_case_with_colon=Expressions in 'switch' case wtih colon
 FormatterModifyDialog_lineWrap_pref_conditionals=Conditionals
 FormatterModifyDialog_lineWrap_pref_module_statements=Module statements
 FormatterModifyDialog_lineWrap_pref_assertion_message='assert' messages
@@ -259,6 +264,7 @@
 FormatterModifyDialog_lineWrap_pref_shift_operators=Shift operators (<<, >>, >>>)
 FormatterModifyDialog_lineWrap_pref_string_concatenation=String concatenation
 FormatterModifyDialog_lineWrap_pref_superinterfaces='implements' clause
+FormatterModifyDialog_lineWrap_pref_switch_case_with_arrow='switch' case with arrow
 FormatterModifyDialog_lineWrap_pref_assignments=Assignments
 FormatterModifyDialog_lineWrap_tree_annotations=Annotations
 FormatterModifyDialog_lineWrap_tree_binary_expressions=Binary expressions
@@ -441,6 +447,8 @@
 FormatterModifyDialog_newLines_pref_keep_record_constructor_declaration_on_one_line=Record constructor declaration
 FormatterModifyDialog_newLines_pref_keep_record_declaration_on_one_line=Record declaration
 FormatterModifyDialog_newLines_pref_keep_simple_getter_setter_on_one_line=Keep simple getters and setters on one line
+FormatterModifyDialog_newLines_pref_keep_switch_body_block_on_one_line=Switch expression/statement with arrows
+FormatterModifyDialog_newLines_pref_keep_switch_case_with_arrow_on_one_line=Switch case with arrow
 FormatterModifyDialog_newLines_pref_keep_type_declaration_on_one_line=Class declaration
 
 FormatterModifyDialog_newLines_pref_end_of_file=At end of file
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterModifyDialog.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterModifyDialog.java
index 8f17643..edb73b1 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterModifyDialog.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/formatter/FormatterModifyDialog.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 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
@@ -521,7 +521,7 @@
 		}
 
 		public static ModifyAll<Spinner> addModifyAll(Section section, final Images images) {
-			return new ModifyAll<Spinner>(section, images) {
+			return new ModifyAll<>(section, images) {
 
 				private Label fLabel;
 				private ToolItem fRemoveLinesItem;
@@ -1054,7 +1054,9 @@
 								.pref(FormatterMessages.FormatterModifyDialog_whiteSpace_pref_before_opening_brace_of_a_class, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_TYPE_DECLARATION)
 								.pref(FormatterMessages.FormatterModifyDialog_whiteSpace_pref_before_opening_brace_of_anon_class, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_OPENING_BRACE_IN_ANONYMOUS_TYPE_DECLARATION)
 								.pref(FormatterMessages.FormatterModifyDialog_whiteSpace_pref_before_comma_implements, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_SUPERINTERFACES)
-								.pref(FormatterMessages.FormatterModifyDialog_whiteSpace_pref_after_comma_implements, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_SUPERINTERFACES))
+								.pref(FormatterMessages.FormatterModifyDialog_whiteSpace_pref_after_comma_implements, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_SUPERINTERFACES)
+								.pref(FormatterMessages.FormatterModifyDialog_whiteSpace_pref_before_comma_in_permits, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_PERMITTED_TYPES)
+								.pref(FormatterMessages.FormatterModifyDialog_whiteSpace_pref_after_comma_in_permits, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_PERMITTED_TYPES))
 						.node(fTree.builder(FormatterMessages.FormatterModifyDialog_whiteSpace_tree_fields, "-fields", modAll) //$NON-NLS-1$
 								.pref(FormatterMessages.FormatterModifyDialog_whiteSpace_pref_before_comma_fields, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_COMMA_IN_MULTIPLE_FIELD_DECLARATIONS)
 								.pref(FormatterMessages.FormatterModifyDialog_whiteSpace_pref_after_comma_fields, DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_COMMA_IN_MULTIPLE_FIELD_DECLARATIONS))
@@ -1408,6 +1410,8 @@
 					pref.addDependant(guardianPref, valueAcceptor(oneLineOptions[0], oneLineOptions[1], oneLineOptions[4]));
 				})
 				.pref(FormatterMessages.FormatterModifyDialog_newLines_pref_keep_lambda_body_block_on_one_line, DefaultCodeFormatterConstants.FORMATTER_KEEP_LAMBDA_BODY_BLOCK_ON_ONE_LINE)
+				.pref(FormatterMessages.FormatterModifyDialog_newLines_pref_keep_switch_case_with_arrow_on_one_line, DefaultCodeFormatterConstants.FORMATTER_KEEP_SWITCH_CASE_WITH_ARROW_ON_ONE_LINE)
+				.pref(FormatterMessages.FormatterModifyDialog_newLines_pref_keep_switch_body_block_on_one_line, DefaultCodeFormatterConstants.FORMATTER_KEEP_SWITCH_BODY_BLOCK_ON_ONE_LINE)
 				.pref(FormatterMessages.FormatterModifyDialog_newLines_pref_keep_code_block_on_one_line, DefaultCodeFormatterConstants.FORMATTER_KEEP_CODE_BLOCK_ON_ONE_LINE)
 				.gap()
 				.pref(FormatterMessages.FormatterModifyDialog_newLines_pref_keep_method_body_on_one_line, DefaultCodeFormatterConstants.FORMATTER_KEEP_METHOD_BODY_ON_ONE_LINE, pref -> {
@@ -1423,7 +1427,7 @@
 				.pref(FormatterMessages.FormatterModifyDialog_newLines_pref_keep_record_constructor_declaration_on_one_line, DefaultCodeFormatterConstants.FORMATTER_KEEP_RECORD_CONSTRUCTOR_ON_ONE_LINE)
 				.pref(FormatterMessages.FormatterModifyDialog_newLines_pref_keep_annotation_declaration_on_one_line, DefaultCodeFormatterConstants.FORMATTER_KEEP_ANNOTATION_DECLARATION_ON_ONE_LINE);
 
-		return fTree.new SimpleTreeBuilder<PreferenceTreeNode<?>>(null, null, null) {
+		return fTree.new SimpleTreeBuilder<>(null, null, null) {
 			@Override
 			protected PreferenceTreeNode<?> build(Section parent, PreferenceBuilder ignored) {
 				return sectionBuilder.build(parent, prefBuilder);
@@ -1465,7 +1469,12 @@
 						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_superinterfaces, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SUPERINTERFACES_IN_RECORD_DECLARATION))
 				.node(fTree.builder(FormatterMessages.FormatterModifyDialog_lineWrap_tree_function_calls, null, modAll)
 						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_arguments, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_METHOD_INVOCATION)
-						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_qualified_invocations, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SELECTOR_IN_METHOD_INVOCATION)
+						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_qualified_invocations, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SELECTOR_IN_METHOD_INVOCATION, p -> {
+							CheckboxPreference child= fTree.addCheckbox(p, FormatterMessages.FormatterModifyDialog_lineWrap_pref_qualified_invocations_indent_from_base_expression_first_line,
+									DefaultCodeFormatterConstants.FORMATTER_ALIGN_SELECTOR_IN_METHOD_INVOCATION_ON_EXPRESSION_FIRST_LINE, CheckboxPreference.FALSE_TRUE);
+							p.addDependant(child, v -> DefaultCodeFormatterConstants.getWrappingStyle(v) != DefaultCodeFormatterConstants.WRAP_NO_SPLIT
+									&& DefaultCodeFormatterConstants.getIndentStyle(v) != DefaultCodeFormatterConstants.INDENT_ON_COLUMN);
+						})
 						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_explicit_constructor_invocations, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_EXPLICIT_CONSTRUCTOR_CALL)
 						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_object_allocation_arguments, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_ALLOCATION_EXPRESSION)
 						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_qualified_object_allocation_arguments, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ARGUMENTS_IN_QUALIFIED_ALLOCATION_EXPRESSION))
@@ -1488,6 +1497,9 @@
 						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_compact_loops, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_COMPACT_LOOP)
 						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_try, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_RESOURCES_IN_TRY)
 						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_catch, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_UNION_TYPE_IN_MULTICATCH)
+						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_switch_case_with_arrow, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SWITCH_CASE_WITH_ARROW)
+						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_expressions_in_switch_case_with_arrow, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_SWITCH_CASE_WITH_ARROW)
+						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_expressions_in_switch_case_with_colon, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_EXPRESSIONS_IN_SWITCH_CASE_WITH_COLON)
 						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_assertion_message, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ASSERTION_MESSAGE))
 				.node(fTree.builder(FormatterMessages.FormatterModifyDialog_lineWrap_tree_parameterized_types, null, modAll)
 						.pref(FormatterMessages.FormatterModifyDialog_lineWrap_pref_param_type_ref, DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_PARAMETERIZED_TYPE_REFERENCES)
@@ -1538,6 +1550,9 @@
 						case DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ASSIGNMENT:
 							wrapBeforeKey= DefaultCodeFormatterConstants.FORMATTER_WRAP_BEFORE_ASSIGNMENT_OPERATOR;
 							break;
+						case DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_SWITCH_CASE_WITH_ARROW:
+							wrapBeforeKey= DefaultCodeFormatterConstants.FORMATTER_WRAP_BEFORE_SWITCH_CASE_ARROW_OPERATOR;
+							break;
 						case DefaultCodeFormatterConstants.FORMATTER_ALIGNMENT_FOR_ASSERTION_MESSAGE:
 							wrapBeforeKey= DefaultCodeFormatterConstants.FORMATTER_WRAP_BEFORE_ASSERTION_MESSAGE_OPERATOR;
 							break;
@@ -1670,7 +1685,7 @@
 			}
 		}
 
-		return fTree.new SimpleTreeBuilder<PreferenceTreeNode<?>>(null, null, null) {
+		return fTree.new SimpleTreeBuilder<>(null, null, null) {
 
 			@Override
 			protected PreferenceTreeNode<?> build(Section parent, PreferenceBuilder prefBuilder) {
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/OccurrencesSearchResultPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/OccurrencesSearchResultPage.java
index 96d6c88..84bca35 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/OccurrencesSearchResultPage.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/OccurrencesSearchResultPage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 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
@@ -52,7 +52,9 @@
 import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
 
+import org.eclipse.jdt.internal.core.manipulation.search.ExceptionOccurrencesFinder;
 import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder;
+import org.eclipse.jdt.internal.core.manipulation.search.ImplementOccurrencesFinder;
 import org.eclipse.jdt.internal.core.manipulation.search.OccurrencesFinder;
 
 import org.eclipse.jdt.ui.JavaUI;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/SearchMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/SearchMessages.java
index f8e6ab2..ae8e048 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/SearchMessages.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/SearchMessages.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
@@ -139,17 +139,6 @@
 	public static String Search_FindOccurrencesInFile_tooltip;
 	public static String FindOccurrencesEngine_noSource_text;
 	public static String FindOccurrencesEngine_cannotParse_text;
-	public static String ExceptionOccurrencesFinder_no_exception;
-	public static String ExceptionOccurrencesFinder_searchfor;
-	public static String ExceptionOccurrencesFinder_label_singular;
-	public static String ExceptionOccurrencesFinder_label_plural;
-	public static String ExceptionOccurrencesFinder_occurrence_description;
-	public static String ExceptionOccurrencesFinder_occurrence_implicit_close_description;
-	public static String ImplementOccurrencesFinder_invalidTarget;
-	public static String ImplementOccurrencesFinder_searchfor;
-	public static String ImplementOccurrencesFinder_label_singular;
-	public static String ImplementOccurrencesFinder_label_plural;
-	public static String ImplementOccurrencesFinder_occurrence_description;
 	public static String JavaSearchOperation_singularDeclarationsPostfix;
 	public static String JavaSearchOperation_singularReferencesPostfix;
 	public static String JavaSearchOperation_singularReadReferencesPostfix;
@@ -249,21 +238,6 @@
 	public static String MatchFilter_InexactFilter_name;
 	public static String MatchFilter_InexactFilter_actionLabel;
 	public static String MatchFilter_InexactFilter_description;
-	public static String MethodExitsFinder_job_label;
-	public static String MethodExitsFinder_label_plural;
-	public static String MethodExitsFinder_label_singular;
-	public static String MethodExitsFinder_no_return_type_selected;
-	public static String MethodExitsFinder_occurrence_exit_description;
-	public static String MethodExitsFinder_occurrence_exit_impclict_close_description;
-	public static String MethodExitsFinder_occurrence_return_description;
-	public static String BreakContinueTargetFinder_break_label_plural;
-	public static String BreakContinueTargetFinder_break_label_singular;
-	public static String BreakContinueTargetFinder_cannot_highlight;
-	public static String BreakContinueTargetFinder_continue_label_plural;
-	public static String BreakContinueTargetFinder_continue_label_singular;
-	public static String BreakContinueTargetFinder_job_label;
-	public static String BreakContinueTargetFinder_no_break_or_continue_selected;
-	public static String BreakContinueTargetFinder_occurrence_description;
 	public static String EnumConstructorTargetFinder_description;
 	public static String TextSearchLabelProvider_matchCountFormat;
 	static {
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/SearchMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/SearchMessages.properties
index f826d40..23b9dba 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/SearchMessages.properties
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/search/SearchMessages.properties
@@ -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
@@ -139,25 +139,6 @@
 FindOccurrencesEngine_noSource_text= No source available. To perform this operation you need to attach source.
 FindOccurrencesEngine_cannotParse_text= Cannot analyze the compilation unit or class file.
 
-ExceptionOccurrencesFinder_no_exception= Cannot search for current selection. Please select an exception.
-ExceptionOccurrencesFinder_searchfor= Search for Exception Occurrences
-
-# The first argument will be replaced by the element name and the second one by the file name
-ExceptionOccurrencesFinder_label_singular=''{0}'' - 1 exception occurrence in ''{1}''
-# The first argument will be replaced by the element name, the second by the count and the last by the file name
-ExceptionOccurrencesFinder_label_plural=''{0}'' - {1} exception occurrences in ''{2}''
-ExceptionOccurrencesFinder_occurrence_description=Occurrences throwing ''{0}''
-ExceptionOccurrencesFinder_occurrence_implicit_close_description=''{0}'' is thrown from implicit close() methods of highlighted resources.
-
-ImplementOccurrencesFinder_invalidTarget= Cannot search for current selection. Please select a type behind 'implements' or 'extends'.
-ImplementOccurrencesFinder_searchfor= Search for Implement Occurrences
-
-# The first argument will be replaced by the element name and the second one by the file name
-ImplementOccurrencesFinder_label_singular=''{0}'' - 1 implement occurrence in ''{1}''
-# The first argument will be replaced by the element name, the second by the count and the last by the file name
-ImplementOccurrencesFinder_label_plural=''{0}'' - {1} implement occurrences in ''{2}''
-ImplementOccurrencesFinder_occurrence_description=Implementors of methods in ''{0}''
-
 
 # The first argument will be replaced by the pattern and the second by the scope
 JavaSearchOperation_singularDeclarationsPostfix=''{0}'' - 1 declaration in {1}
@@ -375,23 +356,6 @@
 MatchLocations_instanceof_description=instanceof
 MatchLocations_instanceof_label='instance&of' checks
 
-MethodExitsFinder_job_label=Search for Method Exit Occurrences
-MethodExitsFinder_label_plural=''{0}(...)'' - {1} method exit occurrence in ''{2}''
-MethodExitsFinder_label_singular=''{0}(...)'' - 1 method exit occurrence in ''{1}''
-MethodExitsFinder_no_return_type_selected=No return type selected
-MethodExitsFinder_occurrence_exit_description=Exit point of ''{0}()''
-MethodExitsFinder_occurrence_exit_impclict_close_description=Exit point of ''{0}()'': Exception is thrown from implicit close() methods of highlighted resources.
-MethodExitsFinder_occurrence_return_description=Return type of ''{0}()''
-
-BreakContinueTargetFinder_break_label_plural=''{0}'' - {1} break target occurrences in ''{2}''
-BreakContinueTargetFinder_break_label_singular=''{0}'' - 1 break target occurrence in ''{1}''
-BreakContinueTargetFinder_cannot_highlight=Occurrences in this element cannot be highlighted
-BreakContinueTargetFinder_continue_label_plural=''{0}'' - {1} continue target occurrences in ''{2}''
-BreakContinueTargetFinder_continue_label_singular=''{0}'' - 1 continue target occurrence in ''{1}''
-BreakContinueTargetFinder_job_label=Search for Break/Continue Target Occurrences
-BreakContinueTargetFinder_no_break_or_continue_selected=No break or continue selected
-BreakContinueTargetFinder_occurrence_description=Target of ''{0}''
-
 EnumConstructorTargetFinder_description=Find Enum constructor of ''{0}''
 
 TextSearchLabelProvider_matchCountFormat={0} ({1} matches)
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaCompositeReconcilingStrategy.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaCompositeReconcilingStrategy.java
index 29205f7..ee21a30 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaCompositeReconcilingStrategy.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaCompositeReconcilingStrategy.java
@@ -158,6 +158,10 @@
 
 	}
 
+	public void aboutToWork(JavaReconciler javaReconciler) {
+		fJavaStrategy.aboutToWork(javaReconciler);
+	}
+
 	/**
 	 * Called when reconcile has finished.
 	 *
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaReconciler.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaReconciler.java
index da0dc0a..fc30d83 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaReconciler.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/JavaReconciler.java
@@ -390,16 +390,18 @@
 		strategy.notifyListeners(false);
 	}
 
-	/*
-	 * @see org.eclipse.jface.text.reconciler.AbstractReconciler#aboutToReconcile()
-	 * @since 3.0
-	 */
 	@Override
 	protected void aboutToBeReconciled() {
 		JavaCompositeReconcilingStrategy strategy= (JavaCompositeReconcilingStrategy) getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE);
 		strategy.aboutToBeReconciled();
 	}
 
+	@Override
+	protected void aboutToWork() {
+		JavaCompositeReconcilingStrategy strategy= (JavaCompositeReconcilingStrategy) getReconcilingStrategy(IDocument.DEFAULT_CONTENT_TYPE);
+		strategy.aboutToWork(this);
+	}
+
 	/*
 	 * @see org.eclipse.jface.text.reconciler.AbstractReconciler#reconcilerReset()
 	 */
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/IProposalRelevance.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/IProposalRelevance.java
index 7674090..21438b6 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/IProposalRelevance.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/IProposalRelevance.java
@@ -227,6 +227,7 @@
 	int CHANGE_LAMBDA_BODY_TO_BLOCK= 3;
 	int CHANGE_LAMBDA_BODY_TO_EXPRESSION= 3;
 	int ADD_INFERRED_LAMBDA_PARAMETER_TYPES= 3;
+	int EXTRACT_LAMBDA_BODY_TO_METHOD= 3;
 
 	int ASSIGN_ALL_PARAMS_TO_NEW_FIELDS= 2;
 	int CONVERT_TO_INDEXED_FOR_LOOP= 2;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java
index ca214f2..5278602 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessor.java
@@ -306,6 +306,7 @@
 					|| getUnnecessaryArrayCreationProposal(context, coveringNode, null)
 					|| getExtractVariableProposal(context, false, null)
 					|| getExtractMethodProposal(context, coveringNode, false, null)
+					|| getExtractMethodFromLambdaProposal(context, coveringNode, false, null)
 					|| getInlineLocalProposal(context, coveringNode, null)
 					|| getConvertLocalToFieldProposal(context, coveringNode, null)
 					|| getConvertAnonymousToNestedProposal(context, coveringNode, null)
@@ -376,6 +377,7 @@
 				getCreateInSuperClassProposals(context, coveringNode, resultingCollections);
 				getExtractVariableProposal(context, problemsAtLocation, resultingCollections);
 				getExtractMethodProposal(context, coveringNode, problemsAtLocation, resultingCollections);
+				getExtractMethodFromLambdaProposal(context, coveringNode, problemsAtLocation, resultingCollections);
 				getInlineLocalProposal(context, coveringNode, resultingCollections);
 				getConvertLocalToFieldProposal(context, coveringNode, resultingCollections);
 				getConvertAnonymousToNestedProposal(context, coveringNode, resultingCollections);
@@ -462,7 +464,35 @@
 		return false;
 	}
 
+	private static boolean getExtractMethodFromLambdaProposal(IInvocationContext context, ASTNode coveringNode, boolean problemsAtLocation, Collection<ICommandAccess> proposals) throws CoreException {
+		if (coveringNode instanceof Block && coveringNode.getLocationInParent() == LambdaExpression.BODY_PROPERTY) {
+			return false;
+		}
+		ASTNode node= ASTNodes.getFirstAncestorOrNull(coveringNode, LambdaExpression.class, BodyDeclaration.class);
+		if (!(node instanceof LambdaExpression)) {
+			return false;
+		}
+		ASTNode body= ((LambdaExpression)node).getBody();
+		final ICompilationUnit cu= context.getCompilationUnit();
+		final ExtractMethodRefactoring extractMethodRefactoring= new ExtractMethodRefactoring(context.getASTRoot(), body.getStartPosition(), body.getLength());
+		extractMethodRefactoring.setMethodName("extracted"); //$NON-NLS-1$
+		if (extractMethodRefactoring.checkInitialConditions(new NullProgressMonitor()).isOK()) {
+			if (proposals == null) {
+				return true;
+			}
+			String label= CorrectionMessages.QuickAssistProcessor_extractmethod_from_lambda_description;
+			LinkedProposalModel linkedProposalModel= new LinkedProposalModel();
+			extractMethodRefactoring.setLinkedProposalModel(linkedProposalModel);
 
+			Image image= JavaPluginImages.get(JavaPluginImages.IMG_MISC_PUBLIC);
+			int relevance= problemsAtLocation ? IProposalRelevance.EXTRACT_METHOD_ERROR : IProposalRelevance.EXTRACT_LAMBDA_BODY_TO_METHOD;
+			RefactoringCorrectionProposal proposal= new RefactoringCorrectionProposal(label, cu, extractMethodRefactoring, relevance, image);
+			proposal.setLinkedProposalModel(linkedProposalModel);
+			proposals.add(proposal);
+			return true;
+		}
+		return false;
+	}
 
 	private static boolean getExtractVariableProposal(IInvocationContext context, boolean problemsAtLocation, Collection<ICommandAccess> proposals) throws CoreException {
 
@@ -4536,25 +4566,31 @@
 
 		try {
 			ImportRewrite importRewrite= StubUtility.createImportRewrite(context.getCompilationUnit(), true);
-			ImportRewrite importRewriteReplaceAllOccurences= StubUtility.createImportRewrite(context.getCompilationUnit(), true);
 			ASTRewrite astRewrite= ASTRewrite.create(node.getAST());
 			ASTRewrite astRewriteReplaceAllOccurrences= ASTRewrite.create(node.getAST());
 
-			int[] allReferencesToDeclaringClass= new int[1];
-			allReferencesToDeclaringClass[0]= 0;
-			int[] referencesFromOtherOccurences= new int[1];
-			referencesFromOtherOccurences[0]= 0;
+			ImportRemover remover= new ImportRemover(context.getCompilationUnit().getJavaProject(), context.getASTRoot());
+			ImportRemover removerAllOccurences= new ImportRemover(context.getCompilationUnit().getJavaProject(), context.getASTRoot());
 			MethodInvocation mi= null;
 			QualifiedName qn= null;
 			if (name.getParent() instanceof MethodInvocation) {
 				mi= (MethodInvocation) name.getParent();
 				// convert the method invocation
 				astRewrite.remove(mi.getExpression(), null);
-				mi.typeArguments().forEach(type -> astRewrite.remove((Type) type, null));
+				remover.registerRemovedNode(mi.getExpression());
+				removerAllOccurences.registerRemovedNode(mi.getExpression());
+				mi.typeArguments().forEach(typeObject -> {
+					Type type= (Type) typeObject;
+					astRewrite.remove(type, null);
+					remover.registerRemovedNode(type);
+					removerAllOccurences.registerRemovedNode(type);
+				});
 			} else if (name.getParent() instanceof QualifiedName) {
 				qn= (QualifiedName) name.getParent();
 				// convert the field access
 				astRewrite.replace(qn, ASTNodeFactory.newName(node.getAST(), name.getFullyQualifiedName()), null);
+				remover.registerRemovedNode(qn);
+				removerAllOccurences.registerRemovedNode(qn);
 			} else {
 				return false;
 			}
@@ -4573,21 +4609,12 @@
 						if (miFinal != null &&
 								miFinal.getExpression() instanceof Name && ((Name) miFinal.getExpression()).getFullyQualifiedName().equals(fullyQualifiedName)
 								&& miFinal.getName().getIdentifier().equals(methodInvocation.getName().getIdentifier())) {
-							methodInvocation.typeArguments().forEach(type -> astRewriteReplaceAllOccurrences.remove((Type) type, null));
+							methodInvocation.typeArguments().forEach(type -> {
+								astRewriteReplaceAllOccurrences.remove((Type) type, null);
+								removerAllOccurences.registerRemovedNode((Type) type);
+							});
 							astRewriteReplaceAllOccurrences.remove(methodInvocationExpression, null);
-							allReferencesToDeclaringClass[0]++;
-						} else if (declaringClass.getName().equals(fullyQualifiedName)) {
-							allReferencesToDeclaringClass[0]++;
-							referencesFromOtherOccurences[0]++;
-						}
-					} else if (methodInvocationExpression instanceof ClassInstanceCreation) {
-						ClassInstanceCreation classInstanceCreation= (ClassInstanceCreation) methodInvocationExpression;
-						if (classInstanceCreation.getType() instanceof SimpleType) {
-							String typeName= ((SimpleType) classInstanceCreation.getType()).getName().getFullyQualifiedName();
-							if (typeName.equals(declaringClass.getName())) {
-								allReferencesToDeclaringClass[0]++;
-								referencesFromOtherOccurences[0]++;
-							}
+							removerAllOccurences.registerRemovedNode(methodInvocationExpression);
 						}
 					}
 
@@ -4601,35 +4628,24 @@
 					if (qnFinal != null &&
 							qualifiedName.getFullyQualifiedName().equals(qnFinal.getFullyQualifiedName())) {
 						astRewriteReplaceAllOccurrences.replace(qualifiedName, ASTNodeFactory.newName(node.getAST(), name.getFullyQualifiedName()), null);
-						allReferencesToDeclaringClass[0]++;
-					} else if (declaringClass.getName().equals(qualifiedName.getQualifier().getFullyQualifiedName())) {
-						allReferencesToDeclaringClass[0]++;
-						referencesFromOtherOccurences[0]++;
+						removerAllOccurences.registerRemovedNode(qualifiedName);
 					}
 					return super.visit(qualifiedName);
 				}
 			});
 
-			// add the static import
 			if (needImport) {
 				importRewrite.addStaticImport(binding);
-				if (allReferencesToDeclaringClass[0] == 1) { // If there are exactly 1 visits, the import can be removed
-					importRewrite.removeImport(declaringClass.getQualifiedName());
-				}
-				importRewriteReplaceAllOccurences.addStaticImport(binding);
-				if (referencesFromOtherOccurences[0] == 0) {
-					importRewriteReplaceAllOccurences.removeImport(declaringClass.getQualifiedName());
-				}
 			}
-
-			ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(CorrectionMessages.QuickAssistProcessor_convert_to_static_import, context.getCompilationUnit(), astRewrite,
+			ASTRewriteRemoveImportsCorrectionProposal proposal= new ASTRewriteRemoveImportsCorrectionProposal(CorrectionMessages.QuickAssistProcessor_convert_to_static_import, context.getCompilationUnit(), astRewrite,
 					IProposalRelevance.ADD_STATIC_IMPORT, image);
 			proposal.setImportRewrite(importRewrite);
+			proposal.setImportRemover(remover);
 			proposals.add(proposal);
-			ASTRewriteCorrectionProposal proposalReplaceAllOccurrences= new ASTRewriteCorrectionProposal(CorrectionMessages.QuickAssistProcessor_convert_to_static_import_replace_all,
-					context.getCompilationUnit(), astRewriteReplaceAllOccurrences,
+			ASTRewriteRemoveImportsCorrectionProposal proposalReplaceAllOccurrences= new ASTRewriteRemoveImportsCorrectionProposal(CorrectionMessages.QuickAssistProcessor_convert_to_static_import_replace_all, context.getCompilationUnit(), astRewriteReplaceAllOccurrences,
 					IProposalRelevance.ADD_STATIC_IMPORT, image);
-			proposalReplaceAllOccurrences.setImportRewrite(importRewriteReplaceAllOccurences);
+			proposalReplaceAllOccurrences.setImportRewrite(importRewrite);
+			proposalReplaceAllOccurrences.setImportRemover(removerAllOccurences);
 			proposals.add(proposalReplaceAllOccurrences);
 		} catch (IllegalArgumentException e) {
 			// Wrong use of ASTRewrite or ImportRewrite API, see bug 541586
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/NewDefiningMethodProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/NewDefiningMethodProposal.java
index 38df0d9..d41c5d8 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/NewDefiningMethodProposal.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/NewDefiningMethodProposal.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
@@ -35,7 +35,9 @@
 import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.Annotation;
+import org.eclipse.jdt.core.dom.ArrayType;
 import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.Dimension;
 import org.eclipse.jdt.core.dom.IExtendedModifier;
 import org.eclipse.jdt.core.dom.IMethodBinding;
 import org.eclipse.jdt.core.dom.ITypeBinding;
@@ -150,6 +152,23 @@
 				addLinkedPositionProposal(groupId, proposedName, null);
 			}
 		}
+		if (params.isEmpty() || bindings.length == 0) {
+			return;
+		}
+		if (fMethod.isVarargs()) {
+			// only last parameter can be vararg
+			SingleVariableDeclaration singleVariableDeclaration= params.get(bindings.length - 1);
+			singleVariableDeclaration.setVarargs(true);
+			Type type= singleVariableDeclaration.getType();
+			if (type != null && type.isArrayType()) {
+				List<Dimension> dimensions= ((ArrayType) type).dimensions();
+				if (dimensions.isEmpty()) {
+					return;
+				}
+				// remove last dimension added by vararg conversion
+				dimensions.remove(dimensions.size() - 1);
+			}
+		}
 	}
 
 	@Override
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/IJavaReconcilingListener.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/IJavaReconcilingListener.java
index 70b021d..fd40830 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/IJavaReconcilingListener.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/IJavaReconcilingListener.java
@@ -17,6 +17,8 @@
 
 import org.eclipse.jdt.core.dom.CompilationUnit;
 
+import org.eclipse.jdt.internal.ui.text.JavaReconciler;
+
 
 /**
  * Interface of an object listening to Java reconciling.
@@ -31,6 +33,16 @@
 	void aboutToBeReconciled();
 
 	/**
+	 * Called before reconciling is working.
+	 *
+	 * @param javaReconciler The JavaReconciler that starts reconciling
+	 */
+	default void aboutToWork(JavaReconciler javaReconciler) {
+		// do nothing by default.
+	}
+
+
+	/**
 	 * Called after reconciling has been finished.
 	 * @param ast				the compilation unit AST or <code>null</code> if
  * 								the working copy was consistent or reconciliation has been cancelled
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaReconcilingStrategy.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaReconcilingStrategy.java
index 8d80781..59de5dd 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaReconcilingStrategy.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaReconcilingStrategy.java
@@ -38,12 +38,13 @@
 import org.eclipse.jdt.core.dom.CompilationUnit;
 
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
 
 import org.eclipse.jdt.ui.JavaUI;
 
 import org.eclipse.jdt.internal.ui.JavaPlugin;
-import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
 import org.eclipse.jdt.internal.ui.javaeditor.WorkingCopyManager;
+import org.eclipse.jdt.internal.ui.text.JavaReconciler;
 
 public class JavaReconcilingStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension {
 
@@ -207,6 +208,11 @@
 			fJavaReconcilingListener.aboutToBeReconciled();
 	}
 
+	public void aboutToWork(JavaReconciler javaReconciler) {
+		if (fIsJavaReconcilingListener)
+			fJavaReconcilingListener.aboutToWork(javaReconciler);
+	}
+
 	/**
 	 * Called when reconcile has finished.
 	 *
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/ProblemMarkerManager.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/ProblemMarkerManager.java
index 3c43b6b..2b9a5ac 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/ProblemMarkerManager.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/viewsupport/ProblemMarkerManager.java
@@ -14,16 +14,14 @@
 package org.eclipse.jdt.internal.ui.viewsupport;
 
 
+import java.time.Duration;
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
-
-import org.eclipse.swt.widgets.Display;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.ListenerList;
-import org.eclipse.core.runtime.Status;
 
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IMarkerDelta;
@@ -34,16 +32,16 @@
 import org.eclipse.core.resources.IResourceDelta;
 import org.eclipse.core.resources.IResourceDeltaVisitor;
 
+import org.eclipse.jface.util.Throttler;
+
 import org.eclipse.jface.text.source.AnnotationModelEvent;
 import org.eclipse.jface.text.source.IAnnotationModel;
 import org.eclipse.jface.text.source.IAnnotationModelListener;
 import org.eclipse.jface.text.source.IAnnotationModelListenerExtension;
 
 import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.progress.UIJob;
 
 import org.eclipse.jdt.internal.ui.JavaPlugin;
-import org.eclipse.jdt.internal.ui.JavaUIMessages;
 import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitAnnotationModelEvent;
 
 /**
@@ -106,17 +104,14 @@
 		}
 	}
 
-	private ListenerList<IProblemChangedListener> fListeners;
+	private final ListenerList<IProblemChangedListener> fListeners= new ListenerList<>();
 
-	private Set<IResource> fResourcesWithMarkerChanges;
-	private Set<IResource> fResourcesWithAnnotationChanges;
+	private final Set<IResource> fResourcesWithMarkerChanges= ConcurrentHashMap.newKeySet();
+	private final Set<IResource> fResourcesWithAnnotationChanges= ConcurrentHashMap.newKeySet();
 
-	private UIJob fNotifierJob;
+	private final Throttler throttledUpdates= new Throttler(PlatformUI.getWorkbench().getDisplay(), Duration.ofMillis(250), this::runPendingUpdates);
 
 	public ProblemMarkerManager() {
-		fListeners= new ListenerList<>();
-		fResourcesWithMarkerChanges= new HashSet<>();
-		fResourcesWithAnnotationChanges= new HashSet<>();
 	}
 
 	/*
@@ -134,19 +129,8 @@
 			JavaPlugin.log(e.getStatus());
 		}
 
-		if (!changedElements.isEmpty()) {
-			boolean hasChanges= false;
-			synchronized (this) {
-				if (fResourcesWithMarkerChanges.isEmpty()) {
-					fResourcesWithMarkerChanges= changedElements;
-					hasChanges= true;
-				} else {
-					hasChanges= fResourcesWithMarkerChanges.addAll(changedElements);
-				}
-			}
-			if (hasChanges) {
-				fireChanges();
-			}
+		if (fResourcesWithMarkerChanges.addAll(changedElements)) {
+			fireChanges();
 		}
 	}
 
@@ -160,12 +144,8 @@
 		if (event instanceof CompilationUnitAnnotationModelEvent) {
 			CompilationUnitAnnotationModelEvent cuEvent= (CompilationUnitAnnotationModelEvent) event;
 			if (cuEvent.includesProblemMarkerAnnotationChanges()) {
-				boolean hasChanges= false;
-				synchronized (this) {
-					IResource changedResource= cuEvent.getUnderlyingResource();
-					hasChanges= fResourcesWithAnnotationChanges.add(changedResource);
-				}
-				if (hasChanges) {
+				IResource changedResource= cuEvent.getUnderlyingResource();
+				if (fResourcesWithAnnotationChanges.add(changedResource)) {
 					fireChanges();
 				}
 			}
@@ -198,47 +178,24 @@
 	}
 
 	private void fireChanges() {
-		Display display= PlatformUI.getWorkbench().getDisplay();
-		if (display != null && !display.isDisposed()) {
-			postAsyncUpdate(display);
-		}
-	}
-
-	private void postAsyncUpdate(final Display display) {
-		if (fNotifierJob == null) {
-			fNotifierJob= new UIJob(display, JavaUIMessages.ProblemMarkerManager_problem_marker_update_job_description) {
-				@Override
-				public IStatus runInUIThread(IProgressMonitor monitor) {
-					runPendingUpdates();
-					return Status.OK_STATUS;
-				}
-			};
-			fNotifierJob.setSystem(true);
-		}
-		fNotifierJob.schedule();
+		throttledUpdates.throttledExec();
 	}
 
 	/**
 	 * Notify all IProblemChangedListener. Must be called in the display thread.
 	 */
 	private void runPendingUpdates() {
-		IResource[] markerResources= null;
-		IResource[] annotationResources= null;
-		synchronized (this) {
-			if (!fResourcesWithMarkerChanges.isEmpty()) {
-				markerResources= fResourcesWithMarkerChanges.toArray(new IResource[fResourcesWithMarkerChanges.size()]);
-				fResourcesWithMarkerChanges.clear();
-			}
-			if (!fResourcesWithAnnotationChanges.isEmpty()) {
-				annotationResources= fResourcesWithAnnotationChanges.toArray(new IResource[fResourcesWithAnnotationChanges.size()]);
-				fResourcesWithAnnotationChanges.clear();
-			}
-		}
+		ArrayList<IResource> resourcesWithMarkerChanges= new ArrayList<>();
+		ArrayList<IResource> resourcesWithAnnotationChanges= new ArrayList<>();
+		fResourcesWithMarkerChanges.removeIf(e -> resourcesWithMarkerChanges.add(e));
+		fResourcesWithAnnotationChanges.removeIf(e -> resourcesWithAnnotationChanges.add(e));
+		IResource[] markerResources= resourcesWithMarkerChanges.toArray(IResource[]::new);
+		IResource[] annotationResources= resourcesWithAnnotationChanges.toArray(IResource[]::new);
 		for (IProblemChangedListener curr : fListeners) {
-			if (markerResources != null) {
+			if (markerResources.length != 0) {
 				curr.problemsChanged(markerResources, true);
 			}
-			if (annotationResources != null) {
+			if (annotationResources.length != 0) {
 				curr.problemsChanged(annotationResources, false);
 			}
 		}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/BuildPathBasePage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/BuildPathBasePage.java
index 8cb4a06..a847196 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/BuildPathBasePage.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/BuildPathBasePage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 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
@@ -309,15 +309,19 @@
 	 * @param changeNodeDirection indicate in which direction the element should be moved
 	 */
 	protected void moveCPElementAcrossNode(TreeListDialogField<CPListElement> listField, CPListElement selElement, RootNodeChange changeNodeDirection) {
+		boolean firedDialogFieldChanged= false;
 		List<CPListElement> elements= listField.getElements();
 		//remove from module node or classnode
+		int indexOfSelElement = -1;
 		for (CPListElement cpListElement : elements) {
 			if (cpListElement.isRootNodeForPath()) {
 				RootCPListElement rootElement= (RootCPListElement) cpListElement;
 				if (rootElement.isSourceRootNode(changeNodeDirection) && rootElement.getChildren().contains(selElement)) {
+					List<?> children = rootElement.getChildren();
+					indexOfSelElement = children.indexOf(selElement);
 					rootElement.removeCPListElement(selElement);
 					listField.getTreeViewer().remove(selElement);
-					listField.dialogFieldChanged();
+					break;
 				}
 			}
 		}
@@ -328,17 +332,26 @@
 				if (rootCPListElement.isTargetRootNode(changeNodeDirection)) {
 					if (rootCPListElement.getChildren().contains(selElement))
 						break;
-					rootCPListElement.addCPListElement(selElement);
+					if (indexOfSelElement != -1) {
+						rootCPListElement.getChildren().add(indexOfSelElement, selElement);
+					} else {
+						rootCPListElement.addCPListElement(selElement);
+					}
 					List<CPListElement> all= listField.getElements();
-					listField.removeAllElements();
 					listField.setElements(all);
 					listField.refresh();
+					listField.dialogFieldChanged();
+					firedDialogFieldChanged = true;
 					listField.getTreeViewer().expandToLevel(2);
 					listField.postSetSelection(new StructuredSelection(selElement));
 					break;
 				}
 			}
 		}
+		// we found no other root container to move to, fire a change event
+		if (!firedDialogFieldChanged) {
+			listField.dialogFieldChanged();
+		}
 	}
 
 	protected void selectRootNode(TreeListDialogField<CPListElement> list, boolean modulePath) {
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListElement.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListElement.java
index 263a966..e539ffa 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListElement.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/wizards/buildpaths/CPListElement.java
@@ -632,7 +632,11 @@
 
 	@Override
 	public String toString() {
-		return getClasspathEntry().toString();
+		IClasspathEntry classpathEntry= getClasspathEntry();
+		if (classpathEntry != null) {
+			return classpathEntry.toString();
+		}
+		return "null"; //$NON-NLS-1$
 	}
 
 	/**
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/JavaUI.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/JavaUI.java
index f5b7833..fc00098 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/JavaUI.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/JavaUI.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 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
@@ -31,6 +31,7 @@
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.dialogs.SelectionDialog;
 
 import org.eclipse.ui.texteditor.IDocumentProvider;
@@ -412,7 +413,31 @@
 			boolean multipleSelection, boolean removeDuplicates, String filter) {
 
 		int flag= removeDuplicates ? PackageSelectionDialog.F_REMOVE_DUPLICATES : 0;
-		PackageSelectionDialog dialog= new PackageSelectionDialog(parent, context, flag, scope);
+		return createPackageDialog(parent, context, scope, multipleSelection, flag, filter);
+	}
+
+	/**
+	 * Creates a selection dialog that lists all packages of the given Java search scope.
+	 * The caller is responsible for opening the dialog with <code>Window.open</code>,
+	 * and subsequently extracting the selected package (of type
+	 * <code>IPackageFragment</code>) via <code>SelectionDialog.getResult</code>.
+	 *
+	 * @param parent the parent shell of the dialog to be created
+	 * @param context the runnable context to run the search in
+	 * @param scope the scope defining the available packages.
+	 * @param multipleSelection true if multiple selection is allowed
+	 * @param flags a combination of <code>PackageSelectionDialog.F_REMOVE_DUPLICATES</code>, <code>PackageSelectionDialog.F_SHOW_PARENTS</code>,
+	 *  <code>PackageSelectionDialog.F_HIDE_DEFAULT_PACKAGE</code> and  <code>PackageSelectionDialog.F_HIDE_EMPTY_INNER</code>
+	 * @param filter the initial pattern to filter the set of packages. For example "com" shows
+	 * all packages starting with "com". The meta character '?' representing any character and
+	 * '*' representing any string are supported. Clients can pass an empty string if no filtering
+	 * is required.
+	 * @return a new selection dialog
+	 *
+	 * @since 3.26
+	 */
+	public static SelectionDialog createPackageDialog(Shell parent, IRunnableContext context, IJavaSearchScope scope, boolean multipleSelection, int flags, String filter) {
+		PackageSelectionDialog dialog= new PackageSelectionDialog(parent, context, flags, scope);
 		dialog.setFilter(filter);
 		dialog.setIgnoreCase(false);
 		dialog.setMultipleSelection(multipleSelection);
@@ -420,6 +445,24 @@
 	}
 
 	/**
+	 * Creates a selection dialog that lists all packages of all the Java projects.
+	 *
+	 * @since 3.26
+	 * @param shell the parent shell of the dialog to be created
+	 * @param multipleSelection true if multiple selection is allowed
+	 * @param flags a combination of <code>PackageSelectionDialog.F_REMOVE_DUPLICATES</code>, <code>PackageSelectionDialog.F_SHOW_PARENTS</code>,
+	 *  <code>PackageSelectionDialog.F_HIDE_DEFAULT_PACKAGE</code> and  <code>PackageSelectionDialog.F_HIDE_EMPTY_INNER</code>
+	 * @param filter the initial pattern to filter the set of packages. For example "com" shows
+	 * all packages starting with "com". The meta character '?' representing any character and
+	 * '*' representing any string are supported. Clients can pass an empty string if no filtering
+	 * is required.
+	 * @return a new selection dialog
+	 */
+	public static SelectionDialog createPackageDialog(Shell shell, boolean multipleSelection, int flags, String filter) {
+		return createPackageDialog(shell, PlatformUI.getWorkbench().getProgressService(), SearchEngine.createWorkspaceScope(), multipleSelection, flags, filter);
+	}
+
+	/**
 	 * Creates a selection dialog that lists all packages of the given Java project.
 	 * The caller is responsible for opening the dialog with <code>Window.open</code>,
 	 * and subsequently extracting the selected package (of type
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/ProblemsLabelDecorator.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/ProblemsLabelDecorator.java
index ba3c7c1..fc2bee0 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/ProblemsLabelDecorator.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/ProblemsLabelDecorator.java
@@ -13,7 +13,17 @@
  *******************************************************************************/
 package org.eclipse.jdt.ui;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
@@ -21,13 +31,19 @@
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
 
 import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IMarker;
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IResourceStatus;
+import org.eclipse.core.resources.IWorkspaceRoot;
 
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.viewers.IBaseLabelProvider;
@@ -42,6 +58,7 @@
 import org.eclipse.jface.text.source.IAnnotationModel;
 
 import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.progress.WorkbenchJob;
 
 import org.eclipse.ui.texteditor.MarkerAnnotation;
 
@@ -122,6 +139,8 @@
 	private static final int ERRORTICK_IGNORE_OPTIONAL_PROBLEMS= JavaElementImageDescriptor.IGNORE_OPTIONAL_PROBLEMS;
 	private static final int ERRORTICK_INFO= JavaElementImageDescriptor.INFO;
 
+	static final boolean DEBUG = false;
+
 	private ImageDescriptorRegistry fRegistry;
 	private boolean fUseNewRegistry= false;
 	private IProblemChangedListener fProblemChangedListener;
@@ -129,6 +148,9 @@
 	private ListenerList<ILabelProviderListener> fListeners;
 	private ISourceRange fCachedRange;
 
+	/** job to update adornments for container resources in UI thread */
+	private final AdornmentUpdateJob adornmentUpdateJob;
+
 	/**
 	 * Creates a new <code>ProblemsLabelDecorator</code>.
 	 */
@@ -146,7 +168,8 @@
 	 */
 	public ProblemsLabelDecorator(ImageDescriptorRegistry registry) {
 		fRegistry= registry;
-		fProblemChangedListener= null;
+		adornmentUpdateJob = new AdornmentUpdateJob();
+		AdornmentCacheManager.register(this);
 	}
 
 	private ImageDescriptorRegistry getRegistry() {
@@ -192,7 +215,7 @@
 					case IJavaElement.JAVA_MODEL:
 					case IJavaElement.JAVA_PROJECT:
 					case IJavaElement.PACKAGE_FRAGMENT_ROOT:
-						int flags= getErrorTicksFromMarkers(element.getResource(), IResource.DEPTH_INFINITE, null);
+						int flags= computeContainerAdornmentFlags(element.getResource());
 						switch (type) {
 							case IJavaElement.PACKAGE_FRAGMENT_ROOT:
 								IPackageFragmentRoot root= (IPackageFragmentRoot) element;
@@ -212,7 +235,7 @@
 						return getPackageErrorTicksFromMarkers((IPackageFragment) element);
 					case IJavaElement.COMPILATION_UNIT:
 					case IJavaElement.CLASS_FILE:
-						return getErrorTicksFromMarkers(element.getResource(), IResource.DEPTH_ONE, null);
+						return getErrorTicksFromMarkers(element.getResource(), IResource.DEPTH_ONE);
 					case IJavaElement.PACKAGE_DECLARATION:
 					case IJavaElement.IMPORT_DECLARATION:
 					case IJavaElement.IMPORT_CONTAINER:
@@ -231,7 +254,11 @@
 								// open in Java editor: look at annotation model
 								result= getErrorTicksFromAnnotationModel(model, ref);
 							} else {
-								result= getErrorTicksFromMarkers(cu.getResource(), IResource.DEPTH_ONE, ref);
+								if (ref == null) {
+									result= getErrorTicksFromMarkers(cu.getResource(), IResource.DEPTH_ONE);
+								} else {
+									result= getErrorTicksFromMarkers(cu.getResource(), IResource.DEPTH_ONE, ref);
+								}
 							}
 							fCachedRange= null;
 							return result;
@@ -240,7 +267,17 @@
 					default:
 				}
 			} else if (obj instanceof IResource) {
-				return getErrorTicksFromMarkers((IResource) obj, IResource.DEPTH_INFINITE, null);
+				if (obj instanceof IProject || obj instanceof IWorkspaceRoot) {
+					return computeContainerAdornmentFlags((IResource) obj);
+				}
+				if (obj instanceof IFolder) {
+					IFolder folder = (IFolder) obj;
+					// Only cache top level directories to avoid caching everything
+					if (folder.getParent() instanceof IProject) {
+						return computeContainerAdornmentFlags((IResource) obj);
+					}
+				}
+				return getErrorTicksFromMarkers((IResource) obj, IResource.DEPTH_INFINITE);
 			}
 		} catch (CoreException e) {
 			if (e instanceof JavaModelException) {
@@ -258,6 +295,269 @@
 		return 0;
 	}
 
+	final class AdornmentUpdateJob extends WorkbenchJob {
+
+		private final Set<IResource> queue;
+
+		public AdornmentUpdateJob() {
+			super("Java problems decoration update..."); //$NON-NLS-1$
+			this.queue = ConcurrentHashMap.newKeySet();
+			setSystem(true);
+			setPriority(DECORATE);
+		}
+
+		@Override
+		public boolean belongsTo(Object family) {
+			return ProblemsLabelDecorator.class == family;
+		}
+
+		@Override
+		public IStatus runInUIThread(IProgressMonitor monitor) {
+			List<IResource> changed = new ArrayList<>(queue);
+			queue.removeAll(changed);
+			IResource[] changes = changed.toArray(IResource[]::new);
+			if (changes.length > 0 && !monitor.isCanceled()) {
+				if (DEBUG) {
+					String prefix = ProblemsLabelDecorator.this.toString();
+					prefix = prefix.substring(prefix.lastIndexOf('.') + 1);
+					System.err.println(prefix + " : " + " :show: " + Arrays.toString(changes)); //$NON-NLS-1$ //$NON-NLS-2$
+				}
+				fireProblemsChanged(changes, true);
+			}
+			if (monitor.isCanceled()) {
+				queue.clear();
+				return Status.CANCEL_STATUS;
+			} else if (!queue.isEmpty()) {
+				schedule(100);
+			}
+			return Status.OK_STATUS;
+		}
+
+		void schedule(Set<IResource> tasks) {
+			if (queue.addAll(tasks)) {
+				schedule(100);
+			}
+		}
+	}
+
+	static final class AdornmentCacheManager {
+
+		static final AdornmentCacheManager instance = new AdornmentCacheManager();
+
+		final Set<ProblemsLabelDecorator> listeners;
+
+		/**
+		 * Cache for projects and source folders status, key is resource, value is known adornment flags
+		 */
+		final Map<IResource, Integer> adornmentCache;
+
+		/** Job to compute adornments for container resources in background */
+		final AdornmentCalculationJob adornmentJob;
+
+		public AdornmentCacheManager() {
+			adornmentCache = new ConcurrentHashMap<>();
+			adornmentJob = new AdornmentCalculationJob();
+			listeners = Collections.synchronizedSet(new LinkedHashSet<>());
+		}
+
+		static void scheduleTask(IResource resource, AdornmentUpdateJob uiUpdate) {
+			instance.adornmentJob.schedule(new AdornmentTask(resource), uiUpdate);
+		}
+
+		static Integer getAdornment(IResource resource) {
+			return instance.adornmentCache.get(resource);
+		}
+
+		static Integer setAdornment(IResource resource, int adornment) {
+			return instance.adornmentCache.put(resource, Integer.valueOf(adornment));
+		}
+
+		static void register(ProblemsLabelDecorator decorator) {
+			instance.listeners.add(decorator);
+		}
+
+		static void deregister(ProblemsLabelDecorator decorator) {
+			instance.listeners.remove(decorator);
+			if(instance.listeners.isEmpty()) {
+				instance.adornmentJob.cancel();
+				instance.adornmentCache.clear();
+			}
+		}
+	}
+
+	static final class AdornmentCalculationJob extends Job {
+
+		private final LinkedHashMap<AdornmentTask, Set<AdornmentUpdateJob>> queue;
+
+		public AdornmentCalculationJob() {
+			super("Java problems decoration calculation..."); //$NON-NLS-1$
+			this.queue = new LinkedHashMap<>();
+			setSystem(true);
+			setPriority(DECORATE);
+		}
+
+		@Override
+		public boolean belongsTo(Object family) {
+			return ProblemsLabelDecorator.class == family;
+		}
+
+		@Override
+		protected IStatus run(IProgressMonitor monitor) {
+			Map<AdornmentUpdateJob, Set<IResource>> changed = new LinkedHashMap<>();
+			Entry<AdornmentTask, Set<AdornmentUpdateJob>> next;
+			while ((next = poll()) != null && !monitor.isCanceled()) {
+				AdornmentTask task = next.getKey();
+				task.run();
+				if (DEBUG) {
+					System.out.println("calc : " + AdornmentCacheManager.instance.adornmentCache.size() + " : " + task.resource); //$NON-NLS-1$ //$NON-NLS-2$
+				}
+
+				if (task.isAdornmentChanged()) {
+					final IResource resource = task.resource;
+					Set<AdornmentUpdateJob> jobs = next.getValue();
+					for (AdornmentUpdateJob job : jobs) {
+						changed.compute(job, (k, v) -> {
+							if(v == null) {
+								v = new LinkedHashSet<>();
+							}
+							v.add(resource);
+							return v;
+						});
+					}
+				}
+			}
+			if (!changed.isEmpty() && !monitor.isCanceled()) {
+				for (Entry<AdornmentUpdateJob, Set<IResource>> entry : changed.entrySet()) {
+					AdornmentUpdateJob job = entry.getKey();
+					Set<IResource> resources = entry.getValue();
+					job.schedule(resources);
+				}
+			}
+			synchronized (queue) {
+				if (monitor.isCanceled()) {
+					queue.clear();
+					return Status.CANCEL_STATUS;
+				} else if (!queue.isEmpty()) {
+					schedule(100);
+				}
+			}
+			return Status.OK_STATUS;
+		}
+
+		private Entry<AdornmentTask, Set<AdornmentUpdateJob>> poll() {
+			Entry<AdornmentTask, Set<AdornmentUpdateJob>> next = null;
+			synchronized (queue) {
+				if (!queue.isEmpty()) {
+					Iterator<Entry<AdornmentTask, Set<AdornmentUpdateJob>>> iterator = queue.entrySet().iterator();
+					next = iterator.next();
+					iterator.remove();
+				}
+			}
+			return next;
+		}
+
+		void schedule(AdornmentTask task, AdornmentUpdateJob job) {
+			synchronized (queue) {
+				queue.compute(task, (k,v) -> {
+					if (v == null) {
+						v = new LinkedHashSet<>();
+					}
+					if (v.add(job)) {
+						schedule(100);
+					}
+					return v;
+				});
+			}
+		}
+	}
+
+	static final class AdornmentTask {
+
+		final IResource resource;
+		volatile int oldAdornment;
+		volatile int newAdornment;
+
+		public AdornmentTask(IResource resource){
+			this.resource = resource;
+		}
+
+		@Override
+		public int hashCode() {
+			return resource.hashCode();
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj) {
+				return true;
+			}
+			if (!(obj instanceof AdornmentTask)) {
+				return false;
+			}
+			AdornmentTask other = (AdornmentTask) obj;
+			return resource.equals(other.resource);
+		}
+
+		void run() {
+			try {
+				newAdornment = getErrorTicksFromMarkers(resource, IResource.DEPTH_INFINITE);
+			} catch (CoreException e) {
+				boolean shouldLog = true;
+				if (e instanceof JavaModelException) {
+					if (((JavaModelException) e).isDoesNotExist()) {
+						newAdornment = 0;
+						shouldLog = false;
+					}
+				} else {
+					int errorCode = e.getStatus().getCode();
+					if (errorCode == IResourceStatus.MARKER_NOT_FOUND || errorCode == IResourceStatus.RESOURCE_NOT_FOUND) {
+						newAdornment = 0;
+						shouldLog = false;
+					}
+				}
+				if (shouldLog) {
+					JavaPlugin.log(e);
+				}
+			} finally {
+				Integer old = AdornmentCacheManager.setAdornment(resource, newAdornment);
+				if (old != null) {
+					oldAdornment = old.intValue();
+				}
+			}
+		}
+
+		boolean isAdornmentChanged() {
+			return newAdornment != oldAdornment;
+		}
+
+		@Override
+		public String toString() {
+			StringBuilder builder = new StringBuilder();
+			builder.append("AdornmentTask ["); //$NON-NLS-1$
+			if (resource != null) {
+				builder.append("resource="); //$NON-NLS-1$
+				builder.append(resource);
+				builder.append(", "); //$NON-NLS-1$
+			}
+			builder.append("newAdornment="); //$NON-NLS-1$
+			builder.append(newAdornment);
+			builder.append(", oldAdornment="); //$NON-NLS-1$
+			builder.append(oldAdornment);
+			builder.append("]"); //$NON-NLS-1$
+			return builder.toString();
+		}
+	}
+
+	private int computeContainerAdornmentFlags(IResource resource) {
+		if (resource == null) {
+			return 0;
+		}
+		Integer cachedAdornment = AdornmentCacheManager.getAdornment(resource);
+		int adornment = cachedAdornment != null ? cachedAdornment.intValue() : 0;
+		AdornmentCacheManager.scheduleTask(resource, adornmentUpdateJob);
+		return adornment;
+	}
+
 	private boolean isIgnoringOptionalProblems(IClasspathEntry entry) {
 		if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
 			for (IClasspathAttribute attrib : entry.getExtraAttributes()) {
@@ -279,37 +579,46 @@
 		return false;
 	}
 
+	private static int getErrorTicksFromMarkers(IResource res, int depth) throws CoreException {
+		if (res == null || !res.isAccessible()) {
+			return 0;
+		}
+		int severity= -1;
+		if (res instanceof IProject) {
+			severity= res.findMaxProblemSeverity(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
+			if (severity == IMarker.SEVERITY_ERROR) {
+				return ERRORTICK_BUILDPATH_ERROR;
+			}
+			severity= res.findMaxProblemSeverity(JavaRuntime.JRE_CONTAINER_MARKER, true, IResource.DEPTH_ZERO);
+			if (severity == IMarker.SEVERITY_ERROR) {
+				return ERRORTICK_BUILDPATH_ERROR;
+			}
+		}
+		severity= res.findMaxProblemSeverity(IMarker.PROBLEM, true, depth);
+		return convertToTick(severity);
+	}
+
 	private int getErrorTicksFromMarkers(IResource res, int depth, ISourceReference sourceElement) throws CoreException {
 		if (res == null || !res.isAccessible()) {
 			return 0;
 		}
 		int severity= -1;
-		if (sourceElement == null) {
-			if (res instanceof IProject) {
-				severity= res.findMaxProblemSeverity(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, true, IResource.DEPTH_ZERO);
-				if (severity == IMarker.SEVERITY_ERROR) {
-					return ERRORTICK_BUILDPATH_ERROR;
-				}
-				severity= res.findMaxProblemSeverity(JavaRuntime.JRE_CONTAINER_MARKER, true, IResource.DEPTH_ZERO);
-				if (severity == IMarker.SEVERITY_ERROR) {
-					return ERRORTICK_BUILDPATH_ERROR;
-				}
-			}
-			severity= res.findMaxProblemSeverity(IMarker.PROBLEM, true, depth);
-		} else {
-			IMarker[] markers= res.findMarkers(IMarker.PROBLEM, true, depth);
-			if (markers != null && markers.length > 0) {
-				for (int i= 0; i < markers.length && (severity != IMarker.SEVERITY_ERROR); i++) {
-					IMarker curr= markers[i];
-					if (isMarkerInRange(curr, sourceElement)) {
-						int val= curr.getAttribute(IMarker.SEVERITY, -1);
-						if (val == IMarker.SEVERITY_INFO || val == IMarker.SEVERITY_WARNING || val == IMarker.SEVERITY_ERROR) {
-							severity= Math.max(severity, val);
-						}
+		IMarker[] markers= res.findMarkers(IMarker.PROBLEM, true, depth);
+		if (markers != null && markers.length > 0) {
+			for (int i= 0; i < markers.length && (severity != IMarker.SEVERITY_ERROR); i++) {
+				IMarker curr= markers[i];
+				if (isMarkerInRange(curr, sourceElement)) {
+					int val= curr.getAttribute(IMarker.SEVERITY, -1);
+					if (val == IMarker.SEVERITY_INFO || val == IMarker.SEVERITY_WARNING || val == IMarker.SEVERITY_ERROR) {
+						severity= Math.max(severity, val);
 					}
 				}
 			}
 		}
+		return convertToTick(severity);
+	}
+
+	private static int convertToTick(int severity) {
 		switch (severity) {
 		case IMarker.SEVERITY_ERROR:
 			return ERRORTICK_ERROR;
@@ -464,6 +773,11 @@
 		if (fRegistry != null && fUseNewRegistry) {
 			fRegistry.dispose();
 		}
+		if (fListeners != null) {
+			fListeners.clear();
+		}
+		AdornmentCacheManager.deregister(this);
+		adornmentUpdateJob.cancel();
 	}
 
 	@Override
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindBreakContinueTargetOccurrencesAction.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindBreakContinueTargetOccurrencesAction.java
index 7e2816e..d62f062 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindBreakContinueTargetOccurrencesAction.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindBreakContinueTargetOccurrencesAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2011 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
@@ -28,6 +28,8 @@
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 
+import org.eclipse.jdt.internal.core.manipulation.search.BreakContinueTargetFinder;
+
 import org.eclipse.jdt.ui.JavaUI;
 
 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
@@ -36,7 +38,6 @@
 import org.eclipse.jdt.internal.ui.actions.ActionUtil;
 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
 import org.eclipse.jdt.internal.ui.javaeditor.JavaTextSelection;
-import org.eclipse.jdt.internal.ui.search.BreakContinueTargetFinder;
 import org.eclipse.jdt.internal.ui.search.FindOccurrencesEngine;
 
 /**
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindExceptionOccurrencesAction.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindExceptionOccurrencesAction.java
index 6ebb144..9a3e9ae 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindExceptionOccurrencesAction.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindExceptionOccurrencesAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2011 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
@@ -28,6 +28,8 @@
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 
+import org.eclipse.jdt.internal.core.manipulation.search.ExceptionOccurrencesFinder;
+
 import org.eclipse.jdt.ui.JavaUI;
 
 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
@@ -36,7 +38,6 @@
 import org.eclipse.jdt.internal.ui.actions.ActionUtil;
 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
 import org.eclipse.jdt.internal.ui.javaeditor.JavaTextSelection;
-import org.eclipse.jdt.internal.ui.search.ExceptionOccurrencesFinder;
 import org.eclipse.jdt.internal.ui.search.FindOccurrencesEngine;
 
 /**
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindImplementOccurrencesAction.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindImplementOccurrencesAction.java
index 8af7881..3481895 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindImplementOccurrencesAction.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindImplementOccurrencesAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2011 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
@@ -28,6 +28,8 @@
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 
+import org.eclipse.jdt.internal.core.manipulation.search.ImplementOccurrencesFinder;
+
 import org.eclipse.jdt.ui.JavaUI;
 
 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
@@ -37,7 +39,6 @@
 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
 import org.eclipse.jdt.internal.ui.javaeditor.JavaTextSelection;
 import org.eclipse.jdt.internal.ui.search.FindOccurrencesEngine;
-import org.eclipse.jdt.internal.ui.search.ImplementOccurrencesFinder;
 
 /**
  * Action to find all implement occurrences of an extended class or an implemented interface.
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindMethodExitOccurrencesAction.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindMethodExitOccurrencesAction.java
index 0988f74..dffb0c6 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindMethodExitOccurrencesAction.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/FindMethodExitOccurrencesAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2011 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
@@ -28,6 +28,8 @@
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 
+import org.eclipse.jdt.internal.core.manipulation.search.MethodExitsFinder;
+
 import org.eclipse.jdt.ui.JavaUI;
 
 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
@@ -37,7 +39,6 @@
 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
 import org.eclipse.jdt.internal.ui.javaeditor.JavaTextSelection;
 import org.eclipse.jdt.internal.ui.search.FindOccurrencesEngine;
-import org.eclipse.jdt.internal.ui.search.MethodExitsFinder;
 
 /**
  * Action to find all method exits for a given method.