From 5c88a1c63eb3689bf68496124c9c216142bf82a6 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 4 Dec 2015 16:37:05 +0300 Subject: [PATCH] Inline Variable: Parenthesize arguments of the form "e1 < e2" if the next argument has the form "e1 > e2" #KT-8261 Fixed --- .../jetbrains/kotlin/psi/KtExpressionImpl.kt | 4 +- .../org/jetbrains/kotlin/psi/KtPsiUtil.java | 48 ++++++++++++------- .../inline/lessAndGreaterInCallArgs.kt | 4 ++ .../inline/lessAndGreaterInCallArgs.kt.after | 3 ++ .../inline/InlineTestGenerated.java | 6 +++ 5 files changed, 47 insertions(+), 18 deletions(-) create mode 100644 idea/testData/refactoring/inline/lessAndGreaterInCallArgs.kt create mode 100644 idea/testData/refactoring/inline/lessAndGreaterInCallArgs.kt.after diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtExpressionImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtExpressionImpl.kt index 8399c7ee0dd..0c17467a0bd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtExpressionImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtExpressionImpl.kt @@ -59,8 +59,8 @@ public abstract class KtExpressionImpl(node: ASTNode) : KtElementImpl(node), KtE parent.delete() } - parent is KtExpression -> { - if (KtPsiUtil.areParenthesesNecessary(newElement, expression, parent)) { + parent is KtExpression || parent is KtValueArgument -> { + if (KtPsiUtil.areParenthesesNecessary(newElement, expression, parent as KtElement)) { return rawReplaceHandler(KtPsiFactory(expression).createExpressionByPattern("($0)", newElement)) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java index 0f7141b4d4c..8e34f74b75b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java @@ -471,21 +471,25 @@ public class KtPsiUtil { return !areParenthesesNecessary(innerExpression, expression, (KtExpression) parent); } - public static boolean areParenthesesNecessary(@NotNull KtExpression innerExpression, @NotNull KtExpression currentInner, @NotNull KtExpression parentExpression) { - if (parentExpression instanceof KtParenthesizedExpression || innerExpression instanceof KtParenthesizedExpression) { + public static boolean areParenthesesNecessary( + @NotNull KtExpression innerExpression, + @NotNull KtExpression currentInner, + @NotNull KtElement parentElement + ) { + if (parentElement instanceof KtParenthesizedExpression || innerExpression instanceof KtParenthesizedExpression) { return false; } - if (parentExpression instanceof KtPackageDirective) return false; + if (parentElement instanceof KtPackageDirective) return false; - if (parentExpression instanceof KtWhenExpression || innerExpression instanceof KtWhenExpression) { + if (parentElement instanceof KtWhenExpression || innerExpression instanceof KtWhenExpression) { return false; } if (innerExpression instanceof KtIfExpression) { - if (parentExpression instanceof KtQualifiedExpression) return true; + if (parentElement instanceof KtQualifiedExpression) return true; - PsiElement current = parentExpression; + PsiElement current = parentElement; while (!(current instanceof KtBlockExpression || current instanceof KtDeclaration || current instanceof KtStatementExpression)) { if (current.getTextRange().getEndOffset() != currentInner.getTextRange().getEndOffset()) { @@ -496,9 +500,9 @@ public class KtPsiUtil { } } - if (parentExpression instanceof KtCallExpression && currentInner == ((KtCallExpression) parentExpression).getCalleeExpression()) { + if (parentElement instanceof KtCallExpression && currentInner == ((KtCallExpression) parentElement).getCalleeExpression()) { if (innerExpression instanceof KtSimpleNameExpression) return false; - if (KtPsiUtilKt.getQualifiedExpressionForSelector(parentExpression) != null) return true; + if (KtPsiUtilKt.getQualifiedExpressionForSelector(parentElement) != null) return true; return !(innerExpression instanceof KtThisExpression || innerExpression instanceof KtArrayAccessExpression || innerExpression instanceof KtConstantExpression @@ -506,11 +510,23 @@ public class KtPsiUtil { || innerExpression instanceof KtCallExpression); } + if (parentElement instanceof KtValueArgument) { + // a(___, d > (e + f)) => a((b < c), d > (e + f)) to prevent parsing < c, d > as type argument list + KtValueArgument nextArg = PsiTreeUtil.getNextSiblingOfType(parentElement, KtValueArgument.class); + PsiElement nextExpression = nextArg != null ? nextArg.getArgumentExpression() : null; + if (innerExpression instanceof KtBinaryExpression && + ((KtBinaryExpression) innerExpression).getOperationToken() == KtTokens.LT && + nextExpression instanceof KtBinaryExpression && + ((KtBinaryExpression) nextExpression).getOperationToken() == KtTokens.GT) return true; + } + + if (!(parentElement instanceof KtExpression)) return false; + IElementType innerOperation = getOperation(innerExpression); - IElementType parentOperation = getOperation(parentExpression); + IElementType parentOperation = getOperation((KtExpression) parentElement); // 'return (@label{...})' case - if (parentExpression instanceof KtReturnExpression + if (parentElement instanceof KtReturnExpression && (innerExpression instanceof KtLabeledExpression || innerExpression instanceof KtAnnotatedExpression)) return true; // '(x: Int) < y' case @@ -518,26 +534,26 @@ public class KtPsiUtil { return true; } - if (parentExpression instanceof KtLabeledExpression) return false; + if (parentElement instanceof KtLabeledExpression) return false; // 'x ?: ...' case - if (parentExpression instanceof KtBinaryExpression && parentOperation == KtTokens.ELVIS && currentInner == ((KtBinaryExpression) parentExpression).getRight()) { + if (parentElement instanceof KtBinaryExpression && parentOperation == KtTokens.ELVIS && currentInner == ((KtBinaryExpression) parentElement).getRight()) { return false; } int innerPriority = getPriority(innerExpression); - int parentPriority = getPriority(parentExpression); + int parentPriority = getPriority((KtExpression) parentElement); if (innerPriority == parentPriority) { - if (parentExpression instanceof KtBinaryExpression) { + if (parentElement instanceof KtBinaryExpression) { if (innerOperation == KtTokens.ANDAND || innerOperation == KtTokens.OROR) { return false; } - return ((KtBinaryExpression) parentExpression).getRight() == currentInner; + return ((KtBinaryExpression) parentElement).getRight() == currentInner; } //'-(-x)' case - if (parentExpression instanceof KtPrefixExpression && innerExpression instanceof KtPrefixExpression) { + if (parentElement instanceof KtPrefixExpression && innerExpression instanceof KtPrefixExpression) { return innerOperation == parentOperation && (innerOperation == KtTokens.PLUS || innerOperation == KtTokens.MINUS); } return false; diff --git a/idea/testData/refactoring/inline/lessAndGreaterInCallArgs.kt b/idea/testData/refactoring/inline/lessAndGreaterInCallArgs.kt new file mode 100644 index 00000000000..2a22dfe44d0 --- /dev/null +++ b/idea/testData/refactoring/inline/lessAndGreaterInCallArgs.kt @@ -0,0 +1,4 @@ +fun f(a : (Any, Any) -> Unit, b : Int, c : Int, d : Int, e : Int, f : Int) { + val g = b < c + a(g, d > (e + f)) +} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/lessAndGreaterInCallArgs.kt.after b/idea/testData/refactoring/inline/lessAndGreaterInCallArgs.kt.after new file mode 100644 index 00000000000..004ea90c03a --- /dev/null +++ b/idea/testData/refactoring/inline/lessAndGreaterInCallArgs.kt.after @@ -0,0 +1,3 @@ +fun f(a : (Any, Any) -> Unit, b : Int, c : Int, d : Int, e : Int, f : Int) { + a((b < c), d > (e + f)) +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java index 91da7c40b8f..d311e2c1554 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java @@ -59,6 +59,12 @@ public class InlineTestGenerated extends AbstractInlineTest { doTest(fileName); } + @TestMetadata("lessAndGreaterInCallArgs.kt") + public void testLessAndGreaterInCallArgs() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/lessAndGreaterInCallArgs.kt"); + doTest(fileName); + } + @TestMetadata("MethodReference.kt") public void testMethodReference() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/MethodReference.kt");