Bug 570762 - Wrapping with try-with-resources should add catch statement
- add logic to QuickAssistProcessor.getTryWithResourceProposals
to support selections within a try/catch block and to add
a catch clause to handle any un-handled exceptions added by the
auto-close
- do the same with AssignToVariableAssistProposal.doAddLocal() and
SurroundWithTryResourcesRefactoring.createTryWithResourcesStatement()
- expose various methods in SurroundWithTryResourcesRefactoring
for common usage
- add new methods to SurroundWithTryWithResourcesAnalyzer for
common usage
- add new test scenarios to AssistQuickFixTest1d8 and
SurroundWithResourcesTests1d8
Change-Id: Ic9cb39126ad9d299b8912ec7f8564432806df006
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.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/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/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/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 15201aa..9a06d22 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/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 {