From 354e1dc337b322f5a9c7d1e11a13a5f3d1dcd39c Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 10 Dec 2015 14:28:37 +0300 Subject: [PATCH] Extract Function: Parenthesize binary expressions if operation reference starts with a new line --- .../extractionEngine/extractorUtil.kt | 11 ++++--- .../refactoring/introduce/introduceUtil.kt | 11 +++++-- .../multiline/multilineBinaryExpression.kt | 6 ++++ .../multilineBinaryExpression.kt.after | 8 +++++ .../multilineBinaryExpressionWithComments.kt | 6 ++++ ...ilineBinaryExpressionWithComments.kt.after | 8 +++++ .../multilineNestedBinaryExpression1.kt | 6 ++++ .../multilineNestedBinaryExpression1.kt.after | 8 +++++ .../multilineNestedBinaryExpression2.kt | 6 ++++ .../multilineNestedBinaryExpression2.kt.after | 8 +++++ .../introduce/ExtractionTestGenerated.java | 33 +++++++++++++++++++ 11 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpression.kt create mode 100644 idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpression.kt.after create mode 100644 idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpressionWithComments.kt create mode 100644 idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpressionWithComments.kt.after create mode 100644 idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression1.kt create mode 100644 idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression1.kt.after create mode 100644 idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression2.kt create mode 100644 idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression2.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt index 9aff40f6830..bb2cf75b98f 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/extractorUtil.kt @@ -31,12 +31,9 @@ import org.jetbrains.kotlin.idea.intentions.ConvertToExpressionBodyIntention import org.jetbrains.kotlin.idea.intentions.InfixCallToOrdinaryIntention import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention -import org.jetbrains.kotlin.idea.refactoring.introduce.extractableSubstringInfo +import org.jetbrains.kotlin.idea.refactoring.introduce.* import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.OutputValue.* import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.OutputValueBoxer.AsTuple -import org.jetbrains.kotlin.idea.refactoring.introduce.getPhysicalTextRange -import org.jetbrains.kotlin.idea.refactoring.introduce.replaceWith -import org.jetbrains.kotlin.idea.refactoring.introduce.substringContextOrThis import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.ShortenReferences import org.jetbrains.kotlin.idea.util.psi.patternMatching.* @@ -466,6 +463,12 @@ fun ExtractionGeneratorConfiguration.generateDeclaration( fun adjustDeclarationBody(declaration: KtNamedDeclaration) { val body = declaration.getGeneratedBody() + (body.blockExpressionsOrSingle().singleOrNull() as? KtExpression)?.let { + if (it.mustBeParenthesizedInInitializerPosition()) { + it.replace(psiFactory.createExpressionByPattern("($0)", it)) + } + } + val jumpValue = descriptor.controlFlow.jumpOutputValue if (jumpValue != null) { val replacingReturn = psiFactory.createExpression(if (jumpValue.conditional) "return true" else "return") diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceUtil.kt index 9e462326a8f..c82d3508bee 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/introduceUtil.kt @@ -22,10 +22,10 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util.Key import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement +import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils import org.jetbrains.kotlin.idea.core.refactoring.chooseContainerElementIfNecessary -import org.jetbrains.kotlin.idea.core.refactoring.removeTemplateEntryBracesIfPossible import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringBundle import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringUtil import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiRange @@ -83,7 +83,7 @@ fun selectElementsWithTargetParent( fun selectTargetContainer(elements: List) { val physicalElements = elements.map { it.substringContextOrThis } val parent = PsiTreeUtil.findCommonParent(physicalElements) - ?: throw AssertionError("Should have at least one parent: ${physicalElements.joinToString("\n")}") + ?: throw AssertionError("Should have at least one parent: ${physicalElements.joinToString("\n")}") val containers = getContainers(physicalElements, parent) if (containers.isEmpty()) { @@ -196,4 +196,11 @@ fun ExtractableSubstringInfo.replaceWith(replacement: KtExpression): KtExpressio addedRefEntry.expression!! } +} + +fun KtExpression.mustBeParenthesizedInInitializerPosition(): Boolean { + if (this !is KtBinaryExpression) return false + + if (left?.mustBeParenthesizedInInitializerPosition() ?: false) return true + return PsiChildRange(left, operationReference).any { (it is PsiWhiteSpace) && it.textContains('\n') } } \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpression.kt b/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpression.kt new file mode 100644 index 00000000000..01c92bdd09e --- /dev/null +++ b/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpression.kt @@ -0,0 +1,6 @@ +fun foo(i: Int) { } + +fun test() { + foo(1 + + 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpression.kt.after b/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpression.kt.after new file mode 100644 index 00000000000..6536c613e63 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpression.kt.after @@ -0,0 +1,8 @@ +fun foo(i: Int) { } + +fun test() { + foo(i()) +} + +private fun i() = (1 + + 2) \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpressionWithComments.kt b/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpressionWithComments.kt new file mode 100644 index 00000000000..3ea6345a6b4 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpressionWithComments.kt @@ -0,0 +1,6 @@ +fun foo(i: Int) { } + +fun test() { + foo(1 // abc + /*def*/ + 2) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpressionWithComments.kt.after b/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpressionWithComments.kt.after new file mode 100644 index 00000000000..ee0d9d5a11c --- /dev/null +++ b/idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpressionWithComments.kt.after @@ -0,0 +1,8 @@ +fun foo(i: Int) { } + +fun test() { + foo(i()) +} + +private fun i() = (1 // abc + /*def*/ + 2) \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression1.kt b/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression1.kt new file mode 100644 index 00000000000..2602d7ce7ff --- /dev/null +++ b/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression1.kt @@ -0,0 +1,6 @@ +fun foo(i: Int) { } + +fun test() { + foo(1 + + 2 - 3) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression1.kt.after b/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression1.kt.after new file mode 100644 index 00000000000..24e252f7fb8 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression1.kt.after @@ -0,0 +1,8 @@ +fun foo(i: Int) { } + +fun test() { + foo(i()) +} + +private fun i() = (1 + + 2 - 3) \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression2.kt b/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression2.kt new file mode 100644 index 00000000000..3808a0a0a50 --- /dev/null +++ b/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression2.kt @@ -0,0 +1,6 @@ +fun foo(i: Int) { } + +fun test() { + foo(1 + 2 + - 3) +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression2.kt.after b/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression2.kt.after new file mode 100644 index 00000000000..0fba86619ac --- /dev/null +++ b/idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression2.kt.after @@ -0,0 +1,8 @@ +fun foo(i: Int) { } + +fun test() { + foo(i()) +} + +private fun i() = (1 + 2 + - 3) \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java index 16ec371ae1e..0f9fbee83b1 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java @@ -2038,6 +2038,39 @@ public class ExtractionTestGenerated extends AbstractExtractionTest { } } + @TestMetadata("idea/testData/refactoring/extractFunction/multiline") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Multiline extends AbstractExtractionTest { + public void testAllFilesPresentInMultiline() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/extractFunction/multiline"), Pattern.compile("^(.+)\\.(kt|kts)$"), true); + } + + @TestMetadata("multilineBinaryExpression.kt") + public void testMultilineBinaryExpression() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpression.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("multilineBinaryExpressionWithComments.kt") + public void testMultilineBinaryExpressionWithComments() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/multiline/multilineBinaryExpressionWithComments.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("multilineNestedBinaryExpression1.kt") + public void testMultilineNestedBinaryExpression1() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression1.kt"); + doExtractFunctionTest(fileName); + } + + @TestMetadata("multilineNestedBinaryExpression2.kt") + public void testMultilineNestedBinaryExpression2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/multiline/multilineNestedBinaryExpression2.kt"); + doExtractFunctionTest(fileName); + } + } + @TestMetadata("idea/testData/refactoring/extractFunction/parameters") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)