Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabrice Tiercelin2020-11-15 09:14:51 +0000
committerFabrice Tiercelin2020-11-15 12:20:08 +0000
commitb4d4824ed84c5dd3f8af41448ac1c2ced44cde76 (patch)
treeec1b9878d56a1449ef3d2f6e4e0b51dd3e550bab
parent9148815e2eb76c4f56db14553e556b208859210c (diff)
downloadeclipse.jdt.ui-b4d4824ed84c5dd3f8af41448ac1c2ced44cde76.tar.gz
eclipse.jdt.ui-b4d4824ed84c5dd3f8af41448ac1c2ced44cde76.tar.xz
eclipse.jdt.ui-b4d4824ed84c5dd3f8af41448ac1c2ced44cde76.zip
Bug 568088 - [AutoRefactor immigration #37/141] [cleanup & saveaction]
try-with-resource Change-Id: If847e94774241882996aac7f5914018507ea20c8 Signed-off-by: Fabrice Tiercelin <fabrice.tiercelin@yahoo.fr>
-rw-r--r--org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java2
-rw-r--r--org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties2
-rw-r--r--org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/dom/ASTNodes.java38
-rw-r--r--org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java12
-rw-r--r--org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d7.java207
-rw-r--r--org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d9.java249
-rw-r--r--org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTestCaseSuite.java1
-rw-r--r--org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java6
-rw-r--r--org.eclipse.jdt.ui/plugin.xml5
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/TryWithResourceCleanUp.java336
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/VarDefinitionsUsesVisitor.java33
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java2
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties2
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/UnnecessaryCodeTabPage.java7
14 files changed, 901 insertions, 1 deletions
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 e6c29d328f..8ce5730457 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
@@ -161,6 +161,8 @@ public class MultiFixMessages extends NLS {
public static String CheckSignOfBitwiseOperation_description;
+ public static String TryWithResourceCleanup_description;
+
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, MultiFixMessages.class);
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 45ce8bfc3f..2737cadbaf 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
@@ -142,3 +142,5 @@ AddAllCleanup_description=Add elements in collections without loop
ObjectsEqualsCleanup_description=Use Objects.equals() in the equals method implementation
CheckSignOfBitwiseOperation_description=Use != 0 instead of > 0 when comparing the result of a bitwise expression
SwitchExpressionsCleanUp_ConvertToSwitchExpressions_description=Convert to switch expression where possible
+
+TryWithResourceCleanup_description=Use try-with-resource
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 2f60640f9e..1dabe292c9 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
@@ -2124,6 +2124,26 @@ public class ASTNodes {
return siblings.get(siblings.size() - 1);
}
+ /**
+ * Returns the previous statement in the source file if it exists.
+ *
+ * @param startNode the start node
+ * @return the previous statement in the source file if it exists, null
+ * otherwise
+ */
+ public static Statement getPreviousStatement(final Statement startNode) {
+ Statement previousSibling= getPreviousSibling(startNode);
+ if (previousSibling != null) {
+ return previousSibling;
+ }
+ ASTNode parent= startNode.getParent();
+ if (parent instanceof Statement) {
+ return getPreviousStatement((Statement) parent);
+ }
+
+ return null;
+ }
+
private static List<Statement> getSiblings(final Statement startNode, final boolean isForward) {
Statement statementAtLevel= statementAtLevel(startNode);
@@ -2614,6 +2634,24 @@ public class ASTNodes {
}
/**
+ * Returns whether the provided nodes all represent the same variable.
+ *
+ * @param node0 the first node to compare
+ * @param otherNodes the other nodes to compare
+ * @return true if all the provided nodes represent the same variable, false
+ * otherwise
+ */
+ public static boolean areSameVariables(final ASTNode node0, final ASTNode... otherNodes) {
+ for (ASTNode nodeN : otherNodes) {
+ if (!isSameVariable(node0, nodeN)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
* Returns whether the two provided nodes represent the same variable.
*
* @param node1 the first node to compare
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 31e9757d93..4aa5489a23 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
@@ -1718,6 +1718,18 @@ public class CleanUpConstants {
public static final String ADD_MISSING_METHODES= "cleanup.add_missing_methods"; //$NON-NLS-1$
/**
+ * Changes code to make use of Java 7 try-with-resources feature. In particular, it removes now useless finally clauses.
+ * <p>
+ * Possible values: {TRUE, FALSE}
+ * <p>
+ *
+ * @see CleanUpOptionsCore#TRUE
+ * @see CleanUpOptionsCore#FALSE
+ * @since 4.18
+ */
+ public static final String TRY_WITH_RESOURCE= "cleanup.try_with_resource"; //$NON-NLS-1$
+
+ /**
* Should the Clean Up Wizard be shown when executing the Clean Up Action? <br>
* <br>
* Possible values: {<code><b>true</b></code>, <code><b>false</b></code>} <br>
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d7.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d7.java
index 5630ee94e8..f69519d888 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d7.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d7.java
@@ -13,6 +13,11 @@
*******************************************************************************/
package org.eclipse.jdt.ui.tests.quickfix;
+import static org.junit.Assert.assertNotEquals;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
import org.junit.Rule;
import org.junit.Test;
@@ -446,6 +451,208 @@ public class CleanUpTest1d7 extends CleanUpTestCase {
}
@Test
+ public void testUseTryWithResource() throws Exception {
+ IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
+ String given= "" //
+ + "package test1;\n" //
+ + "\n" //
+ + "import java.io.FileInputStream;\n" //
+ + "\n" //
+ + "public class E {\n" //
+ + " public void refactorFullyInitializedResourceRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " // Keep this comment too\n" //
+ + " try {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorFullyInitializedResourceDoNotRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " // Keep this comment too\n" //
+ + " try {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " inputStream.close();\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorNullInitializedResourceRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " FileInputStream inputStream = null;\n" //
+ + " // Keep this comment too\n" //
+ + " try {\n" //
+ + " inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " if (inputStream != null) {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorNullInitializedResourceDoNotRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " FileInputStream inputStream = null;\n" //
+ + " // Keep this comment too\n" //
+ + " try {\n" //
+ + " inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " if (inputStream != null) {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + " }\n" //
+ + "}\n";
+ ICompilationUnit cu= pack.createCompilationUnit("E.java", given, false, null);
+
+ enable(CleanUpConstants.TRY_WITH_RESOURCE);
+
+ String expected= "" //
+ + "package test1;\n" //
+ + "\n" //
+ + "import java.io.FileInputStream;\n" //
+ + "\n" //
+ + "public class E {\n" //
+ + " public void refactorFullyInitializedResourceRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " // Keep this comment too\n" //
+ + " try (FileInputStream inputStream = new FileInputStream(\"out.txt\")) {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorFullyInitializedResourceDoNotRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " // Keep this comment too\n" //
+ + " try (FileInputStream inputStream = new FileInputStream(\"out.txt\")) {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorNullInitializedResourceRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " // Keep this comment too\n" //
+ + " try (FileInputStream inputStream = new FileInputStream(\"out.txt\")) {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorNullInitializedResourceDoNotRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " // Keep this comment too\n" //
+ + " try (FileInputStream inputStream = new FileInputStream(\"out.txt\")) {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + " }\n" //
+ + "}\n";
+
+ assertNotEquals("The class must be changed", given, expected);
+ assertGroupCategoryUsed(new ICompilationUnit[] { cu }, new HashSet<>(Arrays.asList(MultiFixMessages.TryWithResourceCleanup_description)));
+ assertRefactoringResultAsExpected(new ICompilationUnit[] { cu }, new String[] { expected });
+ }
+
+ @Test
+ public void testDoNotUseTryWithResource() throws Exception {
+ IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
+ String sample= "" //
+ + "package test1;\n" //
+ + "\n" //
+ + "import java.io.FileInputStream;\n" //
+ + "\n" //
+ + "public class E {\n" //
+ + " public void doNotRefactorNonEffectivelyFinalResource() throws Exception {\n" //
+ + " try (FileInputStream inputStream = new FileInputStream(\"out.txt\")) {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void doNotRefactorFurtherAssignmentsToResource() throws Exception {\n" //
+ + " FileInputStream inputStream = null;\n" //
+ + " try {\n" //
+ + " inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " } finally {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public boolean doNotRefactorStillUsedCloseable() throws Exception {\n" //
+ + " FileInputStream inputStream = null;\n" //
+ + " try {\n" //
+ + " inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + "\n" //
+ + " return inputStream != null;\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void doNotRefactorUnrelated() throws Exception {\n" //
+ + " FileInputStream aStream = new FileInputStream(\"out.txt\");\n" //
+ + " Object o = null;\n" //
+ + " try {\n" //
+ + " o = aStream.read();\n" //
+ + " } finally {\n" //
+ + " aStream.close();\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void doNotRefactorUnclosedStream(int i) throws Exception {\n" //
+ + " FileInputStream inputStream = null;\n" //
+ + " try {\n" //
+ + " inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " if (inputStream != null) {\n" //
+ + " i = inputStream.available();\n" //
+ + " }\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void doNotMoveVariableFromOtherScope(boolean isValid) throws Exception {\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " if (isValid) {\n" //
+ + " try {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void doNotMoveReusedVariable() throws Exception {\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " try {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + "\n" //
+ + " inputStream.getFD();\n" //
+ + " }\n" //
+ + "}\n";
+ ICompilationUnit cu= pack.createCompilationUnit("E.java", sample, false, null);
+
+ enable(CleanUpConstants.TRY_WITH_RESOURCE);
+
+ assertRefactoringHasNoChange(new ICompilationUnit[] { cu });
+ }
+
+ @Test
public void testObjectsEqualsWithImportConflict() throws Exception {
IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
String sample= "" //
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d9.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d9.java
new file mode 100644
index 0000000000..a6dc3ae5bd
--- /dev/null
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d9.java
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * Copyright (c) 2016, 2020 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.ui.tests.quickfix;
+
+import static org.junit.Assert.assertNotEquals;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragment;
+
+import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
+
+import org.eclipse.jdt.ui.tests.core.rules.Java9ProjectTestSetup;
+import org.eclipse.jdt.ui.tests.core.rules.ProjectTestSetup;
+
+import org.eclipse.jdt.internal.ui.fix.MultiFixMessages;
+
+/**
+ * Tests the cleanup features related to Java 9.
+ */
+public class CleanUpTest1d9 extends CleanUpTestCase {
+ @Rule
+ public ProjectTestSetup projectSetup= new Java9ProjectTestSetup();
+
+ @Override
+ protected IJavaProject getProject() {
+ return projectSetup.getProject();
+ }
+
+ @Override
+ protected IClasspathEntry[] getDefaultClasspath() throws CoreException {
+ return projectSetup.getDefaultClasspath();
+ }
+
+ @Test
+ public void testUseTryWithResource() throws Exception {
+ IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
+ String given= "" //
+ + "package test1;\n" //
+ + "\n" //
+ + "import java.io.FileInputStream;\n" //
+ + "\n" //
+ + "public class E {\n" //
+ + " public void refactorFullyInitializedResourceRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"data.txt\");\n" //
+ + " // Keep this comment too\n" //
+ + " try {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorFullyInitializedResourceDoNotRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " // Keep this comment too\n" //
+ + " try {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " inputStream.close();\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public boolean removeClosureOnStillUsedCloseable() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"input.txt\");\n" //
+ + " // Keep this comment too\n" //
+ + " try {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " inputStream.close();\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + "\n" //
+ + " return inputStream != null;\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorFullyInitializedResourceOnlyRemoveFinallyIf() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " // Keep this comment too\n" //
+ + " try {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " if (inputStream != null) {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorNullInitializedResourceRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " FileInputStream inputStream = null;\n" //
+ + " // Keep this comment too\n" //
+ + " try {\n" //
+ + " inputStream = new FileInputStream(\"output.txt\");\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " if (inputStream != null) {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorNullInitializedResourceDoNotRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " FileInputStream inputStream = null;\n" //
+ + " // Keep this comment too\n" //
+ + " try {\n" //
+ + " inputStream = new FileInputStream(\"file.txt\");\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " if (null != inputStream) {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + " }\n" //
+ + "}\n";
+ ICompilationUnit cu= pack.createCompilationUnit("E.java", given, false, null);
+
+ enable(CleanUpConstants.TRY_WITH_RESOURCE);
+
+ String expected= "" //
+ + "package test1;\n" //
+ + "\n" //
+ + "import java.io.FileInputStream;\n" //
+ + "\n" //
+ + "public class E {\n" //
+ + " public void refactorFullyInitializedResourceRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"data.txt\");\n" //
+ + " // Keep this comment too\n" //
+ + " try (inputStream) {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorFullyInitializedResourceDoNotRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " // Keep this comment too\n" //
+ + " try (inputStream) {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public boolean removeClosureOnStillUsedCloseable() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"input.txt\");\n" //
+ + " // Keep this comment too\n" //
+ + " try (inputStream) {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + "\n" //
+ + " return inputStream != null;\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorFullyInitializedResourceOnlyRemoveFinallyIf() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " final FileInputStream inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " // Keep this comment too\n" //
+ + " try (inputStream) {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorNullInitializedResourceRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " // Keep this comment too\n" //
+ + " try (FileInputStream inputStream = new FileInputStream(\"output.txt\")) {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " }\n" //
+ + " }\n" //
+ + "\n" //
+ + " public void refactorNullInitializedResourceDoNotRemoveFinally() throws Exception {\n" //
+ + " // Keep this comment\n" //
+ + " // Keep this comment too\n" //
+ + " try (FileInputStream inputStream = new FileInputStream(\"file.txt\")) {\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " System.out.println(\"Done\");\n" //
+ + " }\n" //
+ + " }\n" //
+ + "}\n";
+
+ assertNotEquals("The class must be changed", given, expected);
+ assertGroupCategoryUsed(new ICompilationUnit[] { cu }, new HashSet<>(Arrays.asList(MultiFixMessages.TryWithResourceCleanup_description)));
+ assertRefactoringResultAsExpected(new ICompilationUnit[] { cu }, new String[] { expected });
+ }
+
+ @Test
+ public void testDoNotUseTryWithResource() throws Exception {
+ IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
+ String sample= "" //
+ + "package test1;\n" //
+ + "\n" //
+ + "import java.io.FileInputStream;\n" //
+ + "\n" //
+ + "public class E {\n" //
+ + " public boolean doNotRefactorStillUsedCloseable() throws Exception {\n" //
+ + " FileInputStream inputStream = null;\n" //
+ + " try {\n" //
+ + " inputStream = new FileInputStream(\"out.txt\");\n" //
+ + " System.out.println(inputStream.read());\n" //
+ + " } finally {\n" //
+ + " inputStream.close();\n" //
+ + " }\n" //
+ + "\n" //
+ + " return inputStream != null;\n" //
+ + " }\n" //
+ + "}\n";
+ ICompilationUnit cu= pack.createCompilationUnit("E.java", sample, false, null);
+
+ enable(CleanUpConstants.TRY_WITH_RESOURCE);
+
+ assertRefactoringHasNoChange(new ICompilationUnit[] { cu });
+ }
+}
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTestCaseSuite.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTestCaseSuite.java
index 5a5c0b521e..4f3893c22d 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTestCaseSuite.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTestCaseSuite.java
@@ -25,6 +25,7 @@ import org.junit.runners.Suite;
CleanUpTest1d6.class,
CleanUpTest1d7.class,
CleanUpTest1d8.class,
+ CleanUpTest1d9.class,
CleanUpTest1d10.class,
CleanUpAnnotationTest.class,
SaveParticipantTest.class,
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 5660eb2b5d..a7cab903a1 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
@@ -160,6 +160,9 @@ public class CleanUpConstantsOptions extends CleanUpConstants {
// Duplicate Code
options.setOption(STRICTLY_EQUAL_OR_DIFFERENT, CleanUpOptions.FALSE);
+
+ // Java Features
+ options.setOption(TRY_WITH_RESOURCE, CleanUpOptions.FALSE);
}
private static void setSaveParticipantSettings(CleanUpOptions options) {
@@ -298,6 +301,9 @@ public class CleanUpConstantsOptions extends CleanUpConstants {
// Duplicate Code
options.setOption(STRICTLY_EQUAL_OR_DIFFERENT, CleanUpOptions.FALSE);
+
+ // Java Features
+ options.setOption(TRY_WITH_RESOURCE, CleanUpOptions.FALSE);
}
public static void initDefaults(IPreferenceStore store) {
diff --git a/org.eclipse.jdt.ui/plugin.xml b/org.eclipse.jdt.ui/plugin.xml
index 6fa20e69ea..3d92d89704 100644
--- a/org.eclipse.jdt.ui/plugin.xml
+++ b/org.eclipse.jdt.ui/plugin.xml
@@ -7321,6 +7321,11 @@
id="org.eclipse.jdt.ui.cleanup.if_condition"
runAfter="org.eclipse.jdt.ui.cleanup.redundant_falling_through_block_end">
</cleanUp>
+ <cleanUp
+ class="org.eclipse.jdt.internal.ui.fix.TryWithResourceCleanUp"
+ id="org.eclipse.jdt.ui.cleanup.try_with_resource"
+ runAfter="org.eclipse.jdt.ui.cleanup.if_condition">
+ </cleanUp>
</extension>
<extension
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/TryWithResourceCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/TryWithResourceCleanUp.java
new file mode 100644
index 0000000000..fc99d48a45
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/TryWithResourceCleanUp.java
@@ -0,0 +1,336 @@
+/*******************************************************************************
+ * Copyright (c) 2020 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.io.Closeable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.text.edits.TextEditGroup;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.Assignment;
+import org.eclipse.jdt.core.dom.Block;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.IVariableBinding;
+import org.eclipse.jdt.core.dom.IfStatement;
+import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.Statement;
+import org.eclipse.jdt.core.dom.TryStatement;
+import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
+import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
+import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
+import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
+import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
+
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
+import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFix;
+import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFix.CompilationUnitRewriteOperation;
+import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
+import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
+import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
+
+import org.eclipse.jdt.ui.cleanup.CleanUpRequirements;
+import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
+import org.eclipse.jdt.ui.text.java.IProblemLocation;
+
+/**
+ * A fix that changes code to make use of Java 7 try-with-resources feature. In particular, it removes now useless finally clauses.
+ */
+public class TryWithResourceCleanUp extends AbstractMultiFix implements ICleanUpFix {
+ public TryWithResourceCleanUp() {
+ this(Collections.emptyMap());
+ }
+
+ public TryWithResourceCleanUp(final Map<String, String> options) {
+ super(options);
+ }
+
+ @Override
+ public CleanUpRequirements getRequirements() {
+ boolean requireAST= isEnabled(CleanUpConstants.TRY_WITH_RESOURCE);
+ return new CleanUpRequirements(requireAST, false, false, null);
+ }
+
+ @Override
+ public String[] getStepDescriptions() {
+ if (isEnabled(CleanUpConstants.TRY_WITH_RESOURCE)) {
+ return new String[] { MultiFixMessages.TryWithResourceCleanup_description };
+ }
+
+ return new String[0];
+ }
+
+ @Override
+ public String getPreview() {
+ if (isEnabled(CleanUpConstants.TRY_WITH_RESOURCE)) {
+ return "" //$NON-NLS-1$
+ + "final FileInputStream inputStream = new FileInputStream(\"out.txt\");\n" //$NON-NLS-1$
+ + "try (inputStream) {\n" //$NON-NLS-1$
+ + " System.out.println(inputStream.read());\n" //$NON-NLS-1$
+ + "}\n\n\n"; //$NON-NLS-1$
+ }
+
+ return "" //$NON-NLS-1$
+ + "final FileInputStream inputStream = new FileInputStream(\"out.txt\");\n" //$NON-NLS-1$
+ + "try {\n" //$NON-NLS-1$
+ + " System.out.println(inputStream.read());\n" //$NON-NLS-1$
+ + "} finally {\n" //$NON-NLS-1$
+ + " inputStream.close();\n" //$NON-NLS-1$
+ + "}\n"; //$NON-NLS-1$
+ }
+
+ @Override
+ protected ICleanUpFix createFix(final CompilationUnit unit) throws CoreException {
+ if (!isEnabled(CleanUpConstants.TRY_WITH_RESOURCE) || !JavaModelUtil.is1d7OrHigher(unit.getJavaElement().getJavaProject())) {
+ return null;
+ }
+
+ final List<CompilationUnitRewriteOperation> rewriteOperations= new ArrayList<>();
+
+ unit.accept(new ASTVisitor() {
+ @Override
+ public boolean visit(final Block visited) {
+ DeclarationAndTryVisitor declarationAndTryVisitor= new DeclarationAndTryVisitor(visited);
+ visited.accept(declarationAndTryVisitor);
+ return declarationAndTryVisitor.result;
+ }
+
+ final class DeclarationAndTryVisitor extends ASTVisitor {
+ private final Block startNode;
+ private boolean result= true;
+
+ public DeclarationAndTryVisitor(final Block startNode) {
+ this.startNode= startNode;
+ }
+
+ @Override
+ public boolean visit(final Block visited) {
+ return startNode == visited;
+ }
+
+ @Override
+ public boolean visit(final TryStatement visited) {
+ if (!result) {
+ return true;
+ }
+
+ VariableDeclarationStatement previousDeclarationStatement= ASTNodes.as(ASTNodes.getPreviousSibling(visited),
+ VariableDeclarationStatement.class);
+ List<Statement> finallyStatements= ASTNodes.asList(visited.getFinally());
+
+ if (previousDeclarationStatement == null
+ || finallyStatements.isEmpty()) {
+ return true;
+ }
+
+ VariableDeclarationFragment previousDeclarationFragment= ASTNodes.getUniqueFragment(previousDeclarationStatement);
+
+ if (previousDeclarationFragment == null
+ || previousDeclarationFragment.resolveBinding() == null) {
+ return true;
+ }
+
+ Statement finallyFirstFStatement= finallyStatements.get(0);
+ List<ASTNode> nodesToRemove= new ArrayList<>();
+ nodesToRemove.add(finallyStatements.size() == 1 ? visited.getFinally() : finallyFirstFStatement);
+
+ boolean isCloseableUsedAfter= isCloseableUsedAfter(previousDeclarationFragment, visited);
+ Expression closedVariable= getClosedVariable(previousDeclarationFragment, finallyFirstFStatement);
+
+ if ((isCloseableUsedAfter && !JavaModelUtil.is9OrHigher(((CompilationUnit) visited.getRoot()).getJavaElement().getJavaProject()))
+ || closedVariable == null
+ || !ASTNodes.areSameVariables(previousDeclarationFragment, closedVariable)) {
+ return true;
+ }
+
+ return maybeUseTryWithResource( visited, previousDeclarationStatement, previousDeclarationFragment, isCloseableUsedAfter, nodesToRemove);
+ }
+
+ private boolean maybeUseTryWithResource(
+ final TryStatement visited,
+ final VariableDeclarationStatement previousDeclarationStatement,
+ final VariableDeclarationFragment previousDeclarationFragment,
+ final boolean isCloseableUsedAfter,
+ final List<ASTNode> nodesToRemove) {
+ VarDefinitionsUsesVisitor visitor= new VarDefinitionsUsesVisitor(previousDeclarationFragment);
+ List<SimpleName> closeableAssignments= visitor.getWrites();
+ List<Statement> tryStatements= ASTNodes.asList(visited.getBody());
+
+ if (!isCloseableUsedAfter
+ && !tryStatements.isEmpty()) {
+ Statement tryFirstStatement= tryStatements.get(0);
+ Assignment assignResource= ASTNodes.asExpression(tryFirstStatement, Assignment.class);
+
+ if (assignResource != null
+ && ASTNodes.isSameVariable(previousDeclarationFragment, assignResource.getLeftHandSide())) {
+ if (!containsExactly(closeableAssignments, previousDeclarationFragment.getName(), assignResource.getLeftHandSide())) {
+ return true;
+ }
+
+ nodesToRemove.add(tryFirstStatement);
+ rewriteOperations.add(new TryWithResourceOperation(visited, previousDeclarationStatement, previousDeclarationFragment, assignResource, nodesToRemove));
+
+ result= false;
+ return false;
+ }
+ }
+
+ if (containsExactly(closeableAssignments, previousDeclarationFragment.getName())) {
+ rewriteOperations.add(new TryWithResourceOperation(visited, previousDeclarationStatement, previousDeclarationFragment, null, nodesToRemove));
+
+ result= false;
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean containsExactly(final List<SimpleName> closeableOccurrences, final Expression... simpleNames) {
+ return closeableOccurrences.size() == simpleNames.length && closeableOccurrences.containsAll(Arrays.asList(simpleNames));
+ }
+
+ private boolean isCloseableUsedAfter(final VariableDeclarationFragment previousDeclarationFragment, final TryStatement visited) {
+ IVariableBinding varBinding= previousDeclarationFragment.resolveBinding();
+ List<Statement> nextStatements= ASTNodes.getNextSiblings(visited);
+
+ for (Statement nextStatement : nextStatements) {
+ VarDefinitionsUsesVisitor visitor= new VarDefinitionsUsesVisitor(varBinding, nextStatement, true);
+
+ if (!visitor.getReads().isEmpty() || !visitor.getWrites().isEmpty()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private Expression getClosedVariable(final VariableDeclarationFragment previousDeclarationFragment, final Statement finallyStatement) {
+ Statement firstStatement= finallyStatement;
+ IfStatement finallyIfStatement= ASTNodes.as(finallyStatement, IfStatement.class);
+
+ if (finallyIfStatement != null
+ && ASTNodes.asList(finallyIfStatement.getThenStatement()).size() == 1
+ && ASTNodes.asList(finallyIfStatement.getElseStatement()).isEmpty()) {
+ Expression closedVariable= ASTNodes.getNullCheckedExpression(finallyIfStatement.getExpression());
+
+ if (ASTNodes.areSameVariables(previousDeclarationFragment, closedVariable)) {
+ firstStatement= ASTNodes.asList(finallyIfStatement.getThenStatement()).get(0);
+ }
+ }
+
+ MethodInvocation closeMethod= ASTNodes.asExpression(firstStatement, MethodInvocation.class);
+
+ if (closeMethod != null
+ && ASTNodes.usesGivenSignature(closeMethod, Closeable.class.getCanonicalName(), "close")) { //$NON-NLS-1$
+ return closeMethod.getExpression();
+ }
+
+ return null;
+ }
+ }
+ });
+
+ if (rewriteOperations.isEmpty()) {
+ return null;
+ }
+
+ return new CompilationUnitRewriteOperationsFix(MultiFixMessages.TryWithResourceCleanup_description, unit,
+ rewriteOperations.toArray(new CompilationUnitRewriteOperation[0]));
+ }
+
+ @Override
+ public CompilationUnitChange createChange(IProgressMonitor progressMonitor) throws CoreException {
+ return null;
+ }
+
+ @Override
+ public boolean canFix(final ICompilationUnit compilationUnit, final IProblemLocation problem) {
+ return false;
+ }
+
+ @Override
+ protected ICleanUpFix createFix(final CompilationUnit unit, final IProblemLocation[] problems) throws CoreException {
+ return null;
+ }
+
+ private static class TryWithResourceOperation extends CompilationUnitRewriteOperation {
+ private final TryStatement visited;
+ private final VariableDeclarationStatement previousDeclStatement;
+ private final VariableDeclarationFragment previousDeclFragment;
+ private final Assignment assignResource;
+ private final List<ASTNode> nodesToRemove;
+
+ public TryWithResourceOperation(final TryStatement visited,
+ final VariableDeclarationStatement previousDeclStatement,
+ final VariableDeclarationFragment previousDeclFragment,
+ final Assignment assignResource,
+ final List<ASTNode> nodesToRemove) {
+ this.visited= visited;
+ this.previousDeclStatement= previousDeclStatement;
+ this.previousDeclFragment= previousDeclFragment;
+ this.assignResource= assignResource;
+ this.nodesToRemove= nodesToRemove;
+ }
+
+ @Override
+ public void rewriteAST(final CompilationUnitRewrite cuRewrite, final LinkedProposalModel linkedModel) throws CoreException {
+ ASTRewrite rewrite= cuRewrite.getASTRewrite();
+ AST ast= cuRewrite.getRoot().getAST();
+ TextEditGroup group= createTextEditGroup(MultiFixMessages.TryWithResourceCleanup_description, cuRewrite);
+
+ Expression newResource;
+ if (JavaModelUtil.is9OrHigher(((CompilationUnit) visited.getRoot()).getJavaElement().getJavaProject())
+ && assignResource == null) {
+ // So we are in Java 9 or higher
+ newResource= (Expression) rewrite.createCopyTarget(previousDeclFragment.getName());
+ } else {
+ VariableDeclarationFragment newFragment;
+ if (assignResource != null) {
+ newFragment= ast.newVariableDeclarationFragment();
+ newFragment.setName(ASTNodes.createMoveTarget(rewrite, previousDeclFragment.getName()));
+ newFragment.setInitializer(ASTNodes.createMoveTarget(rewrite, assignResource.getRightHandSide()));
+ } else {
+ newFragment= ASTNodes.createMoveTarget(rewrite, previousDeclFragment);
+ }
+
+ VariableDeclarationExpression newResourceDeclaration= ast.newVariableDeclarationExpression(newFragment);
+ newResourceDeclaration.setType(ASTNodes.createMoveTarget(rewrite, previousDeclStatement.getType()));
+
+ newResource= newResourceDeclaration;
+ ASTNodes.removeButKeepComment(rewrite, previousDeclStatement, group);
+ }
+
+ ListRewrite listRewrite= rewrite.getListRewrite(visited, TryStatement.RESOURCES2_PROPERTY);
+ listRewrite.insertFirst(newResource, group);
+
+ for (ASTNode nodeToRemove : nodesToRemove) {
+ ASTNodes.removeButKeepComment(rewrite, nodeToRemove, group);
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/VarDefinitionsUsesVisitor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/VarDefinitionsUsesVisitor.java
index 4f3bd3991f..2e476dad27 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/VarDefinitionsUsesVisitor.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/VarDefinitionsUsesVisitor.java
@@ -24,6 +24,7 @@ import org.eclipse.jdt.core.dom.ChildPropertyDescriptor;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+import org.eclipse.jdt.core.dom.VariableDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.internal.corext.dom.ASTNodes;
@@ -37,6 +38,16 @@ public final class VarDefinitionsUsesVisitor extends ASTVisitor {
private final List<SimpleName> reads= new ArrayList<>();
/**
+ * Builds from a {@link VariableDeclaration} and infers the variable binding and
+ * the scope from it.
+ *
+ * @param variableDeclaration the variable declaration, cannot be {@code null}
+ */
+ public VarDefinitionsUsesVisitor(final VariableDeclaration variableDeclaration) {
+ this(variableDeclaration.resolveBinding(), getDeclaringScope(variableDeclaration), true);
+ }
+
+ /**
* Builds with the variable binding to look for and the scope where to look for
* references.
*
@@ -56,6 +67,28 @@ public final class VarDefinitionsUsesVisitor extends ASTVisitor {
scopeNode.accept(this);
}
+ private static ASTNode getDeclaringScope(final VariableDeclaration variableDeclaration) {
+ ASTNode node= variableDeclaration.getParent();
+ while (isVariableDeclaration(node)) {
+ node= node.getParent();
+ }
+
+ return node;
+ }
+
+ private static boolean isVariableDeclaration(final ASTNode node) {
+ switch (node.getNodeType()) {
+ case ASTNode.SINGLE_VARIABLE_DECLARATION:
+ case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
+ case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
+ case ASTNode.VARIABLE_DECLARATION_STATEMENT:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
@Override
public boolean visit(final SimpleName node) {
if (ASTNodes.isSameLocalVariable(variableBinding, node)) {
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 f62e815b1c..e5a631d560 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
@@ -173,6 +173,8 @@ public class CleanUpMessages extends NLS {
public static String DuplicateCodeTabPage_CheckboxName_RedundantFallingThroughBlockEnd;
public static String DuplicateCodeTabPage_CheckboxName_RedundantIfCondition;
+ public static String JavaFeatureTabPage_CheckboxName_TryWithResource;
+
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, CleanUpMessages.class);
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 ce0c7d5abd..3a7fc56e71 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
@@ -147,3 +147,5 @@ DuplicateCodeTabPage_CheckboxName_StrictlyEqualOrDifferent=Use '==' or '^' on bo
DuplicateCodeTabPage_CheckboxName_MergeConditionalBlocks=Merge &conditions of if/else if/else that have the same blocks
DuplicateCodeTabPage_CheckboxName_RedundantFallingThroughBlockEnd=Remove redundant end of block with &jump statement
DuplicateCodeTabPage_CheckboxName_RedundantIfCondition=R&edundant if condition
+
+JavaFeatureTabPage_CheckboxName_TryWithResource=Use try-with-resource (1.7 or higher)
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/UnnecessaryCodeTabPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/UnnecessaryCodeTabPage.java
index 5a842fc375..ab120d3b70 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/UnnecessaryCodeTabPage.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/UnnecessaryCodeTabPage.java
@@ -41,6 +41,7 @@ import org.eclipse.jdt.internal.ui.fix.RedundantModifiersCleanUp;
import org.eclipse.jdt.internal.ui.fix.RedundantSemicolonsCleanUp;
import org.eclipse.jdt.internal.ui.fix.RedundantSuperCallCleanUp;
import org.eclipse.jdt.internal.ui.fix.StringCleanUp;
+import org.eclipse.jdt.internal.ui.fix.TryWithResourceCleanUp;
import org.eclipse.jdt.internal.ui.fix.TypeParametersCleanUp;
import org.eclipse.jdt.internal.ui.fix.UnboxingCleanUp;
import org.eclipse.jdt.internal.ui.fix.UnnecessaryArrayCreationCleanUp;
@@ -80,7 +81,8 @@ public final class UnnecessaryCodeTabPage extends AbstractCleanUpTabPage {
new UnnecessaryArrayCreationCleanUp(values),
new UselessReturnCleanUp(values),
new UselessContinueCleanUp(values),
- new ObjectsEqualsCleanUp(values)
+ new ObjectsEqualsCleanUp(values),
+ new TryWithResourceCleanUp(values)
};
}
@@ -180,5 +182,8 @@ public final class UnnecessaryCodeTabPage extends AbstractCleanUpTabPage {
CheckboxPreference objectsEquals= createCheckboxPref(unnecessaryGroup, numColumns, CleanUpMessages.UnnecessaryCodeTabPage_CheckboxName_ObjectsEquals, CleanUpConstants.USE_OBJECTS_EQUALS, CleanUpModifyDialog.FALSE_TRUE);
registerPreference(objectsEquals);
+
+ CheckboxPreference tryWithResource= createCheckboxPref(unnecessaryGroup, numColumns, CleanUpMessages.JavaFeatureTabPage_CheckboxName_TryWithResource, CleanUpConstants.TRY_WITH_RESOURCE, CleanUpModifyDialog.FALSE_TRUE);
+ registerPreference(tryWithResource);
}
}

Back to the top