Merge remote-tracking branch 'origin/master' into BETA_JAVA16 after M3

Conflicts:
	org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceTestCase14.java

Change-Id: I905af9738941d6bb5918daeb7d05300702fa8ec2
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/InvertEqualsCleanUpCore.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/InvertEqualsCleanUpCore.java
new file mode 100644
index 0000000..913c43b
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/InvertEqualsCleanUpCore.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.manipulation.CleanUpContextCore;
+import org.eclipse.jdt.core.manipulation.CleanUpRequirementsCore;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
+import org.eclipse.jdt.internal.corext.fix.InvertEqualsFixCore;
+
+public class InvertEqualsCleanUpCore extends AbstractCleanUpCore {
+	public InvertEqualsCleanUpCore(final Map<String, String> options) {
+		super(options);
+	}
+
+	public InvertEqualsCleanUpCore() {
+	}
+
+	@Override
+	public CleanUpRequirementsCore getRequirementsCore() {
+		return new CleanUpRequirementsCore(requireAST(), false, false, null);
+	}
+
+	public boolean requireAST() {
+		return isEnabled(CleanUpConstants.INVERT_EQUALS);
+	}
+
+	@Override
+	public ICleanUpFixCore createFixCore(final CleanUpContextCore context) throws CoreException {
+		CompilationUnit compilationUnit= context.getAST();
+
+		if (compilationUnit == null || !isEnabled(CleanUpConstants.INVERT_EQUALS)) {
+			return null;
+		}
+
+		return InvertEqualsFixCore.createCleanUp(compilationUnit);
+	}
+
+	@Override
+	public String[] getStepDescriptions() {
+		List<String> result= new ArrayList<>();
+
+		if (isEnabled(CleanUpConstants.INVERT_EQUALS)) {
+			result.add(MultiFixMessages.InvertEqualsCleanUp_description);
+		}
+
+		return result.toArray(new String[0]);
+	}
+
+	@Override
+	public String getPreview() {
+		if (isEnabled(CleanUpConstants.INVERT_EQUALS)) {
+			return "" //$NON-NLS-1$
+					+ "boolean result = \"foo\".equals(text);\n" //$NON-NLS-1$
+					+ "boolean result2 = (text1 + text2).equals(text);\n" //$NON-NLS-1$
+					+ "boolean result3 = DayOfWeek.MONDAY.equals(object);\n" //$NON-NLS-1$
+					+ "boolean result4 = \"foo\".equalsIgnoreCase(text);\n"; //$NON-NLS-1$
+		}
+
+		return "" //$NON-NLS-1$
+				+ "boolean result = text.equals(\"foo\");\n" //$NON-NLS-1$
+				+ "boolean result2 = text.equals(text1 + text2);\n" //$NON-NLS-1$
+				+ "boolean result3 = object.equals(DayOfWeek.MONDAY);\n" //$NON-NLS-1$
+				+ "boolean result4 = text.equalsIgnoreCase(\"foo\");\n"; //$NON-NLS-1$
+	}
+}
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java
index 2ed3b55..226520f 100644
--- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java
@@ -131,6 +131,7 @@
 	public static String BreakLoopCleanUp_description;
 	public static String StaticInnerClassCleanUp_description;
 	public static String StringBuilderCleanUp_description;
+	public static String PlainReplacementCleanUp_description;
 	public static String CodeStyleCleanUp_LazyLogical_description;
 	public static String PrimitiveComparisonCleanUp_description;
 	public static String PrimitiveParsingCleanUp_description;
@@ -171,6 +172,7 @@
 	public static String AddAllCleanup_description;
 	public static String ObjectsEqualsCleanup_description;
 
+	public static String InvertEqualsCleanUp_description;
 	public static String CheckSignOfBitwiseOperation_description;
 	public static String StandardComparisonCleanUp_description;
 
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties
index 8863cac..b339d0a 100644
--- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties
@@ -113,6 +113,7 @@
 BreakLoopCleanUp_description=Exit loop earlier
 StaticInnerClassCleanUp_description=Make inner classes static where possible
 StringBuilderCleanUp_description=Replace String concatenation by StringBuilder
+PlainReplacementCleanUp_description=Use String::replace instead of String::replaceAll when no regex used
 CodeStyleCleanUp_LazyLogical_description=Use lazy logical operator (&& and ||)
 PrimitiveComparisonCleanUp_description=Primitive comparison
 PrimitiveParsingCleanUp_description=Primitive parsing
@@ -152,6 +153,8 @@
 UnloopedWhileCleanUp_description=Convert loop into if
 AddAllCleanup_description=Add elements in collections without loop
 ObjectsEqualsCleanup_description=Use Objects.equals() in the equals method implementation
+
+InvertEqualsCleanUp_description=Avoid Object::equals or String::equalsIgnoreCase on null objects
 CheckSignOfBitwiseOperation_description=Use != 0 instead of > 0 when comparing the result of a bitwise expression
 StandardComparisonCleanUp_description=Compare to zero
 SwitchExpressionsCleanUp_ConvertToSwitchExpressions_description=Convert to switch expression where possible
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/PlainReplacementCleanUpCore.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/PlainReplacementCleanUpCore.java
new file mode 100644
index 0000000..181cbd4
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/PlainReplacementCleanUpCore.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.manipulation.CleanUpContextCore;
+import org.eclipse.jdt.core.manipulation.CleanUpRequirementsCore;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
+import org.eclipse.jdt.internal.corext.fix.PlainReplacementFixCore;
+
+public class PlainReplacementCleanUpCore extends AbstractCleanUpCore {
+	public PlainReplacementCleanUpCore(final Map<String, String> options) {
+		super(options);
+	}
+
+	public PlainReplacementCleanUpCore() {
+	}
+
+	@Override
+	public CleanUpRequirementsCore getRequirementsCore() {
+		return new CleanUpRequirementsCore(requireAST(), false, false, null);
+	}
+
+	public boolean requireAST() {
+		return isEnabled(CleanUpConstants.PLAIN_REPLACEMENT);
+	}
+
+	@Override
+	public ICleanUpFixCore createFixCore(final CleanUpContextCore context) throws CoreException {
+		CompilationUnit compilationUnit= context.getAST();
+
+		if (compilationUnit == null || !isEnabled(CleanUpConstants.PLAIN_REPLACEMENT)) {
+			return null;
+		}
+
+		return PlainReplacementFixCore.createCleanUp(compilationUnit);
+	}
+
+	@Override
+	public String[] getStepDescriptions() {
+		List<String> result= new ArrayList<>();
+
+		if (isEnabled(CleanUpConstants.PLAIN_REPLACEMENT)) {
+			result.add(MultiFixMessages.PlainReplacementCleanUp_description);
+		}
+
+		return result.toArray(new String[0]);
+	}
+
+	@Override
+	public String getPreview() {
+		if (isEnabled(CleanUpConstants.PLAIN_REPLACEMENT)) {
+			return "" //$NON-NLS-1$
+					+ "String result = text.replace(\"foo\", \"bar\");\n" //$NON-NLS-1$
+					+ "String result2 = text.replace(\"&\", \"&amp;\");\n" //$NON-NLS-1$
+					+ "String result3 = text.replaceAll(\"[ab]\", \"c\");\n" //$NON-NLS-1$
+					+ "String result4 = text.replaceAll(\"\\s\". \"\");\n"; //$NON-NLS-1$
+		}
+
+		return "" //$NON-NLS-1$
+				+ "String result = text.replaceAll(\"foo\", \"bar\");\n" //$NON-NLS-1$
+				+ "String result2 = text.replaceAll(\"&\", \"&amp;\");\n" //$NON-NLS-1$
+				+ "String result3 = text.replaceAll(\"[ab]\", \"c\");\n" //$NON-NLS-1$
+				+ "String result4 = text.replaceAll(\"\\s\". \"\");\n"; //$NON-NLS-1$
+	}
+}
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/preferences/JavaPreferencesSettings.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/preferences/JavaPreferencesSettings.java
index 1606667..8b119b6 100644
--- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/preferences/JavaPreferencesSettings.java
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/preferences/JavaPreferencesSettings.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -11,9 +11,11 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Red Hat Inc. - moved to jdt.core.manipulation and modified
+ *     Microsoft Corporation - add helper method to read preferences from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.preferences;
 
+import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.manipulation.JavaManipulation;
 
@@ -34,6 +36,28 @@
 		return res;
 	}
 
+	public static CodeGenerationSettings getCodeGenerationSettings(ICompilationUnit cu) {
+		CodeGenerationSettings res= new CodeGenerationSettings();
+		res.createComments= Boolean.parseBoolean(getPreference(CodeGenerationSettingsConstants.CODEGEN_ADD_COMMENTS, cu));
+		res.useKeywordThis= Boolean.parseBoolean(getPreference(CodeGenerationSettingsConstants.CODEGEN_KEYWORD_THIS, cu));
+		res.overrideAnnotation= Boolean.parseBoolean(getPreference(CodeGenerationSettingsConstants.CODEGEN_USE_OVERRIDE_ANNOTATION, cu));
+		res.importIgnoreLowercase= Boolean.parseBoolean(getPreference(CodeGenerationSettingsConstants.ORGIMPORTS_IGNORELOWERCASE, cu));
+		res.tabWidth= CodeFormatterUtil.getTabWidth(cu);
+		res.indentWidth= CodeFormatterUtil.getIndentWidth(cu);
+		return res;
+	}
+
+	private static String getPreference(String key, ICompilationUnit cu) {
+		if (cu != null) {
+			String val= cu.getCustomOptions().getOrDefault(key, null);
+			if (val != null) {
+				return val;
+			}
+			return JavaManipulation.getPreference(key, cu.getJavaProject());
+		}
+		return JavaManipulation.getPreference(key, null);
+	}
+
 	private JavaPreferencesSettings() {
 	}
 
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/util/Strings.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/util/Strings.java
index 1852cf6..62f131d 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/util/Strings.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/util/Strings.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 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
+ *     Microsoft Corporation - add helper methods to read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.core.manipulation.util;
 
@@ -22,6 +23,7 @@
 import org.eclipse.jface.text.ILineTracker;
 import org.eclipse.jface.text.IRegion;
 
+import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.formatter.IndentManipulation;
 
@@ -240,6 +242,18 @@
 	 * are not counted.
 	 *
 	 * @param line the text line
+	 * @param cu the compilation unit from which to get the formatter preferences
+	 * @return the number of indent units
+	 */
+	public static int computeIndentUnits(String line, ICompilationUnit cu) {
+		return IndentManipulation.measureIndentUnits(line, CodeFormatterUtil.getTabWidth(cu), CodeFormatterUtil.getIndentWidth(cu));
+	}
+
+	/**
+	 * Returns the indent of the given string in indentation units. Odd spaces
+	 * are not counted.
+	 *
+	 * @param line the text line
 	 * @param tabWidth the width of the '\t' character in space equivalents
 	 * @param indentWidth the width of one indentation unit in space equivalents
 	 * @return the indent of the given string in indentation units
@@ -285,6 +299,20 @@
 	 * Removes the given number of indents from the line. Asserts that the given line
 	 * has the requested number of indents. If <code>indentsToRemove <= 0</code>
 	 * the line is returned.
+	 *
+	 * @param line the line
+	 * @param indentsToRemove the indents to remove
+	 * @param cu the compilation unit from which to get the formatter preferences
+	 * @return the trimmed line
+	 */
+	public static String trimIndent(String line, int indentsToRemove, ICompilationUnit cu) {
+		return IndentManipulation.trimIndent(line, indentsToRemove, CodeFormatterUtil.getTabWidth(cu), CodeFormatterUtil.getIndentWidth(cu));
+	}
+
+	/**
+	 * Removes the given number of indents from the line. Asserts that the given line
+	 * has the requested number of indents. If <code>indentsToRemove <= 0</code>
+	 * the line is returned.
 	 * @param line the line
 	 * @param indentsToRemove the indents to remove
 	 * @param tabWidth the tab width
@@ -309,6 +337,7 @@
 	public static void trimIndentation(String[] lines, IJavaProject project) {
 		trimIndentation(lines, CodeFormatterUtil.getTabWidth(project), CodeFormatterUtil.getIndentWidth(project), true);
 	}
+
 	/**
 	 * Removes the common number of indents from all lines. If a line
 	 * only consists out of white space it is ignored.
@@ -341,6 +370,19 @@
 	 * Removes the common number of indents from all lines. If a line
 	 * only consists out of white space it is ignored. If <code>
 	 * considerFirstLine</code> is false the first line will be ignored.
+	 *
+	 * @param lines the lines
+	 * @param cu the compilation unit from which to get the formatter preferences
+	 * @param considerFirstLine  If <code>considerFirstLine</code> is false the first line will be ignored.
+	 */
+	public static void trimIndentation(String[] lines, ICompilationUnit cu, boolean considerFirstLine) {
+		trimIndentation(lines, CodeFormatterUtil.getTabWidth(cu), CodeFormatterUtil.getIndentWidth(cu), considerFirstLine);
+	}
+
+	/**
+	 * Removes the common number of indents from all lines. If a line
+	 * only consists out of white space it is ignored. If <code>
+	 * considerFirstLine</code> is false the first line will be ignored.
 	 * @param lines the lines
 	 * @param tabWidth the size of one tab in space equivalents
 	 * @param indentWidth the size of the indent in space equivalents
@@ -399,6 +441,18 @@
 	 * a multiple of indentation units.
 	 *
 	 * @param line the line to scan
+	 * @param cu the compilation unit from which to get the formatter preferences
+	 * @return the indent part of <code>line</code>, but no odd spaces
+	 */
+	public static String getIndentString(String line, ICompilationUnit cu) {
+		return IndentManipulation.extractIndentString(line, CodeFormatterUtil.getTabWidth(cu), CodeFormatterUtil.getIndentWidth(cu));
+	}
+
+	/**
+	 * Returns that part of the indentation of <code>line</code> that makes up
+	 * a multiple of indentation units.
+	 *
+	 * @param line the line to scan
 	 * @param tabWidth the size of one tab in space equivalents
 	 * @param indentWidth the size of the indent in space equivalents
 	 * @return the indent part of <code>line</code>, but no odd spaces
@@ -442,6 +496,22 @@
 	}
 
 	/**
+	 * Change the indent of, possible multi-line, code range. The current indent is removed, a new indent added.
+	 * The first line of the code will not be changed. (It is considered to have no indent as it might start in
+	 * the middle of a line)
+	 *
+	 * @param code the code
+	 * @param codeIndentLevel level of indentation
+	 * @param cu the compilation unit from which to get the formatter preferences
+	 * @param newIndent new indent
+	 * @param lineDelim line delimiter
+	 * @return the changed code
+	 */
+	public static String changeIndent(String code, int codeIndentLevel, ICompilationUnit cu, String newIndent, String lineDelim) {
+		return IndentManipulation.changeIndent(code, codeIndentLevel, CodeFormatterUtil.getTabWidth(cu), CodeFormatterUtil.getIndentWidth(cu), newIndent, lineDelim);
+	}
+
+	/**
 	 * Change the indent of, possible muti-line, code range. The current indent is removed, a new indent added.
 	 * The first line of the code will not be changed. (It is considered to have no indent as it might start in
 	 * the middle of a line)
@@ -462,6 +532,10 @@
 		return trimIndentation(source, CodeFormatterUtil.getTabWidth(project), CodeFormatterUtil.getIndentWidth(project), considerFirstLine);
 	}
 
+	public static String trimIndentation(String source, ICompilationUnit cu, boolean considerFirstLine) {
+		return trimIndentation(source, CodeFormatterUtil.getTabWidth(cu), CodeFormatterUtil.getIndentWidth(cu), considerFirstLine);
+	}
+
 	public static String trimIndentation(String source, int tabWidth, int indentWidth, boolean considerFirstLine) {
 		try {
 			ILineTracker tracker= new DefaultLineTracker();
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddUnimplementedConstructorsOperation.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddUnimplementedConstructorsOperation.java
index 54705d5..7d4bc65 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddUnimplementedConstructorsOperation.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddUnimplementedConstructorsOperation.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
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Microsoft Corporation - refactored to jdt.core.manipulation
+ *     Microsoft Corporation - read preferences from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.codemanipulation;
 
@@ -236,7 +237,7 @@
 				// not possible, we checked this in the constructor
 			}
 
-			final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu.getJavaProject());
+			final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu);
 			settings.createComments= fCreateComments;
 
 			ASTNode insertion= getNodeToInsertBefore(memberRewriter);
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility2Core.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility2Core.java
index 178019f..970f7cb 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility2Core.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/codemanipulation/StubUtility2Core.java
@@ -12,6 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Red Hat Inc. - copied and pared down to methods needed by jdt.core.manipulation
  *     Microsoft Corporation - copied methods needed by jdt.core.manipulation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.codemanipulation;
 
@@ -119,7 +120,7 @@
 				varDecl= iterator.next();
 				invocation.arguments().add(ast.newSimpleName(varDecl.getName().getIdentifier()));
 			}
-			bodyStatement= ASTNodes.asFormattedString(invocation, 0, delimiter, formatSettings == null ? unit.getJavaProject().getOptions(true) : formatSettings);
+			bodyStatement= ASTNodes.asFormattedString(invocation, 0, delimiter, formatSettings == null ? unit.getOptions(true) : formatSettings);
 		}
 
 		if (todo) {
@@ -353,7 +354,7 @@
 		if (!inInterface || (declaringType != typeObject && JavaModelUtil.is1d8OrHigher(javaProject))) {
 			// generate a method body
 
-			Map<String, String> options= javaProject.getOptions(true);
+			Map<String, String> options= unit.getOptions(true);
 
 			Block body= ast.newBlock();
 			decl.setBody(body);
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java
index 45efba7..715d888 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java
@@ -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
@@ -30,6 +30,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -501,6 +502,26 @@
 		return ((ArrayType)type).getElementType();
 	}
 
+	/**
+	 * Filter a list of type bindings to remove any bindings that are sub-classes of others already in the list
+	 *
+	 * @param typeBindings - list of ITypeBinding to filter
+	 * @return updated list of ITypeBinding
+	 */
+	public static List<ITypeBinding> filterSubtypes(List<ITypeBinding> typeBindings) {
+		List<ITypeBinding> filteredBindings= new ArrayList<>(typeBindings);
+		for (Iterator<ITypeBinding> subtypeIterator= filteredBindings.iterator(); subtypeIterator.hasNext();) {
+			ITypeBinding iTypeBinding= subtypeIterator.next();
+			for (ITypeBinding superTypeBinding : filteredBindings) {
+				if (!iTypeBinding.equals(superTypeBinding) && iTypeBinding.isSubTypeCompatible(superTypeBinding)) {
+					subtypeIterator.remove();
+					break;
+				}
+			}
+		}
+		return filteredBindings;
+	}
+
 	public static ASTNode findDeclaration(IBinding binding, ASTNode root) {
 		root= root.getRoot();
 		if (root instanceof CompilationUnit) {
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AddUnimplementedMethodsOperation.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AddUnimplementedMethodsOperation.java
index cd59475..54ffc1a 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AddUnimplementedMethodsOperation.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/AddUnimplementedMethodsOperation.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
@@ -13,6 +13,7 @@
  *     Mateusz Wenus <mateusz.wenus@gmail.com> - [override method] generate in declaration order [code generation] - https://bugs.eclipse.org/bugs/show_bug.cgi?id=140971
  *     Stephan Herrmann - Contribution for Bug 463360 - [override method][null] generating method override should not create redundant null annotations
  *     Red Hat Inc. - moved to jdt.core.manipulation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 
 package org.eclipse.jdt.internal.corext.fix;
@@ -74,7 +75,7 @@
 		ImportRewriteContext context= new ContextSensitiveImportRewriteContext(fTypeNode, cuRewrite.getImportRewrite());
 		ASTRewrite rewrite= cuRewrite.getASTRewrite();
 		ICompilationUnit unit= cuRewrite.getCu();
-		CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(unit.getJavaProject());
+		CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(unit);
 
 		ListRewrite listRewrite;
 
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java
index 6e8b13c..820f743 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java
@@ -970,6 +970,18 @@
 	public static final String PRECOMPILE_REGEX= "cleanup.precompile_regex"; //$NON-NLS-1$
 
 	/**
+	 * Invert calls to <code>Object.equals(Object)</code> and <code>String.equalsIgnoreCase(String)</code> when it is known that the second operand is not null and the first can be null.
+	 * <p>
+	 * Possible values: {TRUE, FALSE}
+	 * <p>
+	 *
+	 * @see CleanUpOptionsCore#TRUE
+	 * @see CleanUpOptionsCore#FALSE
+	 * @since 4.19
+	 */
+	public static final String INVERT_EQUALS= "cleanup.invert_equals"; //$NON-NLS-1$
+
+	/**
 	 * Check for sign of bitwise operation.
 	 * <p>
 	 * Possible values: {TRUE, FALSE}
@@ -1083,6 +1095,18 @@
 	public static final String STRINGBUILDER= "cleanup.stringbuilder"; //$NON-NLS-1$
 
 	/**
+	 * Replaces <code>String.replaceAll()</code> by <code>String.replace()</code>.
+	 * <p>
+	 * Possible values: {TRUE, FALSE}
+	 * <p>
+	 *
+	 * @see CleanUpOptionsCore#TRUE
+	 * @see CleanUpOptionsCore#FALSE
+	 * @since 4.19
+	 */
+	public static final String PLAIN_REPLACEMENT= "cleanup.plain_replacement"; //$NON-NLS-1$
+
+	/**
 	 * Removes unused imports. <br>
 	 * <br>
 	 * Possible values: {TRUE, FALSE}<br>
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java
index 8c2070f..518a44e 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java
@@ -115,6 +115,8 @@
 	public static String CodeStyleFix_ChangeAccessUsingDeclaring_description;
 	public static String CodeStyleFix_QualifyMethodWithDeclClass_description;
 	public static String CodeStyleFix_QualifyFieldWithDeclClass_description;
+
+	public static String InvertEqualsFix_invert;
 	public static String StandardComparisonFix_compare_to_zero;
 
 	public static String SerialVersion_group_description;
@@ -131,6 +133,8 @@
 	public static String VariableDeclarationFix_changeModifierOfUnknownToFinal_description;
 	public static String VariableDeclarationFix_ChangeMidifiersToFinalWherPossible_description;
 
+	public static String PlainReplacementFix_use_plain_text;
+
 	public static String NullAnnotationsFix_add_annotation_change_name;
 	public static String NullAnnotationsRewriteOperations_change_method_parameter_nullness;
 	public static String NullAnnotationsRewriteOperations_change_target_method_parameter_nullness;
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties
index 7cafc29..3366950 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties
@@ -78,6 +78,8 @@
 CodeStyleFix_QualifyMethodWithDeclClass_description=Qualify method call with declaring type
 CodeStyleFix_QualifyFieldWithDeclClass_description=Qualify field access with declaring type
 CodeStyleFix_removeThis_groupDescription=Remove 'this' qualifier
+
+InvertEqualsFix_invert=Avoid Object::equals or String::equalsIgnoreCase on null objects
 StandardComparisonFix_compare_to_zero=Compare to zero
 CodeStyleFix_ChangeAccessToStaticUsingInstanceType_description=Change access to static using ''{0}'' (instance type)
 
@@ -118,6 +120,8 @@
 SortMembersFix_Change_description=Sort Members
 SortMembersFix_Fix_description=Sort Members
 
+PlainReplacementFix_use_plain_text=Use String::replace instead of String::replaceAll when no regex used
+
 NullAnnotationsFix_add_annotation_change_name=Add Annotations
 NullAnnotationsRewriteOperations_change_method_parameter_nullness=Change parameter ''{0}'' to ''@{1}''
 NullAnnotationsRewriteOperations_change_target_method_parameter_nullness=Change parameter of ''{0}(..)'' to ''@{1}''
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/InvertEqualsFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/InvertEqualsFixCore.java
new file mode 100644
index 0000000..a80bcb9
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/InvertEqualsFixCore.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.corext.fix;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.text.edits.TextEditGroup;
+
+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.CompilationUnit;
+import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IVariableBinding;
+import org.eclipse.jdt.core.dom.InfixExpression;
+import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.Name;
+import org.eclipse.jdt.core.dom.ThisExpression;
+import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
+
+import org.eclipse.jdt.internal.ui.fix.MultiFixMessages;
+
+public class InvertEqualsFixCore extends CompilationUnitRewriteOperationsFixCore {
+	public static final class InvertEqualsFinder extends ASTVisitor {
+		private List<InvertEqualsFixOperation> fResult;
+
+		public InvertEqualsFinder(List<InvertEqualsFixOperation> ops) {
+			fResult= ops;
+		}
+
+		@Override
+		public boolean visit(final MethodInvocation visited) {
+			Expression expression= visited.getExpression();
+			InfixExpression concatenation= ASTNodes.as(expression, InfixExpression.class);
+
+			if (expression == null
+					|| ASTNodes.is(expression, ThisExpression.class)
+					|| isConstant(expression)
+					|| concatenation != null && ASTNodes.hasOperator(concatenation, InfixExpression.Operator.PLUS) && ASTNodes.hasType(concatenation, String.class.getCanonicalName())) {
+				return true;
+			}
+
+			if (ASTNodes.usesGivenSignature(visited, Object.class.getCanonicalName(), "equals", Object.class.getCanonicalName()) //$NON-NLS-1$
+					|| ASTNodes.usesGivenSignature(visited, String.class.getCanonicalName(), "equalsIgnoreCase", String.class.getCanonicalName())) { //$NON-NLS-1$
+				Expression arg0= (Expression) visited.arguments().get(0);
+				InfixExpression concatenationArgument= ASTNodes.as(arg0, InfixExpression.class);
+
+				if (isConstant(arg0) && arg0.resolveTypeBinding() != null && !arg0.resolveTypeBinding().isPrimitive()
+						|| ASTNodes.is(arg0, ThisExpression.class)
+						|| concatenationArgument != null && ASTNodes.hasOperator(concatenationArgument, InfixExpression.Operator.PLUS) && ASTNodes.hasType(concatenationArgument, String.class.getCanonicalName())) {
+					fResult.add(new InvertEqualsFixOperation(expression, arg0));
+					return false;
+				}
+			}
+
+			return true;
+		}
+
+		private static boolean isConstant(final Expression expression) {
+			if (expression != null && expression.resolveConstantExpressionValue() != null) {
+				return true;
+			}
+
+			if (expression instanceof Name) {
+				IBinding binding= ((Name) expression).resolveBinding();
+
+				if (binding instanceof IVariableBinding) {
+					return ((IVariableBinding) binding).isEnumConstant();
+				}
+			}
+
+			return false;
+		}
+	}
+
+	public static class InvertEqualsFixOperation extends CompilationUnitRewriteOperation {
+		private final Expression expression;
+		private final Expression arg0;
+
+		public InvertEqualsFixOperation(final Expression expression, final Expression arg0) {
+			this.expression= expression;
+			this.arg0= arg0;
+		}
+
+		@Override
+		public void rewriteAST(final CompilationUnitRewrite cuRewrite, final LinkedProposalModelCore linkedModel) throws CoreException {
+			ASTRewrite rewrite= cuRewrite.getASTRewrite();
+			AST ast= cuRewrite.getRoot().getAST();
+			TextEditGroup group= createTextEditGroup(MultiFixMessages.InvertEqualsCleanUp_description, cuRewrite);
+			rewrite.setTargetSourceRangeComputer(new TargetSourceRangeComputer() {
+				@Override
+				public SourceRange computeSourceRange(final ASTNode nodeWithComment) {
+					if (Boolean.TRUE.equals(nodeWithComment.getProperty(ASTNodes.UNTOUCH_COMMENT))) {
+						return new SourceRange(nodeWithComment.getStartPosition(), nodeWithComment.getLength());
+					}
+
+					return super.computeSourceRange(nodeWithComment);
+				}
+			});
+
+
+			ASTNodes.replaceButKeepComment(rewrite, expression, ASTNodeFactory.parenthesizeIfNeeded(ast, ASTNodes.createMoveTarget(rewrite, arg0)), group);
+			ASTNodes.replaceButKeepComment(rewrite, arg0, ASTNodes.createMoveTarget(rewrite, ASTNodes.getUnparenthesedExpression(expression)), group);
+		}
+	}
+
+
+	public static ICleanUpFixCore createCleanUp(final CompilationUnit compilationUnit) {
+		List<InvertEqualsFixOperation> operations= new ArrayList<>();
+		InvertEqualsFinder finder= new InvertEqualsFinder(operations);
+		compilationUnit.accept(finder);
+
+		if (operations.isEmpty()) {
+			return null;
+		}
+
+		CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] ops= operations.toArray(new CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[0]);
+		return new InvertEqualsFixCore(FixMessages.InvertEqualsFix_invert, compilationUnit, ops);
+	}
+
+	protected InvertEqualsFixCore(final String name, final CompilationUnit compilationUnit, final CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] fixRewriteOperations) {
+		super(name, compilationUnit, fixRewriteOperations);
+	}
+}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java
index 3c60763..31bc399 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/LambdaExpressionsFixCore.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2020 IBM Corporation and others.
+ * Copyright (c) 2013, 2021 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -12,6 +12,7 @@
  *     Jerome Cambon <jerome.cambon@oracle.com> - [1.8][clean up][quick assist] Convert lambda to anonymous must qualify references to 'this'/'super' - https://bugs.eclipse.org/430573
  *     Stephan Herrmann - Contribution for Bug 463360 - [override method][null] generating method override should not create redundant null annotations
  *     Red Hat Inc. - modified to create core class in jdt.core.manipulation
+ *     Microsoft Corporation - read preferences from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.fix;
 
@@ -800,7 +801,7 @@
 		public MethodDeclaration getMethodDeclaration(ICompilationUnit cu, ASTRewrite rewrite, ImportRewrite rewrites,
 				ImportRewriteContext context, IMethodBinding binding, String[] parameterNames, ITypeBinding targetType,
 				boolean inInterface, ASTNode astNode) throws CoreException {
-			final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu.getJavaProject());
+			final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu);
 			MethodDeclaration methodDeclaration= StubUtility2Core.createImplementationStubCore(cu, rewrite, rewrites, context, binding, parameterNames, targetType, settings, inInterface,
 					astNode,
 					false);
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/PlainReplacementFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/PlainReplacementFixCore.java
new file mode 100644
index 0000000..753de43
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/PlainReplacementFixCore.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.corext.fix;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.text.edits.TextEditGroup;
+
+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.CompilationUnit;
+import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
+
+import org.eclipse.jdt.internal.ui.fix.MultiFixMessages;
+
+public class PlainReplacementFixCore extends CompilationUnitRewriteOperationsFixCore {
+	public static final class PlainReplacementFinder extends ASTVisitor {
+		private Pattern HAS_REGEX_CHARACTER= Pattern.compile(".*[\\\\\\[\\]\\{\\}\\(\\)\\*\\+\\?\\.\\^\\$\\|].*"); //$NON-NLS-1$
+
+		private List<PlainReplacementFixOperation> fResult;
+
+		public PlainReplacementFinder(List<PlainReplacementFixOperation> ops) {
+			fResult= ops;
+		}
+
+		@Override
+		public boolean visit(final MethodInvocation visited) {
+			if (ASTNodes.usesGivenSignature(visited, String.class.getCanonicalName(), "replaceAll", String.class.getCanonicalName(), String.class.getCanonicalName())) { //$NON-NLS-1$
+				Object pattern= ((Expression) visited.arguments().get(0)).resolveConstantExpressionValue();
+				Object replacement= ((Expression) visited.arguments().get(1)).resolveConstantExpressionValue();
+
+				if (pattern instanceof String
+						&& !HAS_REGEX_CHARACTER.matcher((String) pattern).matches()
+						&& replacement instanceof String
+						&& ((String) replacement).equals(Matcher.quoteReplacement((String) replacement))) {
+					fResult.add(new PlainReplacementFixOperation(visited));
+					return false;
+				}
+			}
+
+			return true;
+		}
+	}
+
+	public static class PlainReplacementFixOperation extends CompilationUnitRewriteOperation {
+		private final MethodInvocation visited;
+
+		public PlainReplacementFixOperation(final MethodInvocation visited) {
+			this.visited= visited;
+		}
+
+		@Override
+		public void rewriteAST(final CompilationUnitRewrite cuRewrite, final LinkedProposalModelCore linkedModel) throws CoreException {
+			ASTRewrite rewrite= cuRewrite.getASTRewrite();
+			AST ast= cuRewrite.getRoot().getAST();
+			TextEditGroup group= createTextEditGroup(MultiFixMessages.PlainReplacementCleanUp_description, cuRewrite);
+			rewrite.setTargetSourceRangeComputer(new TargetSourceRangeComputer() {
+				@Override
+				public SourceRange computeSourceRange(final ASTNode nodeWithComment) {
+					if (Boolean.TRUE.equals(nodeWithComment.getProperty(ASTNodes.UNTOUCH_COMMENT))) {
+						return new SourceRange(nodeWithComment.getStartPosition(), nodeWithComment.getLength());
+					}
+
+					return super.computeSourceRange(nodeWithComment);
+				}
+			});
+
+			rewrite.set(visited, MethodInvocation.NAME_PROPERTY, ast.newSimpleName("replace"), group); //$NON-NLS-1$
+		}
+	}
+
+
+	public static ICleanUpFixCore createCleanUp(final CompilationUnit compilationUnit) {
+		List<PlainReplacementFixOperation> operations= new ArrayList<>();
+		PlainReplacementFinder finder= new PlainReplacementFinder(operations);
+		compilationUnit.accept(finder);
+
+		if (operations.isEmpty()) {
+			return null;
+		}
+
+		CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] ops= operations.toArray(new CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[0]);
+		return new PlainReplacementFixCore(FixMessages.PlainReplacementFix_use_plain_text, compilationUnit, ops);
+	}
+
+	protected PlainReplacementFixCore(final String name, final CompilationUnit compilationUnit, final CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] fixRewriteOperations) {
+		super(name, compilationUnit, fixRewriteOperations);
+	}
+}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/CallInliner.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/CallInliner.java
index a128463..8fda5b7 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/CallInliner.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/CallInliner.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
@@ -24,6 +24,7 @@
  *     Nikolay Metchev <nikolaymetchev@gmail.com> - Anonymous class using final parameter breaks method inlining - https://bugs.eclipse.org/269401
  *     Microsoft Corporation - copied to jdt.core.manipulation
  *     Pierre-Yves B. <pyvesdev@gmail.com> - [inline] Inlining a local variable leads to ambiguity with overloaded methods - https://bugs.eclipse.org/434747
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.code;
 
@@ -458,7 +459,7 @@
 	}
 
 	public TextEdit getModifications() {
-		return fRewrite.rewriteAST(fBuffer.getDocument(), fCUnit.getJavaProject().getOptions(true));
+		return fRewrite.rewriteAST(fBuffer.getDocument(), fCUnit.getOptions(true));
 	}
 
 	private void computeRealArguments() {
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/CodeRefactoringUtil.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/CodeRefactoringUtil.java
index 333619c..32285f5 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/CodeRefactoringUtil.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/CodeRefactoringUtil.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 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
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.code;
 
@@ -64,7 +65,7 @@
 			ITextFileBuffer buffer= FileBuffers.getTextFileBufferManager().getTextFileBuffer(fullPath, LocationKind.IFILE);
 			try {
 				IRegion region= buffer.getDocument().getLineInformationOfOffset(node.getStartPosition());
-				return Strings.computeIndentUnits(buffer.getDocument().get(region.getOffset(), region.getLength()), unit.getJavaProject());
+				return Strings.computeIndentUnits(buffer.getDocument().get(region.getOffset(), region.getLength()), unit);
 			} catch (BadLocationException exception) {
 				JavaManipulationPlugin.log(exception);
 			}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/InlineConstantRefactoring.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/InlineConstantRefactoring.java
index f4def4d..70ac4e6 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/InlineConstantRefactoring.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/InlineConstantRefactoring.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
@@ -12,6 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Nikolay Metchev <nikolaymetchev@gmail.com> - [inline] problem with fields from generic types - https://bugs.eclipse.org/218431
  *     Microsoft Corporation - copied to jdt.core.manipulation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.code;
 
@@ -570,14 +571,14 @@
 			IDocument document= new Document(fInitializerUnit.getBuffer().getContents()); // could reuse document when generating and applying undo edits
 
 			final RangeMarker marker= new RangeMarker(fInitializer.getStartPosition(), fInitializer.getLength());
-			TextEdit[] rewriteEdits= initializerRewrite.rewriteAST(document, fInitializerUnit.getJavaProject().getOptions(true)).removeChildren();
+			TextEdit[] rewriteEdits= initializerRewrite.rewriteAST(document, fInitializerUnit.getOptions(true)).removeChildren();
 			marker.addChildren(rewriteEdits);
 			try {
 				marker.apply(document, TextEdit.UPDATE_REGIONS);
 				String rewrittenInitializer= document.get(marker.getOffset(), marker.getLength());
 				IRegion region= document.getLineInformation(document.getLineOfOffset(marker.getOffset()));
-				int oldIndent= Strings.computeIndentUnits(document.get(region.getOffset(), region.getLength()), project);
-				return Strings.changeIndent(rewrittenInitializer, oldIndent, project, "", TextUtilities.getDefaultLineDelimiter(document)); //$NON-NLS-1$
+				int oldIndent= Strings.computeIndentUnits(document.get(region.getOffset(), region.getLength()), fInitializerUnit);
+				return Strings.changeIndent(rewrittenInitializer, oldIndent, fInitializerUnit, "", TextUtilities.getDefaultLineDelimiter(document)); //$NON-NLS-1$
 			} catch (MalformedTreeException | BadLocationException e) {
 				JavaManipulationPlugin.log(e);
 			}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/InlineTempRefactoring.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/InlineTempRefactoring.java
index 366abc4..3599486 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/InlineTempRefactoring.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/InlineTempRefactoring.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
@@ -12,6 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Pierre-Yves B. <pyvesdev@gmail.com> - [inline] Allow inlining of local variable initialized to null. - https://bugs.eclipse.org/93850
  *     Microsoft Corporation - copied to jdt.core.manipulation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.code;
 
@@ -448,15 +449,14 @@
 
 		IDocument document= new Document(fCu.getBuffer().getContents());
 		final RangeMarker marker= new RangeMarker(invocation.getStartPosition(), invocation.getLength());
-		IJavaProject project= fCu.getJavaProject();
-		TextEdit[] rewriteEdits= rewrite.rewriteAST(document, project.getOptions(true)).removeChildren();
+		TextEdit[] rewriteEdits= rewrite.rewriteAST(document, fCu.getOptions(true)).removeChildren();
 		marker.addChildren(rewriteEdits);
 		try {
 			marker.apply(document, TextEdit.UPDATE_REGIONS);
 			String rewrittenInitializer= document.get(marker.getOffset(), marker.getLength());
 			IRegion region= document.getLineInformation(document.getLineOfOffset(marker.getOffset()));
-			int oldIndent= Strings.computeIndentUnits(document.get(region.getOffset(), region.getLength()), project);
-			return Strings.changeIndent(rewrittenInitializer, oldIndent, project, "", TextUtilities.getDefaultLineDelimiter(document)); //$NON-NLS-1$
+			int oldIndent= Strings.computeIndentUnits(document.get(region.getOffset(), region.getLength()), fCu);
+			return Strings.changeIndent(rewrittenInitializer, oldIndent, fCu, "", TextUtilities.getDefaultLineDelimiter(document)); //$NON-NLS-1$
 		} catch (MalformedTreeException | BadLocationException e) {
 			JavaManipulationPlugin.log(e);
 		}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/SourceProvider.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/SourceProvider.java
index b246b6c..6d6e152 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/SourceProvider.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/code/SourceProvider.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
@@ -18,12 +18,14 @@
  *       o inline call a field initializer: could detect self reference
  *         (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=44417)
  *     Microsoft Corporation - copied to jdt.core.manipulation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.code;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.CoreException;
@@ -46,6 +48,8 @@
 
 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
 
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.ITypeRoot;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.dom.AST;
@@ -349,7 +353,9 @@
 	public TextEdit getDeleteEdit() {
 		final ASTRewrite rewriter= ASTRewrite.create(fDeclaration.getAST());
 		rewriter.remove(fDeclaration, null);
-		return rewriter.rewriteAST(fDocument, fTypeRoot.getJavaProject().getOptions(true));
+		Map<String, String> options= fTypeRoot instanceof ICompilationUnit ?
+				((ICompilationUnit) fTypeRoot).getOptions(true) : fTypeRoot.getJavaProject().getOptions(true);
+		return rewriter.rewriteAST(fDocument, options);
 	}
 
 	public String[] getCodeBlocks(CallContext context, ImportRewrite importRewrite) throws CoreException {
@@ -378,7 +384,9 @@
 			}
 		}
 
-		final TextEdit dummy= rewriter.rewriteAST(fDocument, fTypeRoot.getJavaProject().getOptions(true));
+		Map<String, String> options= fTypeRoot instanceof ICompilationUnit ?
+				((ICompilationUnit) fTypeRoot).getOptions(true) : fTypeRoot.getJavaProject().getOptions(true);
+		final TextEdit dummy= rewriter.rewriteAST(fDocument, options);
 		int size= ranges.size();
 		RangeMarker[] markers= new RangeMarker[size];
 		for (int i= 0; i < markers.length; i++) {
@@ -693,13 +701,19 @@
 
 	private String[] getBlocks(RangeMarker[] markers) throws BadLocationException {
 		String[] result= new String[markers.length];
+		final ICompilationUnit cu= fTypeRoot instanceof ICompilationUnit ? (ICompilationUnit) fTypeRoot : null;
+		final IJavaProject project= fTypeRoot.getJavaProject();
 		for (int i= 0; i < markers.length; i++) {
 			RangeMarker marker= markers[i];
 			String content= fDocument.get(marker.getOffset(), marker.getLength());
 			String lines[]= Strings.convertIntoLines(content);
-			Strings.trimIndentation(lines, fTypeRoot.getJavaProject(), false);
+			if (cu != null) {
+				Strings.trimIndentation(lines, cu, false);
+			} else {
+				Strings.trimIndentation(lines, project, false);
+			}
 			if (fMarkerMode == STATEMENT_MODE && lines.length == 2 && isSingleControlStatementWithoutBlock()) {
-				lines[1]= CodeFormatterUtil.createIndentString(1, fTypeRoot.getJavaProject()) + lines[1];
+				lines[1]= cu != null ? CodeFormatterUtil.createIndentString(1, cu) + lines[1] : CodeFormatterUtil.createIndentString(1, project) + lines[1];
 			}
 			result[i]= Strings.concatenate(lines, TextUtilities.getDefaultLineDelimiter(fDocument));
 		}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/delegates/DelegateCreator.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/delegates/DelegateCreator.java
index 1a9ae7b..cfc7de6 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/delegates/DelegateCreator.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/delegates/DelegateCreator.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
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Microsoft Corporation - copied to jdt.core.manipulation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.delegates;
 
@@ -154,7 +155,7 @@
 	 */
 	public void setSourceRewrite(CompilationUnitRewrite rewrite) {
 		fOriginalRewrite= rewrite;
-		fPreferences= JavaPreferencesSettings.getCodeGenerationSettings(rewrite.getCu().getJavaProject());
+		fPreferences= JavaPreferencesSettings.getCodeGenerationSettings(rewrite.getCu());
 
 		fDelegateRewrite= new CompilationUnitRewrite(rewrite.getCu(), rewrite.getRoot());
 		fDelegateRewrite.getASTRewrite().setTargetSourceRangeComputer(rewrite.getASTRewrite().getExtendedSourceRangeComputer());
@@ -366,7 +367,7 @@
 	public void createEdit() throws JavaModelException {
 		try {
 			IDocument document= new Document(fDelegateRewrite.getCu().getBuffer().getContents());
-			TextEdit edit= fDelegateRewrite.getASTRewrite().rewriteAST(document, fDelegateRewrite.getCu().getJavaProject().getOptions(true));
+			TextEdit edit= fDelegateRewrite.getASTRewrite().rewriteAST(document, fDelegateRewrite.getCu().getOptions(true));
 			edit.apply(document, TextEdit.UPDATE_REGIONS);
 
 			String newSource= Strings.trimIndentation(document.get(fTrackedPosition.getStartPosition(), fTrackedPosition.getLength()),
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/CompilationUnitRewrite.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/CompilationUnitRewrite.java
index e1eec36..576c8a6 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/CompilationUnitRewrite.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/CompilationUnitRewrite.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
@@ -12,6 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Red Hat Inc, - copied to jdt.core.manipulation
  *     Microsoft Corporation - Add fFormattingOptions field - https://bugs.eclipse.org/551601
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.structure;
 
@@ -283,7 +284,7 @@
 				clearGroupDescriptionEdits();
 				TextEdit rewriteEdit;
 				if (fRememberContent != null) {
-					rewriteEdit= fRewrite.rewriteAST(fRememberContent, fFormattingOptions == null ? fCu.getJavaProject().getOptions(true) : fFormattingOptions);
+					rewriteEdit= fRewrite.rewriteAST(fRememberContent, fFormattingOptions == null ? fCu.getOptions(true) : fFormattingOptions);
 				} else {
 					if (fFormattingOptions == null) {
 						rewriteEdit= fRewrite.rewriteAST();
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInnerToTopRefactoring.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInnerToTopRefactoring.java
index b79742a..5ebea4b 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInnerToTopRefactoring.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInnerToTopRefactoring.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
@@ -12,6 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Samrat Dhillon samrat.dhillon@gmail.com - [move member type] Moving a member interface to its own file adds the host's type parameters to it - https://bugs.eclipse.org/bugs/show_bug.cgi?id=385237
  *     Microsoft Corporation - copied to jdt.core.manipulation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.structure;
 
@@ -1108,7 +1109,7 @@
 	private String getAlignedSourceBlock(final ICompilationUnit unit, final String block) {
 		Assert.isNotNull(block);
 		final String[] lines= Strings.convertIntoLines(block);
-		Strings.trimIndentation(lines, unit.getJavaProject(), false);
+		Strings.trimIndentation(lines, unit, false);
 		return Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(fType.getJavaProject()));
 	}
 
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInstanceMethodProcessor.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInstanceMethodProcessor.java
index a580cfa..3b91eb9 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInstanceMethodProcessor.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveInstanceMethodProcessor.java
@@ -14,6 +14,7 @@
  *     Nikolay Metchev <nikolaymetchev@gmail.com> - [move method] Move method with static imported method calls introduces compiler error - https://bugs.eclipse.org/217753
  *     Nikolay Metchev <nikolaymetchev@gmail.com> - [move method] Annotation error in applying move-refactoring to inherited methods - https://bugs.eclipse.org/404471
  *     Microsoft Corporation - copied to jdt.core.manipulation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.structure;
 
@@ -1854,7 +1855,7 @@
 			}
 
 			adjustor.rewriteVisibility(new SubProgressMonitor(monitor, 1));
-			sourceRewrite.rewriteAST(document, fMethod.getJavaProject().getOptions(true));
+			sourceRewrite.rewriteAST(document, fMethod.getCompilationUnit().getOptions(true));
 			createMethodSignature(document, declaration, sourceRewrite, rewrites);
 			ICompilationUnit unit= null;
 			CompilationUnitRewrite rewrite= null;
@@ -2254,7 +2255,9 @@
 		final IRegion range= new Region(declaration.getStartPosition(), declaration.getLength());
 		final RangeMarker marker= new RangeMarker(range.getOffset(), range.getLength());
 		final IJavaProject project= fMethod.getJavaProject();
-		for (TextEdit edit : rewrite.rewriteAST(document, project.getOptions(true)).removeChildren())
+		final ICompilationUnit cu= fMethod.getCompilationUnit();
+		Map<String, String> options= cu != null ? cu.getOptions(true) : project.getOptions(true);
+		for (TextEdit edit : rewrite.rewriteAST(document, options).removeChildren())
 			marker.addChild(edit);
 		final MultiTextEdit result= new MultiTextEdit();
 		result.addChild(marker);
@@ -2262,6 +2265,9 @@
 		processor.getRoot().addChild(result);
 		processor.performEdits();
 		final IRegion region= document.getLineInformation(document.getLineOfOffset(marker.getOffset()));
+		if (cu != null) {
+			return Strings.changeIndent(document.get(marker.getOffset(), marker.getLength()), Strings.computeIndentUnits(document.get(region.getOffset(), region.getLength()), cu), cu, "", TextUtilities.getDefaultLineDelimiter(document)); //$NON-NLS-1$
+		}
 		return Strings.changeIndent(document.get(marker.getOffset(), marker.getLength()), Strings.computeIndentUnits(document.get(region.getOffset(), region.getLength()), project), project, "", TextUtilities.getDefaultLineDelimiter(document)); //$NON-NLS-1$
 	}
 
@@ -2862,7 +2868,7 @@
 		fMethodName= method.getElementName();
 		fTargetName= suggestTargetName();
 		if (fSettings == null)
-			fSettings= JavaPreferencesSettings.getCodeGenerationSettings(fMethod.getJavaProject());
+			fSettings= JavaPreferencesSettings.getCodeGenerationSettings(fMethod.getCompilationUnit());
 	}
 
 	private RefactoringStatus initialize(JavaRefactoringArguments extended) {
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveStaticMembersProcessor.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveStaticMembersProcessor.java
index 50f0ed0..64e5145 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveStaticMembersProcessor.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/refactoring/structure/MoveStaticMembersProcessor.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
@@ -12,6 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Jerome Cambon <jerome.cambon@oracle.com> - [code style] don't generate redundant modifiers "public static final abstract" for interface members - https://bugs.eclipse.org/71627
  *     Microsoft Corporation - copied to jdt.core.manipulation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.structure;
 
@@ -974,7 +975,7 @@
 		// extract updated members
 		String[] updatedMemberSources= new String[members.length];
 		IDocument document= new Document(fSource.getCu().getBuffer().getContents());
-		TextEdit edit= fSource.getASTRewrite().rewriteAST(document, fSource.getCu().getJavaProject().getOptions(true));
+		TextEdit edit= fSource.getASTRewrite().rewriteAST(document, fSource.getCu().getOptions(true));
 		edit.apply(document, TextEdit.UPDATE_REGIONS);
 		for (int i= 0; i < members.length; i++) {
 			updatedMemberSources[i]= getUpdatedMember(document, members[i]);
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/CodeFormatterUtil.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/CodeFormatterUtil.java
index 6e0501c..234db82 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/CodeFormatterUtil.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/CodeFormatterUtil.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 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
+ *     Microsoft Corporation - add helper methods to read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.util;
 
@@ -23,6 +24,7 @@
 import org.eclipse.jface.text.Document;
 import org.eclipse.jface.text.IRegion;
 
+import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.ToolFactory;
@@ -54,6 +56,20 @@
 	}
 
 	/**
+	 * Creates a string that represents the given number of indentation units.
+	 *
+	 * @param indentationUnits
+	 *        the number of indentation units to generate
+	 * @param cu
+	 *        the compilation unit from which to get the formatter settings
+	 * @return the indent string
+	 */
+	public static String createIndentString(int indentationUnits, ICompilationUnit cu) {
+		Map<String, String> options= cu != null ? cu.getOptions(true) : JavaCore.getOptions();
+		return ToolFactory.createCodeFormatter(options).createIndentationString(indentationUnits);
+	}
+
+	/**
 	 * Gets the current tab width.
 	 *
 	 * @param project
@@ -78,6 +94,29 @@
 	}
 
 	/**
+	 * Gets the current tab width.
+	 *
+	 * @param cu
+	 *        the compilation unit from which to get the formatter settings
+	 * @return The tab width
+	 */
+	public static int getTabWidth(ICompilationUnit cu) {
+		/*
+		 * If the tab-char is SPACE, FORMATTER_INDENTATION_SIZE is not used
+		 * by the core formatter.
+		 * We piggy back the visual tab length setting in that preference in
+		 * that case.
+		 */
+		String key;
+		if (JavaCore.SPACE.equals(getCoreOption(cu, DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR)))
+			key= DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE;
+		else
+			key= DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE;
+
+		return getCoreOption(cu, key, 4);
+	}
+
+	/**
 	 * Returns the current indent width.
 	 *
 	 * @param project
@@ -97,6 +136,23 @@
 	}
 
 	/**
+	 * Returns the current indent width.
+	 *
+	 * @param cu
+	 *        the compilation unit from which to get the formatter settings
+	 * @return the indent width
+	 */
+	public static int getIndentWidth(ICompilationUnit cu) {
+		String key;
+		if (DefaultCodeFormatterConstants.MIXED.equals(getCoreOption(cu, DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR)))
+			key= DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE;
+		else
+			key= DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE;
+
+		return getCoreOption(cu, key, 4);
+	}
+
+	/**
 	 * Returns the possibly <code>project</code>-specific core preference defined under <code>key</code>.
 	 *
 	 * @param project
@@ -135,6 +191,20 @@
 		}
 	}
 
+	private static String getCoreOption(ICompilationUnit cu, String key) {
+		if (cu == null)
+			return JavaCore.getOption(key);
+		return cu.getOptions(true).get(key);
+	}
+
+	private static int getCoreOption(ICompilationUnit cu, String key, int def) {
+		try {
+			return Integer.parseInt(getCoreOption(cu, key));
+		} catch (NumberFormatException e) {
+			return def;
+		}
+	}
+
 	// transition code
 
 	/**
diff --git a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/CodeCompletionTest1d8.java b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/CodeCompletionTest1d8.java
index 07668a1..75d7e5c 100644
--- a/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/CodeCompletionTest1d8.java
+++ b/org.eclipse.jdt.text.tests/src/org/eclipse/jdt/text/tests/contentassist/CodeCompletionTest1d8.java
@@ -856,4 +856,68 @@
 			NullTestUtils.disableAnnotationBasedNullAnalysis(sourceFolder);
 		}
 	}
+
+	@Test
+	public void testBug458321() throws Exception {
+		IPackageFragmentRoot sourceFolder= JavaProjectHelper.addSourceContainer(fJProject1, "src");
+
+		IPackageFragment pack1= sourceFolder.createPackageFragment("test1", false, null);
+		StringBuffer buf= new StringBuffer();
+		buf.append("package test1;\n");
+		buf.append("\n");
+		buf.append("import java.util.function.Consumer;\n");
+		buf.append("\n");
+		buf.append("public class A {\n");
+		buf.append("    public void foo() {\n");
+		buf.append("        Runnable r = () -> {\n");
+		buf.append("        };\n");
+		buf.append("        add(o -> r.)\n");
+		buf.append("    }\n");
+		buf.append("    static void add(Consumer<Object> consumer) {}\n");
+		buf.append("}\n");
+		String contents= buf.toString();
+
+		ICompilationUnit cu= pack1.createCompilationUnit("A.java", contents, false, null);
+
+		IEditorPart part= JavaUI.openInEditor(cu);
+		try {
+			String str= "r.";
+
+			int offset= contents.indexOf(str) + 2;
+
+			CompletionProposalCollector collector= createCollector(cu, offset);
+			collector.setReplacementLength(0);
+
+			codeComplete(cu, offset, collector);
+
+			IJavaCompletionProposal proposal= null;
+
+			for (IJavaCompletionProposal p : collector.getJavaCompletionProposals()) {
+				if (p.getDisplayString().startsWith("run")) {
+					proposal= p;
+				}
+			}
+			assertNotNull("no proposal for run()", proposal);
+
+			IDocument doc= JavaUI.getDocumentProvider().getDocument(part.getEditorInput());
+			proposal.apply(doc);
+
+			buf= new StringBuffer();
+			buf.append("package test1;\n");
+			buf.append("\n");
+			buf.append("import java.util.function.Consumer;\n");
+			buf.append("\n");
+			buf.append("public class A {\n");
+			buf.append("    public void foo() {\n");
+			buf.append("        Runnable r = () -> {\n");
+			buf.append("        };\n");
+			buf.append("        add(o -> r.run())\n");
+			buf.append("    }\n");
+			buf.append("    static void add(Consumer<Object> consumer) {}\n");
+			buf.append("}\n");
+			assertEquals(buf.toString(), doc.get());
+		} finally {
+			part.getSite().getPage().closeAllEditors(false);
+		}
+	}
 }
diff --git a/org.eclipse.jdt.ui.junit.sampleproject/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jdt.ui.junit.sampleproject/.settings/org.eclipse.core.resources.prefs
index 98034e5..dfad7ca 100644
--- a/org.eclipse.jdt.ui.junit.sampleproject/.settings/org.eclipse.core.resources.prefs
+++ b/org.eclipse.jdt.ui.junit.sampleproject/.settings/org.eclipse.core.resources.prefs
@@ -1,3 +1,3 @@
 eclipse.preferences.version=1
 encoding//src/main/java/junit/framework/TestSuite.java=UTF-8
-encoding/<project>=ISO-8859-1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_in/TestWithThrows2.java b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_in/TestWithThrows2.java
new file mode 100644
index 0000000..f39f9f4
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_in/TestWithThrows2.java
@@ -0,0 +1,17 @@
+package trycatch18_in;
+
+import java.net.Socket;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.zip.DataFormatException;
+
+class TestWithThrows1 {
+	void foo(int a) throws FileNotFoundException {
+		/*[*/Socket s=new Socket();
+		FileInputStream is=new FileInputStream("a.b");
+		s.getInetAddress();/*]*/
+		if (s.getTcpNoDelay())
+			throw new DataFormatException();
+		is.available();
+	}
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestWithThrows2.java b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestWithThrows2.java
new file mode 100644
index 0000000..74af139
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests.refactoring/resources/SurroundWithWorkSpace/SurroundWithTests/tryresources18_out/TestWithThrows2.java
@@ -0,0 +1,22 @@
+package trycatch18_in;
+
+import java.net.Socket;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.zip.DataFormatException;
+
+class TestWithThrows1 {
+	void foo(int a) throws FileNotFoundException {
+		try (/*[*/ Socket s = new Socket();
+				FileInputStream is = new FileInputStream("a.b")) {
+			s.getInetAddress();/*]*/
+			if (s.getTcpNoDelay())
+				throw new DataFormatException();
+			is.available();
+		} catch (FileNotFoundException e) {
+			throw e;
+		} catch (DataFormatException | IOException e) {
+		}
+	}
+}
diff --git a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/SurroundWithResourcesTests1d8.java b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/SurroundWithResourcesTests1d8.java
index a898254..0956650 100644
--- a/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/SurroundWithResourcesTests1d8.java
+++ b/org.eclipse.jdt.ui.tests.refactoring/test cases/org/eclipse/jdt/ui/tests/refactoring/SurroundWithResourcesTests1d8.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2020 IBM Corporation and others.
+ * Copyright (c) 2020, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -115,6 +115,11 @@
 	}
 
 	@Test
+	public void testWithThrows2() throws Exception {
+		tryResourcesTest();
+	}
+
+	@Test
 	public void testInvalidStatement1() throws Exception {
 		tryResourcesInvalidTest();
 	}
diff --git a/org.eclipse.jdt.ui.tests/performance/org/eclipse/jdt/ui/tests/performance/views/CleanUpPerfTest.java b/org.eclipse.jdt.ui.tests/performance/org/eclipse/jdt/ui/tests/performance/views/CleanUpPerfTest.java
index 3457153..59677b9 100644
--- a/org.eclipse.jdt.ui.tests/performance/org/eclipse/jdt/ui/tests/performance/views/CleanUpPerfTest.java
+++ b/org.eclipse.jdt.ui.tests/performance/org/eclipse/jdt/ui/tests/performance/views/CleanUpPerfTest.java
@@ -76,6 +76,7 @@
 import org.eclipse.jdt.internal.ui.fix.EvaluateNullableCleanUp;
 import org.eclipse.jdt.internal.ui.fix.ExpressionsCleanUp;
 import org.eclipse.jdt.internal.ui.fix.HashCleanUp;
+import org.eclipse.jdt.internal.ui.fix.InvertEqualsCleanUp;
 import org.eclipse.jdt.internal.ui.fix.ImportsCleanUp;
 import org.eclipse.jdt.internal.ui.fix.Java50CleanUp;
 import org.eclipse.jdt.internal.ui.fix.JoinCleanUp;
@@ -86,6 +87,7 @@
 import org.eclipse.jdt.internal.ui.fix.ReduceIndentationCleanUp;
 import org.eclipse.jdt.internal.ui.fix.SingleUsedFieldCleanUp;
 import org.eclipse.jdt.internal.ui.fix.SortMembersCleanUp;
+import org.eclipse.jdt.internal.ui.fix.PlainReplacementCleanUp;
 import org.eclipse.jdt.internal.ui.fix.StandardComparisonCleanUp;
 import org.eclipse.jdt.internal.ui.fix.StringCleanUp;
 import org.eclipse.jdt.internal.ui.fix.SwitchExpressionsCleanUp;
@@ -606,6 +608,22 @@
 	}
 
 	@Test
+	public void testPlainReplacementCleanUp() throws Exception {
+		CleanUpRefactoring cleanUpRefactoring= new CleanUpRefactoring();
+		addAllCUs(cleanUpRefactoring, MyTestSetup.fJProject1.getChildren());
+
+		Map<String, String> node= getNullSettings();
+
+		node.put(CleanUpConstants.PLAIN_REPLACEMENT, CleanUpOptions.TRUE);
+
+		storeSettings(node);
+
+		cleanUpRefactoring.addCleanUp(new PlainReplacementCleanUp());
+
+		doCleanUp(cleanUpRefactoring);
+	}
+
+	@Test
 	public void testCollectionCloningCleanUp() throws Exception {
 		CleanUpRefactoring cleanUpRefactoring= new CleanUpRefactoring();
 		addAllCUs(cleanUpRefactoring, MyTestSetup.fJProject1.getChildren());
@@ -798,6 +816,22 @@
 	}
 
 	@Test
+	public void testInvertEqualsCleanUp() throws Exception {
+		CleanUpRefactoring cleanUpRefactoring= new CleanUpRefactoring();
+		addAllCUs(cleanUpRefactoring, MyTestSetup.fJProject1.getChildren());
+
+		Map<String, String> node= getNullSettings();
+
+		node.put(CleanUpConstants.INVERT_EQUALS, CleanUpOptions.TRUE);
+
+		storeSettings(node);
+
+		cleanUpRefactoring.addCleanUp(new InvertEqualsCleanUp());
+
+		doCleanUp(cleanUpRefactoring);
+	}
+
+	@Test
 	public void testStandardComparisonCleanUp() throws Exception {
 		CleanUpRefactoring cleanUpRefactoring= new CleanUpRefactoring();
 		addAllCUs(cleanUpRefactoring, MyTestSetup.fJProject1.getChildren());
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/AddUnimplementedConstructorsTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/AddUnimplementedConstructorsTest.java
index fe7a76d..4beb413 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/AddUnimplementedConstructorsTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/AddUnimplementedConstructorsTest.java
@@ -131,7 +131,7 @@
 
 		StubUtility.setCodeTemplate(CodeTemplateContextType.CONSTRUCTORCOMMENT_ID, comment.toString(), null);
 		StubUtility.setCodeTemplate(CodeTemplateContextType.CONSTRUCTORSTUB_ID, "${body_statement}\n// TODO", null);
-		fSettings= JavaPreferencesSettings.getCodeGenerationSettings(null);
+		fSettings= JavaPreferencesSettings.getCodeGenerationSettings((IJavaProject)null);
 		fSettings.createComments= true;
 	}
 
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceTestCase.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceTestCase.java
index 3dc2f24..23d6136 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceTestCase.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceTestCase.java
@@ -92,7 +92,7 @@
 		StubUtility.setCodeTemplate(CodeTemplateContextType.CONSTRUCTORCOMMENT_ID, constructorComment, null);
 		StubUtility.setCodeTemplate(CodeTemplateContextType.CONSTRUCTORSTUB_ID, constructorBody, null);
 
-		fSettings= JavaPreferencesSettings.getCodeGenerationSettings(null);
+		fSettings= JavaPreferencesSettings.getCodeGenerationSettings((IJavaProject)null);
 		fSettings.createComments= true;
 	}
 
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceTestCase16.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceTestCase16.java
index 32d869b..c82dfac 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceTestCase16.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/core/source/SourceTestCase16.java
@@ -98,7 +98,7 @@
 		StubUtility.setCodeTemplate(CodeTemplateContextType.CONSTRUCTORCOMMENT_ID, constructorComment, null);
 		StubUtility.setCodeTemplate(CodeTemplateContextType.CONSTRUCTORSTUB_ID, constructorBody, null);
 
-		fSettings= JavaPreferencesSettings.getCodeGenerationSettings(null);
+		fSettings= JavaPreferencesSettings.getCodeGenerationSettings((IJavaProject)null);
 		fSettings.createComments= true;
 	}
 
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java
index e50a675..217150b 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/AssistQuickFixTest1d8.java
@@ -5543,7 +5543,7 @@
 	}
 
 	@Test
-	public void testSurroundWithTryWithResource() throws Exception {
+	public void testSurroundWithTryWithResource_01() throws Exception {
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("p", false, null);
 		StringBuffer bufOrg= new StringBuffer();
 		bufOrg.append("package p;\n");
@@ -5639,6 +5639,193 @@
 		assertCorrectLabels(proposals);
 	}
 	@Test
+	public void testSurroundWithTryWithResource_02() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("p", false, null);
+		StringBuffer bufOrg= new StringBuffer();
+		bufOrg.append("package p;\n");
+		bufOrg.append("\n");
+		bufOrg.append("import java.io.FileInputStream;\n");
+		bufOrg.append("import java.io.FileNotFoundException;\n");
+		bufOrg.append("import java.io.InputStream;\n");
+		bufOrg.append("import java.net.Socket;\n");
+		bufOrg.append("\n");
+		bufOrg.append("public class E {\n");
+		bufOrg.append("    public void foo() throws FileNotFoundException {\n");
+		bufOrg.append("        /*1*/Socket s = new Socket(), s2 = new Socket();\n");
+		bufOrg.append("        /*2*/InputStream is = s.getInputStream();\n");
+		bufOrg.append("        /*3*/FileInputStream f = new FileInputStream(\"a.b\");\n");
+		bufOrg.append("        /*4*/int i = 0;\n");
+		bufOrg.append("        System.out.println(s.getInetAddress().toString());\n");
+		bufOrg.append("        System.out.println(is.markSupported());/*0*/\n");
+		bufOrg.append("    }\n");
+		bufOrg.append("}\n");
+		bufOrg.append("\n");
+
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", bufOrg.toString(), false, null);
+		String strEnd= "/*0*/";
+
+		String str1= "/*1*/";
+		AssistContext context= getCorrectionContext(cu, bufOrg.toString().indexOf(str1), bufOrg.toString().indexOf(strEnd) - bufOrg.toString().indexOf(str1));
+		List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+
+		assertNumberOfProposals(proposals, 4);
+		assertCorrectLabels(proposals);
+
+		CUCorrectionProposal proposal= (CUCorrectionProposal) proposals.get(0);
+		String preview1= getPreviewContent(proposal);
+
+		StringBuffer buf= new StringBuffer();
+		buf.append("package p;\n");
+		buf.append("\n");
+		buf.append("import java.io.FileInputStream;\n");
+		buf.append("import java.io.FileNotFoundException;\n");
+		buf.append("import java.io.IOException;\n");
+		buf.append("import java.io.InputStream;\n");
+		buf.append("import java.net.Socket;\n");
+		buf.append("\n");
+		buf.append("public class E {\n");
+		buf.append("    public void foo() throws FileNotFoundException {\n");
+		buf.append("        try (/*1*/Socket s = new Socket();\n");
+		buf.append("                Socket s2 = new Socket();\n");
+		buf.append("                /*2*/InputStream is = s.getInputStream();\n");
+		buf.append("                /*3*/FileInputStream f = new FileInputStream(\"a.b\")) {\n");
+		buf.append("            /*4*/int i = 0;\n");
+		buf.append("            System.out.println(s.getInetAddress().toString());\n");
+		buf.append("            System.out.println(is.markSupported());/*0*/\n");
+		buf.append("        } catch (FileNotFoundException e) {\n");
+		buf.append("            throw e;\n");
+		buf.append("        } catch (IOException e) {\n");
+		buf.append("            // TODO Auto-generated catch block\n");
+		buf.append("            e.printStackTrace();\n");
+		buf.append("        }\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("\n");
+		String expected1= buf.toString();
+
+		assertEqualStringsIgnoreOrder(new String[] { preview1 }, new String[] { expected1 });
+
+		str1= "/*2*/";
+		context= getCorrectionContext(cu, bufOrg.toString().indexOf(str1), bufOrg.toString().indexOf(strEnd) - bufOrg.toString().indexOf(str1));
+		proposals= collectAssists(context, false);
+
+		assertNumberOfProposals(proposals, 4);
+		assertCorrectLabels(proposals);
+
+		proposal= (CUCorrectionProposal) proposals.get(0);
+		String preview2= getPreviewContent(proposal);
+
+		buf= new StringBuffer();
+		buf.append("package p;\n");
+		buf.append("\n");
+		buf.append("import java.io.FileInputStream;\n");
+		buf.append("import java.io.FileNotFoundException;\n");
+		buf.append("import java.io.IOException;\n");
+		buf.append("import java.io.InputStream;\n");
+		buf.append("import java.net.Socket;\n");
+		buf.append("\n");
+		buf.append("public class E {\n");
+		buf.append("    public void foo() throws FileNotFoundException {\n");
+		buf.append("        /*1*/Socket s = new Socket(), s2 = new Socket();\n");
+		buf.append("        try (/*2*/InputStream is = s.getInputStream();\n");
+		buf.append("                /*3*/FileInputStream f = new FileInputStream(\"a.b\")) {\n");
+		buf.append("            /*4*/int i = 0;\n");
+		buf.append("            System.out.println(s.getInetAddress().toString());\n");
+		buf.append("            System.out.println(is.markSupported());/*0*/\n");
+		buf.append("        } catch (FileNotFoundException e) {\n");
+		buf.append("            throw e;\n");
+		buf.append("        } catch (IOException e) {\n");
+		buf.append("            // TODO Auto-generated catch block\n");
+		buf.append("            e.printStackTrace();\n");
+		buf.append("        }\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("\n");
+		String expected2= buf.toString();
+
+		assertEqualStringsIgnoreOrder(new String[] { preview2 }, new String[] { expected2 });
+
+		str1= "/*4*/";
+		context= getCorrectionContext(cu, bufOrg.toString().indexOf(str1), bufOrg.toString().indexOf(strEnd) - bufOrg.toString().indexOf(str1));
+		proposals= collectAssists(context, false);
+
+		assertNumberOfProposals(proposals, 3);
+		assertCorrectLabels(proposals);
+	}
+	@Test
+	public void testSurroundWithTryWithResource_03() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("p", false, null);
+		StringBuffer bufOrg= new StringBuffer();
+		bufOrg.append("package p;\n");
+		bufOrg.append("\n");
+		bufOrg.append("import java.io.FileInputStream;\n");
+		bufOrg.append("import java.io.FileNotFoundException;\n");
+		bufOrg.append("import java.io.InputStream;\n");
+		bufOrg.append("import java.net.Socket;\n");
+		bufOrg.append("\n");
+		bufOrg.append("public class E {\n");
+		bufOrg.append("    public void foo() {\n");
+		bufOrg.append("        try {\n");
+		bufOrg.append("            /*1*/Socket s = new Socket(), s2 = new Socket();\n");
+		bufOrg.append("            /*2*/InputStream is = s.getInputStream();\n");
+		bufOrg.append("            /*3*/FileInputStream f = new FileInputStream(\"a.b\");\n");
+		bufOrg.append("            /*4*/int i = 0;\n");
+		bufOrg.append("            System.out.println(s.getInetAddress().toString());\n");
+		bufOrg.append("            System.out.println(is.markSupported());/*0*/\n");
+		bufOrg.append("        } catch (FileNotFoundException e) {\n");
+		bufOrg.append("        }\n");
+		bufOrg.append("    }\n");
+		bufOrg.append("}\n");
+		bufOrg.append("\n");
+
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", bufOrg.toString(), false, null);
+		String strEnd= "/*0*/";
+
+		String str1= "/*1*/";
+		AssistContext context= getCorrectionContext(cu, bufOrg.toString().indexOf(str1), bufOrg.toString().indexOf(strEnd) - bufOrg.toString().indexOf(str1));
+		List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+
+		assertCorrectLabels(proposals);
+
+		CUCorrectionProposal proposal= (CUCorrectionProposal) proposals.get(0);
+		String preview1= getPreviewContent(proposal);
+
+		StringBuffer buf= new StringBuffer();
+		buf.append("package p;\n");
+		buf.append("\n");
+		buf.append("import java.io.FileInputStream;\n");
+		buf.append("import java.io.FileNotFoundException;\n");
+		buf.append("import java.io.IOException;\n");
+		buf.append("import java.io.InputStream;\n");
+		buf.append("import java.net.Socket;\n");
+		buf.append("\n");
+		buf.append("public class E {\n");
+		buf.append("    public void foo() {\n");
+		buf.append("        try {\n");
+		buf.append("            try (/*1*/Socket s = new Socket();\n");
+		buf.append("                    Socket s2 = new Socket();\n");
+		buf.append("                    /*2*/InputStream is = s.getInputStream();\n");
+		buf.append("                    /*3*/FileInputStream f = new FileInputStream(\"a.b\")) {\n");
+		buf.append("                /*4*/int i = 0;\n");
+		buf.append("                System.out.println(s.getInetAddress().toString());\n");
+		buf.append("                System.out.println(is.markSupported());/*0*/\n");
+		buf.append("            } catch (FileNotFoundException e) {\n");
+		buf.append("                throw e;\n");
+		buf.append("            } catch (IOException e) {\n");
+		buf.append("                // TODO Auto-generated catch block\n");
+		buf.append("                e.printStackTrace();\n");
+		buf.append("            }\n");
+		buf.append("        } catch (FileNotFoundException e) {\n");
+		buf.append("        }\n");
+		buf.append("    }\n");
+		buf.append("}\n");
+		buf.append("\n");
+		String expected1= buf.toString();
+
+		assertEqualStringsIgnoreOrder(new String[] { preview1 }, new String[] { expected1 });
+		assertCorrectLabels(proposals);
+	}
+	@Test
 	public void testWrapInOptional_01() throws Exception {
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("p", false, null);
 		StringBuffer buf= new StringBuffer();
@@ -5765,7 +5952,7 @@
 	}
 
 	@Test
-	public void testAssignInTryWithResources() throws Exception {
+	public void testAssignInTryWithResources_01() throws Exception {
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
 		String src=
 				"package test1;\n" +
@@ -5803,4 +5990,106 @@
 
 		assertExpectedExistInProposals(proposals, new String[] { expected });
 	}
+
+	@Test
+	public void testAssignInTryWithResources_02() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		String src=
+				"package test1;\n" +
+				"\n" +
+				"import java.io.FileInputStream;\n" +
+				"import java.io.FileNotFoundException;\n" +
+				"\n" +
+				"class E {\n" +
+				"    void f() throws FileNotFoundException {\n" +
+				"        new FileInputStream(\"f\");\n" +
+				"    }\n" +
+				"}";
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", src, false, null);
+
+		int offset= src.indexOf("new");
+		AssistContext context= getCorrectionContext(cu, offset, 0);
+		List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+
+		assertNumberOfProposals(proposals, 6);
+		assertCorrectLabels(proposals);
+
+		String expected=
+				"package test1;\n" +
+				"\n" +
+				"import java.io.FileInputStream;\n" +
+				"import java.io.FileNotFoundException;\n" +
+				"import java.io.IOException;\n" +
+				"\n" +
+				"class E {\n" +
+				"    void f() throws FileNotFoundException {\n" +
+				"        try (FileInputStream fileInputStream = new FileInputStream(\"f\")) {\n" +
+				"            \n" +
+				"        } catch (FileNotFoundException e) {\n" +
+				"            throw e;\n" +
+				"        } catch (IOException e) {\n" +
+	            "            // TODO Auto-generated catch block\n" +
+				"            e.printStackTrace();\n" +
+				"        };\n" +
+				"    }\n" +
+				"}";
+
+		assertExpectedExistInProposals(proposals, new String[] { expected });
+	}
+
+	@Test
+	public void testAssignInTryWithResources_03() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		String src=
+				"package test1;\n" +
+				"\n" +
+				"import java.io.FileInputStream;\n" +
+				"import java.io.FileNotFoundException;\n" +
+				"\n" +
+				"class E {\n" +
+				"    void f() {\n" +
+				"        try {\n" +
+				"            new FileInputStream(\"f\");\n" +
+				"        } catch (FileNotFoundException e) {\n" +
+				"            // some action\n" +
+				"        }\n" +
+				"    }\n" +
+				"}";
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", src, false, null);
+
+		int offset= src.indexOf("new");
+		AssistContext context= getCorrectionContext(cu, offset, 0);
+		List<IJavaCompletionProposal> proposals= collectAssists(context, false);
+
+		assertNumberOfProposals(proposals, 6);
+		assertCorrectLabels(proposals);
+
+		String expected=
+				"package test1;\n" +
+				"\n" +
+				"import java.io.FileInputStream;\n" +
+				"import java.io.FileNotFoundException;\n" +
+				"import java.io.IOException;\n" +
+				"\n" +
+				"class E {\n" +
+				"    void f() {\n" +
+				"        try {\n" +
+				"            try (FileInputStream fileInputStream = new FileInputStream(\"f\")) {\n" +
+				"                \n" +
+				"            } catch (FileNotFoundException e) {\n" +
+				"                throw e;\n" +
+				"            } catch (IOException e) {\n" +
+	            "                // TODO Auto-generated catch block\n" +
+				"                e.printStackTrace();\n" +
+				"            };\n" +
+				"        } catch (FileNotFoundException e) {\n" +
+				"            // some action\n" +
+				"        }\n" +
+				"    }\n" +
+				"}";
+
+		assertExpectedExistInProposals(proposals, new String[] { expected });
+	}
+
 }
+
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java
index 65d5516..08ba57b 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java
@@ -15286,6 +15286,95 @@
 	}
 
 	@Test
+	public void testPlainReplacement() throws Exception {
+		// Given
+		IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
+		String given= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    private static final String CONSTANT = \"&\";\n" //
+				+ "\n" //
+				+ "    public void refactor(String text) {\n" //
+				+ "        String s1 = text.replaceAll(\"&\", \"&amp;\");\n" //
+				+ "        String s2 = text.replaceAll(\",:#\", \"/\");\n" //
+				+ "        String s3 = text.replaceAll(\"/\", \".\");\n" //
+				+ "        String s4 = text.replaceAll(CONSTANT, \"&amp;\");\n" //
+				+ "    }\n" //
+				+ "}\n";
+
+		String expected= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    private static final String CONSTANT = \"&\";\n" //
+				+ "\n" //
+				+ "    public void refactor(String text) {\n" //
+				+ "        String s1 = text.replace(\"&\", \"&amp;\");\n" //
+				+ "        String s2 = text.replace(\",:#\", \"/\");\n" //
+				+ "        String s3 = text.replace(\"/\", \".\");\n" //
+				+ "        String s4 = text.replace(CONSTANT, \"&amp;\");\n" //
+				+ "    }\n" //
+				+ "}\n";
+
+		// When
+		ICompilationUnit cu= pack.createCompilationUnit("E.java", given, false, null);
+		enable(CleanUpConstants.PLAIN_REPLACEMENT);
+
+		// Then
+		assertNotEquals("The class must be changed", given, expected);
+		assertGroupCategoryUsed(new ICompilationUnit[] { cu }, new HashSet<>(Arrays.asList(MultiFixMessages.PlainReplacementCleanUp_description)));
+		assertRefactoringResultAsExpected(new ICompilationUnit[] { cu }, new String[] { expected });
+	}
+
+	@Test
+	public void testDoNotUsePlainReplacement() throws Exception {
+		IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
+		String sample= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "import java.util.regex.Matcher;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    public void doNotRefactorEscapableCharacters(String text) {\n" //
+				+ "        String s1 = text.replaceAll(\"[ab]\", \"c\");\n" //
+				+ "        String s2 = text.replaceAll(\"a.b\", \"foo\");\n" //
+				+ "        String s3 = text.replaceAll(\"a?\", \"foo\");\n" //
+				+ "        String s4 = text.replaceAll(\"a+\", \"foo\");\n" //
+				+ "        String s5 = text.replaceAll(\"a*\", \"foo\");\n" //
+				+ "        String s6 = text.replaceAll(\"a{42}\", \"foo\");\n" //
+				+ "        String s7 = text.replaceAll(\"a{1,42}\", \"foo\");\n" //
+				+ "        String s8 = text.replaceAll(\"(a)\", \"foo\");\n" //
+				+ "        String s9 = text.replaceAll(\"^a\", \"foo\");\n" //
+				+ "        String s10 = text.replaceAll(\"a$\", \"foo\");\n" //
+				+ "        String s11 = text.replaceAll(\"\\\\s\", \"\");\n" //
+				+ "        String s12 = text.replaceAll(\"a|b\", \"foo\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public String doNotRefactorReplacementWithCapturedGroup(String text) {\n" //
+				+ "        return text.replaceAll(\"foo\", \"$0\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public String doNotRefactorWithEscapedReplacement(String text) {\n" //
+				+ "        return text.replaceAll(\"foo\", \"\\\\$1\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public String doNotRefactorUnknownPattern(String text, String pattern) {\n" //
+				+ "        return text.replaceAll(pattern, \"c\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public String doNotRefactorOtherMethod(Matcher matcher, String text) {\n" //
+				+ "        return matcher.replaceAll(text);\n" //
+				+ "    }\n" //
+				+ "}\n";
+		ICompilationUnit cu= pack.createCompilationUnit("E.java", sample, false, null);
+
+		enable(CleanUpConstants.PLAIN_REPLACEMENT);
+
+		assertRefactoringHasNoChange(new ICompilationUnit[] { cu });
+	}
+
+	@Test
 	public void testControlFlowMerge() throws Exception {
 		// Given
 		IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
@@ -18215,6 +18304,142 @@
 	}
 
 	@Test
+	public void testInvertEquals() throws Exception {
+		// Given
+		IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
+		String given= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    public static interface Itf {\n" //
+				+ "        int primitiveConstant = 1;\n" //
+				+ "        String objConstant = \"fkjfkjf\";\n" //
+				+ "        String objNullConstant = null;\n" //
+				+ "        MyEnum enumConstant = MyEnum.NOT_NULL;\n" //
+				+ "        MyEnum enumNullConstant = null;\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    private static enum MyEnum {\n" //
+				+ "        NOT_NULL\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public boolean invertEquals(Object obj, String text1, String text2) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        return obj.equals(\"\")\n" //
+				+ "                && obj.equals(Itf.objConstant)\n" //
+				+ "                && obj.equals(\"\" + Itf.objConstant)\n" //
+				+ "                && obj.equals(MyEnum.NOT_NULL)\n" //
+				+ "                && obj.equals(text1 + text2)\n" //
+				+ "                && obj.equals(this);\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public boolean invertEqualsIgnoreCase(String s) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        return s.equalsIgnoreCase(\"\")\n" //
+				+ "                && s.equalsIgnoreCase(Itf.objConstant)\n" //
+				+ "                && s.equalsIgnoreCase(\"\" + Itf.objConstant);\n" //
+				+ "    }\n" //
+				+ "}\n";
+
+		String expected= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    public static interface Itf {\n" //
+				+ "        int primitiveConstant = 1;\n" //
+				+ "        String objConstant = \"fkjfkjf\";\n" //
+				+ "        String objNullConstant = null;\n" //
+				+ "        MyEnum enumConstant = MyEnum.NOT_NULL;\n" //
+				+ "        MyEnum enumNullConstant = null;\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    private static enum MyEnum {\n" //
+				+ "        NOT_NULL\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public boolean invertEquals(Object obj, String text1, String text2) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        return \"\".equals(obj)\n" //
+				+ "                && Itf.objConstant.equals(obj)\n" //
+				+ "                && (\"\" + Itf.objConstant).equals(obj)\n" //
+				+ "                && MyEnum.NOT_NULL.equals(obj)\n" //
+				+ "                && (text1 + text2).equals(obj)\n" //
+				+ "                && this.equals(obj);\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public boolean invertEqualsIgnoreCase(String s) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        return \"\".equalsIgnoreCase(s)\n" //
+				+ "                && Itf.objConstant.equalsIgnoreCase(s)\n" //
+				+ "                && (\"\" + Itf.objConstant).equalsIgnoreCase(s);\n" //
+				+ "    }\n" //
+				+ "}\n";
+
+		// When
+		ICompilationUnit cu= pack.createCompilationUnit("E.java", given, false, null);
+		enable(CleanUpConstants.INVERT_EQUALS);
+
+		// Then
+		assertNotEquals("The class must be changed", given, expected);
+		assertGroupCategoryUsed(new ICompilationUnit[] { cu }, new HashSet<>(Arrays.asList(MultiFixMessages.InvertEqualsCleanUp_description)));
+		assertRefactoringResultAsExpected(new ICompilationUnit[] { cu }, new String[] { expected });
+	}
+
+	@Test
+	public void testDoNotInvertEquals() throws Exception {
+		IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
+		String sample= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    public static interface Itf {\n" //
+				+ "        int primitiveConstant = 1;\n" //
+				+ "        String objConstant = \"fkjfkjf\";\n" //
+				+ "        String objNullConstant = null;\n" //
+				+ "        MyEnum enumConstant = MyEnum.NOT_NULL;\n" //
+				+ "        MyEnum enumNullConstant = null;\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    private static enum MyEnum {\n" //
+				+ "        NOT_NULL\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    private int primitiveField;\n" //
+				+ "\n" //
+				+ "    public boolean doNotInvertEqualsOnInstance() {\n" //
+				+ "        return equals(\"\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public boolean doNotInvertEqualsOnThis() {\n" //
+				+ "        return this.equals(\"\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public boolean doNotInvertEqualsWhenParameterIsNull(Object obj) {\n" //
+				+ "        return obj.equals(Itf.objNullConstant) && obj.equals(Itf.enumNullConstant);\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public boolean doNotInvertEqualsWithPrimitiveParameter(Object obj) {\n" //
+				+ "        return obj.equals(1)\n" //
+				+ "            && obj.equals(Itf.primitiveConstant)\n" //
+				+ "            && obj.equals(primitiveField);\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public boolean doNotInvertEqualsIgnoreCaseWhenParameterIsNull(String s) {\n" //
+				+ "        return s.equalsIgnoreCase(Itf.objNullConstant);\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public boolean doNotInvertEqualsOnOperationThatIsNotConcatenation(Integer number, Integer i1, Integer i2) {\n" //
+				+ "        return number.equals(i1 + i2);\n" //
+				+ "    }\n" //
+				+ "}\n";
+		ICompilationUnit cu= pack.createCompilationUnit("E.java", sample, false, null);
+
+		enable(CleanUpConstants.INVERT_EQUALS);
+
+		assertRefactoringHasNoChange(new ICompilationUnit[] { cu });
+	}
+
+	@Test
 	public void testStandardComparison() throws Exception {
 		// Given
 		IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java
index 4a7946a..76a7e99 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java
@@ -1728,6 +1728,13 @@
 				+ "        return listToSort;\n" //
 				+ "    }\n" //
 				+ "\n" //
+				+ "    public List<Date> replaceLambdaUsingRightType(List<Date> initialPackagesToDelete) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        Collections.sort(initialPackagesToDelete, (Date one, Date two) -> one.toString().compareTo(two.toString()));\n" //
+				+ "\n" //
+				+ "        return initialPackagesToDelete;\n" //
+				+ "    }\n" //
+				+ "\n" //
 				+ "    public List<Date> useMethodRefNullFirst(List<Date> listToSort) {\n" //
 				+ "        // Keep this comment\n" //
 				+ "        Comparator<Date> comparator = new Comparator<Date>() {\n" //
@@ -2085,6 +2092,13 @@
 				+ "        return listToSort;\n" //
 				+ "    }\n" //
 				+ "\n" //
+				+ "    public List<Date> replaceLambdaUsingRightType(List<Date> initialPackagesToDelete) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        Collections.sort(initialPackagesToDelete, Comparator.comparing(Date::toString));\n" //
+				+ "\n" //
+				+ "        return initialPackagesToDelete;\n" //
+				+ "    }\n" //
+				+ "\n" //
 				+ "    public List<Date> useMethodRefNullFirst(List<Date> listToSort) {\n" //
 				+ "        // Keep this comment\n" //
 				+ "        Comparator<Date> comparator = Comparator.nullsFirst(Comparator.comparing(Date::toString));\n" //
diff --git a/org.eclipse.jdt.ui/META-INF/MANIFEST.MF b/org.eclipse.jdt.ui/META-INF/MANIFEST.MF
index 111e620..3a1794c 100644
--- a/org.eclipse.jdt.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.ui/META-INF/MANIFEST.MF
@@ -110,7 +110,7 @@
  org.eclipse.help;bundle-version="[3.4.0,4.0.0)",
  org.eclipse.core.expressions;bundle-version="[3.4.100,4.0.0)",
  org.eclipse.core.filesystem;bundle-version="[1.2.0,2.0.0)",
- org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.core.resources;bundle-version="[3.14.0,4.0.0)",
  org.eclipse.core.variables;bundle-version="[3.2.200,4.0.0)",
  org.eclipse.jdt.core;bundle-version="[3.22.0,4.0.0)",
  org.eclipse.search;bundle-version="[3.10.0,4.0.0)",
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddJavaDocStubOperation.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddJavaDocStubOperation.java
index ec8822e..0939f60 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddJavaDocStubOperation.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddJavaDocStubOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.codemanipulation;
 
@@ -40,7 +41,6 @@
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IField;
 import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IMember;
 import org.eclipse.jdt.core.IMethod;
 import org.eclipse.jdt.core.IType;
@@ -49,10 +49,10 @@
 import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.manipulation.CodeGeneration;
 
-import org.eclipse.jdt.internal.corext.dom.TokenScanner;
-import org.eclipse.jdt.internal.corext.util.MethodOverrideTester;
 import org.eclipse.jdt.internal.core.manipulation.StubUtility;
 import org.eclipse.jdt.internal.core.manipulation.util.Strings;
+import org.eclipse.jdt.internal.corext.dom.TokenScanner;
+import org.eclipse.jdt.internal.corext.util.MethodOverrideTester;
 import org.eclipse.jdt.internal.corext.util.SuperTypeHierarchyCache;
 
 import org.eclipse.jdt.internal.ui.JavaUIStatus;
@@ -157,13 +157,12 @@
 					}
 				}
 
-				final IJavaProject project= cu.getJavaProject();
 				IRegion region= document.getLineInformationOfOffset(memberStartOffset);
 
 				String line= document.get(region.getOffset(), region.getLength());
-				String indentString= Strings.getIndentString(line, project);
+				String indentString= Strings.getIndentString(line, cu);
 
-				String indentedComment= Strings.changeIndent(comment, 0, project, indentString, lineDelim);
+				String indentedComment= Strings.changeIndent(comment, 0, cu, indentString, lineDelim);
 
 				edit.addChild(new InsertEdit(memberStartOffset, indentedComment));
 
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddUnimplementedMethodsOperation.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddUnimplementedMethodsOperation.java
index dae1a81..f56d717 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddUnimplementedMethodsOperation.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/codemanipulation/AddUnimplementedMethodsOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -12,6 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Mateusz Wenus <mateusz.wenus@gmail.com> - [override method] generate in declaration order [code generation] - https://bugs.eclipse.org/bugs/show_bug.cgi?id=140971
  *     Stephan Herrmann - Contribution for Bug 463360 - [override method][null] generating method override should not create redundant null annotations
+ *     Microsoft Corporation - read preferences from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.codemanipulation;
 
@@ -193,7 +194,7 @@
 				// not possible, we checked this in the constructor
 			}
 
-			final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu.getJavaProject());
+			final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu);
 			settings.createComments= fDoCreateComments;
 
 			ASTNode insertion= getNodeToInsertBefore(memberRewriter);
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java
index 41c5716..ea50e45 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java
@@ -78,6 +78,7 @@
 		options.setOption(BREAK_LOOP, CleanUpOptions.FALSE);
 		options.setOption(STATIC_INNER_CLASS, CleanUpOptions.FALSE);
 		options.setOption(STRINGBUILDER, CleanUpOptions.FALSE);
+		options.setOption(PLAIN_REPLACEMENT, CleanUpOptions.FALSE);
 		options.setOption(USE_LAZY_LOGICAL_OPERATOR, CleanUpOptions.FALSE);
 		options.setOption(PRIMITIVE_COMPARISON, CleanUpOptions.FALSE);
 		options.setOption(PRIMITIVE_PARSING, CleanUpOptions.FALSE);
@@ -150,7 +151,8 @@
 		options.setOption(MODERNIZE_HASH, CleanUpOptions.FALSE);
 		options.setOption(USE_OBJECTS_EQUALS, CleanUpOptions.FALSE);
 
-		// Code fixing
+		// Source fixing
+		options.setOption(INVERT_EQUALS, CleanUpOptions.FALSE);
 		options.setOption(STANDARD_COMPARISON, CleanUpOptions.FALSE);
 		options.setOption(CHECK_SIGN_OF_BITWISE_OPERATION, CleanUpOptions.FALSE);
 
@@ -160,6 +162,8 @@
 		options.setOption(MERGE_CONDITIONAL_BLOCKS, CleanUpOptions.FALSE);
 		options.setOption(CONTROLFLOW_MERGE, CleanUpOptions.FALSE);
 
+		// Code fixing
+
 		// Java Features
 		options.setOption(USE_PATTERN_MATCHING_FOR_INSTANCEOF, CleanUpOptions.FALSE);
 		options.setOption(CONTROL_STATEMENTS_CONVERT_TO_SWITCH_EXPRESSIONS, CleanUpOptions.FALSE);
@@ -233,6 +237,7 @@
 		options.setOption(BREAK_LOOP, CleanUpOptions.FALSE);
 		options.setOption(STATIC_INNER_CLASS, CleanUpOptions.FALSE);
 		options.setOption(STRINGBUILDER, CleanUpOptions.FALSE);
+		options.setOption(PLAIN_REPLACEMENT, CleanUpOptions.FALSE);
 		options.setOption(USE_LAZY_LOGICAL_OPERATOR, CleanUpOptions.FALSE);
 		options.setOption(PRIMITIVE_COMPARISON, CleanUpOptions.FALSE);
 		options.setOption(PRIMITIVE_PARSING, CleanUpOptions.FALSE);
@@ -273,6 +278,8 @@
 		options.setOption(REMOVE_USELESS_CONTINUE, CleanUpOptions.FALSE);
 		options.setOption(UNLOOPED_WHILE, CleanUpOptions.FALSE);
 
+		// Code fixing
+
 		//Missing Code
 		options.setOption(ADD_MISSING_ANNOTATIONS, CleanUpOptions.TRUE);
 		options.setOption(ADD_MISSING_ANNOTATIONS_OVERRIDE, CleanUpOptions.TRUE);
@@ -307,7 +314,8 @@
 
 		options.setOption(CLEANUP_ON_SAVE_ADDITIONAL_OPTIONS, CleanUpOptions.FALSE);
 
-		// Code fixing
+		// Source fixing
+		options.setOption(INVERT_EQUALS, CleanUpOptions.FALSE);
 		options.setOption(STANDARD_COMPARISON, CleanUpOptions.FALSE);
 		options.setOption(CHECK_SIGN_OF_BITWISE_OPERATION, CleanUpOptions.FALSE);
 
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/TypedSource.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/TypedSource.java
index b560022..bdf7ae8 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/TypedSource.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/TypedSource.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring;
 
@@ -36,11 +37,10 @@
 import org.eclipse.jdt.core.dom.FieldDeclaration;
 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
 
+import org.eclipse.jdt.internal.core.manipulation.util.Strings;
+import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
 import org.eclipse.jdt.internal.corext.refactoring.reorg.ReorgUtils;
 import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil;
-import org.eclipse.jdt.internal.core.manipulation.util.Strings;
-
-import org.eclipse.jdt.internal.corext.dom.IASTSharedValues;
 
 /**
  * A tuple used to keep source of an element and its type.
@@ -181,7 +181,7 @@
 			ISourceReference reference= (ISourceReference) elem;
 			String source= reference.getSource();
 			if (source != null)
-				return Strings.trimIndentation(source, cu.getJavaProject(), false);
+				return Strings.trimIndentation(source, cu, false);
 		}
 		return ""; //$NON-NLS-1$
 	}
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/ExtractConstantRefactoring.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/ExtractConstantRefactoring.java
index 1a00c9a..1f48e70 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/ExtractConstantRefactoring.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/code/ExtractConstantRefactoring.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
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Pierre-Yves B. <pyvesdev@gmail.com> - [inline] Allow inlining of local variable initialized to null. - https://bugs.eclipse.org/93850
+ *     Microsoft Corporation - read preferences from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.code;
 
@@ -493,7 +494,7 @@
 		fieldDeclaration.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD));
 		fieldDeclaration.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.FINAL_KEYWORD));
 
-		boolean createComments= JavaPreferencesSettings.getCodeGenerationSettings(fCu.getJavaProject()).createComments;
+		boolean createComments= JavaPreferencesSettings.getCodeGenerationSettings(fCu).createComments;
 		if (createComments) {
 			String comment= CodeGeneration.getFieldComment(fCu, getConstantTypeName(), fConstantName, StubUtility.getLineDelimiterUsed(fCu));
 			if (comment != null && comment.length() > 0) {
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/nls/AccessorClassModifier.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/nls/AccessorClassModifier.java
index 1734d05..c57643a 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/nls/AccessorClassModifier.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/nls/AccessorClassModifier.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 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
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.nls;
 
@@ -133,7 +134,7 @@
 		if (document == null)
 			document= new Document(fCU.getSource());
 
-		return fASTRewrite.rewriteAST(document, fCU.getJavaProject().getOptions(true));
+		return fASTRewrite.rewriteAST(document, fCU.getOptions(true));
 	}
 
 	public static Change create(ICompilationUnit cu, NLSSubstitution[] substitutions) throws CoreException {
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/reorg/DeleteChangeCreator.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/reorg/DeleteChangeCreator.java
index 7e6c89f..cb2b2cd 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/reorg/DeleteChangeCreator.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/reorg/DeleteChangeCreator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2011 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
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.reorg;
 
@@ -133,7 +134,7 @@
 	private static TextChange addTextEditFromRewrite(TextChangeManager manager, ICompilationUnit cu, ASTRewrite rewrite) throws CoreException {
 		try {
 			ITextFileBuffer buffer= RefactoringFileBuffers.acquire(cu);
-			TextEdit resultingEdits= rewrite.rewriteAST(buffer.getDocument(), cu.getJavaProject().getOptions(true));
+			TextEdit resultingEdits= rewrite.rewriteAST(buffer.getDocument(), cu.getOptions(true));
 			TextChange textChange= manager.get(cu);
 			if (textChange instanceof TextFileChange) {
 				TextFileChange tfc= (TextFileChange) textChange;
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/ExtractInterfaceProcessor.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/ExtractInterfaceProcessor.java
index 9876243..174ebdd 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/ExtractInterfaceProcessor.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/ExtractInterfaceProcessor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Jerome Cambon <jerome.cambon@oracle.com> - [code style] don't generate redundant modifiers "public static final abstract" for interface members - https://bugs.eclipse.org/71627
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.structure;
 
@@ -476,7 +477,7 @@
 		try {
 			final IDocument document= new Document(buffer.getDocument().get());
 			try {
-				rewrite.rewriteAST(document, unit.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
+				rewrite.rewriteAST(document, unit.getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
 				targetRewrite.getListRewrite(targetDeclaration, targetDeclaration.getBodyDeclarationsProperty()).insertFirst(targetRewrite.createStringPlaceholder(normalizeText(document.get(position.getStartPosition(), position.getLength())), ASTNode.FIELD_DECLARATION), null);
 			} catch (MalformedTreeException | BadLocationException exception) {
 				JavaPlugin.log(exception);
@@ -683,7 +684,7 @@
 		try {
 			IDocument document= new Document(buffer.getDocument().get());
 			try {
-				rewrite.rewriteAST(document, unit.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
+				rewrite.rewriteAST(document, unit.getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
 				targetRewrite.getListRewrite(targetDeclaration, targetDeclaration.getBodyDeclarationsProperty()).insertFirst(targetRewrite.createStringPlaceholder(normalizeText(document.get(position.getStartPosition(), position.getLength())), ASTNode.METHOD_DECLARATION), null);
 			} catch (MalformedTreeException | BadLocationException exception) {
 				JavaPlugin.log(exception);
@@ -897,7 +898,7 @@
 			attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + count;
 		}
 		fMembers= elements.toArray(new IMember[elements.size()]);
-		fSettings= JavaPreferencesSettings.getCodeGenerationSettings(fSubType.getJavaProject());
+		fSettings= JavaPreferencesSettings.getCodeGenerationSettings(fSubType.getCompilationUnit());
 		if (!status.isOK())
 			return status;
 		return new RefactoringStatus();
@@ -942,7 +943,7 @@
 		Assert.isNotNull(code);
 		final String[] lines= Strings.convertIntoLines(code);
 		final IJavaProject project= fSubType.getJavaProject();
-		Strings.trimIndentation(lines, project, false);
+		Strings.trimIndentation(lines, fSubType.getCompilationUnit(), false);
 		return Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(project));
 	}
 
@@ -1038,7 +1039,7 @@
 			try {
 				final IDocument document= new Document(buffer.getDocument().get());
 				try {
-					rewrite.rewriteAST(document, fSubType.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
+					rewrite.rewriteAST(document, fSubType.getCompilationUnit().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
 				} catch (MalformedTreeException | BadLocationException exception) {
 					JavaPlugin.log(exception);
 				}
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/HierarchyProcessor.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/HierarchyProcessor.java
index 6714bcb..f31d7ef 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/HierarchyProcessor.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/HierarchyProcessor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2018 IBM Corporation and others.
+ * Copyright (c) 2006, 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
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.structure;
 
@@ -81,6 +82,8 @@
 import org.eclipse.jdt.core.search.SearchMatch;
 import org.eclipse.jdt.core.search.SearchPattern;
 
+import org.eclipse.jdt.internal.core.manipulation.StubUtility;
+import org.eclipse.jdt.internal.core.manipulation.util.Strings;
 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
@@ -101,8 +104,6 @@
 import org.eclipse.jdt.internal.corext.util.JdtFlags;
 import org.eclipse.jdt.internal.corext.util.Messages;
 import org.eclipse.jdt.internal.corext.util.SearchUtils;
-import org.eclipse.jdt.internal.core.manipulation.StubUtility;
-import org.eclipse.jdt.internal.core.manipulation.util.Strings;
 
 import org.eclipse.jdt.ui.JavaElementLabels;
 
@@ -318,7 +319,7 @@
 			final ASTRewrite rewriter= ASTRewrite.create(expression.getAST());
 			final ITrackedNodePosition position= rewriter.track(expression);
 			expression.accept(new TypeVariableMapper(rewriter, mapping));
-			rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
+			rewriter.rewriteAST(document, declaringCu.getOptions(true)).apply(document, TextEdit.NONE);
 			result= (Expression) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.METHOD_INVOCATION);
 		} catch (MalformedTreeException | BadLocationException exception) {
 			JavaPlugin.log(exception);
@@ -333,7 +334,7 @@
 			ModifierRewrite.create(rewriter, bodyDeclaration).setVisibility(Modifier.PROTECTED, null);
 			final ITrackedNodePosition position= rewriter.track(bodyDeclaration);
 			final IDocument document= new Document(declaringCu.getBuffer().getText(declaringCuNode.getStartPosition(), declaringCuNode.getLength()));
-			rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
+			rewriter.rewriteAST(document, declaringCu.getOptions(true)).apply(document, TextEdit.UPDATE_REGIONS);
 			text= document.get(position.getStartPosition(), position.getLength());
 		} catch (BadLocationException exception) {
 			text= getNewText(bodyDeclaration, declaringCu, removeIndentation);
@@ -367,7 +368,7 @@
 					return true;
 				}
 			});
-			rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
+			rewriter.rewriteAST(document, declaringCu.getOptions(true)).apply(document, TextEdit.NONE);
 			result= (BodyDeclaration) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.TYPE_DECLARATION);
 		} catch (MalformedTreeException | BadLocationException exception) {
 			JavaPlugin.log(exception);
@@ -386,7 +387,7 @@
 			final ASTRewrite rewriter= ASTRewrite.create(declaration.getAST());
 			final ITrackedNodePosition position= rewriter.track(declaration);
 			declaration.accept(new TypeVariableMapper(rewriter, mapping));
-			rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
+			rewriter.rewriteAST(document, declaringCu.getOptions(true)).apply(document, TextEdit.NONE);
 			result= (SingleVariableDeclaration) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.SINGLE_VARIABLE_DECLARATION);
 		} catch (MalformedTreeException | BadLocationException exception) {
 			JavaPlugin.log(exception);
@@ -405,7 +406,7 @@
 			final ASTRewrite rewriter= ASTRewrite.create(type.getAST());
 			final ITrackedNodePosition position= rewriter.track(type);
 			type.accept(new TypeVariableMapper(rewriter, mapping));
-			rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
+			rewriter.rewriteAST(document, declaringCu.getOptions(true)).apply(document, TextEdit.NONE);
 			result= (Type) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.SIMPLE_TYPE);
 		} catch (MalformedTreeException | BadLocationException exception) {
 			JavaPlugin.log(exception);
@@ -424,7 +425,7 @@
 			final ASTRewrite rewriter= ASTRewrite.create(bodyDeclaration.getAST());
 			final ITrackedNodePosition position= rewriter.track(bodyDeclaration);
 			bodyDeclaration.accept(new TypeVariableMapper(rewriter, mapping));
-			rewriter.rewriteAST(document, declaringCu.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
+			rewriter.rewriteAST(document, declaringCu.getOptions(true)).apply(document, TextEdit.NONE);
 			result= (BodyDeclaration) rewrite.createStringPlaceholder(document.get(position.getStartPosition(), position.getLength()), ASTNode.TYPE_DECLARATION);
 		} catch (MalformedTreeException | BadLocationException exception) {
 			JavaPlugin.log(exception);
@@ -487,7 +488,7 @@
 
 	protected static String getUnindentedText(final String text, final ICompilationUnit declaringCu) throws JavaModelException {
 		final String[] lines= Strings.convertIntoLines(text);
-		Strings.trimIndentation(lines, declaringCu.getJavaProject(), false);
+		Strings.trimIndentation(lines, declaringCu, false);
 		return Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(declaringCu));
 	}
 
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PullUpRefactoringProcessor.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PullUpRefactoringProcessor.java
index 87afa93..e25834f 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PullUpRefactoringProcessor.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PullUpRefactoringProcessor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2020 IBM Corporation and others.
+ * Copyright (c) 2006, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -12,6 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Benjamin Muskalla - 228950: [pull up] exception if target calls super with multiple parameters
  *     Jerome Cambon <jerome.cambon@oracle.com> - [code style] don't generate redundant modifiers "public static final abstract" for interface members - https://bugs.eclipse.org/71627
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.structure;
 
@@ -1012,10 +1013,10 @@
 			final ASTRewrite rewrite= ASTRewrite.create(body.getAST());
 			final ITrackedNodePosition position= rewrite.track(body);
 			body.accept(new PullUpAstNodeMapper(sourceRewrite, targetRewrite, rewrite, getDeclaringSuperTypeHierarchy(monitor).getSuperclass(getDeclaringType()), mapping, oldMethod.resolveBinding()));
-			rewrite.rewriteAST(document, method.getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
+			rewrite.rewriteAST(document, method.getCompilationUnit().getOptions(true)).apply(document, TextEdit.NONE);
 			String content= document.get(position.getStartPosition(), position.getLength());
 			final String[] lines= Strings.convertIntoLines(content);
-			Strings.trimIndentation(lines, method.getJavaProject(), false);
+			Strings.trimIndentation(lines, method.getCompilationUnit(), false);
 			content= Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(method));
 			newMethod.setBody((Block) targetRewrite.getASTRewrite().createStringPlaceholder(content, ASTNode.BLOCK));
 		} catch (MalformedTreeException | BadLocationException exception) {
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PushDownRefactoringProcessor.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PushDownRefactoringProcessor.java
index 730563a..4676bae 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PushDownRefactoringProcessor.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/PushDownRefactoringProcessor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2020 IBM Corporation and others.
+ * Copyright (c) 2006, 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
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.corext.refactoring.structure;
 
@@ -612,10 +613,10 @@
 			final ITrackedNodePosition position= rewriter.track(body);
 			body.accept(new TypeVariableMapper(rewriter, mapping));
 			body.accept(new ThisVisitor(rewriter, fCachedDeclaringType));
-			rewriter.rewriteAST(document, getDeclaringType().getCompilationUnit().getJavaProject().getOptions(true)).apply(document, TextEdit.NONE);
+			rewriter.rewriteAST(document, getDeclaringType().getCompilationUnit().getOptions(true)).apply(document, TextEdit.NONE);
 			String content= document.get(position.getStartPosition(), position.getLength());
 			String[] lines= Strings.convertIntoLines(content);
-			Strings.trimIndentation(lines, method.getJavaProject(), false);
+			Strings.trimIndentation(lines, method.getCompilationUnit(), false);
 			content= Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(method));
 			newMethod.setBody((Block) targetRewrite.createStringPlaceholder(content, ASTNode.BLOCK));
 		} catch (MalformedTreeException | BadLocationException exception) {
@@ -871,7 +872,7 @@
 		if (info.copyJavadocToCopiesInSubclasses())
 			copyJavadocNode(rewrite, oldMethod, newMethod);
 		final IJavaProject project= rewriter.getCu().getJavaProject();
-		if (info.isNewMethodToBeDeclaredAbstract() && JavaModelUtil.is50OrHigher(project) && JavaPreferencesSettings.getCodeGenerationSettings(project).overrideAnnotation) {
+		if (info.isNewMethodToBeDeclaredAbstract() && JavaModelUtil.is50OrHigher(project) && JavaPreferencesSettings.getCodeGenerationSettings(rewriter.getCu()).overrideAnnotation) {
 			final MarkerAnnotation annotation= ast.newMarkerAnnotation();
 			annotation.setTypeName(ast.newSimpleName("Override")); //$NON-NLS-1$
 			newMethod.modifiers().add(annotation);
diff --git a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesAnalyzer.java b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesAnalyzer.java
index d3c0872..bee6a31 100644
--- a/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesAnalyzer.java
+++ b/org.eclipse.jdt.ui/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryWithResourcesAnalyzer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2020 IBM Corporation and others.
+ * Copyright (c) 2020, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -16,6 +16,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -25,6 +26,7 @@
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.dom.ASTNode;
 import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.CatchClause;
 import org.eclipse.jdt.core.dom.CompilationUnit;
 import org.eclipse.jdt.core.dom.IBinding;
 import org.eclipse.jdt.core.dom.IMethodBinding;
@@ -34,10 +36,14 @@
 import org.eclipse.jdt.core.dom.MethodDeclaration;
 import org.eclipse.jdt.core.dom.MethodReference;
 import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+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.VariableDeclarationFragment;
 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
 
+import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving;
 import org.eclipse.jdt.internal.corext.dom.Bindings;
 import org.eclipse.jdt.internal.corext.dom.Selection;
 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
@@ -55,7 +61,7 @@
 
 	public ITypeBinding[] getExceptions(Selection selection) {
 		if (fEnclosingNode != null && !getStatus().hasFatalError()) {
-			fExceptions= ExceptionAnalyzer.perform(fEnclosingNode, selection, true);
+			fExceptions= ExceptionAnalyzer.perform(fEnclosingNode, selection, false);
 			if (fExceptions == null || fExceptions.length == 0) {
 				if (fEnclosingNode instanceof MethodReference) {
 					invalidSelection(RefactoringCoreMessages.SurroundWithTryCatchAnalyzer_doesNotContain);
@@ -72,6 +78,36 @@
 		return fExceptions;
 	}
 
+	public ITypeBinding[] getCaughtExceptions() {
+		List<ITypeBinding> exceptions= new ArrayList<>();
+		TryStatement enclosingTry= (TryStatement)ASTResolving.findAncestor(getFirstSelectedNode(), ASTNode.TRY_STATEMENT);
+		while (enclosingTry != null) {
+			List<CatchClause> catchClauses= enclosingTry.catchClauses();
+			for (CatchClause catchClause : catchClauses) {
+				SingleVariableDeclaration sdv= catchClause.getException();
+				Type type= sdv.getType();
+				if (type instanceof UnionType) {
+					UnionType unionType= (UnionType)type;
+					List<Type> types= unionType.types();
+					for (Type t : types) {
+						ITypeBinding binding= t.resolveBinding();
+						if (binding == null) {
+							break;
+						}
+						exceptions.add(binding);
+					}
+				} else {
+					ITypeBinding binding= type.resolveBinding();
+					if (binding != null) {
+						exceptions.add(binding);
+					}
+				}
+			}
+			enclosingTry= (TryStatement)ASTResolving.findAncestor(enclosingTry.getParent(), ASTNode.TRY_STATEMENT);
+		}
+		return exceptions.toArray(new ITypeBinding[0]);
+	}
+
 	public ITypeBinding[] getThrownExceptions() {
 		List<ITypeBinding> exceptions= new ArrayList<>();
 		if (fEnclosingNode.getNodeType() == ASTNode.METHOD_DECLARATION) {
@@ -99,6 +135,49 @@
 		return exceptions.toArray(new ITypeBinding[0]);
 	}
 
+	public List<ITypeBinding> calculateCatchesAndRethrows(List<ITypeBinding> exceptions, List<ITypeBinding> mustRethrowList) {
+		List<ITypeBinding> exceptionList= new ArrayList<>(exceptions);
+		ITypeBinding[] caughtExceptions= getCaughtExceptions();
+		if (caughtExceptions.length > 0) {
+			for (Iterator<ITypeBinding> iter= exceptionList.iterator(); iter.hasNext();) {
+				ITypeBinding binding= iter.next();
+				for (ITypeBinding caughtException : caughtExceptions) {
+					if (binding.isAssignmentCompatible(caughtException)) {
+						iter.remove();
+						break;
+					}
+				}
+			}
+			for (ITypeBinding binding : exceptionList) {
+				for (ITypeBinding caughtException : caughtExceptions) {
+					if (caughtException.isAssignmentCompatible(binding)) {
+						mustRethrowList.add(caughtException);
+						break;
+					}
+				}
+			}
+		}
+		ITypeBinding[] thrownExceptions= getThrownExceptions();
+		for (Iterator<ITypeBinding> iter= exceptionList.iterator(); iter.hasNext();) {
+			ITypeBinding binding= iter.next();
+			for (ITypeBinding thrownException : thrownExceptions) {
+				if (binding.isAssignmentCompatible(thrownException)) {
+					iter.remove();
+					break;
+				}
+			}
+		}
+		for (ITypeBinding binding : exceptionList) {
+			for (ITypeBinding thrownException : thrownExceptions) {
+				if (thrownException.isAssignmentCompatible(binding)) {
+					mustRethrowList.add(thrownException);
+					break;
+				}
+			}
+		}
+		return exceptionList;
+	}
+
 	public ASTNode getEnclosingNode() {
 		return fEnclosingNode;
 	}
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 8c4f6bd..645126c 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
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2020 IBM Corporation and others.
+ * Copyright (c) 2020, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -58,6 +58,7 @@
 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;
@@ -410,19 +411,9 @@
 				if (typeBinding != null) {
 					IMethodBinding close= findAutocloseMethod(typeBinding);
 					if (close != null) {
-						ITypeBinding[] thrownExceptions= fAnalyzer.getThrownExceptions();
 						for (ITypeBinding exceptionType : close.getExceptionTypes()) {
 							if (!allExceptions.contains(exceptionType)) {
-								boolean isThrown= false;
-								for (ITypeBinding thrownException : thrownExceptions) {
-									if (exceptionType.isAssignmentCompatible(thrownException)) {
-										isThrown= true;
-										break;
-									}
-								}
-								if (!isThrown) {
-									allExceptions.add(exceptionType);
-								}
+								allExceptions.add(exceptionType);
 							}
 						}
 					}
@@ -470,11 +461,28 @@
 			}
 		}
 
-		List<ITypeBinding> filteredExceptions= filterSubtypeExceptions(allExceptions);
-		if (allExceptions.size() > 0) {
+		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;
+			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();
-			int i=0;
 			for (ITypeBinding exception : filteredExceptions) {
 				Type type= fImportRewrite.addImport(exception, getAST(), context, TypeLocation.EXCEPTION);
 				types.add(type);
@@ -549,7 +557,7 @@
 
 	}
 
-	private IMethodBinding findAutocloseMethod(ITypeBinding type) {
+	public static IMethodBinding findAutocloseMethod(ITypeBinding type) {
 		while (type != null) {
 			IMethodBinding[] methods= type.getDeclaredMethods();
 			for (IMethodBinding method : methods) {
@@ -581,7 +589,7 @@
 	}
 
 	// find all nodes (statements) that are within the start/end positions
-	private List<ASTNode> findNodesInRange(ASTNode astNode, final int start, final int end) {
+	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;
@@ -602,7 +610,8 @@
 							Statement pStatement= (Statement) statement.getParent();
 							switch (pStatement.getNodeType()) {
 								case ASTNode.BLOCK:
-									if (pStatement.getParent().getNodeType() != ASTNode.METHOD_DECLARATION) {
+									if (pStatement.getParent().getNodeType() != ASTNode.METHOD_DECLARATION &&
+									pStatement.getParent().getNodeType() != ASTNode.TRY_STATEMENT) {
 										statement= pStatement;
 										continue;
 									} else {
@@ -628,20 +637,6 @@
 		return nodesInRange;
 	}
 
-	private List<ITypeBinding> filterSubtypeExceptions(List<ITypeBinding> exceptions) {
-		List<ITypeBinding> filteredExceptions= new ArrayList<>(exceptions);
-		for (Iterator<ITypeBinding> subtypeIterator= filteredExceptions.iterator(); subtypeIterator.hasNext();) {
-			ITypeBinding iTypeBinding= subtypeIterator.next();
-			for (ITypeBinding superTypeBinding : filteredExceptions) {
-				if (!iTypeBinding.equals(superTypeBinding) && iTypeBinding.isSubTypeCompatible(superTypeBinding)) {
-					subtypeIterator.remove();
-					break;
-				}
-			}
-		}
-		return filteredExceptions;
-	}
-
 	private List<ASTNode> getSpecialVariableDeclarationStatements() {
 		List<ASTNode> result= new ArrayList<>(3);
 		for (VariableDeclaration local : fAnalyzer.getAffectedLocals()) {
diff --git a/org.eclipse.jdt.ui/plugin.xml b/org.eclipse.jdt.ui/plugin.xml
index cc1e418..eac7ceb 100644
--- a/org.eclipse.jdt.ui/plugin.xml
+++ b/org.eclipse.jdt.ui/plugin.xml
@@ -7138,9 +7138,14 @@
             runAfter="org.eclipse.jdt.ui.cleanup.static_inner_class">
       </cleanUp>
       <cleanUp
+            class="org.eclipse.jdt.internal.ui.fix.PlainReplacementCleanUp"
+            id="org.eclipse.jdt.ui.cleanup.plain_replacement"
+            runAfter="org.eclipse.jdt.ui.cleanup.stringbuilder">
+      </cleanUp>
+      <cleanUp
             class="org.eclipse.jdt.internal.ui.fix.LazyLogicalCleanUp"
             id="org.eclipse.jdt.ui.cleanup.lazy_logical"
-            runAfter="org.eclipse.jdt.ui.cleanup.stringbuilder">
+            runAfter="org.eclipse.jdt.ui.cleanup.plain_replacement">
       </cleanUp>
       <cleanUp
             class="org.eclipse.jdt.internal.ui.fix.PrimitiveComparisonCleanUp"
@@ -7313,9 +7318,14 @@
             runAfter="org.eclipse.jdt.ui.cleanup.collection_cloning">
       </cleanUp>
       <cleanUp
+            class="org.eclipse.jdt.internal.ui.fix.InvertEqualsCleanUp"
+            id="org.eclipse.jdt.ui.cleanup.invert_equals"
+            runAfter="org.eclipse.jdt.ui.cleanup.map_cloning">
+      </cleanUp>
+      <cleanUp
             class="org.eclipse.jdt.internal.ui.fix.StandardComparisonCleanUp"
             id="org.eclipse.jdt.ui.cleanup.standard_comparison"
-            runAfter="org.eclipse.jdt.ui.cleanup.map_cloning">
+            runAfter="org.eclipse.jdt.ui.cleanup.invert_equals">
       </cleanUp>
       <cleanUp
             class="org.eclipse.jdt.internal.ui.fix.BitwiseConditionalExpressionCleanup"
diff --git a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/code/ExtractMethodInputPage.java b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/code/ExtractMethodInputPage.java
index 27d6998..0e81f1a 100644
--- a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/code/ExtractMethodInputPage.java
+++ b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/code/ExtractMethodInputPage.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
@@ -12,6 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Benjamin Muskalla <bmuskalla@eclipsesource.com> - [extract method] remember selected access modifier - https://bugs.eclipse.org/bugs/show_bug.cgi?id=101233
  *     Samrat Dhillon <samrat.dhillon@gmail.com> -  [extract method] Extracted method should be declared static if extracted expression is also used in another static method https://bugs.eclipse.org/bugs/show_bug.cgi?id=393098
+ *     Microsoft Corporation - read preferences from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.refactoring.code;
 
@@ -368,7 +369,7 @@
 		if (fSettings == null) {
 			fSettings= getDialogSettings().addNewSection(ExtractMethodWizard.DIALOG_SETTING_SECTION);
 			fSettings.put(THROW_RUNTIME_EXCEPTIONS, false);
-			fSettings.put(GENERATE_JAVADOC, JavaPreferencesSettings.getCodeGenerationSettings(fRefactoring.getCompilationUnit().getJavaProject()).createComments);
+			fSettings.put(GENERATE_JAVADOC, JavaPreferencesSettings.getCodeGenerationSettings(fRefactoring.getCompilationUnit()).createComments);
 			fSettings.put(ACCESS_MODIFIER, Modifier.PRIVATE);
 		}
 		fRefactoring.setThrowRuntimeExceptions(fSettings.getBoolean(THROW_RUNTIME_EXCEPTIONS));
diff --git a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/PasteAction.java b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/PasteAction.java
index 7cbd3ec..9797b6e 100644
--- a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/PasteAction.java
+++ b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/reorg/PasteAction.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
@@ -10,6 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.refactoring.reorg;
 
@@ -945,7 +946,7 @@
 					DocumentRewriteSession rewriteSession= null;
 					if (document instanceof IDocumentExtension4)
 						rewriteSession= ((IDocumentExtension4) document).startRewriteSession(DocumentRewriteSessionType.UNRESTRICTED_SMALL);
-					TextEdit edit= rewrite.rewriteAST(document, cu.getJavaProject().getOptions(true));
+					TextEdit edit= rewrite.rewriteAST(document, cu.getOptions(true));
 					try {
 						edit.apply(document, TextEdit.UPDATE_REGIONS);
 						return textPosition;
@@ -1553,14 +1554,15 @@
 					}
 				}
 				final CompilationUnitChange result= new CompilationUnitChange(ReorgMessages.PasteAction_change_name, getDestinationCu());
+				ICompilationUnit destinationCu= getDestinationCu();
 				try {
-					ITextFileBuffer buffer= RefactoringFileBuffers.acquire(getDestinationCu());
-					TextEdit rootEdit= rewrite.rewriteAST(buffer.getDocument(), fDestination.getJavaProject().getOptions(true));
-					if (getDestinationCu().isWorkingCopy())
+					ITextFileBuffer buffer= RefactoringFileBuffers.acquire(destinationCu);
+					TextEdit rootEdit= rewrite.rewriteAST(buffer.getDocument(), destinationCu.getOptions(true));
+					if (destinationCu.isWorkingCopy())
 						result.setSaveMode(TextFileChange.LEAVE_DIRTY);
 					TextChangeCompatibility.addTextEdit(result, ReorgMessages.PasteAction_edit_name, rootEdit);
 				} finally {
-					RefactoringFileBuffers.release(getDestinationCu());
+					RefactoringFileBuffers.release(destinationCu);
 				}
 				return result;
 			}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/ComparingOnCriteriaCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/ComparingOnCriteriaCleanUp.java
index f7bfd73..dc4e33f 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/ComparingOnCriteriaCleanUp.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/ComparingOnCriteriaCleanUp.java
@@ -546,7 +546,7 @@
 		}
 
 		private TypeMethodReference buildMethod(final ITypeBinding type, final MethodInvocation method, final ASTRewrite rewrite, final AST ast, final ImportRewrite importRewrite) {
-			String comparedClassNameText= importRewrite.addImport(type);
+			String comparedClassNameText= importRewrite.addImport((type.getBound() != null && !type.isUpperbound()) ? type.getBound() : type.getErasure());
 
 			TypeMethodReference typeMethodRef= ast.newTypeMethodReference();
 			typeMethodRef.setType(ast.newSimpleType(ASTNodeFactory.newName(ast, comparedClassNameText)));
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/InvertEqualsCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/InvertEqualsCleanUp.java
new file mode 100644
index 0000000..72514f7
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/InvertEqualsCleanUp.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.ui.cleanup.CleanUpContext;
+import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
+import org.eclipse.jdt.ui.cleanup.CleanUpRequirements;
+import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
+
+/**
+ * A fix that inverts calls to <code>Object.equals(Object)</code> and <code>String.equalsIgnoreCase(String)</code>:
+ * <ul>
+ * <li>It avoids useless null pointer exception,</li>
+ * <li>The caller must be nullable,</li>
+ * <li>The parameter must not be nullable,</li>
+ * <li>Beware! By avoiding null pointer exception, the behavior may change!</li>
+ * </ul>
+ */
+public class InvertEqualsCleanUp extends AbstractCleanUp {
+	private InvertEqualsCleanUpCore coreCleanUp= new InvertEqualsCleanUpCore();
+
+	public InvertEqualsCleanUp(final Map<String, String> options) {
+		setOptions(options);
+	}
+
+	public InvertEqualsCleanUp() {
+	}
+
+	@Override
+	public void setOptions(final CleanUpOptions options) {
+		coreCleanUp.setOptions(options);
+	}
+
+	@Override
+	public CleanUpRequirements getRequirements() {
+		return new CleanUpRequirements(coreCleanUp.getRequirementsCore());
+	}
+
+	@Override
+	public ICleanUpFix createFix(final CleanUpContext context) throws CoreException {
+		ICleanUpFixCore fixCore= coreCleanUp.createFixCore(context);
+		return fixCore != null ? new CleanUpFixWrapper(fixCore) : null;
+	}
+
+	@Override
+	public String[] getStepDescriptions() {
+		return coreCleanUp.getStepDescriptions();
+	}
+
+	@Override
+	public String getPreview() {
+		return coreCleanUp.getPreview();
+	}
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/PlainReplacementCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/PlainReplacementCleanUp.java
new file mode 100644
index 0000000..9d8f114
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/PlainReplacementCleanUp.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.ui.cleanup.CleanUpContext;
+import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
+import org.eclipse.jdt.ui.cleanup.CleanUpRequirements;
+import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
+
+/**
+ * A fix that replaces <code>String.replaceAll()</code> by <code>String.replace()</code> when the pattern is a plain text:
+ * <ul>
+ * <li>The pattern must be a constant.</li>
+ * </ul>
+ */
+public class PlainReplacementCleanUp extends AbstractCleanUp {
+	private PlainReplacementCleanUpCore coreCleanUp= new PlainReplacementCleanUpCore();
+
+	public PlainReplacementCleanUp(final Map<String, String> options) {
+		setOptions(options);
+	}
+
+	public PlainReplacementCleanUp() {
+	}
+
+	@Override
+	public void setOptions(final CleanUpOptions options) {
+		coreCleanUp.setOptions(options);
+	}
+
+	@Override
+	public CleanUpRequirements getRequirements() {
+		return new CleanUpRequirements(coreCleanUp.getRequirementsCore());
+	}
+
+	@Override
+	public ICleanUpFix createFix(final CleanUpContext context) throws CoreException {
+		ICleanUpFixCore fixCore= coreCleanUp.createFixCore(context);
+		return fixCore != null ? new CleanUpFixWrapper(fixCore) : null;
+	}
+
+	@Override
+	public String[] getStepDescriptions() {
+		return coreCleanUp.getStepDescriptions();
+	}
+
+	@Override
+	public String getPreview() {
+		return coreCleanUp.getPreview();
+	}
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EditorUtility.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EditorUtility.java
index 1e0ba6d..7a8a0e1 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EditorUtility.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/EditorUtility.java
@@ -15,8 +15,10 @@
 
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.osgi.framework.Bundle;
@@ -311,9 +313,11 @@
 					protected void execute(IProgressMonitor monitor) throws CoreException {
 						IMarker marker= null;
 						try {
-							marker= ((IFileEditorInput)input).getFile().createMarker(IMarker.TEXT);
-							marker.setAttribute(IMarker.CHAR_START, offset);
-							marker.setAttribute(IMarker.CHAR_END, offset + length);
+							Map<String,Object> attributes = new HashMap<>();
+							attributes.put(IMarker.CHAR_START, Integer.valueOf(offset));
+							attributes.put(IMarker.CHAR_END, Integer.valueOf(offset + length));
+
+							marker= ((IFileEditorInput)input).getFile().createMarker(IMarker.TEXT, attributes);
 
 							gotoMarkerTarget.gotoMarker(marker);
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/SmartTypingConfigurationBlock.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/SmartTypingConfigurationBlock.java
index 5a6d46b..7a540e5 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/SmartTypingConfigurationBlock.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/SmartTypingConfigurationBlock.java
@@ -35,6 +35,7 @@
 
 import org.eclipse.ui.dialogs.PreferencesUtil;
 
+import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
 
@@ -295,11 +296,11 @@
 	}
 
 	private int getIndentSize() {
-		return CodeFormatterUtil.getIndentWidth(null);
+		return CodeFormatterUtil.getIndentWidth((IJavaProject)null);
 	}
 
 	private int getTabDisplaySize() {
-		return CodeFormatterUtil.getTabWidth(null);
+		return CodeFormatterUtil.getTabWidth((IJavaProject)null);
 	}
 
 }
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java
index c581eb8..8ec3ba6 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java
@@ -85,6 +85,7 @@
 	public static String OptimizationTabPage_CheckboxName_BreakLoop;
 	public static String OptimizationTabPage_CheckboxName_StaticInnerClass;
 	public static String OptimizationTabPage_CheckboxName_StringBuilder;
+	public static String OptimizationTabPage_CheckboxName_PlainReplacement;
 	public static String OptimizationTabPage_CheckboxName_UseLazyLogicalOperator;
 	public static String OptimizationTabPage_CheckboxName_PrimitiveComparison;
 	public static String OptimizationTabPage_CheckboxName_PrimitiveParsing;
@@ -162,6 +163,7 @@
 
 	public static String SourceFixingTabPage_GroupName_standardCode;
 
+	public static String SourceFixingTabPage_CheckboxName_InvertEquals;
 	public static String SourceFixingTabPage_CheckboxName_StandardComparison;
 	public static String SourceFixingTabPage_CheckboxName_CheckSignOfBitwiseOperation;
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties
index 46b5119..6e3afdc 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties
@@ -64,6 +64,7 @@
 OptimizationTabPage_CheckboxName_BreakLoop=Exit &loop earlier
 OptimizationTabPage_CheckboxName_StaticInnerClass=Make inner classes static where possible
 OptimizationTabPage_CheckboxName_StringBuilder=Replace &String concatenation by StringBuilder
+OptimizationTabPage_CheckboxName_PlainReplacement=Use String::replace instead of String::replaceAll when no regex used
 OptimizationTabPage_CheckboxName_UseLazyLogicalOperator=Use la&zy logical operator
 OptimizationTabPage_CheckboxName_PrimitiveComparison=Primitive comparison
 OptimizationTabPage_CheckboxName_PrimitiveParsing=Primitive parsing
@@ -139,6 +140,7 @@
 
 SourceFixingTabPage_GroupName_standardCode=Code standardization
 
+SourceFixingTabPage_CheckboxName_InvertEquals=Avoid Object::equals or String::equalsIgnoreCase on null objects
 SourceFixingTabPage_CheckboxName_StandardComparison=Compare to zero
 SourceFixingTabPage_CheckboxName_CheckSignOfBitwiseOperation=&Compare with != 0 for bitwise expressions
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/OptimizationTabPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/OptimizationTabPage.java
index ca79c45..0abce49 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/OptimizationTabPage.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/OptimizationTabPage.java
@@ -26,6 +26,7 @@
 import org.eclipse.jdt.internal.ui.fix.LazyLogicalCleanUp;
 import org.eclipse.jdt.internal.ui.fix.NoStringCreationCleanUp;
 import org.eclipse.jdt.internal.ui.fix.PatternCleanUp;
+import org.eclipse.jdt.internal.ui.fix.PlainReplacementCleanUp;
 import org.eclipse.jdt.internal.ui.fix.PrimitiveComparisonCleanUp;
 import org.eclipse.jdt.internal.ui.fix.PrimitiveParsingCleanUp;
 import org.eclipse.jdt.internal.ui.fix.PrimitiveSerializationCleanUp;
@@ -43,6 +44,7 @@
 				new BreakLoopCleanUp(values),
 				new StaticInnerClassCleanUp(values),
 				new StringBuilderCleanUp(values),
+				new PlainReplacementCleanUp(values),
 				new LazyLogicalCleanUp(values),
 				new PrimitiveComparisonCleanUp(values),
 				new PrimitiveParsingCleanUp(values),
@@ -69,6 +71,9 @@
 		final CheckboxPreference stringBuilderPref= createCheckboxPref(optimizationGroup, numColumns, CleanUpMessages.OptimizationTabPage_CheckboxName_StringBuilder, CleanUpConstants.STRINGBUILDER, CleanUpModifyDialog.FALSE_TRUE);
 		registerPreference(stringBuilderPref);
 
+		final CheckboxPreference plainReplacementPref= createCheckboxPref(optimizationGroup, numColumns, CleanUpMessages.OptimizationTabPage_CheckboxName_PlainReplacement, CleanUpConstants.PLAIN_REPLACEMENT, CleanUpModifyDialog.FALSE_TRUE);
+		registerPreference(plainReplacementPref);
+
 		final CheckboxPreference useLazyLogicalPref= createCheckboxPref(optimizationGroup, numColumns, CleanUpMessages.OptimizationTabPage_CheckboxName_UseLazyLogicalOperator,
 				CleanUpConstants.USE_LAZY_LOGICAL_OPERATOR, CleanUpModifyDialog.FALSE_TRUE);
 		registerPreference(useLazyLogicalPref);
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/SourceFixingTabPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/SourceFixingTabPage.java
index 096e5ef..ad5d312 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/SourceFixingTabPage.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/SourceFixingTabPage.java
@@ -27,6 +27,7 @@
 
 import org.eclipse.jdt.internal.ui.fix.AbstractCleanUp;
 import org.eclipse.jdt.internal.ui.fix.BitwiseConditionalExpressionCleanup;
+import org.eclipse.jdt.internal.ui.fix.InvertEqualsCleanUp;
 import org.eclipse.jdt.internal.ui.fix.StandardComparisonCleanUp;
 
 public final class SourceFixingTabPage extends AbstractCleanUpTabPage {
@@ -35,6 +36,7 @@
 	@Override
 	protected AbstractCleanUp[] createPreviewCleanUps(final Map<String, String> values) {
 		return new AbstractCleanUp[] {
+				new InvertEqualsCleanUp(values),
 				new StandardComparisonCleanUp(values),
 				new BitwiseConditionalExpressionCleanup(values)
 		};
@@ -49,6 +51,9 @@
 
 		Group standardCodeGroup= createGroup(numColumns, composite, CleanUpMessages.SourceFixingTabPage_GroupName_standardCode);
 
+		final CheckboxPreference invertEqualsPref= createCheckboxPref(standardCodeGroup, numColumns, CleanUpMessages.SourceFixingTabPage_CheckboxName_InvertEquals, CleanUpConstants.INVERT_EQUALS, CleanUpModifyDialog.FALSE_TRUE);
+		registerPreference(invertEqualsPref);
+
 		final CheckboxPreference standardComparisonPref= createCheckboxPref(standardCodeGroup, numColumns, CleanUpMessages.SourceFixingTabPage_CheckboxName_StandardComparison, CleanUpConstants.STANDARD_COMPARISON, CleanUpModifyDialog.FALSE_TRUE);
 		registerPreference(standardComparisonPref);
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/JavadocTagsSubProcessor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/JavadocTagsSubProcessor.java
index 79d9a69..3b08f90 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/JavadocTagsSubProcessor.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/JavadocTagsSubProcessor.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
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Red Hat Inc. - add module-info support
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.text.correction;
 
@@ -116,12 +117,12 @@
 		protected void addEdits(IDocument document, TextEdit rootEdit) throws CoreException {
 			try {
 				String lineDelimiter= TextUtilities.getDefaultLineDelimiter(document);
-				final IJavaProject project= getCompilationUnit().getJavaProject();
+				final ICompilationUnit unit= getCompilationUnit();
 				IRegion region= document.getLineInformationOfOffset(fInsertPosition);
 
 				String lineContent= document.get(region.getOffset(), region.getLength());
-				String indentString= Strings.getIndentString(lineContent, project);
-				String str= Strings.changeIndent(fComment, 0, project, indentString, lineDelimiter);
+				String indentString= Strings.getIndentString(lineContent, unit);
+				String str= Strings.changeIndent(fComment, 0, unit, indentString, lineDelimiter);
 				InsertEdit edit= new InsertEdit(fInsertPosition, str);
 				rootEdit.addChild(edit);
 				if (fComment.charAt(fComment.length() - 1) != '\n') {
@@ -150,7 +151,7 @@
 			try {
 				Javadoc javadoc= null;
 				String lineDelimiter= TextUtilities.getDefaultLineDelimiter(document);
-				final IJavaProject project= getCompilationUnit().getJavaProject();
+				final ICompilationUnit unit= getCompilationUnit();
 				CompilationUnit cu= (CompilationUnit)fDecl.getParent();
 				Name name= fDecl.getName();
 				List<Comment> comments= cu.getCommentList();
@@ -176,8 +177,8 @@
 				IRegion region= document.getLineInformationOfOffset(insertPosition);
 
 				String lineContent= document.get(region.getOffset(), region.getLength());
-				String indentString= Strings.getIndentString(lineContent, project);
-				String str= Strings.changeIndent(comment.toString(), 0, project, indentString, lineDelimiter);
+				String indentString= Strings.getIndentString(lineContent, unit);
+				String str= Strings.changeIndent(comment.toString(), 0, unit, indentString, lineDelimiter);
 				InsertEdit edit= new InsertEdit(insertPosition, str);
 				rootEdit.addChild(edit);
 			} catch (BadLocationException e) {
@@ -240,7 +241,7 @@
 				Javadoc javadoc= null;
 				int insertPosition;
 				String lineDelimiter= TextUtilities.getDefaultLineDelimiter(document);
-				final IJavaProject project= getCompilationUnit().getJavaProject();
+				final ICompilationUnit unit= getCompilationUnit();
 				CompilationUnit cu= (CompilationUnit)fDecl.getParent();
 				Name moduleName= fDecl.getName();
 				List<Comment> comments= cu.getCommentList();
@@ -282,8 +283,8 @@
 				IRegion region= document.getLineInformationOfOffset(insertPosition);
 
 				String lineContent= document.get(region.getOffset(), region.getLength());
-				String indentString= Strings.getIndentString(lineContent, project);
-				String str= Strings.changeIndent(comment.toString(), 0, project, indentString, lineDelimiter);
+				String indentString= Strings.getIndentString(lineContent, unit);
+				String str= Strings.changeIndent(comment.toString(), 0, unit, indentString, lineDelimiter);
 				InsertEdit edit= new InsertEdit(insertPosition, str);
 				rootEdit.addChild(edit);
 			} catch (BadLocationException e) {
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/LocalCorrectionsSubProcessor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/LocalCorrectionsSubProcessor.java
index b50365e..f048d6f 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/LocalCorrectionsSubProcessor.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/LocalCorrectionsSubProcessor.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
@@ -15,6 +15,7 @@
  *     Lukas Hanke <hanke@yatta.de> - Bug 241696 [quick fix] quickfix to iterate over a collection - https://bugs.eclipse.org/bugs/show_bug.cgi?id=241696
  *     Sandra Lions <sandra.lions-piron@oracle.com> - [quick fix] for qualified enum constants in switch-case labels - https://bugs.eclipse.org/bugs/90140
  *     Stephan Herrmann - Contribution for Bug 463360 - [override method][null] generating method override should not create redundant null annotations
+ *     Microsoft Corporation - read preferences from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.text.correction;
 
@@ -2132,7 +2133,7 @@
 		LinkedCorrectionProposal proposal2= new LinkedCorrectionProposal(label, cu, rewrite, IProposalRelevance.OVERRIDE_HASHCODE, image);
 		ImportRewrite importRewrite= proposal2.createImportRewrite(astRoot);
 
-		final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu.getJavaProject());
+		final CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu);
 
 		try {
 			ImportRewriteContext importContext= new ContextSensitiveImportRewriteContext(astRoot, problem.getOffset(), importRewrite);
@@ -2279,7 +2280,7 @@
 
 		ImportRewrite importRewrite= proposal.createImportRewrite(astRoot);
 		ImportRewriteContext importRewriteContext= new ContextSensitiveImportRewriteContext(astRoot, typeNode.getStartPosition(), importRewrite);
-		CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu.getJavaProject());
+		CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu);
 		try {
 			MethodDeclaration stub= StubUtility2.createImplementationStub(cu, rewrite, importRewrite, importRewriteContext, methodToOverride, typeBinding, settings,
 					typeBinding.isInterface(), new NodeFinder(astRoot, typeNode.getStartPosition(), 0).getCoveringNode());
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 e8f5852..07655ca 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
@@ -126,6 +126,7 @@
 import org.eclipse.jdt.core.dom.SwitchStatement;
 import org.eclipse.jdt.core.dom.SynchronizedStatement;
 import org.eclipse.jdt.core.dom.ThisExpression;
+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.TypeDeclaration;
@@ -152,6 +153,7 @@
 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
 import org.eclipse.jdt.internal.corext.dom.Bindings;
+import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
 import org.eclipse.jdt.internal.corext.dom.DimensionRewrite;
 import org.eclipse.jdt.internal.corext.dom.JdtASTMatcher;
 import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
@@ -179,6 +181,8 @@
 import org.eclipse.jdt.internal.corext.refactoring.code.Invocations;
 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.util.TightSourceRangeComputer;
 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
 import org.eclipse.jdt.internal.corext.util.Messages;
@@ -3307,7 +3311,7 @@
 	}
 
 	private static boolean getTryWithResourceProposals(IInvocationContext context, ASTNode node, ArrayList<ASTNode> coveredNodes, Collection<ICommandAccess> resultingCollections)
-			throws IllegalArgumentException, JavaModelException {
+			throws IllegalArgumentException, CoreException {
 
 		ASTNode parentStatement= ASTResolving.findAncestor(node, ASTNode.VARIABLE_DECLARATION_STATEMENT);
 		if (!(parentStatement instanceof VariableDeclarationStatement) &&
@@ -3334,9 +3338,7 @@
 		if (coveredAutoClosableNodes.isEmpty()) {
 			return false;
 		}
-		if (isParentTryStatement(coveredAutoClosableNodes.get(0))) {
-			return false;
-		}
+
 		BodyDeclaration parentBodyDeclaration= ASTResolving.findParentBodyDeclaration(node);
 		int start= coveredAutoClosableNodes.get(0).getStartPosition();
 		int end= start;
@@ -3347,7 +3349,7 @@
 		}
 
 		// recursive loop to find all nodes affected by wrapping in try block
-		List<ASTNode> nodesInRange= findNodesInRange(parentBodyDeclaration, start, end);
+		List<ASTNode> nodesInRange= SurroundWithTryWithResourcesRefactoring.findNodesInRange(parentBodyDeclaration, start, end);
 		int oldEnd= end;
 		while (true) {
 			int newEnd= oldEnd;
@@ -3357,7 +3359,7 @@
 			}
 			if (newEnd > oldEnd) {
 				oldEnd= newEnd;
-				nodesInRange= findNodesInRange(parentBodyDeclaration, start, newEnd);
+				nodesInRange= SurroundWithTryWithResourcesRefactoring.findNodesInRange(parentBodyDeclaration, start, newEnd);
 				continue;
 			}
 			break;
@@ -3371,6 +3373,14 @@
 		TryStatement newTryStatement= ast.newTryStatement();
 		Block newTryBody= ast.newBlock();
 		newTryStatement.setBody(newTryBody);
+		ICompilationUnit icu= context.getCompilationUnit();
+		ASTNode lastNode= nodesInRange.isEmpty() ? coveredAutoClosableNodes.get(coveredAutoClosableNodes.size() - 1)
+				: nodesInRange.get(nodesInRange.size() - 1);
+		Selection selection= Selection.createFromStartLength(start, lastNode.getStartPosition() - start + lastNode.getLength());
+		SurroundWithTryWithResourcesAnalyzer analyzer= new SurroundWithTryWithResourcesAnalyzer(icu, selection);
+		cu.accept(analyzer);
+		ITypeBinding[] exceptions= analyzer.getExceptions(analyzer.getSelection());
+		List<ITypeBinding> allExceptions= new ArrayList<>(Arrays.asList(exceptions));
 		for (ASTNode coveredNode : coveredAutoClosableNodes) {
 			ASTNode findAncestor= ASTResolving.findAncestor(coveredNode, ASTNode.VARIABLE_DECLARATION_STATEMENT);
 			if (findAncestor == null) {
@@ -3384,6 +3394,17 @@
 					commentToken= buffer.getText(extendedStatementStart, vds.getStartPosition() - extendedStatementStart);
 				}
 				Type type= vds.getType();
+				ITypeBinding typeBinding= type.resolveBinding();
+				if (typeBinding != null) {
+					IMethodBinding close= SurroundWithTryWithResourcesRefactoring.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()) {
@@ -3420,10 +3441,74 @@
 			return false;
 		}
 
+		String label= CorrectionMessages.QuickAssistProcessor_convert_to_try_with_resource;
+		Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
+		LinkedCorrectionProposal proposal= new LinkedCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.SURROUND_WITH_TRY_CATCH, image);
+
+		ImportRewrite imports= proposal.createImportRewrite(context.getASTRoot());
+		ImportRewriteContext importRewriteContext= new ContextSensitiveImportRewriteContext(node, imports);
+
+		CatchClause catchClause= ast.newCatchClause();
+		SingleVariableDeclaration decl= ast.newSingleVariableDeclaration();
+		String varName= StubUtility.getExceptionVariableName(icu.getJavaProject());
+		parentBodyDeclaration.getRoot().accept(analyzer);
+		CodeScopeBuilder.Scope scope= CodeScopeBuilder.perform(analyzer.getEnclosingBodyDeclaration(), selection).
+				findScope(selection.getOffset(), selection.getLength());
+		scope.setCursor(selection.getOffset());
+		String name= scope.createName(varName, false);
+		decl.setName(ast.newSimpleName(name));
+
+		List<ITypeBinding> mustRethrowList= new ArrayList<>();
+		List<ITypeBinding> catchExceptions= analyzer.calculateCatchesAndRethrows(ASTNodes.filterSubtypes(allExceptions), mustRethrowList);
+		List<ITypeBinding> filteredExceptions= ASTNodes.filterSubtypes(catchExceptions);
+
+		if (catchExceptions.size() > 0) {
+			final String GROUP_EXC_NAME= "exc_name"; //$NON-NLS-1$
+			final String GROUP_EXC_TYPE= "exc_type"; //$NON-NLS-1$
+			LinkedProposalModel linkedProposalModel= new LinkedProposalModel();
+
+			int i= 0;
+			for (ITypeBinding mustThrow : mustRethrowList) {
+				CatchClause newClause= ast.newCatchClause();
+				SingleVariableDeclaration newDecl= ast.newSingleVariableDeclaration();
+				newDecl.setName(ast.newSimpleName(name));
+				Type importType= imports.addImport(mustThrow, ast, importRewriteContext, 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(rewrite.track(decl.getName()), false);
+				newClause.getBody().statements().add(newThrowStatement);
+				newTryStatement.catchClauses().add(newClause);
+				++i;
+			}
+			UnionType unionType= ast.newUnionType();
+			List<Type> types= unionType.types();
+			for (ITypeBinding exception : filteredExceptions) {
+				Type type= imports.addImport(exception, ast, importRewriteContext, TypeLocation.EXCEPTION);
+				types.add(type);
+				linkedProposalModel.getPositionGroup(GROUP_EXC_TYPE + i, true).addPosition(rewrite.track(type), i == 0);
+				i++;
+			}
+
+			decl.setType(unionType);
+			catchClause.setException(decl);
+			linkedProposalModel.getPositionGroup(GROUP_EXC_NAME + 0, true).addPosition(rewrite.track(decl.getName()), false);
+			Statement st= null;
+			String s= StubUtility.getCatchBodyContent(icu, "Exception", name, coveredNodes.get(0), icu.findRecommendedLineSeparator()); //$NON-NLS-1$
+			if (s != null) {
+				st= (Statement)rewrite.createStringPlaceholder(s, ASTNode.RETURN_STATEMENT);
+			}
+			if (st != null) {
+				catchClause.getBody().statements().add(st);
+			}
+			newTryStatement.catchClauses().add(catchClause);
+		}
+
 		if (!nodesInRange.isEmpty()) {
 			ASTNode firstNode= nodesInRange.get(0);
-			MethodDeclaration methodDeclaration= ASTResolving.findParentMethodDeclaration(firstNode);
-			ListRewrite listRewrite= rewrite.getListRewrite(methodDeclaration.getBody(), Block.STATEMENTS_PROPERTY);
+			ASTNode methodDeclaration= ASTResolving.findAncestor(firstNode, ASTNode.BLOCK);
+			ListRewrite listRewrite= rewrite.getListRewrite(methodDeclaration, Block.STATEMENTS_PROPERTY);
 			ASTNode createCopyTarget= listRewrite.createMoveTarget(firstNode, nodesInRange.get(nodesInRange.size() - 1));
 			rewrite.getListRewrite(newTryBody, Block.STATEMENTS_PROPERTY).insertFirst(createCopyTarget, null);
 		}
@@ -3434,24 +3519,10 @@
 			rewrite.remove(coveredAutoClosableNodes.get(i), null);
 		}
 
-		String label= CorrectionMessages.QuickAssistProcessor_convert_to_try_with_resource;
-		Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
-		ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(
-				label, context.getCompilationUnit(), rewrite, IProposalRelevance.SURROUND_WITH_TRY_CATCH, image);
 		resultingCollections.add(proposal);
 		return true;
 	}
 
-	private static boolean isParentTryStatement(ASTNode astNode) {
-		while (astNode != null) {
-			if (astNode instanceof TryStatement) {
-				return true;
-			}
-			astNode= astNode.getParent();
-		}
-		return false;
-	}
-
 	private static int findEndPostion(ASTNode node) {
 		int end= node.getStartPosition() + node.getLength();
 		Map<SimpleName, IVariableBinding> nodeSimpleNameBindings= getVariableStatementBinding(node);
@@ -3535,54 +3606,6 @@
 		return variableBindings;
 	}
 
-	// find all nodes (statements) that are within the start/end positions
-	private 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) {
-										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 static boolean getAddBlockProposals(IInvocationContext context, ASTNode node, Collection<ICommandAccess> resultingCollections) {
 		if (!(node instanceof Statement)) {
 			return false;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/AbstractMethodCorrectionProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/AbstractMethodCorrectionProposal.java
index 9c753d6..71c2283 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/AbstractMethodCorrectionProposal.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/AbstractMethodCorrectionProposal.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
@@ -12,6 +12,7 @@
  *     IBM Corporation - initial API and implementation
  *     Benjamin Muskalla - [quick fix] Create Method in void context should 'box' void. - https://bugs.eclipse.org/bugs/show_bug.cgi?id=107985
  *     Jerome Cambon <jerome.cambon@oracle.com> - [code style] don't generate redundant modifiers "public static final abstract" for interface members - https://bugs.eclipse.org/71627
+ *     Microsoft Corporation - read preferences from the compilation unit
  *******************************************************************************/
 
 package org.eclipse.jdt.internal.ui.text.correction.proposals;
@@ -175,7 +176,7 @@
 		}
 		decl.setBody(body);
 
-		CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(getCompilationUnit().getJavaProject());
+		CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(getCompilationUnit());
 		if (settings.createComments && !fSenderBinding.isAnonymous()) {
 			String string= CodeGeneration.getMethodComment(getCompilationUnit(), fSenderBinding.getName(), decl, null, String.valueOf('\n'));
 			if (string != null) {
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 00c2f82..a8a3ce3 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
@@ -37,6 +37,7 @@
 import org.eclipse.jdt.core.dom.Assignment;
 import org.eclipse.jdt.core.dom.Block;
 import org.eclipse.jdt.core.dom.BodyDeclaration;
+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.EmptyStatement;
@@ -44,6 +45,7 @@
 import org.eclipse.jdt.core.dom.ExpressionStatement;
 import org.eclipse.jdt.core.dom.FieldAccess;
 import org.eclipse.jdt.core.dom.FieldDeclaration;
+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.Initializer;
@@ -52,8 +54,10 @@
 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.VariableDeclarationExpression;
 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
@@ -69,11 +73,17 @@
 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
 import org.eclipse.jdt.internal.corext.dom.Bindings;
+import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
 import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
+import org.eclipse.jdt.internal.corext.dom.Selection;
 import org.eclipse.jdt.internal.corext.dom.TokenScanner;
 import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
 import org.eclipse.jdt.internal.corext.fix.CleanUpPostSaveListener;
 import org.eclipse.jdt.internal.corext.fix.CleanUpPreferenceUtil;
+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.util.Messages;
 
 import org.eclipse.jdt.ui.PreferenceConstants;
@@ -98,16 +108,20 @@
 
 	private final String KEY_NAME= "name";  //$NON-NLS-1$
 	private final String KEY_TYPE= "type";  //$NON-NLS-1$
+	private final String GROUP_EXC_TYPE= "exc_type"; //$NON-NLS-1$
+	private final String GROUP_EXC_NAME= "exc_name"; //$NON-NLS-1$
 
 	private final int  fVariableKind;
 	private final List<ASTNode> fNodesToAssign; // ExpressionStatement or SingleVariableDeclaration(s)
 	private final ITypeBinding fTypeBinding;
+	private final ICompilationUnit fCUnit;
 
 	private VariableDeclarationFragment fExistingFragment;
 
 	public AssignToVariableAssistProposal(ICompilationUnit cu, int variableKind, ExpressionStatement node, ITypeBinding typeBinding, int relevance) {
 		super("", cu, null, relevance, null); //$NON-NLS-1$
 
+		fCUnit= cu;
 		fVariableKind= variableKind;
 		fNodesToAssign= new ArrayList<>();
 		fNodesToAssign.add(node);
@@ -129,6 +143,7 @@
 	public AssignToVariableAssistProposal(ICompilationUnit cu, SingleVariableDeclaration parameter, VariableDeclarationFragment existingFragment, ITypeBinding typeBinding, int relevance) {
 		super("", cu, null, relevance, null); //$NON-NLS-1$
 
+		fCUnit= cu;
 		fVariableKind= FIELD;
 		fNodesToAssign= new ArrayList<>();
 		fNodesToAssign.add(parameter);
@@ -146,6 +161,7 @@
 	public AssignToVariableAssistProposal(ICompilationUnit cu, List<SingleVariableDeclaration> parameters, int relevance) {
 		super("", cu, null, relevance, null); //$NON-NLS-1$
 
+		fCUnit= cu;
 		fVariableKind= FIELD;
 		fNodesToAssign= new ArrayList<>();
 		fNodesToAssign.addAll(parameters);
@@ -169,14 +185,14 @@
 		}
 	}
 
-	private ASTRewrite doAddLocal() {
+	private ASTRewrite doAddLocal() throws CoreException {
 		ASTNode nodeToAssign= fNodesToAssign.get(0);
 		Expression expression= ((ExpressionStatement) nodeToAssign).getExpression();
 		AST ast= nodeToAssign.getAST();
 
 		ASTRewrite rewrite= ASTRewrite.create(ast);
 
-		createImportRewrite((CompilationUnit) nodeToAssign.getRoot());
+		ImportRewrite importRewrite= createImportRewrite((CompilationUnit) nodeToAssign.getRoot());
 
 		String[] varNames= suggestLocalVariableNames(fTypeBinding, expression);
 		for (String varName : varNames) {
@@ -217,6 +233,69 @@
 			EmptyStatement blankLine = (EmptyStatement) rewrite.createStringPlaceholder("", ASTNode.EMPTY_STATEMENT); //$NON-NLS-1$
 			tryStatement.getBody().statements().add(blankLine);
 
+			CatchClause catchClause= ast.newCatchClause();
+			SingleVariableDeclaration decl= ast.newSingleVariableDeclaration();
+			Selection selection= Selection.createFromStartLength(expression.getStartPosition(), expression.getLength());
+			String varName= StubUtility.getExceptionVariableName(fCUnit.getJavaProject());
+			SurroundWithTryWithResourcesAnalyzer analyzer= new SurroundWithTryWithResourcesAnalyzer(fCUnit, selection);
+			expression.getRoot().accept(analyzer);
+			CodeScopeBuilder.Scope scope= CodeScopeBuilder.perform(analyzer.getEnclosingBodyDeclaration(), selection).
+					findScope(selection.getOffset(), selection.getLength());
+			scope.setCursor(selection.getOffset());
+			String name= scope.createName(varName, false);
+			decl.setName(ast.newSimpleName(name));
+			ITypeBinding[] exceptions= 	ExceptionAnalyzer.perform(expression.getParent(), selection, false);
+			List<ITypeBinding> allExceptions= new ArrayList<>(Arrays.asList(exceptions));
+			List<ITypeBinding> mustRethrowList= new ArrayList<>();
+
+			if (fTypeBinding != null) {
+				IMethodBinding close= SurroundWithTryWithResourcesRefactoring.findAutocloseMethod(fTypeBinding);
+				if (close != null) {
+					for (ITypeBinding exceptionType : close.getExceptionTypes()) {
+						if (!allExceptions.contains(exceptionType)) {
+							allExceptions.add(exceptionType);
+						}
+					}
+				}
+			}
+			List<ITypeBinding> catchExceptions= analyzer.calculateCatchesAndRethrows(ASTNodes.filterSubtypes(allExceptions), mustRethrowList);
+			if (catchExceptions.size() > 0) {
+				ImportRewriteContext context= new ContextSensitiveImportRewriteContext(analyzer.getEnclosingBodyDeclaration(), importRewrite);
+				LinkedProposalModel linkedProposalModel= new LinkedProposalModel();
+				int i= 0;
+				for (ITypeBinding mustThrow : mustRethrowList) {
+					CatchClause newClause= ast.newCatchClause();
+					SingleVariableDeclaration newDecl= ast.newSingleVariableDeclaration();
+					newDecl.setName(ast.newSimpleName(name));
+					Type importType= importRewrite.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(rewrite.track(decl.getName()), false);
+					newClause.getBody().statements().add(newThrowStatement);
+					tryStatement.catchClauses().add(newClause);
+					++i;
+				}
+				List<ITypeBinding> filteredExceptions= ASTNodes.filterSubtypes(catchExceptions);
+				UnionType unionType= ast.newUnionType();
+				List<Type> types= unionType.types();
+				for (ITypeBinding exception : filteredExceptions) {
+					Type importType= importRewrite.addImport(exception, ast, context, TypeLocation.EXCEPTION);
+					types.add(importType);
+					linkedProposalModel.getPositionGroup(GROUP_EXC_TYPE + i, true).addPosition(rewrite.track(type), i == 0);
+					i++;
+				}
+				decl.setType(unionType);
+				catchClause.setException(decl);
+				linkedProposalModel.getPositionGroup(GROUP_EXC_NAME + 0, true).addPosition(rewrite.track(decl.getName()), false);
+				Statement st= getCatchBody(rewrite, expression, "Exception", name, fCUnit.findRecommendedLineSeparator()); //$NON-NLS-1$
+				if (st != null) {
+					catchClause.getBody().statements().add(st);
+				}
+				tryStatement.catchClauses().add(catchClause);
+			}
+
 			rewrite.replace(expression, tryStatement, null);
 			setEndPosition(rewrite.track(blankLine));
 		}
@@ -227,6 +306,15 @@
 		return rewrite;
 	}
 
+	private Statement getCatchBody(ASTRewrite rewrite, Expression expression, String type, String name, String lineSeparator) throws CoreException {
+		String s= StubUtility.getCatchBodyContent(fCUnit, type, name, expression, lineSeparator);
+		if (s == null) {
+			return null;
+		} else {
+			return (Statement)rewrite.createStringPlaceholder(s, ASTNode.RETURN_STATEMENT);
+		}
+	}
+
 	private boolean needsSemicolon(Expression expression) {
 		if ((expression.getParent().getFlags() & ASTNode.RECOVERED) != 0) {
 			try {
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/ConstructorFromSuperclassProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/ConstructorFromSuperclassProposal.java
index d89bb22..6046eff 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/ConstructorFromSuperclassProposal.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/proposals/ConstructorFromSuperclassProposal.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Microsoft Corporation - read preferences from the compilation unit
  *******************************************************************************/
 
 package org.eclipse.jdt.internal.ui.text.correction.proposals;
@@ -41,6 +42,7 @@
 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.TypeLocation;
 import org.eclipse.jdt.core.manipulation.CodeGeneration;
 
+import org.eclipse.jdt.internal.core.manipulation.StubUtility;
 import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
 import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
@@ -58,8 +60,6 @@
 import org.eclipse.jdt.internal.ui.text.correction.CorrectionMessages;
 import org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider;
 
-import org.eclipse.jdt.internal.core.manipulation.StubUtility;
-
 public class ConstructorFromSuperclassProposal extends LinkedCorrectionProposal {
 
 	private TypeDeclaration fTypeNode;
@@ -104,7 +104,7 @@
 
 		createImportRewrite((CompilationUnit) fTypeNode.getRoot());
 
-		CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(getCompilationUnit().getJavaProject());
+		CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(getCompilationUnit());
 		if (!settings.createComments) {
 			settings= null;
 		}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaMethodCompletionProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaMethodCompletionProposal.java
index 5ef3cb4..63ff989 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaMethodCompletionProposal.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaMethodCompletionProposal.java
@@ -24,7 +24,14 @@
 import org.eclipse.jface.text.contentassist.IContextInformation;
 
 import org.eclipse.jdt.core.CompletionProposal;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
 import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.ILocalVariable;
+import org.eclipse.jdt.core.IMember;
+import org.eclipse.jdt.core.ISourceRange;
+import org.eclipse.jdt.core.ISourceReference;
+import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.Signature;
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.formatter.CodeFormatter;
@@ -133,6 +140,10 @@
 		return fHasParameters;
 	}
 
+	public enum State {
+		NORMAL, SEEN_SLASH, IN_LINE_COMMENT, IN_BLOCK_COMMENT, SEEN_ASTERISK
+	}
+
 	/**
 	 * Returns whether we automatically complete the method with a semicolon.
 	 *
@@ -141,7 +152,112 @@
 	 * @since 3.9
 	 */
 	protected final boolean canAutomaticallyAppendSemicolon() {
-		return !fProposal.isConstructor() && CharOperation.equals(new char[] { Signature.C_VOID }, Signature.getReturnType(fProposal.getSignature()));
+		if (!fProposal.isConstructor() && CharOperation.equals(new char[] { Signature.C_VOID }, Signature.getReturnType(fProposal.getSignature()))) {
+			try {
+				// don't want to add semicolon if we are completing a method parameter
+				ICompilationUnit cu= fInvocationContext.getCompilationUnit();
+				IJavaElement element= cu.getElementAt(getReplacementOffset());
+				if (element instanceof IMember) {
+					// check if parentheses' are matched
+					return areParenthesesMatched(cu, (IMember)element);
+				} else if (element instanceof ILocalVariable) {
+					ILocalVariable localVar= (ILocalVariable)element;
+					return !localVar.isParameter();
+				}
+			} catch (JavaModelException e) {
+				return false;
+			}
+			return true;
+		}
+		return false;
+	}
+
+	// Simple member parser to see if we are not in matched parentheses and thus might be in a parameter list
+	private boolean areParenthesesMatched(ICompilationUnit cu, IMember element) throws JavaModelException {
+		String source= cu.getSource();
+		ISourceRange sourceRange= ((ISourceReference)element).getSourceRange();
+		int cnt= 0;
+		State state= State.NORMAL;
+		for (int i= sourceRange.getOffset(); i < getReplacementOffset(); ++i) {
+			char c= source.charAt(i);
+			switch (c) {
+				case '/':
+					switch (state) {
+						case SEEN_SLASH:
+							state= State.IN_LINE_COMMENT;
+							break;
+						case NORMAL:
+							state= State.SEEN_SLASH;
+							break;
+						case SEEN_ASTERISK:
+							state= State.NORMAL;
+							break;
+						case IN_BLOCK_COMMENT:
+						case IN_LINE_COMMENT:
+						default:
+							// no change
+							break;
+					}
+					break;
+				case '*':
+					switch (state) {
+						case SEEN_SLASH:
+							state= State.IN_BLOCK_COMMENT;
+							break;
+						case IN_BLOCK_COMMENT:
+							state= State.SEEN_ASTERISK;
+							break;
+						case SEEN_ASTERISK:
+						case NORMAL:
+						case IN_LINE_COMMENT:
+						default:
+							// no change
+							break;
+					}
+					break;
+				case '(':
+				case ')':
+					switch (state) {
+						case SEEN_SLASH:
+						case SEEN_ASTERISK:
+							state= State.NORMAL;
+							break;
+						case NORMAL:
+							if (c == '(') {
+								++cnt;
+							} else {
+								--cnt;
+							}
+							break;
+						case IN_BLOCK_COMMENT:
+						case IN_LINE_COMMENT:
+						default:
+							// no change
+							break;
+					}
+					break;
+				case '\n':
+					switch (state) {
+						case SEEN_SLASH:
+						case IN_LINE_COMMENT:
+							state= State.NORMAL;
+							break;
+						case SEEN_ASTERISK:
+							state= State.IN_BLOCK_COMMENT;
+							break;
+						case IN_BLOCK_COMMENT:
+						case NORMAL:
+						default:
+							// no change
+							break;
+					}
+					break;
+				default:
+					// do nothing
+					break;
+			}
+		}
+		return cnt == 0;
 	}
 
 	private boolean computeHasParameters() throws IllegalArgumentException {
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/OverrideCompletionProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/OverrideCompletionProposal.java
index 0132c3a..1301c7f 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/OverrideCompletionProposal.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/OverrideCompletionProposal.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2021 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Stephan Herrmann - Contribution for Bug 463360 - [override method][null] generating method override should not create redundant null annotations
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.text.java;
 
@@ -62,7 +63,6 @@
 
 public class OverrideCompletionProposal extends JavaTypeCompletionProposal implements ICompletionProposalExtension4 {
 
-	private IJavaProject fJavaProject;
 	private String fMethodName;
 	private String[] fParamTypes;
 
@@ -76,8 +76,6 @@
 		fParamTypes= paramTypes;
 		fMethodName= methodName;
 
-		fJavaProject= jproject;
-
 		StringBuilder buffer= new StringBuilder();
 		buffer.append(completionProposal);
 		buffer.append(" {};"); //$NON-NLS-1$
@@ -162,14 +160,14 @@
 				methodToOverride= Bindings.findMethodInType(node.getAST().resolveWellKnownType("java.lang.Object"), fMethodName, fParamTypes); //$NON-NLS-1$
 			}
 			if (methodToOverride != null) {
-				CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(fJavaProject);
+				CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(fCompilationUnit);
 				MethodDeclaration stub= StubUtility2.createImplementationStub(fCompilationUnit, rewrite, importRewrite, context, methodToOverride, declaringType, settings, declaringType.isInterface(), astNode);
 				ListRewrite rewriter= rewrite.getListRewrite(node, descriptor);
 				rewriter.insertFirst(stub, null);
 
 				ITrackedNodePosition position= rewrite.track(stub);
 				try {
-					rewrite.rewriteAST(recoveredDocument, fJavaProject.getOptions(true)).apply(recoveredDocument);
+					rewrite.rewriteAST(recoveredDocument, fCompilationUnit.getOptions(true)).apply(recoveredDocument);
 
 					String generatedCode= recoveredDocument.get(position.getStartPosition(), position.getLength());
 					int generatedIndent= IndentManipulation.measureIndentUnits(getIndentAt(recoveredDocument, position.getStartPosition(), settings), settings.tabWidth, settings.indentWidth);
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/template/contentassist/SurroundWithTemplateProposal.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/template/contentassist/SurroundWithTemplateProposal.java
index 2efde9e..8c9bf68 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/template/contentassist/SurroundWithTemplateProposal.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/template/contentassist/SurroundWithTemplateProposal.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
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.text.template.contentassist;
 
@@ -239,7 +240,7 @@
 		AssistContext invocationContext= new AssistContext(fCompilationUnit, fContext.getStart(), fContext.getEnd() - fContext.getStart());
 
 		SurroundWithTemplate surroundWith= new SurroundWithTemplate(invocationContext, fSelectedNodes, fTemplate);
-		Map<String, String> options= fCompilationUnit.getJavaProject().getOptions(true);
+		Map<String, String> options= fCompilationUnit.getOptions(true);
 
 		surroundWith.getRewrite().rewriteAST(document, options).apply(document);
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/AddGetterSetterAction.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/AddGetterSetterAction.java
index f688762..7f6badd 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/AddGetterSetterAction.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/AddGetterSetterAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2020 IBM Corporation and others.
+ * Copyright (c) 2000, 20201 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -11,6 +11,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Philippe Ombredanne - bug 149382
+ *     Microsoft Corporation - read formatting options from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.ui.actions;
 
@@ -585,7 +586,7 @@
 			target.beginCompoundChange();
 		}
 		try {
-			CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu.getJavaProject());
+			CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu);
 			settings.createComments= fGenerateComment;
 
 			AddGetterSetterOperation op= new AddGetterSetterOperation(type, getterFields, setterFields, getterSetterFields, unit, skipReplaceQuery(), elementPosition, settings, true, false);
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/OrganizeImportsAction.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/OrganizeImportsAction.java
index eb1720e..7ffb781 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/OrganizeImportsAction.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/actions/OrganizeImportsAction.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
@@ -10,6 +10,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Microsoft Corporation - read preferences from the compilation unit
  *******************************************************************************/
 package org.eclipse.jdt.ui.actions;
 
@@ -274,7 +275,7 @@
 
 		CompilationUnit astRoot= SharedASTProviderCore.getAST(cu, SharedASTProviderCore.WAIT_ACTIVE_ONLY, null);
 
-		CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu.getJavaProject());
+		CodeGenerationSettings settings= JavaPreferencesSettings.getCodeGenerationSettings(cu);
 		OrganizeImportsOperation op= new OrganizeImportsOperation(cu, astRoot, settings.importIgnoreLowercase, !cu.isWorkingCopy(), true, createChooseImportQuery(editor[0]));
 
 		IRewriteTarget target= editor[0].getAdapter(IRewriteTarget.class);