Bug 576431 - Refactor SurroundWithTryWithResouresRefactoring

- create new SurroundWithTryWithResourcesRefactoringCore and
  have SurroundWithTryWithResourcesRefactoring extend it
- move AbstractExceptionAnalyzer, ExceptionAnalyzer, and
  SurroundWithTryWithResourcesAnalyzer to jdt.core.manipulation
- move a number of static methods from QuickAssistProcessor to
  new QuickAssistProcessorUtil class in jdt.core.manipulation and
  modify users appropriately
- add a new package org.eclipse.jdt.internal.corext.refactoring.surround
  to jdt.core.manipulation and expose it in MANIFEST.MF
- fix TestWithThrows3.java expected output and add
  SurroundWithResourcesTests1d8 to AllTests
- add TestTry1 and TestTry2 tests

Change-Id: I244b7d7802bf1b751f7ca507107b08335810347f
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.ui/+/186117
Tested-by: JDT Bot <jdt-bot@eclipse.org>
Tested-by: Jeff Johnston <jjohnstn@redhat.com>
Reviewed-by: Jeff Johnston <jjohnstn@redhat.com>
diff --git a/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
index 3323eec..bf430e7 100644
--- a/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
@@ -45,6 +45,7 @@
  org.eclipse.jdt.internal.corext.refactoring.rename;x-friends:="org.eclipse.jdt.ui",
  org.eclipse.jdt.internal.corext.refactoring.reorg;x-friends:="org.eclipse.jdt.ui",
  org.eclipse.jdt.internal.corext.refactoring.structure;x-friends:="org.eclipse.jdt.ui",
+ org.eclipse.jdt.internal.corext.refactoring.surround;x-friends:="org.eclipse.jdt.ui",
  org.eclipse.jdt.internal.corext.refactoring.tagging;x-friends:="org.eclipse.jdt.ui",
  org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types;manipulation=split;mandatory:=manipulation;x-friends:="org.eclipse.jdt.ui",
  org.eclipse.jdt.internal.corext.refactoring.util;manipulation=split;mandatory:=manipulation;x-friends:="org.eclipse.jdt.ui",
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessorUtil.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessorUtil.java
new file mode 100644
index 0000000..c54919f
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/correction/QuickAssistProcessorUtil.java
@@ -0,0 +1,388 @@
+/*******************************************************************************
+ * Copyright (c) 2021 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
+ *     Red Hat Inc. - moved static methods from QuickAssistProcessor to here
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.text.correction;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jface.text.link.LinkedPositionGroup;
+
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ArrayCreation;
+import org.eclipse.jdt.core.dom.ArrayType;
+import org.eclipse.jdt.core.dom.Block;
+import org.eclipse.jdt.core.dom.ClassInstanceCreation;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.CreationReference;
+import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.ExpressionMethodReference;
+import org.eclipse.jdt.core.dom.ExpressionStatement;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IMethodBinding;
+import org.eclipse.jdt.core.dom.ITypeBinding;
+import org.eclipse.jdt.core.dom.LambdaExpression;
+import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.MethodReference;
+import org.eclipse.jdt.core.dom.Modifier;
+import org.eclipse.jdt.core.dom.Name;
+import org.eclipse.jdt.core.dom.ParameterizedType;
+import org.eclipse.jdt.core.dom.ReturnStatement;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.Statement;
+import org.eclipse.jdt.core.dom.SuperMethodInvocation;
+import org.eclipse.jdt.core.dom.SuperMethodReference;
+import org.eclipse.jdt.core.dom.ThisExpression;
+import org.eclipse.jdt.core.dom.Type;
+import org.eclipse.jdt.core.dom.TypeMethodReference;
+import org.eclipse.jdt.core.dom.VariableDeclaration;
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
+
+import org.eclipse.jdt.internal.core.manipulation.StubUtility;
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.dom.Bindings;
+import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
+import org.eclipse.jdt.internal.corext.fix.LinkedProposalModelCore;
+
+public class QuickAssistProcessorUtil {
+
+	/**
+	 * Returns the functional interface method being implemented by the given method reference.
+	 *
+	 * @param methodReference the method reference to get the functional method
+	 * @return the functional interface method being implemented by <code>methodReference</code> or
+	 *         <code>null</code> if it could not be derived
+	 */
+	public static IMethodBinding getFunctionalMethodForMethodReference(MethodReference methodReference) {
+		ITypeBinding targetTypeBinding= ASTNodes.getTargetType(methodReference);
+		if (targetTypeBinding == null)
+			return null;
+
+		IMethodBinding functionalMethod= targetTypeBinding.getFunctionalInterfaceMethod();
+		if (functionalMethod != null && functionalMethod.isSynthetic()) {
+			functionalMethod= Bindings.findOverriddenMethodInType(functionalMethod.getDeclaringClass(), functionalMethod);
+		}
+		return functionalMethod;
+	}
+
+	/**
+	 * Converts and replaces the given method reference with corresponding lambda expression in the
+	 * given ASTRewrite.
+	 *
+	 * @param methodReference the method reference to convert
+	 * @param functionalMethod the non-generic functional interface method to be implemented by the
+	 *            lambda expression
+	 * @param astRoot the AST root
+	 * @param rewrite the ASTRewrite
+	 * @param linkedProposalModel to create linked proposals for lambda's parameters or
+	 *            <code>null</code> if linked proposals are not required
+	 * @param createBlockBody <code>true</code> if lambda expression's body should be a block
+	 *
+	 * @return lambda expression used to replace the method reference in the given ASTRewrite
+	 * @throws JavaModelException if an exception occurs while accessing the Java element
+	 *             corresponding to the <code>functionalMethod</code>
+	 */
+	public static LambdaExpression convertMethodRefernceToLambda(MethodReference methodReference, IMethodBinding functionalMethod, CompilationUnit astRoot,
+			ASTRewrite rewrite, LinkedProposalModelCore linkedProposalModel, boolean createBlockBody) throws JavaModelException {
+
+		AST ast= astRoot.getAST();
+		LambdaExpression lambda= ast.newLambdaExpression();
+
+		String[] lambdaParamNames= QuickAssistProcessorUtil.getUniqueParameterNames(methodReference, functionalMethod);
+		List<VariableDeclaration> lambdaParameters= lambda.parameters();
+		for (int i= 0; i < lambdaParamNames.length; i++) {
+			String paramName= lambdaParamNames[i];
+			VariableDeclarationFragment lambdaParameter= ast.newVariableDeclarationFragment();
+			SimpleName name= ast.newSimpleName(paramName);
+			lambdaParameter.setName(name);
+			lambdaParameters.add(lambdaParameter);
+			if (linkedProposalModel != null) {
+				linkedProposalModel.getPositionGroup(name.getIdentifier(), true).addPosition(rewrite.track(name), i == 0);
+			}
+		}
+
+		int noOfLambdaParameters= lambdaParamNames.length;
+		lambda.setParentheses(noOfLambdaParameters != 1);
+
+		ITypeBinding returnTypeBinding= functionalMethod.getReturnType();
+		IMethodBinding referredMethodBinding= methodReference.resolveMethodBinding(); // too often null, see bug 440000, bug 440344, bug 333665
+
+		if (methodReference instanceof CreationReference) {
+			CreationReference creationRef= (CreationReference) methodReference;
+			Type type= creationRef.getType();
+			if (type instanceof ArrayType) {
+				ArrayCreation arrayCreation= ast.newArrayCreation();
+				if (createBlockBody) {
+					Block blockBody= QuickAssistProcessorUtil.getBlockBodyForLambda(arrayCreation, returnTypeBinding, ast);
+					lambda.setBody(blockBody);
+				} else {
+					lambda.setBody(arrayCreation);
+				}
+
+				ArrayType arrayType= (ArrayType) type;
+				Type copiedElementType= (Type) rewrite.createCopyTarget(arrayType.getElementType());
+				arrayCreation.setType(ast.newArrayType(copiedElementType, arrayType.getDimensions()));
+				SimpleName name= ast.newSimpleName(lambdaParamNames[0]);
+				arrayCreation.dimensions().add(name);
+				if (linkedProposalModel != null) {
+					linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
+				}
+			} else {
+				ClassInstanceCreation cic= ast.newClassInstanceCreation();
+				if (createBlockBody) {
+					Block blockBody= QuickAssistProcessorUtil.getBlockBodyForLambda(cic, returnTypeBinding, ast);
+					lambda.setBody(blockBody);
+				} else {
+					lambda.setBody(cic);
+				}
+
+				ITypeBinding typeBinding= type.resolveBinding();
+				if (!(type instanceof ParameterizedType) && typeBinding != null && typeBinding.getTypeDeclaration().isGenericType()) {
+					cic.setType(ast.newParameterizedType((Type) rewrite.createCopyTarget(type)));
+				} else {
+					cic.setType((Type) rewrite.createCopyTarget(type));
+				}
+				List<SimpleName> invocationArgs= QuickAssistProcessorUtil.getInvocationArguments(ast, 0, noOfLambdaParameters, lambdaParamNames);
+				cic.arguments().addAll(invocationArgs);
+				if (linkedProposalModel != null) {
+					for (SimpleName name : invocationArgs) {
+						linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
+					}
+				}
+				cic.typeArguments().addAll(QuickAssistProcessorUtil.getCopiedTypeArguments(rewrite, methodReference.typeArguments()));
+			}
+
+		} else if (referredMethodBinding != null && Modifier.isStatic(referredMethodBinding.getModifiers())) {
+			MethodInvocation methodInvocation= ast.newMethodInvocation();
+			if (createBlockBody) {
+				Block blockBody= QuickAssistProcessorUtil.getBlockBodyForLambda(methodInvocation, returnTypeBinding, ast);
+				lambda.setBody(blockBody);
+			} else {
+				lambda.setBody(methodInvocation);
+			}
+
+			Expression expr= null;
+			boolean hasConflict= QuickAssistProcessorUtil.hasConflict(methodReference.getStartPosition(), referredMethodBinding, ScopeAnalyzer.METHODS | ScopeAnalyzer.CHECK_VISIBILITY, astRoot);
+			if (hasConflict || !Bindings.isSuperType(referredMethodBinding.getDeclaringClass(), ASTNodes.getEnclosingType(methodReference)) || methodReference.typeArguments().size() != 0) {
+				if (methodReference instanceof ExpressionMethodReference) {
+					ExpressionMethodReference expressionMethodReference= (ExpressionMethodReference) methodReference;
+					expr= (Expression) rewrite.createCopyTarget(expressionMethodReference.getExpression());
+				} else if (methodReference instanceof TypeMethodReference) {
+					Type type= ((TypeMethodReference) methodReference).getType();
+					ITypeBinding typeBinding= type.resolveBinding();
+					if (typeBinding != null) {
+						ImportRewrite importRewrite= StubUtility.createImportRewrite(astRoot, true);
+						expr= ast.newName(importRewrite.addImport(typeBinding));
+					}
+				}
+			}
+			methodInvocation.setExpression(expr);
+			SimpleName methodName= QuickAssistProcessorUtil.getMethodInvocationName(methodReference);
+			methodInvocation.setName((SimpleName) rewrite.createCopyTarget(methodName));
+			List<SimpleName> invocationArgs= QuickAssistProcessorUtil.getInvocationArguments(ast, 0, noOfLambdaParameters, lambdaParamNames);
+			methodInvocation.arguments().addAll(invocationArgs);
+			if (linkedProposalModel != null) {
+				for (SimpleName name : invocationArgs) {
+					linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
+				}
+			}
+			methodInvocation.typeArguments().addAll(QuickAssistProcessorUtil.getCopiedTypeArguments(rewrite, methodReference.typeArguments()));
+
+		} else if (methodReference instanceof SuperMethodReference) {
+			SuperMethodInvocation superMethodInvocation= ast.newSuperMethodInvocation();
+			if (createBlockBody) {
+				Block blockBody= QuickAssistProcessorUtil.getBlockBodyForLambda(superMethodInvocation, returnTypeBinding, ast);
+				lambda.setBody(blockBody);
+			} else {
+				lambda.setBody(superMethodInvocation);
+			}
+
+			Name superQualifier= ((SuperMethodReference) methodReference).getQualifier();
+			if (superQualifier != null) {
+				superMethodInvocation.setQualifier((Name) rewrite.createCopyTarget(superQualifier));
+			}
+			SimpleName methodName= QuickAssistProcessorUtil.getMethodInvocationName(methodReference);
+			superMethodInvocation.setName((SimpleName) rewrite.createCopyTarget(methodName));
+			List<SimpleName> invocationArgs= QuickAssistProcessorUtil.getInvocationArguments(ast, 0, noOfLambdaParameters, lambdaParamNames);
+			superMethodInvocation.arguments().addAll(invocationArgs);
+			if (linkedProposalModel != null) {
+				for (SimpleName name : invocationArgs) {
+					linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
+				}
+			}
+			superMethodInvocation.typeArguments().addAll(QuickAssistProcessorUtil.getCopiedTypeArguments(rewrite, methodReference.typeArguments()));
+
+		} else {
+			MethodInvocation methodInvocation= ast.newMethodInvocation();
+			if (createBlockBody) {
+				Block blockBody= QuickAssistProcessorUtil.getBlockBodyForLambda(methodInvocation, returnTypeBinding, ast);
+				lambda.setBody(blockBody);
+			} else {
+				lambda.setBody(methodInvocation);
+			}
+
+			boolean isTypeReference= QuickAssistProcessorUtil.isTypeReferenceToInstanceMethod(methodReference);
+			if (isTypeReference) {
+				SimpleName name= ast.newSimpleName(lambdaParamNames[0]);
+				methodInvocation.setExpression(name);
+				if (linkedProposalModel != null) {
+					linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
+				}
+			} else {
+				Expression expr= ((ExpressionMethodReference) methodReference).getExpression();
+				if (!(expr instanceof ThisExpression) || (methodReference.typeArguments().size() != 0)) {
+					methodInvocation.setExpression((Expression) rewrite.createCopyTarget(expr));
+				}
+			}
+			SimpleName methodName= QuickAssistProcessorUtil.getMethodInvocationName(methodReference);
+			methodInvocation.setName((SimpleName) rewrite.createCopyTarget(methodName));
+			List<SimpleName> invocationArgs= QuickAssistProcessorUtil.getInvocationArguments(ast, isTypeReference ? 1 : 0, noOfLambdaParameters, lambdaParamNames);
+			methodInvocation.arguments().addAll(invocationArgs);
+			if (linkedProposalModel != null) {
+				for (SimpleName name : invocationArgs) {
+					linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
+				}
+			}
+			methodInvocation.typeArguments().addAll(QuickAssistProcessorUtil.getCopiedTypeArguments(rewrite, methodReference.typeArguments()));
+		}
+
+		rewrite.replace(methodReference, lambda, null);
+		return lambda;
+	}
+
+	public static Block getBlockBodyForLambda(Expression bodyExpr, ITypeBinding returnTypeBinding, AST ast) {
+		Statement statementInBlockBody;
+		if (ast.resolveWellKnownType("void").isEqualTo(returnTypeBinding)) { //$NON-NLS-1$
+			ExpressionStatement expressionStatement= ast.newExpressionStatement(bodyExpr);
+			statementInBlockBody= expressionStatement;
+		} else {
+			ReturnStatement returnStatement= ast.newReturnStatement();
+			returnStatement.setExpression(bodyExpr);
+			statementInBlockBody= returnStatement;
+		}
+		Block blockBody= ast.newBlock();
+		blockBody.statements().add(statementInBlockBody);
+		return blockBody;
+	}
+
+	public static List<Type> getCopiedTypeArguments(ASTRewrite rewrite, List<Type> typeArguments) {
+		List<Type> copiedTypeArgs= new ArrayList<>();
+		for (Type typeArg : typeArguments) {
+			copiedTypeArgs.add((Type) rewrite.createCopyTarget(typeArg));
+		}
+		return copiedTypeArgs;
+	}
+
+	private static SimpleName getMethodInvocationName(MethodReference methodReference) {
+		SimpleName name= null;
+		if (methodReference instanceof ExpressionMethodReference) {
+			name= ((ExpressionMethodReference) methodReference).getName();
+		} else if (methodReference instanceof TypeMethodReference) {
+			name= ((TypeMethodReference) methodReference).getName();
+		} else if (methodReference instanceof SuperMethodReference) {
+			name= ((SuperMethodReference) methodReference).getName();
+		}
+		return name;
+	}
+
+	public static String[] getUniqueParameterNames(MethodReference methodReference, IMethodBinding functionalMethod) throws JavaModelException {
+		String[] originalParameterNames= ((IMethod) functionalMethod.getJavaElement()).getParameterNames();
+		String[] newNames= new String[originalParameterNames.length];
+		Set<String> excludedNames= new HashSet<>(ASTNodes.getVisibleLocalVariablesInScope(methodReference));
+
+		for (int i= 0; i < originalParameterNames.length; i++) {
+			String paramName= originalParameterNames[i];
+
+			if (excludedNames.contains(paramName)) {
+				Set<String> allNamesToExclude= new HashSet<>(excludedNames);
+				Collections.addAll(allNamesToExclude, originalParameterNames);
+
+				String newParamName= QuickAssistProcessorUtil.createName(paramName, allNamesToExclude);
+
+				excludedNames.add(newParamName);
+				newNames[i]= newParamName;
+			} else {
+				newNames[i]= paramName;
+			}
+		}
+
+		return newNames;
+	}
+
+	private static String createName(final String nameRoot, final Set<String> excludedNames) {
+		int i= 1;
+		String candidate;
+
+		do {
+			candidate= nameRoot + i++;
+		} while (excludedNames.remove(candidate));
+
+		return candidate;
+	}
+
+	private static List<SimpleName> getInvocationArguments(AST ast, int begIndex, int noOfLambdaParameters, String[] lambdaParamNames) {
+		List<SimpleName> args= new ArrayList<>();
+		for (int i= begIndex; i < noOfLambdaParameters; i++) {
+			args.add(ast.newSimpleName(lambdaParamNames[i]));
+		}
+		return args;
+	}
+
+	private static boolean hasConflict(int startPosition, IMethodBinding referredMethodBinding, int flags, CompilationUnit cu) {
+		ScopeAnalyzer analyzer= new ScopeAnalyzer(cu);
+		for (IBinding decl : analyzer.getDeclarationsInScope(startPosition, flags)) {
+			if (decl.getName().equals(referredMethodBinding.getName()) && !referredMethodBinding.getMethodDeclaration().isEqualTo(decl))
+				return true;
+		}
+		return false;
+	}
+
+	public static boolean isTypeReferenceToInstanceMethod(MethodReference methodReference) {
+		if (methodReference instanceof TypeMethodReference)
+			return true;
+		if (methodReference instanceof ExpressionMethodReference) {
+			Expression expression= ((ExpressionMethodReference) methodReference).getExpression();
+			if (expression instanceof Name) {
+				IBinding nameBinding= ((Name) expression).resolveBinding();
+				if (nameBinding instanceof ITypeBinding) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Changes the expression body of the given lambda expression to block form.
+	 * {@link LambdaExpression#resolveMethodBinding()} should not be <code>null</code> for the given
+	 * lambda expression.
+	 *
+	 * @param lambda the lambda expression to convert the body form
+	 * @param ast the AST to create new nodes
+	 * @param rewrite the ASTRewrite
+	 */
+	public static void changeLambdaBodyToBlock(LambdaExpression lambda, AST ast, ASTRewrite rewrite) {
+		Expression bodyExpr= (Expression) rewrite.createMoveTarget(lambda.getBody());
+		Block blockBody= getBlockBodyForLambda(bodyExpr, lambda.resolveMethodBinding().getReturnType(), ast);
+		rewrite.set(lambda, LambdaExpression.BODY_PROPERTY, blockBody, null);
+	}
+
+}
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/ExceptionAnalyzer.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/surround/ExceptionAnalyzer.java
similarity index 96%
rename from org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/ExceptionAnalyzer.java
rename to org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/surround/ExceptionAnalyzer.java
index 90c0e93..10b5a43 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/ExceptionAnalyzer.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/surround/ExceptionAnalyzer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2019 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
@@ -10,6 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Red Hat Inc. - refactored to jdt.core.manipulation
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.surround;
 
@@ -43,8 +44,11 @@
 import org.eclipse.jdt.internal.corext.dom.Selection;
 import org.eclipse.jdt.internal.corext.refactoring.util.AbstractExceptionAnalyzer;
 
-import org.eclipse.jdt.internal.ui.text.correction.QuickAssistProcessor;
+import org.eclipse.jdt.internal.ui.text.correction.QuickAssistProcessorUtil;
 
+/**
+ * @since 1.16
+ */
 public class ExceptionAnalyzer extends AbstractExceptionAnalyzer {
 
 	private Selection fSelection;
@@ -207,7 +211,7 @@
 		IMethodBinding referredMethodBinding= node.resolveMethodBinding();
 		if (referredMethodBinding == null)
 			return false;
-		IMethodBinding functionalMethod= QuickAssistProcessor.getFunctionalMethodForMethodReference(node);
+		IMethodBinding functionalMethod= QuickAssistProcessorUtil.getFunctionalMethodForMethodReference(node);
 		if (functionalMethod == null || functionalMethod.isGenericMethod()) { // generic lambda expressions are not allowed
 			return false;
 		}
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesAnalyzer.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesAnalyzer.java
similarity index 100%
rename from org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesAnalyzer.java
rename to org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesAnalyzer.java
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesRefactoringCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesRefactoringCore.java
new file mode 100644
index 0000000..1869228
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesRefactoringCore.java
@@ -0,0 +1,697 @@
+/*******************************************************************************
+ * Copyright (c) 2021 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:
+ *     Red Hat Inc. - initial code based on SurroundWithTryCatchRefactoring
+ *******************************************************************************/
+package org.eclipse.jdt.internal.corext.refactoring.surround;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+import org.eclipse.text.edits.MultiTextEdit;
+import org.eclipse.text.edits.TextEdit;
+import org.eclipse.text.edits.TextEditGroup;
+
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.core.refactoring.TextFileChange;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.Assignment;
+import org.eclipse.jdt.core.dom.Block;
+import org.eclipse.jdt.core.dom.CatchClause;
+import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.ExpressionStatement;
+import org.eclipse.jdt.core.dom.IExtendedModifier;
+import org.eclipse.jdt.core.dom.IMethodBinding;
+import org.eclipse.jdt.core.dom.ITypeBinding;
+import org.eclipse.jdt.core.dom.IVariableBinding;
+import org.eclipse.jdt.core.dom.LambdaExpression;
+import org.eclipse.jdt.core.dom.MethodReference;
+import org.eclipse.jdt.core.dom.Modifier;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+import org.eclipse.jdt.core.dom.Statement;
+import org.eclipse.jdt.core.dom.ThrowStatement;
+import org.eclipse.jdt.core.dom.TryStatement;
+import org.eclipse.jdt.core.dom.Type;
+import org.eclipse.jdt.core.dom.UnionType;
+import org.eclipse.jdt.core.dom.VariableDeclaration;
+import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
+import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
+import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
+import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.TypeLocation;
+import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
+import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
+
+import org.eclipse.jdt.internal.core.manipulation.StubUtility;
+import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving;
+import org.eclipse.jdt.internal.core.manipulation.util.Strings;
+import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
+import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
+import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
+import org.eclipse.jdt.internal.corext.dom.Selection;
+import org.eclipse.jdt.internal.corext.fix.LinkedProposalModelCore;
+import org.eclipse.jdt.internal.corext.refactoring.Checks;
+import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
+import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
+import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
+
+import org.eclipse.jdt.internal.ui.text.correction.QuickAssistProcessorUtil;
+
+/**
+ * Surround a set of statements with a try-with-resources block.
+ *
+ * Special case:
+ *
+ * URL url= file.toURL();
+ *
+ * In this case the variable declaration statement gets convert into a
+ * declaration without initializer. So the body of the try/catch block
+ * only consists of new assignments. In this case we can't move the
+ * selected nodes (e.g. the declaration) into the try block.
+ */
+public class SurroundWithTryWithResourcesRefactoringCore extends Refactoring {
+
+	public final String GROUP_EXC_TYPE= "exc_type"; //$NON-NLS-1$
+	public final String GROUP_EXC_NAME= "exc_name"; //$NON-NLS-1$
+	public final String GROUP_TRY_STATEMENT= "try_stmt"; //$NON-NLS-1$
+
+	private Selection fSelection;
+	private SurroundWithTryWithResourcesAnalyzer fAnalyzer;
+	private boolean fLeaveDirty;
+
+	private ICompilationUnit fCUnit;
+	private CompilationUnit fRootNode;
+	private ASTRewrite fRewriter;
+	private ImportRewrite fImportRewrite;
+	private CodeScopeBuilder.Scope fScope;
+	private ASTNode[] fSelectedNodes;
+	private List<ASTNode> fAutoClosableNodes;
+
+	private LinkedProposalModelCore fLinkedProposalModel;
+
+	protected SurroundWithTryWithResourcesRefactoringCore(ICompilationUnit cu, Selection selection) {
+		fCUnit= cu;
+		fSelection= selection;
+		fLeaveDirty= false;
+	}
+
+	public static SurroundWithTryWithResourcesRefactoringCore create(ICompilationUnit cu, int offset, int length) {
+		return new SurroundWithTryWithResourcesRefactoringCore(cu, Selection.createFromStartLength(offset, length));
+	}
+
+	public static SurroundWithTryWithResourcesRefactoringCore create(ICompilationUnit cu, Selection selection) {
+		return new SurroundWithTryWithResourcesRefactoringCore(cu, selection);
+	}
+
+	public LinkedProposalModelCore getLinkedProposalModelCore() {
+		return fLinkedProposalModel;
+	}
+
+	public void setLeaveDirty(boolean leaveDirty) {
+		fLeaveDirty= leaveDirty;
+	}
+
+	public boolean stopExecution() {
+		if (fAnalyzer == null)
+			return true;
+		ITypeBinding[] exceptions= fAnalyzer.getExceptions(fAnalyzer.getSelection());
+		List<ASTNode> autoClosableNodes= fAnalyzer.getCoveredAutoClosableNodes();
+		return (exceptions == null || exceptions.length == 0) && (autoClosableNodes == null || autoClosableNodes.isEmpty());
+	}
+
+	/* non Java-doc
+	 * @see IRefactoring#getName()
+	 */
+	@Override
+	public String getName() {
+		return RefactoringCoreMessages.SurroundWithTryWithResourcesRefactoring_name;
+	}
+
+	public RefactoringStatus checkActivationBasics(CompilationUnit rootNode) throws CoreException {
+		RefactoringStatus result= new RefactoringStatus();
+		fRootNode= rootNode;
+
+		fAnalyzer= new SurroundWithTryWithResourcesAnalyzer(fCUnit, fSelection);
+		fRootNode.accept(fAnalyzer);
+		result.merge(fAnalyzer.getStatus());
+		fAutoClosableNodes= fAnalyzer.getCoveredAutoClosableNodes();
+		if (fAutoClosableNodes == null || fAutoClosableNodes.isEmpty()) {
+			result.merge(RefactoringStatus.createWarningStatus(RefactoringCoreMessages.SurroundWithTryWithResourcesRefactoring_notAutoclosable));
+		}
+		return result;
+	}
+
+
+	/*
+	 * @see Refactoring#checkActivation(IProgressMonitor)
+	 */
+	@Override
+	public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
+		CompilationUnit rootNode= new RefactoringASTParser(IASTSharedValues.SHARED_AST_LEVEL).parse(fCUnit, true, pm);
+		return checkActivationBasics(rootNode);
+	}
+
+	/*
+	 * @see Refactoring#checkInput(IProgressMonitor)
+	 */
+	@Override
+	public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
+		return Checks.validateModifiesFiles(
+			ResourceUtil.getFiles(new ICompilationUnit[]{fCUnit}),
+			getValidationContext(), pm);
+	}
+
+	protected LinkedProposalModelCore createLinkedProposalModel() {
+		return new LinkedProposalModelCore();
+	}
+
+	/* non Java-doc
+	 * @see IRefactoring#createChange(IProgressMonitor)
+	 */
+	@Override
+	public Change createChange(IProgressMonitor pm) throws CoreException {
+		final String NN= ""; //$NON-NLS-1$
+		if (pm == null) pm= new NullProgressMonitor();
+		pm.beginTask(NN, 2);
+		try {
+			final CompilationUnitChange result= new CompilationUnitChange(getName(), fCUnit);
+			if (fLeaveDirty)
+				result.setSaveMode(TextFileChange.LEAVE_DIRTY);
+			MultiTextEdit root= new MultiTextEdit();
+			result.setEdit(root);
+			fRewriter= ASTRewrite.create(fAnalyzer.getEnclosingBodyDeclaration().getAST());
+			fImportRewrite= StubUtility.createImportRewrite(fRootNode, true);
+
+			fLinkedProposalModel= createLinkedProposalModel();
+
+			fScope= CodeScopeBuilder.perform(fAnalyzer.getEnclosingBodyDeclaration(), fSelection).
+				findScope(fSelection.getOffset(), fSelection.getLength());
+			fScope.setCursor(fSelection.getOffset());
+
+			fSelectedNodes= fAnalyzer.getSelectedNodes();
+
+			createTryWithResourcesStatement(fCUnit.getBuffer(), fCUnit.findRecommendedLineSeparator());
+
+			if (fImportRewrite.hasRecordedChanges()) {
+				TextEdit edit= fImportRewrite.rewriteImports(null);
+				root.addChild(edit);
+				result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {edit} ));
+			}
+			TextEdit change= fRewriter.rewriteAST();
+			root.addChild(change);
+			result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {change} ));
+			return result;
+		} finally {
+			pm.done();
+		}
+	}
+
+	private AST getAST() {
+		return fRootNode.getAST();
+	}
+
+	@SuppressWarnings("null")
+	private void createTryWithResourcesStatement(org.eclipse.jdt.core.IBuffer buffer, String lineDelimiter) throws CoreException {
+		List<Statement> result= new ArrayList<>(1);
+		boolean modifyExistingTry= false;
+		TryStatement tryStatement= null;
+		ITypeBinding[] exceptions= fAnalyzer.getExceptions(fAnalyzer.getSelection());
+		ImportRewriteContext context= new ContextSensitiveImportRewriteContext(fAnalyzer.getEnclosingBodyDeclaration(), fImportRewrite);
+
+		TryStatement enclosingTry= (TryStatement)ASTResolving.findAncestor(fSelectedNodes[0], ASTNode.TRY_STATEMENT);
+		ListRewrite resourcesRewriter= null;
+		ListRewrite clausesRewriter= null;
+		ListRewrite statements= null;
+		if (enclosingTry == null || enclosingTry.getBody() == null || enclosingTry.getBody().statements().get(0) != fSelectedNodes[0]) {
+			tryStatement= getAST().newTryStatement();
+			statements= fRewriter.getListRewrite(tryStatement.getBody(), Block.STATEMENTS_PROPERTY);
+		} else {
+			modifyExistingTry= true;
+			resourcesRewriter= fRewriter.getListRewrite(enclosingTry, TryStatement.RESOURCES2_PROPERTY);
+			clausesRewriter= fRewriter.getListRewrite(enclosingTry, TryStatement.CATCH_CLAUSES_PROPERTY);
+		}
+
+		CatchClause catchClause= getAST().newCatchClause();
+		SingleVariableDeclaration decl= getAST().newSingleVariableDeclaration();
+		String varName= StubUtility.getExceptionVariableName(fCUnit.getJavaProject());
+		String name= fScope.createName(varName, false);
+		decl.setName(getAST().newSimpleName(name));
+
+
+		boolean selectedNodeRemoved= false;
+		ASTNode expressionStatement= null;
+		ASTNode replacementNode= null;
+		List<ASTNode> nodesInRange= new ArrayList<>();
+
+		if (!modifyExistingTry) {
+			List<ASTNode> variableDeclarations= getSpecialVariableDeclarationStatements();
+			for (ASTNode node : fSelectedNodes) {
+				if (fAutoClosableNodes.contains(node)) {
+					continue;
+				}
+				if (node instanceof VariableDeclarationStatement && variableDeclarations.contains(node)) {
+					AST ast= getAST();
+					VariableDeclarationStatement statement= (VariableDeclarationStatement)node;
+					// Create a copy and remove the initializer
+					VariableDeclarationStatement copy= (VariableDeclarationStatement)ASTNode.copySubtree(ast, statement);
+					List<IExtendedModifier> modifiers= copy.modifiers();
+					for (Iterator<IExtendedModifier> iter= modifiers.iterator(); iter.hasNext();) {
+						IExtendedModifier modifier= iter.next();
+						if (modifier.isModifier() && Modifier.isFinal(((Modifier)modifier).getKeyword().toFlagValue())) {
+							iter.remove();
+						}
+					}
+					List<VariableDeclarationFragment> fragments= copy.fragments();
+					for (VariableDeclarationFragment fragment : fragments) {
+						fragment.setInitializer(null);
+					}
+
+					// "var" type cannot have null initializer, so change to inferred type
+					if (ASTNodes.isVarType(statement, fRootNode)) {
+						ITypeBinding binding= statement.getType().resolveBinding();
+						if (binding != null) {
+							Type varType= fImportRewrite.addImport(binding, getAST(), context, TypeLocation.LOCAL_VARIABLE);
+							copy.setType(varType);
+						}
+					}
+
+					CompilationUnit root= (CompilationUnit)statement.getRoot();
+					int extendedStart= root.getExtendedStartPosition(statement);
+					// we have a leading comment and the comment is covered by the selection
+					if (extendedStart != statement.getStartPosition() && extendedStart >= fSelection.getOffset()) {
+						String commentToken= buffer.getText(extendedStart, statement.getStartPosition() - extendedStart);
+						commentToken= Strings.trimTrailingTabsAndSpaces(commentToken);
+						Type type= statement.getType();
+						String typeName= buffer.getText(type.getStartPosition(), type.getLength());
+						copy.setType((Type)fRewriter.createStringPlaceholder(commentToken + typeName, type.getNodeType()));
+					}
+					result.add(copy);
+					// convert the fragments into expression statements
+					fragments= statement.fragments();
+					if (!fragments.isEmpty()) {
+						List<ExpressionStatement> newExpressionStatements= new ArrayList<>();
+						for (VariableDeclarationFragment fragment : fragments) {
+							Expression initializer= fragment.getInitializer();
+							if (initializer != null) {
+								Assignment assignment= ast.newAssignment();
+								assignment.setLeftHandSide((Expression)fRewriter.createCopyTarget(fragment.getName()));
+								assignment.setRightHandSide((Expression)fRewriter.createCopyTarget(initializer));
+								newExpressionStatements.add(ast.newExpressionStatement(assignment));
+							}
+						}
+						if (!newExpressionStatements.isEmpty()) {
+							if (fSelectedNodes.length == 1) {
+								expressionStatement= fRewriter.createGroupNode(newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()]));
+							} else {
+								fRewriter.replace(
+										statement,
+										fRewriter.createGroupNode(newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()])),
+										null);
+							}
+						} else {
+							fRewriter.remove(statement, null);
+							selectedNodeRemoved= true;
+						}
+					} else {
+						fRewriter.remove(statement, null);
+						selectedNodeRemoved= true;
+					}
+				}
+			}
+			result.add(tryStatement);
+			if (result.size() == 1) {
+				replacementNode= result.get(0);
+			} else {
+				replacementNode= fRewriter.createGroupNode(result.toArray(new ASTNode[result.size()]));
+			}
+
+			ASTNode node= fSelectedNodes[0];
+			List<ASTNode> coveredStatements= new ArrayList<>();
+			for (ASTNode coveredNode : fSelectedNodes) {
+				Statement statement= ASTResolving.findParentStatement(coveredNode);
+				if (statement == null) {
+					continue;
+				}
+				if (!coveredStatements.contains(statement)) {
+					coveredStatements.add(statement);
+				}
+			}
+
+			Selection nodesInRangeSelection= fAnalyzer.getSelection();
+			if (!fAutoClosableNodes.isEmpty()) {
+				ASTNode parentBodyDeclaration= ASTResolving.findParentBodyDeclaration(node);
+				int start= fAutoClosableNodes.get(0).getStartPosition();
+				ASTNode lastSelectedNode= fSelectedNodes[fSelectedNodes.length - 1];
+				int end= lastSelectedNode.getStartPosition() + lastSelectedNode.getLength();
+
+				for (ASTNode astNode : fAutoClosableNodes) {
+					int endPosition= findEndPosition(astNode);
+					end= Math.max(end, endPosition);
+				}
+
+				// recursive loop to find all nodes affected by wrapping in try block
+				nodesInRange= findNodesInRange(parentBodyDeclaration, start, end);
+				int oldEnd= end;
+				int newEnd= end;
+				while (true) {
+					newEnd= oldEnd;
+					for (ASTNode astNode : nodesInRange) {
+						int endPosition= findEndPosition(astNode);
+						newEnd= Math.max(newEnd, endPosition);
+					}
+					if (newEnd > oldEnd) {
+						oldEnd= newEnd;
+						nodesInRange= findNodesInRange(parentBodyDeclaration, start, newEnd);
+						continue;
+					}
+					break;
+				}
+				if (nodesInRange.size() > 0) {
+					// must recalculate exceptions as additional lines are now in try statement
+					ASTNode lastNode= nodesInRange.get(nodesInRange.size() - 1);
+					nodesInRangeSelection= Selection.createFromStartEnd(start, lastNode.getStartPosition() + lastNode.getLength());
+					exceptions= fAnalyzer.getExceptions(nodesInRangeSelection);
+				}
+				nodesInRange.removeAll(fAutoClosableNodes);
+				nodesInRange.removeAll(Arrays.asList(fSelectedNodes));
+			}
+		}
+
+		// add required resource statements
+		CompilationUnit cu= (CompilationUnit)fSelectedNodes[0].getRoot();
+		AST ast= fSelectedNodes[0].getAST();
+		Set<String> resourceNameList= new HashSet<>();
+		List<ITypeBinding> allExceptions= new ArrayList<>(Arrays.asList(exceptions));
+		for (ASTNode coveredNode : fAutoClosableNodes) {
+			ASTNode findAncestor= ASTResolving.findAncestor(coveredNode, ASTNode.VARIABLE_DECLARATION_STATEMENT);
+			if (findAncestor == null) {
+				findAncestor= ASTResolving.findAncestor(coveredNode, ASTNode.ASSIGNMENT);
+			}
+			if (findAncestor instanceof VariableDeclarationStatement) {
+				VariableDeclarationStatement vds= (VariableDeclarationStatement) findAncestor;
+				String commentToken= null;
+				int extendedStatementStart= cu.getExtendedStartPosition(vds);
+				if(vds.getStartPosition() > extendedStatementStart) {
+					commentToken= buffer.getText(extendedStatementStart, vds.getStartPosition() - extendedStatementStart);
+				}
+				Type type= vds.getType();
+				ITypeBinding typeBinding= type.resolveBinding();
+				if (typeBinding != null) {
+					IMethodBinding close= findAutocloseMethod(typeBinding);
+					if (close != null) {
+						for (ITypeBinding exceptionType : close.getExceptionTypes()) {
+							if (!allExceptions.contains(exceptionType)) {
+								allExceptions.add(exceptionType);
+							}
+						}
+					}
+				}
+				String typeName= buffer.getText(type.getStartPosition(), type.getLength());
+
+				for (Object object : vds.fragments()) {
+					VariableDeclarationFragment variableDeclarationFragment= (VariableDeclarationFragment) object;
+					VariableDeclarationFragment newVariableDeclarationFragment= ast.newVariableDeclarationFragment();
+					SimpleName vdsName= variableDeclarationFragment.getName();
+
+					if(commentToken == null) {
+						int extendedStart= cu.getExtendedStartPosition(variableDeclarationFragment);
+						commentToken= buffer.getText(extendedStart, variableDeclarationFragment.getStartPosition() - extendedStart);
+					}
+					commentToken= Strings.trimTrailingTabsAndSpaces(commentToken);
+					commentToken += commentToken.isEmpty() ? "" : " "; //$NON-NLS-1$ //$NON-NLS-2$
+
+					newVariableDeclarationFragment.setName(ast.newSimpleName(vdsName.getIdentifier()));
+					Expression newExpression= null;
+					Expression initializer= variableDeclarationFragment.getInitializer();
+					if (initializer == null) {
+						fRewriter.remove(coveredNode, null);
+						continue;
+					} else {
+						newExpression= (Expression) fRewriter.createMoveTarget(initializer);
+					}
+					resourceNameList.add(vdsName.getIdentifier());
+					newVariableDeclarationFragment.setInitializer(newExpression);
+					VariableDeclarationExpression newVariableDeclarationExpression= ast.newVariableDeclarationExpression(newVariableDeclarationFragment);
+					newVariableDeclarationExpression.setType(
+							(Type) fRewriter.createStringPlaceholder(commentToken + typeName, type.getNodeType()));
+					if (modifyExistingTry) {
+						if (enclosingTry.resources().isEmpty()) {
+							resourcesRewriter.insertFirst(newVariableDeclarationExpression, null);
+						} else {
+							resourcesRewriter.insertLast(newVariableDeclarationExpression, null);
+						}
+					} else {
+						tryStatement.resources().add(newVariableDeclarationExpression);
+					}
+					commentToken= null;
+				}
+//				String commentToken2= ""; //$NON-NLS-1$
+//				int extendedStart= cu.getExtendedStartPosition(vds);
+//				int extendedLength= cu.getExtendedLength(vds);
+//				int endCommentLength= extendedLength - (vds.getStartPosition() - extendedStart) - vds.getLength();
+//				if (endCommentLength > 0) {
+//					commentToken2= buffer.getText(vds.getStartPosition() + vds.getLength(),
+//							endCommentLength);
+//					commentToken2= Strings.trimLeadingTabsAndSpaces(commentToken2);
+//				}
+			}
+		}
+
+		List<ITypeBinding> mustRethrowList= new ArrayList<>();
+		List<ITypeBinding> catchExceptions= fAnalyzer.calculateCatchesAndRethrows(ASTNodes.filterSubtypes(allExceptions), mustRethrowList);
+		List<ITypeBinding> filteredExceptions= ASTNodes.filterSubtypes(catchExceptions);
+		if (catchExceptions.size() > 0) {
+			LinkedProposalModelCore linkedProposalModel= new LinkedProposalModelCore();
+			int i= 0;
+			if (!modifyExistingTry) {
+				for (ITypeBinding mustThrow : mustRethrowList) {
+					CatchClause newClause= ast.newCatchClause();
+					SingleVariableDeclaration newDecl= ast.newSingleVariableDeclaration();
+					newDecl.setName(ast.newSimpleName(name));
+					Type importType= fImportRewrite.addImport(mustThrow, ast, context, TypeLocation.EXCEPTION);
+					newDecl.setType(importType);
+					newClause.setException(newDecl);
+					ThrowStatement newThrowStatement= ast.newThrowStatement();
+					newThrowStatement.setExpression(ast.newSimpleName(name));
+					linkedProposalModel.getPositionGroup(GROUP_EXC_NAME + i, true).addPosition(fRewriter.track(decl.getName()), false);
+					newClause.getBody().statements().add(newThrowStatement);
+					tryStatement.catchClauses().add(newClause);
+					++i;
+				}
+			}
+			UnionType unionType= getAST().newUnionType();
+			List<Type> types= unionType.types();
+			for (ITypeBinding exception : filteredExceptions) {
+				Type type= fImportRewrite.addImport(exception, getAST(), context, TypeLocation.EXCEPTION);
+				types.add(type);
+				fLinkedProposalModel.getPositionGroup(GROUP_EXC_TYPE + i, true).addPosition(fRewriter.track(type), i == 0);
+				i++;
+			}
+
+			decl.setType(unionType);
+			catchClause.setException(decl);
+			fLinkedProposalModel.getPositionGroup(GROUP_EXC_NAME + 0, true).addPosition(fRewriter.track(decl.getName()), false);
+			Statement st= getCatchBody("Exception", name, lineDelimiter); //$NON-NLS-1$
+			if (st != null) {
+				catchClause.getBody().statements().add(st);
+			}
+			if (modifyExistingTry) {
+				clausesRewriter.insertLast(catchClause, null);
+			} else {
+				tryStatement.catchClauses().add(catchClause);
+			}
+		}
+
+
+		if (fSelectedNodes.length == 1 && fAutoClosableNodes.isEmpty()) {
+			ASTNode selectedNode= fSelectedNodes[0];
+
+			if (selectedNode instanceof MethodReference) {
+				MethodReference methodReference= (MethodReference) selectedNode;
+				IMethodBinding functionalMethod= QuickAssistProcessorUtil.getFunctionalMethodForMethodReference(methodReference);
+				// functionalMethod is non-null and non-generic. See ExceptionAnalyzer.handleMethodReference(MethodReference node).
+				Assert.isTrue(functionalMethod != null && !functionalMethod.isGenericMethod());
+				LambdaExpression lambda= QuickAssistProcessorUtil.convertMethodRefernceToLambda(methodReference, functionalMethod, fRootNode, fRewriter, null, true);
+				ASTNode statementInBlock= (ASTNode) ((Block) lambda.getBody()).statements().get(0);
+				fRewriter.replace(statementInBlock, replacementNode, null);
+				statements.insertLast(statementInBlock, null);
+				return;
+			}
+
+			LambdaExpression enclosingLambda= ASTResolving.findEnclosingLambdaExpression(selectedNode);
+			if (enclosingLambda != null && selectedNode.getLocationInParent() == LambdaExpression.BODY_PROPERTY && enclosingLambda.resolveMethodBinding() != null) {
+				QuickAssistProcessorUtil.changeLambdaBodyToBlock(enclosingLambda, getAST(), fRewriter);
+				Block blockBody= (Block) fRewriter.get(enclosingLambda, LambdaExpression.BODY_PROPERTY);
+				ASTNode statementInBlock= (ASTNode) blockBody.statements().get(0);
+				fRewriter.replace(statementInBlock, replacementNode, null);
+				statements.insertLast(statementInBlock, null);
+				return;
+			}
+
+			if (expressionStatement != null) {
+				statements.insertLast(expressionStatement, null);
+			} else {
+				if (!selectedNodeRemoved)
+					statements.insertLast(fRewriter.createMoveTarget(selectedNode), null);
+			}
+			fRewriter.replace(selectedNode, replacementNode, null);
+		} else if (modifyExistingTry) {
+			ListRewrite source= fRewriter.getListRewrite(enclosingTry.getBody(), Block.STATEMENTS_PROPERTY);
+			for (ASTNode node : fAutoClosableNodes) {
+				source.remove(node, null);
+			}
+		} else {
+			ListRewrite source= fRewriter.getListRewrite(
+					fSelectedNodes[0].getParent(),
+					(ChildListPropertyDescriptor)fSelectedNodes[0].getLocationInParent());
+			List<ASTNode> nodes= new ArrayList<>(Arrays.asList(fSelectedNodes));
+			if (!nodesInRange.isEmpty()) {
+				nodes.addAll(nodesInRange);
+			}
+			int index= fAutoClosableNodes.size();
+			if (index < nodes.size()) {
+				ASTNode toMove= source.createMoveTarget(nodes.get(index), nodes.get(nodes.size() - 1),
+						index == 0 ? replacementNode : null, null);
+				statements.insertLast(toMove, null);
+			}
+			if (index > 0) {
+				source.replace(fAutoClosableNodes.get(0), replacementNode, null);
+				for (int i= 1; i < index; ++i) {
+					source.remove(fAutoClosableNodes.get(i), null);
+				}
+			}
+		}
+
+	}
+
+	public static IMethodBinding findAutocloseMethod(ITypeBinding type) {
+		while (type != null) {
+			IMethodBinding[] methods= type.getDeclaredMethods();
+			for (IMethodBinding method : methods) {
+				if ("close".equals(method.getName()) && method.getParameterTypes().length == 0) { //$NON-NLS-1$
+					return method;
+				}
+			}
+			type= type.getSuperclass();
+		}
+		return null;
+	}
+
+	private int findEndPosition(ASTNode node) {
+		int end= node.getStartPosition() + node.getLength();
+		Map<SimpleName, IVariableBinding> nodeSimpleNameBindings= fAnalyzer.getVariableStatementBinding(node);
+		List<SimpleName> nodeNames= new ArrayList<>(nodeSimpleNameBindings.keySet());
+		if (nodeNames.isEmpty()) {
+			return -1;
+		}
+		SimpleName nodeSimpleName= nodeNames.get(0);
+		SimpleName[] coveredNodeBindings= LinkedNodeFinder.findByNode(node.getRoot(), nodeSimpleName);
+		if (coveredNodeBindings.length == 0) {
+			return -1;
+		}
+		for (ASTNode astNode : coveredNodeBindings) {
+			end= Math.max(end, (astNode.getStartPosition() + astNode.getLength()));
+		}
+		return end;
+	}
+
+	// find all nodes (statements) that are within the start/end positions
+	public static List<ASTNode> findNodesInRange(ASTNode astNode, final int start, final int end) {
+		List<ASTNode> nodesInRange= new ArrayList<>();
+		astNode.accept(new ASTVisitor() {
+			int pre= start;
+
+			@Override
+			public void preVisit(ASTNode preNode) {
+				pre= preNode.getStartPosition();
+				super.preVisit(preNode);
+			}
+
+			@Override
+			public void postVisit(ASTNode postNode) {
+				int post= postNode.getStartPosition() + postNode.getLength();
+				if (pre >= start && post <= end) {
+					Statement statement= ASTResolving.findParentStatement(postNode);
+					loop: while (statement != null) {
+						if (statement.getParent() instanceof Statement) {
+							Statement pStatement= (Statement) statement.getParent();
+							switch (pStatement.getNodeType()) {
+								case ASTNode.BLOCK:
+									if (pStatement.getParent().getNodeType() != ASTNode.METHOD_DECLARATION &&
+									pStatement.getParent().getNodeType() != ASTNode.TRY_STATEMENT) {
+										statement= pStatement;
+										continue;
+									} else {
+										break loop;
+									}
+								case ASTNode.METHOD_DECLARATION:
+									break loop;
+								default:
+									break;
+							}
+							statement= pStatement;
+						} else {
+							break;
+						}
+					}
+					if (statement != null && !nodesInRange.contains(statement)) {
+						nodesInRange.add(statement);
+					}
+				}
+				super.postVisit(postNode);
+			}
+		});
+		return nodesInRange;
+	}
+
+	private List<ASTNode> getSpecialVariableDeclarationStatements() {
+		List<ASTNode> result= new ArrayList<>(3);
+		for (VariableDeclaration local : fAnalyzer.getAffectedLocals()) {
+			ASTNode parent= local.getParent();
+			if (parent instanceof VariableDeclarationStatement && !result.contains(parent))
+				result.add(parent);
+		}
+		return result;
+
+	}
+
+	private Statement getCatchBody(String type, String name, String lineSeparator) throws CoreException {
+		String s= StubUtility.getCatchBodyContent(fCUnit, type, name, fSelectedNodes[0], lineSeparator);
+		if (s == null) {
+			return null;
+		} else {
+			return (Statement)fRewriter.createStringPlaceholder(s, ASTNode.RETURN_STATEMENT);
+		}
+	}
+}
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/util/AbstractExceptionAnalyzer.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/util/AbstractExceptionAnalyzer.java
similarity index 100%
rename from org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/util/AbstractExceptionAnalyzer.java
rename to org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/util/AbstractExceptionAnalyzer.java
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_in/TestTry1.java b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_in/TestTry1.java
new file mode 100644
index 0000000..7352ca1
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_in/TestTry1.java
@@ -0,0 +1,16 @@
+package trycatch18_in;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+class TestTry1 {
+	FileInputStream foo() {
+		try {
+			/*[*/FileInputStream f = new FileInputStream("a.b");
+			return f;/*]*/
+		} catch (FileNotFoundException e) {
+			// do nothing
+		}
+		return null;
+	}
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_in/TestTry2.java b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_in/TestTry2.java
new file mode 100644
index 0000000..bc4d4f3
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_in/TestTry2.java
@@ -0,0 +1,17 @@
+package trycatch18_in;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+class TestTry1 {
+	FileInputStream foo() {
+		try {
+			String name = "a.b";
+			/*[*/FileInputStream f = new FileInputStream(name);
+			return f;/*]*/
+		} catch (FileNotFoundException e) {
+			// do nothing
+		}
+		return null;
+	}
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestTry1.java b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestTry1.java
new file mode 100644
index 0000000..a2764af
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestTry1.java
@@ -0,0 +1,17 @@
+package trycatch18_out;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+class TestTry1 {
+	FileInputStream foo() {
+		try (/*[*/ FileInputStream f = new FileInputStream("a.b")) {
+			return f;/*]*/
+		} catch (FileNotFoundException e) {
+			// do nothing
+		} catch (IOException e) {
+		}
+		return null;
+	}
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestTry2.java b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestTry2.java
new file mode 100644
index 0000000..d32e746
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestTry2.java
@@ -0,0 +1,22 @@
+package trycatch18_out;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+class TestTry1 {
+	FileInputStream foo() {
+		try {
+			String name = "a.b";
+			try (/*[*/ FileInputStream f = new FileInputStream(name)) {
+				return f;/*]*/
+			} catch (FileNotFoundException e) {
+				throw e;
+			} catch (IOException e) {
+			}
+		} catch (FileNotFoundException e) {
+			// do nothing
+		}
+		return null;
+	}
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestWithThrows3.java b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestWithThrows3.java
index 3c4c1d7..fe0e0d0 100644
--- a/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestWithThrows3.java
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestWithThrows3.java
@@ -6,15 +6,11 @@
 
 class TestWithThrows3 {
 	public FileInputStream foo(int a) throws FileNotFoundException {
-		try {
-			try (/*[*/ FileInputStream f = new FileInputStream("a.b")) {
-				return f;/*]*/
-			} catch (FileNotFoundException e) {
-				throw e;
-			} catch (IOException e) {
-			}
+		try (/*[*/ FileInputStream f = new FileInputStream("a.b")) {
+			return f;/*]*/
 		} catch (FileNotFoundException e) {
 			// do nothing
+		} catch (IOException e) {
 		}
 		return null;
 	}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/AllTests.java b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/AllTests.java
index 694794b..cc26ae5 100644
--- a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/AllTests.java
+++ b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/AllTests.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
@@ -26,6 +26,7 @@
 	SurroundWithTests.class,
 	SurroundWithTests1d7.class,
 	SurroundWithTests1d8.class,
+	SurroundWithResourcesTests1d8.class,
 })
 public class AllTests {
 }
\ No newline at end of file
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryCatchRefactoring.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryCatchRefactoring.java
index e8ef5c1..e96439e 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryCatchRefactoring.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryCatchRefactoring.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
@@ -80,7 +80,7 @@
 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
 import org.eclipse.jdt.internal.corext.refactoring.util.SelectionAwareSourceRangeComputer;
 
-import org.eclipse.jdt.internal.ui.text.correction.QuickAssistProcessor;
+import org.eclipse.jdt.internal.ui.text.correction.QuickAssistProcessorUtil;
 
 /**
  * Surround a set of statements with a try/catch block or a try/multi-catch block.
@@ -380,10 +380,10 @@
 
 			if (selectedNode instanceof MethodReference) {
 				MethodReference methodReference= (MethodReference) selectedNode;
-				IMethodBinding functionalMethod= QuickAssistProcessor.getFunctionalMethodForMethodReference(methodReference);
+				IMethodBinding functionalMethod= QuickAssistProcessorUtil.getFunctionalMethodForMethodReference(methodReference);
 				// functionalMethod is non-null and non-generic. See ExceptionAnalyzer.handleMethodReference(MethodReference node).
 				Assert.isTrue(functionalMethod != null && !functionalMethod.isGenericMethod());
-				LambdaExpression lambda= QuickAssistProcessor.convertMethodRefernceToLambda(methodReference, functionalMethod, fRootNode, fRewriter, null, true);
+				LambdaExpression lambda= QuickAssistProcessorUtil.convertMethodRefernceToLambda(methodReference, functionalMethod, fRootNode, fRewriter, null, true);
 				ASTNode statementInBlock= (ASTNode) ((Block) lambda.getBody()).statements().get(0);
 				fRewriter.replace(statementInBlock, replacementNode, null);
 				statements.insertLast(statementInBlock, null);
@@ -392,7 +392,7 @@
 
 			LambdaExpression enclosingLambda= ASTResolving.findEnclosingLambdaExpression(selectedNode);
 			if (enclosingLambda != null && selectedNode.getLocationInParent() == LambdaExpression.BODY_PROPERTY && enclosingLambda.resolveMethodBinding() != null) {
-				QuickAssistProcessor.changeLambdaBodyToBlock(enclosingLambda, getAST(), fRewriter);
+				QuickAssistProcessorUtil.changeLambdaBodyToBlock(enclosingLambda, getAST(), fRewriter);
 				Block blockBody= (Block) fRewriter.get(enclosingLambda, LambdaExpression.BODY_PROPERTY);
 				ASTNode statementInBlock= (ASTNode) blockBody.statements().get(0);
 				fRewriter.replace(statementInBlock, replacementNode, null);
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesRefactoring.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesRefactoring.java
index 4209ae5..010461d 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesRefactoring.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesRefactoring.java
@@ -13,82 +13,13 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.surround;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.eclipse.core.runtime.Assert;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
-
-import org.eclipse.text.edits.MultiTextEdit;
-import org.eclipse.text.edits.TextEdit;
-import org.eclipse.text.edits.TextEditGroup;
-
 import org.eclipse.jface.text.ITextSelection;
 
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.TextFileChange;
-
 import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.dom.AST;
-import org.eclipse.jdt.core.dom.ASTNode;
-import org.eclipse.jdt.core.dom.ASTVisitor;
-import org.eclipse.jdt.core.dom.Assignment;
-import org.eclipse.jdt.core.dom.Block;
-import org.eclipse.jdt.core.dom.CatchClause;
-import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
-import org.eclipse.jdt.core.dom.CompilationUnit;
-import org.eclipse.jdt.core.dom.Expression;
-import org.eclipse.jdt.core.dom.ExpressionStatement;
-import org.eclipse.jdt.core.dom.IExtendedModifier;
-import org.eclipse.jdt.core.dom.IMethodBinding;
-import org.eclipse.jdt.core.dom.ITypeBinding;
-import org.eclipse.jdt.core.dom.IVariableBinding;
-import org.eclipse.jdt.core.dom.LambdaExpression;
-import org.eclipse.jdt.core.dom.MethodReference;
-import org.eclipse.jdt.core.dom.Modifier;
-import org.eclipse.jdt.core.dom.SimpleName;
-import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
-import org.eclipse.jdt.core.dom.Statement;
-import org.eclipse.jdt.core.dom.ThrowStatement;
-import org.eclipse.jdt.core.dom.TryStatement;
-import org.eclipse.jdt.core.dom.Type;
-import org.eclipse.jdt.core.dom.UnionType;
-import org.eclipse.jdt.core.dom.VariableDeclaration;
-import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
-import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
-import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
-import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
-import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
-import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
-import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.TypeLocation;
-import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
-import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
 
-import org.eclipse.jdt.internal.core.manipulation.StubUtility;
-import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving;
-import org.eclipse.jdt.internal.core.manipulation.util.Strings;
-import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
-import org.eclipse.jdt.internal.corext.dom.ASTNodes;
-import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
-import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
-import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
 import org.eclipse.jdt.internal.corext.dom.Selection;
 import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
-import org.eclipse.jdt.internal.corext.refactoring.Checks;
-import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
-import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
-import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
-
-import org.eclipse.jdt.internal.ui.text.correction.QuickAssistProcessor;
+import org.eclipse.jdt.internal.corext.fix.LinkedProposalModelCore;
 
 /**
  * Surround a set of statements with a try-with-resources block.
@@ -102,30 +33,10 @@
  * only consists of new assignments. In this case we can't move the
  * selected nodes (e.g. the declaration) into the try block.
  */
-public class SurroundWithTryWithResourcesRefactoring extends Refactoring {
-
-	public final String GROUP_EXC_TYPE= "exc_type"; //$NON-NLS-1$
-	public final String GROUP_EXC_NAME= "exc_name"; //$NON-NLS-1$
-	public final String GROUP_TRY_STATEMENT= "try_stmt"; //$NON-NLS-1$
-
-	private Selection fSelection;
-	private SurroundWithTryWithResourcesAnalyzer fAnalyzer;
-	private boolean fLeaveDirty;
-
-	private ICompilationUnit fCUnit;
-	private CompilationUnit fRootNode;
-	private ASTRewrite fRewriter;
-	private ImportRewrite fImportRewrite;
-	private CodeScopeBuilder.Scope fScope;
-	private ASTNode[] fSelectedNodes;
-	private List<ASTNode> fAutoClosableNodes;
-
-	private LinkedProposalModel fLinkedProposalModel;
+public class SurroundWithTryWithResourcesRefactoring extends SurroundWithTryWithResourcesRefactoringCore {
 
 	private SurroundWithTryWithResourcesRefactoring(ICompilationUnit cu, Selection selection) {
-		fCUnit= cu;
-		fSelection= selection;
-		fLeaveDirty= false;
+		super(cu, selection);
 	}
 
 	public static SurroundWithTryWithResourcesRefactoring create(ICompilationUnit cu, int offset, int length) {
@@ -136,560 +47,13 @@
 		return new SurroundWithTryWithResourcesRefactoring(cu, Selection.createFromStartLength(selection.getOffset(), selection.getLength()));
 	}
 
+	@Override
+	protected LinkedProposalModelCore createLinkedProposalModel() {
+		return new LinkedProposalModel();
+	}
+
 	public LinkedProposalModel getLinkedProposalModel() {
-		return fLinkedProposalModel;
+		return (LinkedProposalModel)getLinkedProposalModelCore();
 	}
 
-	public void setLeaveDirty(boolean leaveDirty) {
-		fLeaveDirty= leaveDirty;
-	}
-
-	public boolean stopExecution() {
-		if (fAnalyzer == null)
-			return true;
-		ITypeBinding[] exceptions= fAnalyzer.getExceptions(fAnalyzer.getSelection());
-		List<ASTNode> autoClosableNodes= fAnalyzer.getCoveredAutoClosableNodes();
-		return (exceptions == null || exceptions.length == 0) && (autoClosableNodes == null || autoClosableNodes.isEmpty());
-	}
-
-	/* non Java-doc
-	 * @see IRefactoring#getName()
-	 */
-	@Override
-	public String getName() {
-		return RefactoringCoreMessages.SurroundWithTryWithResourcesRefactoring_name;
-	}
-
-	public RefactoringStatus checkActivationBasics(CompilationUnit rootNode) throws CoreException {
-		RefactoringStatus result= new RefactoringStatus();
-		fRootNode= rootNode;
-
-		fAnalyzer= new SurroundWithTryWithResourcesAnalyzer(fCUnit, fSelection);
-		fRootNode.accept(fAnalyzer);
-		result.merge(fAnalyzer.getStatus());
-		fAutoClosableNodes= fAnalyzer.getCoveredAutoClosableNodes();
-		if (fAutoClosableNodes == null || fAutoClosableNodes.isEmpty()) {
-			result.merge(RefactoringStatus.createWarningStatus(RefactoringCoreMessages.SurroundWithTryWithResourcesRefactoring_notAutoclosable));
-		}
-		return result;
-	}
-
-
-	/*
-	 * @see Refactoring#checkActivation(IProgressMonitor)
-	 */
-	@Override
-	public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
-		CompilationUnit rootNode= new RefactoringASTParser(IASTSharedValues.SHARED_AST_LEVEL).parse(fCUnit, true, pm);
-		return checkActivationBasics(rootNode);
-	}
-
-	/*
-	 * @see Refactoring#checkInput(IProgressMonitor)
-	 */
-	@Override
-	public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
-		return Checks.validateModifiesFiles(
-			ResourceUtil.getFiles(new ICompilationUnit[]{fCUnit}),
-			getValidationContext(), pm);
-	}
-
-	/* non Java-doc
-	 * @see IRefactoring#createChange(IProgressMonitor)
-	 */
-	@Override
-	public Change createChange(IProgressMonitor pm) throws CoreException {
-		final String NN= ""; //$NON-NLS-1$
-		if (pm == null) pm= new NullProgressMonitor();
-		pm.beginTask(NN, 2);
-		try {
-			final CompilationUnitChange result= new CompilationUnitChange(getName(), fCUnit);
-			if (fLeaveDirty)
-				result.setSaveMode(TextFileChange.LEAVE_DIRTY);
-			MultiTextEdit root= new MultiTextEdit();
-			result.setEdit(root);
-			fRewriter= ASTRewrite.create(fAnalyzer.getEnclosingBodyDeclaration().getAST());
-			fImportRewrite= StubUtility.createImportRewrite(fRootNode, true);
-
-			fLinkedProposalModel= new LinkedProposalModel();
-
-			fScope= CodeScopeBuilder.perform(fAnalyzer.getEnclosingBodyDeclaration(), fSelection).
-				findScope(fSelection.getOffset(), fSelection.getLength());
-			fScope.setCursor(fSelection.getOffset());
-
-			fSelectedNodes= fAnalyzer.getSelectedNodes();
-
-			createTryWithResourcesStatement(fCUnit.getBuffer(), fCUnit.findRecommendedLineSeparator());
-
-			if (fImportRewrite.hasRecordedChanges()) {
-				TextEdit edit= fImportRewrite.rewriteImports(null);
-				root.addChild(edit);
-				result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {edit} ));
-			}
-			TextEdit change= fRewriter.rewriteAST();
-			root.addChild(change);
-			result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {change} ));
-			return result;
-		} finally {
-			pm.done();
-		}
-	}
-
-	private AST getAST() {
-		return fRootNode.getAST();
-	}
-
-	@SuppressWarnings("null")
-	private void createTryWithResourcesStatement(org.eclipse.jdt.core.IBuffer buffer, String lineDelimiter) throws CoreException {
-		List<Statement> result= new ArrayList<>(1);
-		boolean modifyExistingTry= false;
-		TryStatement tryStatement= null;
-		ITypeBinding[] exceptions= fAnalyzer.getExceptions(fAnalyzer.getSelection());
-		ImportRewriteContext context= new ContextSensitiveImportRewriteContext(fAnalyzer.getEnclosingBodyDeclaration(), fImportRewrite);
-
-		TryStatement enclosingTry= (TryStatement)ASTResolving.findAncestor(fSelectedNodes[0], ASTNode.TRY_STATEMENT);
-		ListRewrite resourcesRewriter= null;
-		ListRewrite clausesRewriter= null;
-		ListRewrite statements= null;
-		if (enclosingTry == null || enclosingTry.getBody() == null || enclosingTry.getBody().statements().get(0) != fSelectedNodes[0]) {
-			tryStatement= getAST().newTryStatement();
-			statements= fRewriter.getListRewrite(tryStatement.getBody(), Block.STATEMENTS_PROPERTY);
-		} else {
-			modifyExistingTry= true;
-			resourcesRewriter= fRewriter.getListRewrite(enclosingTry, TryStatement.RESOURCES2_PROPERTY);
-			clausesRewriter= fRewriter.getListRewrite(enclosingTry, TryStatement.CATCH_CLAUSES_PROPERTY);
-		}
-
-		CatchClause catchClause= getAST().newCatchClause();
-		SingleVariableDeclaration decl= getAST().newSingleVariableDeclaration();
-		String varName= StubUtility.getExceptionVariableName(fCUnit.getJavaProject());
-		String name= fScope.createName(varName, false);
-		decl.setName(getAST().newSimpleName(name));
-
-
-		boolean selectedNodeRemoved= false;
-		ASTNode expressionStatement= null;
-		ASTNode replacementNode= null;
-		List<ASTNode> nodesInRange= new ArrayList<>();
-
-		if (!modifyExistingTry) {
-			List<ASTNode> variableDeclarations= getSpecialVariableDeclarationStatements();
-			for (ASTNode node : fSelectedNodes) {
-				if (fAutoClosableNodes.contains(node)) {
-					continue;
-				}
-				if (node instanceof VariableDeclarationStatement && variableDeclarations.contains(node)) {
-					AST ast= getAST();
-					VariableDeclarationStatement statement= (VariableDeclarationStatement)node;
-					// Create a copy and remove the initializer
-					VariableDeclarationStatement copy= (VariableDeclarationStatement)ASTNode.copySubtree(ast, statement);
-					List<IExtendedModifier> modifiers= copy.modifiers();
-					for (Iterator<IExtendedModifier> iter= modifiers.iterator(); iter.hasNext();) {
-						IExtendedModifier modifier= iter.next();
-						if (modifier.isModifier() && Modifier.isFinal(((Modifier)modifier).getKeyword().toFlagValue())) {
-							iter.remove();
-						}
-					}
-					List<VariableDeclarationFragment> fragments= copy.fragments();
-					for (VariableDeclarationFragment fragment : fragments) {
-						fragment.setInitializer(null);
-					}
-
-					// "var" type cannot have null initializer, so change to inferred type
-					if (ASTNodes.isVarType(statement, fRootNode)) {
-						ITypeBinding binding= statement.getType().resolveBinding();
-						if (binding != null) {
-							Type varType= fImportRewrite.addImport(binding, getAST(), context, TypeLocation.LOCAL_VARIABLE);
-							copy.setType(varType);
-						}
-					}
-
-					CompilationUnit root= (CompilationUnit)statement.getRoot();
-					int extendedStart= root.getExtendedStartPosition(statement);
-					// we have a leading comment and the comment is covered by the selection
-					if (extendedStart != statement.getStartPosition() && extendedStart >= fSelection.getOffset()) {
-						String commentToken= buffer.getText(extendedStart, statement.getStartPosition() - extendedStart);
-						commentToken= Strings.trimTrailingTabsAndSpaces(commentToken);
-						Type type= statement.getType();
-						String typeName= buffer.getText(type.getStartPosition(), type.getLength());
-						copy.setType((Type)fRewriter.createStringPlaceholder(commentToken + typeName, type.getNodeType()));
-					}
-					result.add(copy);
-					// convert the fragments into expression statements
-					fragments= statement.fragments();
-					if (!fragments.isEmpty()) {
-						List<ExpressionStatement> newExpressionStatements= new ArrayList<>();
-						for (VariableDeclarationFragment fragment : fragments) {
-							Expression initializer= fragment.getInitializer();
-							if (initializer != null) {
-								Assignment assignment= ast.newAssignment();
-								assignment.setLeftHandSide((Expression)fRewriter.createCopyTarget(fragment.getName()));
-								assignment.setRightHandSide((Expression)fRewriter.createCopyTarget(initializer));
-								newExpressionStatements.add(ast.newExpressionStatement(assignment));
-							}
-						}
-						if (!newExpressionStatements.isEmpty()) {
-							if (fSelectedNodes.length == 1) {
-								expressionStatement= fRewriter.createGroupNode(newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()]));
-							} else {
-								fRewriter.replace(
-										statement,
-										fRewriter.createGroupNode(newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()])),
-										null);
-							}
-						} else {
-							fRewriter.remove(statement, null);
-							selectedNodeRemoved= true;
-						}
-					} else {
-						fRewriter.remove(statement, null);
-						selectedNodeRemoved= true;
-					}
-				}
-			}
-			result.add(tryStatement);
-			if (result.size() == 1) {
-				replacementNode= result.get(0);
-			} else {
-				replacementNode= fRewriter.createGroupNode(result.toArray(new ASTNode[result.size()]));
-			}
-
-			ASTNode node= fSelectedNodes[0];
-			List<ASTNode> coveredStatements= new ArrayList<>();
-			for (ASTNode coveredNode : fSelectedNodes) {
-				Statement statement= ASTResolving.findParentStatement(coveredNode);
-				if (statement == null) {
-					continue;
-				}
-				if (!coveredStatements.contains(statement)) {
-					coveredStatements.add(statement);
-				}
-			}
-
-			Selection nodesInRangeSelection= fAnalyzer.getSelection();
-			if (!fAutoClosableNodes.isEmpty()) {
-				ASTNode parentBodyDeclaration= ASTResolving.findParentBodyDeclaration(node);
-				int start= fAutoClosableNodes.get(0).getStartPosition();
-				ASTNode lastSelectedNode= fSelectedNodes[fSelectedNodes.length - 1];
-				int end= lastSelectedNode.getStartPosition() + lastSelectedNode.getLength();
-
-				for (ASTNode astNode : fAutoClosableNodes) {
-					int endPosition= findEndPosition(astNode);
-					end= Math.max(end, endPosition);
-				}
-
-				// recursive loop to find all nodes affected by wrapping in try block
-				nodesInRange= findNodesInRange(parentBodyDeclaration, start, end);
-				int oldEnd= end;
-				int newEnd= end;
-				while (true) {
-					newEnd= oldEnd;
-					for (ASTNode astNode : nodesInRange) {
-						int endPosition= findEndPosition(astNode);
-						newEnd= Math.max(newEnd, endPosition);
-					}
-					if (newEnd > oldEnd) {
-						oldEnd= newEnd;
-						nodesInRange= findNodesInRange(parentBodyDeclaration, start, newEnd);
-						continue;
-					}
-					break;
-				}
-				if (nodesInRange.size() > 0) {
-					// must recalculate exceptions as additional lines are now in try statement
-					ASTNode lastNode= nodesInRange.get(nodesInRange.size() - 1);
-					nodesInRangeSelection= Selection.createFromStartEnd(start, lastNode.getStartPosition() + lastNode.getLength());
-					exceptions= fAnalyzer.getExceptions(nodesInRangeSelection);
-				}
-				nodesInRange.removeAll(fAutoClosableNodes);
-				nodesInRange.removeAll(Arrays.asList(fSelectedNodes));
-			}
-		}
-
-		// add required resource statements
-		CompilationUnit cu= (CompilationUnit)fSelectedNodes[0].getRoot();
-		AST ast= fSelectedNodes[0].getAST();
-		Set<String> resourceNameList= new HashSet<>();
-		List<ITypeBinding> allExceptions= new ArrayList<>(Arrays.asList(exceptions));
-		for (ASTNode coveredNode : fAutoClosableNodes) {
-			ASTNode findAncestor= ASTResolving.findAncestor(coveredNode, ASTNode.VARIABLE_DECLARATION_STATEMENT);
-			if (findAncestor == null) {
-				findAncestor= ASTResolving.findAncestor(coveredNode, ASTNode.ASSIGNMENT);
-			}
-			if (findAncestor instanceof VariableDeclarationStatement) {
-				VariableDeclarationStatement vds= (VariableDeclarationStatement) findAncestor;
-				String commentToken= null;
-				int extendedStatementStart= cu.getExtendedStartPosition(vds);
-				if(vds.getStartPosition() > extendedStatementStart) {
-					commentToken= buffer.getText(extendedStatementStart, vds.getStartPosition() - extendedStatementStart);
-				}
-				Type type= vds.getType();
-				ITypeBinding typeBinding= type.resolveBinding();
-				if (typeBinding != null) {
-					IMethodBinding close= findAutocloseMethod(typeBinding);
-					if (close != null) {
-						for (ITypeBinding exceptionType : close.getExceptionTypes()) {
-							if (!allExceptions.contains(exceptionType)) {
-								allExceptions.add(exceptionType);
-							}
-						}
-					}
-				}
-				String typeName= buffer.getText(type.getStartPosition(), type.getLength());
-
-				for (Object object : vds.fragments()) {
-					VariableDeclarationFragment variableDeclarationFragment= (VariableDeclarationFragment) object;
-					VariableDeclarationFragment newVariableDeclarationFragment= ast.newVariableDeclarationFragment();
-					SimpleName vdsName= variableDeclarationFragment.getName();
-
-					if(commentToken == null) {
-						int extendedStart= cu.getExtendedStartPosition(variableDeclarationFragment);
-						commentToken= buffer.getText(extendedStart, variableDeclarationFragment.getStartPosition() - extendedStart);
-					}
-					commentToken= Strings.trimTrailingTabsAndSpaces(commentToken);
-					commentToken += commentToken.isEmpty() ? "" : " "; //$NON-NLS-1$ //$NON-NLS-2$
-
-					newVariableDeclarationFragment.setName(ast.newSimpleName(vdsName.getIdentifier()));
-					Expression newExpression= null;
-					Expression initializer= variableDeclarationFragment.getInitializer();
-					if (initializer == null) {
-						fRewriter.remove(coveredNode, null);
-						continue;
-					} else {
-						newExpression= (Expression) fRewriter.createMoveTarget(initializer);
-					}
-					resourceNameList.add(vdsName.getIdentifier());
-					newVariableDeclarationFragment.setInitializer(newExpression);
-					VariableDeclarationExpression newVariableDeclarationExpression= ast.newVariableDeclarationExpression(newVariableDeclarationFragment);
-					newVariableDeclarationExpression.setType(
-							(Type) fRewriter.createStringPlaceholder(commentToken + typeName, type.getNodeType()));
-					if (modifyExistingTry) {
-						if (enclosingTry.resources().isEmpty()) {
-							resourcesRewriter.insertFirst(newVariableDeclarationExpression, null);
-						} else {
-							resourcesRewriter.insertLast(newVariableDeclarationExpression, null);
-						}
-					} else {
-						tryStatement.resources().add(newVariableDeclarationExpression);
-					}
-					commentToken= null;
-				}
-//				String commentToken2= ""; //$NON-NLS-1$
-//				int extendedStart= cu.getExtendedStartPosition(vds);
-//				int extendedLength= cu.getExtendedLength(vds);
-//				int endCommentLength= extendedLength - (vds.getStartPosition() - extendedStart) - vds.getLength();
-//				if (endCommentLength > 0) {
-//					commentToken2= buffer.getText(vds.getStartPosition() + vds.getLength(),
-//							endCommentLength);
-//					commentToken2= Strings.trimLeadingTabsAndSpaces(commentToken2);
-//				}
-			}
-		}
-
-		List<ITypeBinding> mustRethrowList= new ArrayList<>();
-		List<ITypeBinding> catchExceptions= fAnalyzer.calculateCatchesAndRethrows(ASTNodes.filterSubtypes(allExceptions), mustRethrowList);
-		List<ITypeBinding> filteredExceptions= ASTNodes.filterSubtypes(catchExceptions);
-		if (catchExceptions.size() > 0) {
-			LinkedProposalModel linkedProposalModel= new LinkedProposalModel();
-			int i= 0;
-			if (!modifyExistingTry) {
-				for (ITypeBinding mustThrow : mustRethrowList) {
-					CatchClause newClause= ast.newCatchClause();
-					SingleVariableDeclaration newDecl= ast.newSingleVariableDeclaration();
-					newDecl.setName(ast.newSimpleName(name));
-					Type importType= fImportRewrite.addImport(mustThrow, ast, context, TypeLocation.EXCEPTION);
-					newDecl.setType(importType);
-					newClause.setException(newDecl);
-					ThrowStatement newThrowStatement= ast.newThrowStatement();
-					newThrowStatement.setExpression(ast.newSimpleName(name));
-					linkedProposalModel.getPositionGroup(GROUP_EXC_NAME + i, true).addPosition(fRewriter.track(decl.getName()), false);
-					newClause.getBody().statements().add(newThrowStatement);
-					tryStatement.catchClauses().add(newClause);
-					++i;
-				}
-			}
-			UnionType unionType= getAST().newUnionType();
-			List<Type> types= unionType.types();
-			for (ITypeBinding exception : filteredExceptions) {
-				Type type= fImportRewrite.addImport(exception, getAST(), context, TypeLocation.EXCEPTION);
-				types.add(type);
-				fLinkedProposalModel.getPositionGroup(GROUP_EXC_TYPE + i, true).addPosition(fRewriter.track(type), i == 0);
-				i++;
-			}
-
-			decl.setType(unionType);
-			catchClause.setException(decl);
-			fLinkedProposalModel.getPositionGroup(GROUP_EXC_NAME + 0, true).addPosition(fRewriter.track(decl.getName()), false);
-			Statement st= getCatchBody("Exception", name, lineDelimiter); //$NON-NLS-1$
-			if (st != null) {
-				catchClause.getBody().statements().add(st);
-			}
-			if (modifyExistingTry) {
-				clausesRewriter.insertLast(catchClause, null);
-			} else {
-				tryStatement.catchClauses().add(catchClause);
-			}
-		}
-
-
-		if (fSelectedNodes.length == 1 && fAutoClosableNodes.isEmpty()) {
-			ASTNode selectedNode= fSelectedNodes[0];
-
-			if (selectedNode instanceof MethodReference) {
-				MethodReference methodReference= (MethodReference) selectedNode;
-				IMethodBinding functionalMethod= QuickAssistProcessor.getFunctionalMethodForMethodReference(methodReference);
-				// functionalMethod is non-null and non-generic. See ExceptionAnalyzer.handleMethodReference(MethodReference node).
-				Assert.isTrue(functionalMethod != null && !functionalMethod.isGenericMethod());
-				LambdaExpression lambda= QuickAssistProcessor.convertMethodRefernceToLambda(methodReference, functionalMethod, fRootNode, fRewriter, null, true);
-				ASTNode statementInBlock= (ASTNode) ((Block) lambda.getBody()).statements().get(0);
-				fRewriter.replace(statementInBlock, replacementNode, null);
-				statements.insertLast(statementInBlock, null);
-				return;
-			}
-
-			LambdaExpression enclosingLambda= ASTResolving.findEnclosingLambdaExpression(selectedNode);
-			if (enclosingLambda != null && selectedNode.getLocationInParent() == LambdaExpression.BODY_PROPERTY && enclosingLambda.resolveMethodBinding() != null) {
-				QuickAssistProcessor.changeLambdaBodyToBlock(enclosingLambda, getAST(), fRewriter);
-				Block blockBody= (Block) fRewriter.get(enclosingLambda, LambdaExpression.BODY_PROPERTY);
-				ASTNode statementInBlock= (ASTNode) blockBody.statements().get(0);
-				fRewriter.replace(statementInBlock, replacementNode, null);
-				statements.insertLast(statementInBlock, null);
-				return;
-			}
-
-			if (expressionStatement != null) {
-				statements.insertLast(expressionStatement, null);
-			} else {
-				if (!selectedNodeRemoved)
-					statements.insertLast(fRewriter.createMoveTarget(selectedNode), null);
-			}
-			fRewriter.replace(selectedNode, replacementNode, null);
-		} else if (modifyExistingTry) {
-			ListRewrite source= fRewriter.getListRewrite(enclosingTry.getBody(), Block.STATEMENTS_PROPERTY);
-			for (ASTNode node : fAutoClosableNodes) {
-				source.remove(node, null);
-			}
-		} else {
-			ListRewrite source= fRewriter.getListRewrite(
-					fSelectedNodes[0].getParent(),
-					(ChildListPropertyDescriptor)fSelectedNodes[0].getLocationInParent());
-			List<ASTNode> nodes= new ArrayList<>(Arrays.asList(fSelectedNodes));
-			if (!nodesInRange.isEmpty()) {
-				nodes.addAll(nodesInRange);
-			}
-			int index= fAutoClosableNodes.size();
-			if (index < nodes.size()) {
-				ASTNode toMove= source.createMoveTarget(nodes.get(index), nodes.get(nodes.size() - 1),
-						index == 0 ? replacementNode : null, null);
-				statements.insertLast(toMove, null);
-			}
-			if (index > 0) {
-				source.replace(fAutoClosableNodes.get(0), replacementNode, null);
-				for (int i= 1; i < index; ++i) {
-					source.remove(fAutoClosableNodes.get(i), null);
-				}
-			}
-		}
-
-	}
-
-	public static IMethodBinding findAutocloseMethod(ITypeBinding type) {
-		while (type != null) {
-			IMethodBinding[] methods= type.getDeclaredMethods();
-			for (IMethodBinding method : methods) {
-				if ("close".equals(method.getName()) && method.getParameterTypes().length == 0) { //$NON-NLS-1$
-					return method;
-				}
-			}
-			type= type.getSuperclass();
-		}
-		return null;
-	}
-
-	private int findEndPosition(ASTNode node) {
-		int end= node.getStartPosition() + node.getLength();
-		Map<SimpleName, IVariableBinding> nodeSimpleNameBindings= fAnalyzer.getVariableStatementBinding(node);
-		List<SimpleName> nodeNames= new ArrayList<>(nodeSimpleNameBindings.keySet());
-		if (nodeNames.isEmpty()) {
-			return -1;
-		}
-		SimpleName nodeSimpleName= nodeNames.get(0);
-		SimpleName[] coveredNodeBindings= LinkedNodeFinder.findByNode(node.getRoot(), nodeSimpleName);
-		if (coveredNodeBindings.length == 0) {
-			return -1;
-		}
-		for (ASTNode astNode : coveredNodeBindings) {
-			end= Math.max(end, (astNode.getStartPosition() + astNode.getLength()));
-		}
-		return end;
-	}
-
-	// find all nodes (statements) that are within the start/end positions
-	public static List<ASTNode> findNodesInRange(ASTNode astNode, final int start, final int end) {
-		List<ASTNode> nodesInRange= new ArrayList<>();
-		astNode.accept(new ASTVisitor() {
-			int pre= start;
-
-			@Override
-			public void preVisit(ASTNode preNode) {
-				pre= preNode.getStartPosition();
-				super.preVisit(preNode);
-			}
-
-			@Override
-			public void postVisit(ASTNode postNode) {
-				int post= postNode.getStartPosition() + postNode.getLength();
-				if (pre >= start && post <= end) {
-					Statement statement= ASTResolving.findParentStatement(postNode);
-					loop: while (statement != null) {
-						if (statement.getParent() instanceof Statement) {
-							Statement pStatement= (Statement) statement.getParent();
-							switch (pStatement.getNodeType()) {
-								case ASTNode.BLOCK:
-									if (pStatement.getParent().getNodeType() != ASTNode.METHOD_DECLARATION &&
-									pStatement.getParent().getNodeType() != ASTNode.TRY_STATEMENT) {
-										statement= pStatement;
-										continue;
-									} else {
-										break loop;
-									}
-								case ASTNode.METHOD_DECLARATION:
-									break loop;
-								default:
-									break;
-							}
-							statement= pStatement;
-						} else {
-							break;
-						}
-					}
-					if (statement != null && !nodesInRange.contains(statement)) {
-						nodesInRange.add(statement);
-					}
-				}
-				super.postVisit(postNode);
-			}
-		});
-		return nodesInRange;
-	}
-
-	private List<ASTNode> getSpecialVariableDeclarationStatements() {
-		List<ASTNode> result= new ArrayList<>(3);
-		for (VariableDeclaration local : fAnalyzer.getAffectedLocals()) {
-			ASTNode parent= local.getParent();
-			if (parent instanceof VariableDeclarationStatement && !result.contains(parent))
-				result.add(parent);
-		}
-		return result;
-
-	}
-
-	private Statement getCatchBody(String type, String name, String lineSeparator) throws CoreException {
-		String s= StubUtility.getCatchBodyContent(fCUnit, type, name, fSelectedNodes[0], lineSeparator);
-		if (s == null) {
-			return null;
-		} else {
-			return (Statement)fRewriter.createStringPlaceholder(s, ASTNode.RETURN_STATEMENT);
-		}
-	}
-}
+}
\ No newline at end of file
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 04e35ef..dbd72e7 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
@@ -19,20 +19,18 @@
  *     Jeremie Bresson <dev@jmini.fr> - Bug 439912: [1.8][quick assist] Add quick assists to add and remove parentheses around single lambda parameter - https://bugs.eclipse.org/439912
  *     Jens Reimann <jens.reimann@ibh-systems.com>, Fabian Pfaff <fabian.pfaff@vogella.com> - Bug 197850: [quick assist] Add import static field/method - https://bugs.eclipse.org/bugs/show_bug.cgi?id=197850
  *     Pierre-Yves B. <pyvesdev@gmail.com> - [inline] Allow inlining of local variable initialized to null. - https://bugs.eclipse.org/93850
+ *     Red Hat Inc. - refactor some static methods to QuickAssistProcessorUtil class in jdt.core.manipulation
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.text.correction;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 
 import org.eclipse.swt.graphics.Image;
 
@@ -53,7 +51,6 @@
 import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaModelMarker;
 import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IMethod;
 import org.eclipse.jdt.core.IType;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
@@ -159,7 +156,6 @@
 import org.eclipse.jdt.internal.corext.dom.JdtASTMatcher;
 import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
 import org.eclipse.jdt.internal.corext.dom.ModifierRewrite;
-import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
 import org.eclipse.jdt.internal.corext.dom.Selection;
 import org.eclipse.jdt.internal.corext.dom.SelectionAnalyzer;
 import org.eclipse.jdt.internal.corext.dom.TokenScanner;
@@ -185,7 +181,7 @@
 import org.eclipse.jdt.internal.corext.refactoring.code.PromoteTempToFieldRefactoring;
 import org.eclipse.jdt.internal.corext.refactoring.structure.ImportRemover;
 import org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithTryWithResourcesAnalyzer;
-import org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithTryWithResourcesRefactoring;
+import org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithTryWithResourcesRefactoringCore;
 import org.eclipse.jdt.internal.corext.refactoring.util.TightSourceRangeComputer;
 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
 import org.eclipse.jdt.internal.corext.util.Messages;
@@ -711,7 +707,7 @@
 			return false;
 		}
 
-		IMethodBinding functionalMethod= getFunctionalMethodForMethodReference(methodReference);
+		IMethodBinding functionalMethod= QuickAssistProcessorUtil.getFunctionalMethodForMethodReference(methodReference);
 		if (functionalMethod == null || functionalMethod.isGenericMethod()) { // generic lambda expressions are not allowed
 			return false;
 		}
@@ -722,7 +718,7 @@
 		ASTRewrite rewrite= ASTRewrite.create(methodReference.getAST());
 		LinkedProposalModel linkedProposalModel= new LinkedProposalModel();
 
-		LambdaExpression lambda= convertMethodRefernceToLambda(methodReference, functionalMethod, context.getASTRoot(), rewrite, linkedProposalModel, false);
+		LambdaExpression lambda= QuickAssistProcessorUtil.convertMethodRefernceToLambda(methodReference, functionalMethod, context.getASTRoot(), rewrite, linkedProposalModel, false);
 
 		// add proposal
 		String label= CorrectionMessages.QuickAssistProcessor_convert_to_lambda_expression;
@@ -772,297 +768,6 @@
 		return true;
 	}
 
-	/**
-	 * Returns the functional interface method being implemented by the given method reference.
-	 *
-	 * @param methodReference the method reference to get the functional method
-	 * @return the functional interface method being implemented by <code>methodReference</code> or
-	 *         <code>null</code> if it could not be derived
-	 */
-	public static IMethodBinding getFunctionalMethodForMethodReference(MethodReference methodReference) {
-		ITypeBinding targetTypeBinding= ASTNodes.getTargetType(methodReference);
-		if (targetTypeBinding == null)
-			return null;
-
-		IMethodBinding functionalMethod= targetTypeBinding.getFunctionalInterfaceMethod();
-		if (functionalMethod != null && functionalMethod.isSynthetic()) {
-			functionalMethod= Bindings.findOverriddenMethodInType(functionalMethod.getDeclaringClass(), functionalMethod);
-		}
-		return functionalMethod;
-	}
-
-	/**
-	 * Converts and replaces the given method reference with corresponding lambda expression in the
-	 * given ASTRewrite.
-	 *
-	 * @param methodReference the method reference to convert
-	 * @param functionalMethod the non-generic functional interface method to be implemented by the
-	 *            lambda expression
-	 * @param astRoot the AST root
-	 * @param rewrite the ASTRewrite
-	 * @param linkedProposalModel to create linked proposals for lambda's parameters or
-	 *            <code>null</code> if linked proposals are not required
-	 * @param createBlockBody <code>true</code> if lambda expression's body should be a block
-	 *
-	 * @return lambda expression used to replace the method reference in the given ASTRewrite
-	 * @throws JavaModelException if an exception occurs while accessing the Java element
-	 *             corresponding to the <code>functionalMethod</code>
-	 */
-	public static LambdaExpression convertMethodRefernceToLambda(MethodReference methodReference, IMethodBinding functionalMethod, CompilationUnit astRoot,
-			ASTRewrite rewrite, LinkedProposalModel linkedProposalModel, boolean createBlockBody) throws JavaModelException {
-
-		AST ast= astRoot.getAST();
-		LambdaExpression lambda= ast.newLambdaExpression();
-
-		String[] lambdaParamNames= getUniqueParameterNames(methodReference, functionalMethod);
-		List<VariableDeclaration> lambdaParameters= lambda.parameters();
-		for (int i= 0; i < lambdaParamNames.length; i++) {
-			String paramName= lambdaParamNames[i];
-			VariableDeclarationFragment lambdaParameter= ast.newVariableDeclarationFragment();
-			SimpleName name= ast.newSimpleName(paramName);
-			lambdaParameter.setName(name);
-			lambdaParameters.add(lambdaParameter);
-			if (linkedProposalModel != null) {
-				linkedProposalModel.getPositionGroup(name.getIdentifier(), true).addPosition(rewrite.track(name), i == 0);
-			}
-		}
-
-		int noOfLambdaParameters= lambdaParamNames.length;
-		lambda.setParentheses(noOfLambdaParameters != 1);
-
-		ITypeBinding returnTypeBinding= functionalMethod.getReturnType();
-		IMethodBinding referredMethodBinding= methodReference.resolveMethodBinding(); // too often null, see bug 440000, bug 440344, bug 333665
-
-		if (methodReference instanceof CreationReference) {
-			CreationReference creationRef= (CreationReference) methodReference;
-			Type type= creationRef.getType();
-			if (type instanceof ArrayType) {
-				ArrayCreation arrayCreation= ast.newArrayCreation();
-				if (createBlockBody) {
-					Block blockBody= getBlockBodyForLambda(arrayCreation, returnTypeBinding, ast);
-					lambda.setBody(blockBody);
-				} else {
-					lambda.setBody(arrayCreation);
-				}
-
-				ArrayType arrayType= (ArrayType) type;
-				Type copiedElementType= (Type) rewrite.createCopyTarget(arrayType.getElementType());
-				arrayCreation.setType(ast.newArrayType(copiedElementType, arrayType.getDimensions()));
-				SimpleName name= ast.newSimpleName(lambdaParamNames[0]);
-				arrayCreation.dimensions().add(name);
-				if (linkedProposalModel != null) {
-					linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
-				}
-			} else {
-				ClassInstanceCreation cic= ast.newClassInstanceCreation();
-				if (createBlockBody) {
-					Block blockBody= getBlockBodyForLambda(cic, returnTypeBinding, ast);
-					lambda.setBody(blockBody);
-				} else {
-					lambda.setBody(cic);
-				}
-
-				ITypeBinding typeBinding= type.resolveBinding();
-				if (!(type instanceof ParameterizedType) && typeBinding != null && typeBinding.getTypeDeclaration().isGenericType()) {
-					cic.setType(ast.newParameterizedType((Type) rewrite.createCopyTarget(type)));
-				} else {
-					cic.setType((Type) rewrite.createCopyTarget(type));
-				}
-				List<SimpleName> invocationArgs= getInvocationArguments(ast, 0, noOfLambdaParameters, lambdaParamNames);
-				cic.arguments().addAll(invocationArgs);
-				if (linkedProposalModel != null) {
-					for (SimpleName name : invocationArgs) {
-						linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
-					}
-				}
-				cic.typeArguments().addAll(getCopiedTypeArguments(rewrite, methodReference.typeArguments()));
-			}
-
-		} else if (referredMethodBinding != null && Modifier.isStatic(referredMethodBinding.getModifiers())) {
-			MethodInvocation methodInvocation= ast.newMethodInvocation();
-			if (createBlockBody) {
-				Block blockBody= getBlockBodyForLambda(methodInvocation, returnTypeBinding, ast);
-				lambda.setBody(blockBody);
-			} else {
-				lambda.setBody(methodInvocation);
-			}
-
-			Expression expr= null;
-			boolean hasConflict= hasConflict(methodReference.getStartPosition(), referredMethodBinding, ScopeAnalyzer.METHODS | ScopeAnalyzer.CHECK_VISIBILITY, astRoot);
-			if (hasConflict || !Bindings.isSuperType(referredMethodBinding.getDeclaringClass(), ASTNodes.getEnclosingType(methodReference)) || methodReference.typeArguments().size() != 0) {
-				if (methodReference instanceof ExpressionMethodReference) {
-					ExpressionMethodReference expressionMethodReference= (ExpressionMethodReference) methodReference;
-					expr= (Expression) rewrite.createCopyTarget(expressionMethodReference.getExpression());
-				} else if (methodReference instanceof TypeMethodReference) {
-					Type type= ((TypeMethodReference) methodReference).getType();
-					ITypeBinding typeBinding= type.resolveBinding();
-					if (typeBinding != null) {
-						ImportRewrite importRewrite= StubUtility.createImportRewrite(astRoot, true);
-						expr= ast.newName(importRewrite.addImport(typeBinding));
-					}
-				}
-			}
-			methodInvocation.setExpression(expr);
-			SimpleName methodName= getMethodInvocationName(methodReference);
-			methodInvocation.setName((SimpleName) rewrite.createCopyTarget(methodName));
-			List<SimpleName> invocationArgs= getInvocationArguments(ast, 0, noOfLambdaParameters, lambdaParamNames);
-			methodInvocation.arguments().addAll(invocationArgs);
-			if (linkedProposalModel != null) {
-				for (SimpleName name : invocationArgs) {
-					linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
-				}
-			}
-			methodInvocation.typeArguments().addAll(getCopiedTypeArguments(rewrite, methodReference.typeArguments()));
-
-		} else if (methodReference instanceof SuperMethodReference) {
-			SuperMethodInvocation superMethodInvocation= ast.newSuperMethodInvocation();
-			if (createBlockBody) {
-				Block blockBody= getBlockBodyForLambda(superMethodInvocation, returnTypeBinding, ast);
-				lambda.setBody(blockBody);
-			} else {
-				lambda.setBody(superMethodInvocation);
-			}
-
-			Name superQualifier= ((SuperMethodReference) methodReference).getQualifier();
-			if (superQualifier != null) {
-				superMethodInvocation.setQualifier((Name) rewrite.createCopyTarget(superQualifier));
-			}
-			SimpleName methodName= getMethodInvocationName(methodReference);
-			superMethodInvocation.setName((SimpleName) rewrite.createCopyTarget(methodName));
-			List<SimpleName> invocationArgs= getInvocationArguments(ast, 0, noOfLambdaParameters, lambdaParamNames);
-			superMethodInvocation.arguments().addAll(invocationArgs);
-			if (linkedProposalModel != null) {
-				for (SimpleName name : invocationArgs) {
-					linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
-				}
-			}
-			superMethodInvocation.typeArguments().addAll(getCopiedTypeArguments(rewrite, methodReference.typeArguments()));
-
-		} else {
-			MethodInvocation methodInvocation= ast.newMethodInvocation();
-			if (createBlockBody) {
-				Block blockBody= getBlockBodyForLambda(methodInvocation, returnTypeBinding, ast);
-				lambda.setBody(blockBody);
-			} else {
-				lambda.setBody(methodInvocation);
-			}
-
-			boolean isTypeReference= isTypeReferenceToInstanceMethod(methodReference);
-			if (isTypeReference) {
-				SimpleName name= ast.newSimpleName(lambdaParamNames[0]);
-				methodInvocation.setExpression(name);
-				if (linkedProposalModel != null) {
-					linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
-				}
-			} else {
-				Expression expr= ((ExpressionMethodReference) methodReference).getExpression();
-				if (!(expr instanceof ThisExpression) || (methodReference.typeArguments().size() != 0)) {
-					methodInvocation.setExpression((Expression) rewrite.createCopyTarget(expr));
-				}
-			}
-			SimpleName methodName= getMethodInvocationName(methodReference);
-			methodInvocation.setName((SimpleName) rewrite.createCopyTarget(methodName));
-			List<SimpleName> invocationArgs= getInvocationArguments(ast, isTypeReference ? 1 : 0, noOfLambdaParameters, lambdaParamNames);
-			methodInvocation.arguments().addAll(invocationArgs);
-			if (linkedProposalModel != null) {
-				for (SimpleName name : invocationArgs) {
-					linkedProposalModel.getPositionGroup(name.getIdentifier(), false).addPosition(rewrite.track(name), LinkedPositionGroup.NO_STOP);
-				}
-			}
-			methodInvocation.typeArguments().addAll(getCopiedTypeArguments(rewrite, methodReference.typeArguments()));
-		}
-
-		rewrite.replace(methodReference, lambda, null);
-		return lambda;
-	}
-
-	private static boolean hasConflict(int startPosition, IMethodBinding referredMethodBinding, int flags, CompilationUnit cu) {
-		ScopeAnalyzer analyzer= new ScopeAnalyzer(cu);
-		for (IBinding decl : analyzer.getDeclarationsInScope(startPosition, flags)) {
-			if (decl.getName().equals(referredMethodBinding.getName()) && !referredMethodBinding.getMethodDeclaration().isEqualTo(decl))
-				return true;
-		}
-		return false;
-	}
-
-	private static String[] getUniqueParameterNames(MethodReference methodReference, IMethodBinding functionalMethod) throws JavaModelException {
-		String[] originalParameterNames= ((IMethod) functionalMethod.getJavaElement()).getParameterNames();
-		String[] newNames= new String[originalParameterNames.length];
-		Set<String> excludedNames= new HashSet<>(ASTNodes.getVisibleLocalVariablesInScope(methodReference));
-
-		for (int i= 0; i < originalParameterNames.length; i++) {
-			String paramName= originalParameterNames[i];
-
-			if (excludedNames.contains(paramName)) {
-				Set<String> allNamesToExclude= new HashSet<>(excludedNames);
-				Collections.addAll(allNamesToExclude, originalParameterNames);
-
-				String newParamName= createName(paramName, allNamesToExclude);
-
-				excludedNames.add(newParamName);
-				newNames[i]= newParamName;
-			} else {
-				newNames[i]= paramName;
-			}
-		}
-
-		return newNames;
-	}
-
-	private static String createName(final String nameRoot, final Set<String> excludedNames) {
-		int i= 1;
-		String candidate;
-
-		do {
-			candidate= nameRoot + i++;
-		} while (excludedNames.remove(candidate));
-
-		return candidate;
-	}
-
-	private static boolean isTypeReferenceToInstanceMethod(MethodReference methodReference) {
-		if (methodReference instanceof TypeMethodReference)
-			return true;
-		if (methodReference instanceof ExpressionMethodReference) {
-			Expression expression= ((ExpressionMethodReference) methodReference).getExpression();
-			if (expression instanceof Name) {
-				IBinding nameBinding= ((Name) expression).resolveBinding();
-				if (nameBinding instanceof ITypeBinding) {
-					return true;
-				}
-			}
-		}
-		return false;
-	}
-
-	private static List<SimpleName> getInvocationArguments(AST ast, int begIndex, int noOfLambdaParameters, String[] lambdaParamNames) {
-		List<SimpleName> args= new ArrayList<>();
-		for (int i= begIndex; i < noOfLambdaParameters; i++) {
-			args.add(ast.newSimpleName(lambdaParamNames[i]));
-		}
-		return args;
-	}
-
-	private static List<Type> getCopiedTypeArguments(ASTRewrite rewrite, List<Type> typeArguments) {
-		List<Type> copiedTypeArgs= new ArrayList<>();
-		for (Type typeArg : typeArguments) {
-			copiedTypeArgs.add((Type) rewrite.createCopyTarget(typeArg));
-		}
-		return copiedTypeArgs;
-	}
-
-	private static SimpleName getMethodInvocationName(MethodReference methodReference) {
-		SimpleName name= null;
-		if (methodReference instanceof ExpressionMethodReference) {
-			name= ((ExpressionMethodReference) methodReference).getName();
-		} else if (methodReference instanceof TypeMethodReference) {
-			name= ((TypeMethodReference) methodReference).getName();
-		} else if (methodReference instanceof SuperMethodReference) {
-			name= ((SuperMethodReference) methodReference).getName();
-		}
-		return name;
-	}
-
 	private static boolean getChangeLambdaBodyToBlockProposal(IInvocationContext context, ASTNode covering, Collection<ICommandAccess> resultingCollections) {
 		LambdaExpression lambda;
 		if (covering instanceof LambdaExpression) {
@@ -1084,7 +789,7 @@
 		AST ast= lambda.getAST();
 		ASTRewrite rewrite= ASTRewrite.create(ast);
 
-		changeLambdaBodyToBlock(lambda, ast, rewrite);
+		QuickAssistProcessorUtil.changeLambdaBodyToBlock(lambda, ast, rewrite);
 
 		// add proposal
 		String label= CorrectionMessages.QuickAssistProcessor_change_lambda_body_to_block;
@@ -1094,36 +799,6 @@
 		return true;
 	}
 
-	/**
-	 * Changes the expression body of the given lambda expression to block form.
-	 * {@link LambdaExpression#resolveMethodBinding()} should not be <code>null</code> for the given
-	 * lambda expression.
-	 *
-	 * @param lambda the lambda expression to convert the body form
-	 * @param ast the AST to create new nodes
-	 * @param rewrite the ASTRewrite
-	 */
-	public static void changeLambdaBodyToBlock(LambdaExpression lambda, AST ast, ASTRewrite rewrite) {
-		Expression bodyExpr= (Expression) rewrite.createMoveTarget(lambda.getBody());
-		Block blockBody= getBlockBodyForLambda(bodyExpr, lambda.resolveMethodBinding().getReturnType(), ast);
-		rewrite.set(lambda, LambdaExpression.BODY_PROPERTY, blockBody, null);
-	}
-
-	private static Block getBlockBodyForLambda(Expression bodyExpr, ITypeBinding returnTypeBinding, AST ast) {
-		Statement statementInBlockBody;
-		if (ast.resolveWellKnownType("void").isEqualTo(returnTypeBinding)) { //$NON-NLS-1$
-			ExpressionStatement expressionStatement= ast.newExpressionStatement(bodyExpr);
-			statementInBlockBody= expressionStatement;
-		} else {
-			ReturnStatement returnStatement= ast.newReturnStatement();
-			returnStatement.setExpression(bodyExpr);
-			statementInBlockBody= returnStatement;
-		}
-		Block blockBody= ast.newBlock();
-		blockBody.statements().add(statementInBlockBody);
-		return blockBody;
-	}
-
 	private static boolean getChangeLambdaBodyToExpressionProposal(IInvocationContext context, ASTNode covering, Collection<ICommandAccess> resultingCollections) {
 		LambdaExpression lambda;
 		if (covering instanceof LambdaExpression) {
@@ -1299,7 +974,7 @@
 				type= ((ParameterizedType) type).getType();
 			}
 			creationReference.setType((Type) rewrite.createCopyTarget(type));
-			creationReference.typeArguments().addAll(getCopiedTypeArguments(rewrite, cic.typeArguments()));
+			creationReference.typeArguments().addAll(QuickAssistProcessorUtil.getCopiedTypeArguments(rewrite, cic.typeArguments()));
 		} else if (exprBody instanceof ArrayCreation) {
 			CreationReference creationReference= ast.newCreationReference();
 			replacement= creationReference;
@@ -1320,7 +995,7 @@
 				importRewrite= StubUtility.createImportRewrite(context.getASTRoot(), true);
 				ITypeBinding invocationTypeBinding= ASTNodes.getInvocationType(superMethodInvocation, methodBinding, superQualifier);
 				typeMethodReference.setType(importRewrite.addImport(invocationTypeBinding.getTypeDeclaration(), ast));
-				typeMethodReference.typeArguments().addAll(getCopiedTypeArguments(rewrite, superMethodInvocation.typeArguments()));
+				typeMethodReference.typeArguments().addAll(QuickAssistProcessorUtil.getCopiedTypeArguments(rewrite, superMethodInvocation.typeArguments()));
 			} else {
 				SuperMethodReference superMethodReference= ast.newSuperMethodReference();
 				replacement= superMethodReference;
@@ -1329,7 +1004,7 @@
 					superMethodReference.setQualifier((Name) rewrite.createCopyTarget(superQualifier));
 				}
 				superMethodReference.setName((SimpleName) rewrite.createCopyTarget(superMethodInvocation.getName()));
-				superMethodReference.typeArguments().addAll(getCopiedTypeArguments(rewrite, superMethodInvocation.typeArguments()));
+				superMethodReference.typeArguments().addAll(QuickAssistProcessorUtil.getCopiedTypeArguments(rewrite, superMethodInvocation.typeArguments()));
 			}
 		} else { // MethodInvocation
 			MethodInvocation methodInvocation= (MethodInvocation) exprBody;
@@ -1349,7 +1024,7 @@
 				invocationTypeBinding= StubUtility2Core.replaceWildcardsAndCaptures(invocationTypeBinding);
 				ImportRewriteContext importRewriteContext= new ContextSensitiveImportRewriteContext(lambda, importRewrite);
 				typeMethodReference.setType(importRewrite.addImport(invocationTypeBinding, ast, importRewriteContext, TypeLocation.OTHER));
-				typeMethodReference.typeArguments().addAll(getCopiedTypeArguments(rewrite, methodInvocation.typeArguments()));
+				typeMethodReference.typeArguments().addAll(QuickAssistProcessorUtil.getCopiedTypeArguments(rewrite, methodInvocation.typeArguments()));
 
 			} else {
 				ExpressionMethodReference exprMethodReference= ast.newExpressionMethodReference();
@@ -1393,7 +1068,7 @@
 					}
 					exprMethodReference.setExpression(newThisExpression);
 				}
-				exprMethodReference.typeArguments().addAll(getCopiedTypeArguments(rewrite, methodInvocation.typeArguments()));
+				exprMethodReference.typeArguments().addAll(QuickAssistProcessorUtil.getCopiedTypeArguments(rewrite, methodInvocation.typeArguments()));
 			}
 		}
 
@@ -1876,7 +1551,7 @@
 		boolean addStaticModifier= false;
 		TypeDeclaration typeDeclaration= ASTNodes.getParent(methodReferenceNode, TypeDeclaration.class);
 
-		if (isTypeReferenceToInstanceMethod(methodReferenceNode)) {
+		if (QuickAssistProcessorUtil.isTypeReferenceToInstanceMethod(methodReferenceNode)) {
 			String methodReferenceQualifiedName= ((Name) methodReferenceNode.getExpression()).getFullyQualifiedName();
 			String typeDeclarationName= astRoot.getPackage().getName().getFullyQualifiedName() + '.' + typeDeclaration.getName().getFullyQualifiedName();
 			if (!methodReferenceQualifiedName.equals(typeDeclarationName)
@@ -3418,7 +3093,7 @@
 		}
 
 		// recursive loop to find all nodes affected by wrapping in try block
-		List<ASTNode> nodesInRange= SurroundWithTryWithResourcesRefactoring.findNodesInRange(parentBodyDeclaration, start, end);
+		List<ASTNode> nodesInRange= SurroundWithTryWithResourcesRefactoringCore.findNodesInRange(parentBodyDeclaration, start, end);
 		int oldEnd= end;
 		while (true) {
 			int newEnd= oldEnd;
@@ -3428,7 +3103,7 @@
 			}
 			if (newEnd > oldEnd) {
 				oldEnd= newEnd;
-				nodesInRange= SurroundWithTryWithResourcesRefactoring.findNodesInRange(parentBodyDeclaration, start, newEnd);
+				nodesInRange= SurroundWithTryWithResourcesRefactoringCore.findNodesInRange(parentBodyDeclaration, start, newEnd);
 				continue;
 			}
 			break;
@@ -3478,7 +3153,7 @@
 				Type type= vds.getType();
 				ITypeBinding typeBinding= type.resolveBinding();
 				if (typeBinding != null) {
-					IMethodBinding close= SurroundWithTryWithResourcesRefactoring.findAutocloseMethod(typeBinding);
+					IMethodBinding close= SurroundWithTryWithResourcesRefactoringCore.findAutocloseMethod(typeBinding);
 					if (close != null) {
 						for (ITypeBinding exceptionType : close.getExceptionTypes()) {
 							if (!allExceptions.contains(exceptionType)) {
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/AssignToVariableAssistProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/AssignToVariableAssistProposal.java
index 0e4ed20..b8a3148 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/AssignToVariableAssistProposal.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/AssignToVariableAssistProposal.java
@@ -86,7 +86,7 @@
 import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
 import org.eclipse.jdt.internal.corext.refactoring.surround.ExceptionAnalyzer;
 import org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithTryWithResourcesAnalyzer;
-import org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithTryWithResourcesRefactoring;
+import org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithTryWithResourcesRefactoringCore;
 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
 import org.eclipse.jdt.internal.corext.util.Messages;
 
@@ -291,7 +291,7 @@
 			List<ITypeBinding> mustRethrowList= new ArrayList<>();
 
 			if (fTypeBinding != null) {
-				IMethodBinding close= SurroundWithTryWithResourcesRefactoring.findAutocloseMethod(fTypeBinding);
+				IMethodBinding close= SurroundWithTryWithResourcesRefactoringCore.findAutocloseMethod(fTypeBinding);
 				if (close != null) {
 					for (ITypeBinding exceptionType : close.getExceptionTypes()) {
 						if (!allExceptions.contains(exceptionType)) {