diff --git a/java/java-impl/src/META-INF/JavaPlugin.xml b/java/java-impl/src/META-INF/JavaPlugin.xml index d97256c1ed35..8efaadb02394 100644 --- a/java/java-impl/src/META-INF/JavaPlugin.xml +++ b/java/java-impl/src/META-INF/JavaPlugin.xml @@ -406,6 +406,7 @@ order="before explicitlyImported"/> + diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/NestedIfJoinLinesHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/NestedIfJoinLinesHandler.java new file mode 100644 index 000000000000..5e839ceaa0a5 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/NestedIfJoinLinesHandler.java @@ -0,0 +1,64 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.codeInsight.editorActions; + +import com.intellij.openapi.editor.Document; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; +import com.siyeh.ig.psiutils.CommentTracker; +import com.siyeh.ig.psiutils.ControlFlowUtils; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import org.jetbrains.annotations.NotNull; + +import static com.intellij.util.ObjectUtils.tryCast; + +/** + *
{@code
+ * if(a) {
+ *   if(b) {
+ *     ...
+ *   }
+ * }
+ * =>
+ * if(a && b) {
+ *   ...
+ * }
+ * }
+ */ +public class NestedIfJoinLinesHandler implements JoinLinesHandlerDelegate { + @Override + public int tryJoinLines(@NotNull final Document document, @NotNull final PsiFile psiFile, final int start, final int end) { + PsiJavaToken elementAtStartLineEnd = tryCast(psiFile.findElementAt(start), PsiJavaToken.class); + PsiElement nextLineElement = psiFile.findElementAt(end); + if (elementAtStartLineEnd == null || nextLineElement == null) return CANNOT_JOIN; + PsiIfStatement outerIf = null; + if (elementAtStartLineEnd.getTokenType().equals(JavaTokenType.RPARENTH)) { + outerIf = tryCast(elementAtStartLineEnd.getParent(), PsiIfStatement.class); + } else if(elementAtStartLineEnd.getTokenType().equals(JavaTokenType.LBRACE)) { + PsiCodeBlock block = tryCast(elementAtStartLineEnd.getParent(), PsiCodeBlock.class); + if (block != null) { + PsiBlockStatement blockStatement = tryCast(block.getParent(), PsiBlockStatement.class); + if (blockStatement != null) { + outerIf = tryCast(blockStatement.getParent(), PsiIfStatement.class); + if (outerIf == null || outerIf.getThenBranch() != blockStatement) return CANNOT_JOIN; + } + } + } + if (outerIf == null || outerIf.getElseBranch() != null) return CANNOT_JOIN; + PsiIfStatement innerIf = tryCast(ControlFlowUtils.stripBraces(outerIf.getThenBranch()), PsiIfStatement.class); + if (!PsiTreeUtil.isAncestor(innerIf, nextLineElement, false)) return CANNOT_JOIN; + if (innerIf.getThenBranch() == null || innerIf.getElseBranch() != null) return CANNOT_JOIN; + + PsiExpression outerCondition = outerIf.getCondition(); + if (outerCondition == null) return CANNOT_JOIN; + PsiExpression innerCondition = innerIf.getCondition(); + if (innerCondition == null) return CANNOT_JOIN; + + CommentTracker ct = new CommentTracker(); + String childConditionText = ParenthesesUtils.getText(ct.markUnchanged(innerCondition), ParenthesesUtils.OR_PRECEDENCE); + String parentConditionText = ParenthesesUtils.getText(ct.markUnchanged(outerCondition), ParenthesesUtils.OR_PRECEDENCE); + + PsiBinaryExpression newCondition = (PsiBinaryExpression)ct.replace(outerCondition, parentConditionText + "&&" + childConditionText); + ct.replaceAndRestoreComments(outerIf.getThenBranch(), innerIf.getThenBranch()); + return newCondition.getOperationSign().getTextRange().getStartOffset(); + } +} diff --git a/java/java-tests/testData/codeInsight/joinLines/IfChain.java b/java/java-tests/testData/codeInsight/joinLines/IfChain.java new file mode 100644 index 000000000000..0b3422feefd0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/joinLines/IfChain.java @@ -0,0 +1,9 @@ +class Foo { + void test(int a, int b) { + if(a > 0) { + if(b < 0) { + System.out.println(a+b); + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/joinLines/IfChainElse.java b/java/java-tests/testData/codeInsight/joinLines/IfChainElse.java new file mode 100644 index 000000000000..43aa552571e1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/joinLines/IfChainElse.java @@ -0,0 +1,11 @@ +class Foo { + void test(int a, int b) { + if(a > 0) { + if(b < 0) { + System.out.println(a+b); + } else { + System.out.println(a-b); + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/joinLines/IfChainElse_after.java b/java/java-tests/testData/codeInsight/joinLines/IfChainElse_after.java new file mode 100644 index 000000000000..262acca60791 --- /dev/null +++ b/java/java-tests/testData/codeInsight/joinLines/IfChainElse_after.java @@ -0,0 +1,9 @@ +class Foo { + void test(int a, int b) { + if(a > 0) if(b < 0) { + System.out.println(a+b); + } else { + System.out.println(a-b); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/joinLines/IfChainNoBraces.java b/java/java-tests/testData/codeInsight/joinLines/IfChainNoBraces.java new file mode 100644 index 000000000000..bf81d2875f79 --- /dev/null +++ b/java/java-tests/testData/codeInsight/joinLines/IfChainNoBraces.java @@ -0,0 +1,6 @@ +class Foo { + void test(int a, int b) { + if(a > 0) + if (b < 0) System.out.println(a + b); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/joinLines/IfChainNoBraces_after.java b/java/java-tests/testData/codeInsight/joinLines/IfChainNoBraces_after.java new file mode 100644 index 000000000000..18b49845703d --- /dev/null +++ b/java/java-tests/testData/codeInsight/joinLines/IfChainNoBraces_after.java @@ -0,0 +1,5 @@ +class Foo { + void test(int a, int b) { + if(a > 0 && b < 0) System.out.println(a + b); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/joinLines/IfChain_after.java b/java/java-tests/testData/codeInsight/joinLines/IfChain_after.java new file mode 100644 index 000000000000..b67ba027537d --- /dev/null +++ b/java/java-tests/testData/codeInsight/joinLines/IfChain_after.java @@ -0,0 +1,7 @@ +class Foo { + void test(int a, int b) { + if(a > 0 && b < 0) { + System.out.println(a+b); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/JoinLinesTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/JoinLinesTest.java index b05b2e8e758d..384d12390b04 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/JoinLinesTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/JoinLinesTest.java @@ -50,6 +50,10 @@ public class JoinLinesTest extends LightCodeInsightTestCase { public void testDeclarationAndReassignmentWithCall() { doTest(); } public void testAssignmentAndReassignmentWithCall() { doTest(); } + public void testIfChain() { doTest(); } + public void testIfChainNoBraces() { doTest(); } + public void testIfChainElse() { doTest(); } + public void testSCR3493() { CommonCodeStyleSettings settings = getJavaSettings(); boolean use_tab_character = settings.getIndentOptions().USE_TAB_CHARACTER;