diff --git a/plugins/IntentionPowerPak/src/META-INF/plugin.xml b/plugins/IntentionPowerPak/src/META-INF/plugin.xml index 878e3435132a..fe23d3c568a2 100644 --- a/plugins/IntentionPowerPak/src/META-INF/plugin.xml +++ b/plugins/IntentionPowerPak/src/META-INF/plugin.xml @@ -390,6 +390,10 @@ com.siyeh.ipp.exceptions.ReplaceArmWithTryFinallyIntention intention.category.other + + com.siyeh.ipp.exceptions.MergeNestedTryStatementsIntention + intention.category.other + com.siyeh.ipp.exceptions.ObscureThrownExceptionsIntention intention.category.other diff --git a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties index 636391392211..82381bfe9db5 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties +++ b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties @@ -151,6 +151,8 @@ split.multicatch.intention.name=Split multi-catch into separate 'catch' blocks split.multicatch.intention.family.name=Split Multi-Catch into Separate Catch Blocks replace.arm.with.try.finally.intention.name=Replace Automatic Resource Management with 'try finally' replace.arm.with.try.finally.intention.family.name=Replace Automatic Resource Management with Try-Finally +merge.nested.try.statements.intention.name=Merge nested try statements +merge.nested.try.statements.intention.family.name=Merge Nest Try Statements obscure.thrown.exceptions.intention.family.name=Replace Exceptions in Throws Clause with Single More General Exception add.array.creation.expression.intention.family.name=Add Array Creation Expression replace.diamond.with.explicit.type.arguments.intention.name=Replace '<>' with explicit type arguments diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/MergeNestedTryStatementsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/MergeNestedTryStatementsIntention.java new file mode 100644 index 000000000000..18f85334023d --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/MergeNestedTryStatementsIntention.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ipp.exceptions; + +import com.intellij.psi.*; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.base.Intention; +import com.siyeh.ipp.base.PsiElementPredicate; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Bas Leijdekkers + */ +public class MergeNestedTryStatementsIntention extends Intention { + + @NotNull + @Override + protected PsiElementPredicate getElementPredicate() { + return new NestedTryStatementsPredicate(); + } + + @Override + protected void processIntention(@NotNull PsiElement element) throws IncorrectOperationException { + final PsiTryStatement tryStatement1 = (PsiTryStatement)element.getParent(); + final StringBuilder newTryStatement = new StringBuilder("try ("); + final PsiResourceList list1 = tryStatement1.getResourceList(); + if (list1 == null) { + return; + } + final List variables1 = list1.getResourceVariables(); + boolean semicolon = false; + for (PsiResourceVariable variable : variables1) { + if (semicolon) { + newTryStatement.append(';'); + } else { + semicolon = true; + } + newTryStatement.append(variable.getText()); + } + final PsiCodeBlock tryBlock1 = tryStatement1.getTryBlock(); + if (tryBlock1 == null) { + return; + } + final PsiStatement[] statements = tryBlock1.getStatements(); + final PsiTryStatement tryStatement2 = (PsiTryStatement)statements[0]; + final PsiResourceList list2 = tryStatement2.getResourceList(); + if (list2 == null) { + return; + } + final List variables2 = list2.getResourceVariables(); + for (PsiResourceVariable variable : variables2) { + newTryStatement.append(';'); + newTryStatement.append(variable.getText()); + } + newTryStatement.append(")"); + final PsiCodeBlock tryBlock2 = tryStatement2.getTryBlock(); + if (tryBlock2 == null) { + return; + } + newTryStatement.append(tryBlock2.getText()); + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(element.getProject()); + final PsiStatement newStatement = factory.createStatementFromText(newTryStatement.toString(), element); + tryStatement1.replace(newStatement); + } +} diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/NestedTryStatementsPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/NestedTryStatementsPredicate.java new file mode 100644 index 000000000000..17f0e9b153b6 --- /dev/null +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/exceptions/NestedTryStatementsPredicate.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ipp.exceptions; + +import com.intellij.psi.*; +import com.intellij.psi.tree.IElementType; +import com.siyeh.ipp.base.PsiElementPredicate; + +/** + * @author Bas Leijdekkers + */ +public class NestedTryStatementsPredicate implements PsiElementPredicate { + + @Override + public boolean satisfiedBy(PsiElement element) { + if (!(element instanceof PsiJavaToken)) { + return false; + } + final PsiJavaToken javaToken = (PsiJavaToken)element; + final IElementType tokenType = javaToken.getTokenType(); + if (!JavaTokenType.TRY_KEYWORD.equals(tokenType)) { + return false; + } + final PsiElement parent = element.getParent(); + if (!isSimpleTryWithResources(parent)) { + return false; + } + final PsiTryStatement tryStatement = (PsiTryStatement)parent; + final PsiCodeBlock block = tryStatement.getTryBlock(); + if (block == null) { + return false; + } + final PsiStatement[] statements = block.getStatements(); + if (statements.length != 1) { + return false; + } + final PsiStatement statement = statements[0]; + return isSimpleTryWithResources(statement); + } + + private static boolean isSimpleTryWithResources(PsiElement element) { + if (!(element instanceof PsiTryStatement)) { + return false; + } + final PsiTryStatement tryStatement = (PsiTryStatement)element; + final PsiResourceList resourceList = tryStatement.getResourceList(); + if (resourceList == null) { + return false; + } + final PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock(); + if (finallyBlock != null) { + return false; + } + final PsiCodeBlock block = tryStatement.getTryBlock(); + return block != null; + } +} diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/MergeNestedTryStatementsIntention/after.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/MergeNestedTryStatementsIntention/after.java.template new file mode 100644 index 000000000000..a8613e304c27 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/MergeNestedTryStatementsIntention/after.java.template @@ -0,0 +1,10 @@ +import java.io.*; + +public class X { + void f(File file1, File file2) throws FileNotFoundException { + try (FileInputStream in = new FileInputStream(file1); FileOutputStream out = new FileOutputStream(file2)) { + // do something + } + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/MergeNestedTryStatementsIntention/before.java.template b/plugins/IntentionPowerPak/src/intentionDescriptions/MergeNestedTryStatementsIntention/before.java.template new file mode 100644 index 000000000000..bc283f663329 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/MergeNestedTryStatementsIntention/before.java.template @@ -0,0 +1,11 @@ +import java.io.*; + +public class X { + void f(File file1, File file2) throws FileNotFoundException { + try (FileInputStream in = new FileInputStream(file1)) { + try (FileOutputStream out = new FileOutputStream(file2)) { + // do something + } + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/src/intentionDescriptions/MergeNestedTryStatementsIntention/description.html b/plugins/IntentionPowerPak/src/intentionDescriptions/MergeNestedTryStatementsIntention/description.html new file mode 100644 index 000000000000..d4f830222325 --- /dev/null +++ b/plugins/IntentionPowerPak/src/intentionDescriptions/MergeNestedTryStatementsIntention/description.html @@ -0,0 +1,6 @@ + + +This intention merges two try-with-resources statements into one, if the first is located inside +the second. + + diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/mergeTry/Simple.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/mergeTry/Simple.java new file mode 100644 index 000000000000..a51451b43edd --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/mergeTry/Simple.java @@ -0,0 +1,16 @@ +package com.siyeh.ipp.exceptions.mergeTry; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +public class Simple { + void foo(File file1, File file2) throws IOException { + try (FileInputStream in = new FileInputStream(file1)) { + try (FileOutputStream out = new FileOutputStream(file2)) { + // do something + } + } + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/mergeTry/Simple_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/mergeTry/Simple_after.java new file mode 100644 index 000000000000..6555dd3d546e --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/exceptions/mergeTry/Simple_after.java @@ -0,0 +1,12 @@ +package com.siyeh.ipp.exceptions.mergeTry; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +public class Simple { + void foo(File file1, File file2) throws IOException { + try (FileInputStream in = new FileInputStream(file1); FileOutputStream out = new FileOutputStream(file2)) { + // do something + } \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/exceptions/MergeNestedTryStatementsIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/exceptions/MergeNestedTryStatementsIntentionTest.java new file mode 100644 index 000000000000..599d1d74b783 --- /dev/null +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/exceptions/MergeNestedTryStatementsIntentionTest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * (c) 2012 Desert Island BV + * created: 16 06 2012 + */ +package com.siyeh.ipp.exceptions; + +import com.siyeh.IntentionPowerPackBundle; +import com.siyeh.ipp.IPPTestCase; + +/** + * @author Bas Leijdekkers + */ +public class MergeNestedTryStatementsIntentionTest extends IPPTestCase { + + public void testSimple() { doTest(); } + + @Override + protected String getIntentionName() { + return IntentionPowerPackBundle.message("merge.nested.try.statements.intention.name"); + } + + @Override + protected String getRelativePath() { + return "exceptions/mergeTry"; + } +}