From db739736744071262b4b7495b54f5d28b49ca68d Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 25 Jun 2015 21:37:27 +0300 Subject: [PATCH] replace operator assignment with assignment (IDEA-137214) --- .../DeclarationJoinLinesHandler.java | 13 ++++++-- .../joinDeclaration/afterParenthesis.java | 6 ++++ .../joinDeclaration/beforeParenthesis.java | 7 ++++ .../siyeh/ig/psiutils/ParenthesesUtils.java | 31 +++++++++++++++++ ...atorAssignmentWithAssignmentIntention.java | 33 +------------------ .../assignment/ConditionalAssignment.java | 7 ++++ .../ConditionalAssignment_after.java | 7 ++++ ...AssignmentWithAssignmentIntentionTest.java | 1 + 8 files changed, 71 insertions(+), 34 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/joinDeclaration/afterParenthesis.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/joinDeclaration/beforeParenthesis.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ConditionalAssignment.java create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ConditionalAssignment_after.java diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/DeclarationJoinLinesHandler.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/DeclarationJoinLinesHandler.java index de19787ba47f..a09e8dd983e6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/DeclarationJoinLinesHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/DeclarationJoinLinesHandler.java @@ -25,6 +25,7 @@ import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiUtil; import com.intellij.util.IncorrectOperationException; +import com.siyeh.ig.psiutils.ParenthesesUtils; public class DeclarationJoinLinesHandler implements JoinLinesHandlerDelegate { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.editorActions.DeclarationJoinLinesHandler"); @@ -105,8 +106,9 @@ public class DeclarationJoinLinesHandler implements JoinLinesHandlerDelegate { PsiAssignmentExpression assignment) { PsiExpression initializerExpression; final IElementType originalOpSign = assignment.getOperationTokenType(); + final PsiExpression rExpression = assignment.getRExpression(); if (originalOpSign == JavaTokenType.EQ) { - initializerExpression = assignment.getRExpression(); + initializerExpression = rExpression; } else { if (var.getInitializer() == null) return null; @@ -147,7 +149,14 @@ public class DeclarationJoinLinesHandler implements JoinLinesHandlerDelegate { try { final Project project = var.getProject(); - final String initializerText = var.getInitializer().getText() + opSign + assignment.getRExpression().getText(); + String initializerText = var.getInitializer().getText() + opSign; + final String rightText = rExpression.getText(); + if (ParenthesesUtils.areParenthesesNeeded(assignment.getOperationSign(), rExpression)) { + initializerText += "(" + rightText + ")"; + } + else { + initializerText += rightText; + } initializerExpression = JavaPsiFacade.getElementFactory(project).createExpressionFromText(initializerText, var); initializerExpression = (PsiExpression)CodeStyleManager.getInstance(project).reformat(initializerExpression); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/joinDeclaration/afterParenthesis.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/joinDeclaration/afterParenthesis.java new file mode 100644 index 000000000000..3e09d0a05a1b --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/joinDeclaration/afterParenthesis.java @@ -0,0 +1,6 @@ +// "Join declaration and assignment" "true" +class Test { + { + int i = 4 * (2 + 3); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/joinDeclaration/beforeParenthesis.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/joinDeclaration/beforeParenthesis.java new file mode 100644 index 000000000000..c30996693eb6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/joinDeclaration/beforeParenthesis.java @@ -0,0 +1,7 @@ +// "Join declaration and assignment" "true" +class Test { + { + int i = 4; + i *= 2 + 3; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ParenthesesUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ParenthesesUtils.java index 29bc9dd6182a..213d69790506 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ParenthesesUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ParenthesesUtils.java @@ -26,6 +26,8 @@ import java.util.Map; public class ParenthesesUtils { + public static final Map tokenMap = new HashMap(); + private ParenthesesUtils() {} public static final int PARENTHESIZED_PRECEDENCE = 0; @@ -50,6 +52,21 @@ public class ParenthesesUtils { private static final Map s_binaryOperatorPrecedence = new HashMap(NUM_PRECEDENCES); + + static { + tokenMap.put(JavaTokenType.PLUSEQ, JavaTokenType.PLUS); + tokenMap.put(JavaTokenType.MINUSEQ, JavaTokenType.MINUS); + tokenMap.put(JavaTokenType.ASTERISKEQ, JavaTokenType.ASTERISK); + tokenMap.put(JavaTokenType.DIVEQ, JavaTokenType.DIV); + tokenMap.put(JavaTokenType.ANDEQ, JavaTokenType.AND); + tokenMap.put(JavaTokenType.OREQ, JavaTokenType.OR); + tokenMap.put(JavaTokenType.XOREQ, JavaTokenType.XOR); + tokenMap.put(JavaTokenType.PERCEQ, JavaTokenType.PERC); + tokenMap.put(JavaTokenType.LTLTEQ, JavaTokenType.LTLT); + tokenMap.put(JavaTokenType.GTGTEQ, JavaTokenType.GTGT); + tokenMap.put(JavaTokenType.GTGTGTEQ, JavaTokenType.GTGTGT); + } + static { s_binaryOperatorPrecedence.put(JavaTokenType.PLUS, ADDITIVE_PRECEDENCE); s_binaryOperatorPrecedence.put(JavaTokenType.MINUS, ADDITIVE_PRECEDENCE); @@ -526,4 +543,18 @@ public class ParenthesesUtils { } return parentPrecedence < childPrecedence; } + + public static boolean areParenthesesNeeded(PsiJavaToken sign, PsiExpression rhs) { + if (rhs instanceof PsiPolyadicExpression) { + final PsiPolyadicExpression binaryExpression = (PsiPolyadicExpression)rhs; + final int precedence1 = getPrecedenceForOperator(binaryExpression.getOperationTokenType()); + final IElementType signTokenType = sign.getTokenType(); + final IElementType newOperatorToken = tokenMap.get(signTokenType); + final int precedence2 = getPrecedenceForOperator(newOperatorToken); + return precedence1 >= precedence2 || !isCommutativeOperator(newOperatorToken); + } + else { + return rhs instanceof PsiConditionalExpression; + } + } } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceOperatorAssignmentWithAssignmentIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceOperatorAssignmentWithAssignmentIntention.java index 35b1470a46ce..2c703e3f8cd8 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceOperatorAssignmentWithAssignmentIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/opassign/ReplaceOperatorAssignmentWithAssignmentIntention.java @@ -16,7 +16,6 @@ package com.siyeh.ipp.opassign; import com.intellij.psi.*; -import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.TypeConversionUtil; import com.siyeh.IntentionPowerPackBundle; import com.siyeh.ig.PsiReplacementUtil; @@ -25,27 +24,8 @@ import com.siyeh.ipp.base.MutablyNamedIntention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; -import java.util.HashMap; -import java.util.Map; - public class ReplaceOperatorAssignmentWithAssignmentIntention extends MutablyNamedIntention { - private static final Map tokenMap = new HashMap(); - - static { - tokenMap.put(JavaTokenType.PLUSEQ, JavaTokenType.PLUS); - tokenMap.put(JavaTokenType.MINUSEQ, JavaTokenType.MINUS); - tokenMap.put(JavaTokenType.ASTERISKEQ, JavaTokenType.ASTERISK); - tokenMap.put(JavaTokenType.DIVEQ, JavaTokenType.DIV); - tokenMap.put(JavaTokenType.ANDEQ, JavaTokenType.AND); - tokenMap.put(JavaTokenType.OREQ, JavaTokenType.OR); - tokenMap.put(JavaTokenType.XOREQ, JavaTokenType.XOR); - tokenMap.put(JavaTokenType.PERCEQ, JavaTokenType.PERC); - tokenMap.put(JavaTokenType.LTLTEQ, JavaTokenType.LTLT); - tokenMap.put(JavaTokenType.GTGTEQ, JavaTokenType.GTGT); - tokenMap.put(JavaTokenType.GTGTGTEQ, JavaTokenType.GTGTGT); - } - @Override @NotNull protected PsiElementPredicate getElementPredicate() { @@ -70,18 +50,7 @@ public class ReplaceOperatorAssignmentWithAssignmentIntention extends MutablyNam final String newOperator = operator.substring(0, operator.length() - 1); final String lhsText = lhs.getText(); final String rhsText = (rhs == null) ? "" : rhs.getText(); - final boolean parentheses; - if (rhs instanceof PsiPolyadicExpression) { - final PsiPolyadicExpression binaryExpression = (PsiPolyadicExpression)rhs; - final int precedence1 = ParenthesesUtils.getPrecedenceForOperator(binaryExpression.getOperationTokenType()); - final IElementType signTokenType = sign.getTokenType(); - final IElementType newOperatorToken = tokenMap.get(signTokenType); - final int precedence2 = ParenthesesUtils.getPrecedenceForOperator(newOperatorToken); - parentheses = precedence1 >= precedence2 || !ParenthesesUtils.isCommutativeOperator(newOperatorToken); - } - else { - parentheses = false; - } + final boolean parentheses = ParenthesesUtils.areParenthesesNeeded(sign, rhs); final String cast = getCastString(lhs, rhs); final StringBuilder newExpression = new StringBuilder(lhsText); newExpression.append('=').append(cast); diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ConditionalAssignment.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ConditionalAssignment.java new file mode 100644 index 000000000000..9845fbf16198 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ConditionalAssignment.java @@ -0,0 +1,7 @@ +package com.siyeh.ipp.opassign.assignment; + +class Conditional { + void x(int i) { + i *= 1==1 ? 2 : 3; + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ConditionalAssignment_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ConditionalAssignment_after.java new file mode 100644 index 000000000000..7d9bdd285af1 --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/opassign/assignment/ConditionalAssignment_after.java @@ -0,0 +1,7 @@ +package com.siyeh.ipp.opassign.assignment; + +class Conditional { + void x(int i) { + i = i * (1 == 1 ? 2 : 3); + } +} \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/opassign/ReplaceOperatorAssignmentWithAssignmentIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/opassign/ReplaceOperatorAssignmentWithAssignmentIntentionTest.java index 026351e96ddf..060f7f79b58c 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/opassign/ReplaceOperatorAssignmentWithAssignmentIntentionTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/opassign/ReplaceOperatorAssignmentWithAssignmentIntentionTest.java @@ -13,6 +13,7 @@ public class ReplaceOperatorAssignmentWithAssignmentIntentionTest extends IPPTes public void testByteOpAssign() { doTest(); } public void testPrecedence() { doTest(); } public void testPolyadicAssignment() { doTest(IntentionPowerPackBundle.message("replace.operator.assignment.with.assignment.intention.name", "*=")); } + public void testConditionalAssignment() { doTest(IntentionPowerPackBundle.message("replace.operator.assignment.with.assignment.intention.name", "*=")); } @Override protected String getIntentionName() {