KotlinExpressionMover: trailing comma support

#KT-34744
This commit is contained in:
Dmitry Gridin
2020-02-13 19:38:41 +07:00
parent 72c8b38864
commit 36ebbc49f4
51 changed files with 581 additions and 197 deletions
@@ -453,6 +453,7 @@ fun main(args: Array<String>) {
model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression") model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression") model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression")
model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression") model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/trailingComma", testMethod = "doTestExpressionWithTrailingComma")
} }
testClass<AbstractMoveLeftRightTest> { testClass<AbstractMoveLeftRightTest> {
@@ -439,6 +439,7 @@ fun main(args: Array<String>) {
model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression") model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression") model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression")
model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression") model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/trailingComma", testMethod = "doTestExpressionWithTrailingComma")
} }
testClass<AbstractMoveLeftRightTest> { testClass<AbstractMoveLeftRightTest> {
@@ -439,6 +439,7 @@ fun main(args: Array<String>) {
model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression") model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression") model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression")
model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression") model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/trailingComma", testMethod = "doTestExpressionWithTrailingComma")
} }
testClass<AbstractMoveLeftRightTest> { testClass<AbstractMoveLeftRightTest> {
@@ -439,6 +439,7 @@ fun main(args: Array<String>) {
model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression") model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression") model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression")
model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression") model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/trailingComma", testMethod = "doTestExpressionWithTrailingComma")
} }
testClass<AbstractMoveLeftRightTest> { testClass<AbstractMoveLeftRightTest> {
@@ -4,16 +4,19 @@
*/ */
package org.jetbrains.kotlin.idea.codeInsight.upDownMover package org.jetbrains.kotlin.idea.codeInsight.upDownMover
import com.intellij.application.options.CodeStyle
import com.intellij.codeInsight.editorActions.moveUpDown.LineRange import com.intellij.codeInsight.editorActions.moveUpDown.LineRange
import com.intellij.codeInsight.editorActions.moveUpDown.StatementUpDownMover import com.intellij.codeInsight.editorActions.moveUpDown.StatementUpDownMover
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.core.util.isMultiLine import org.jetbrains.kotlin.idea.core.util.isMultiLine
import org.jetbrains.kotlin.idea.formatter.TrailingCommaHelper
import org.jetbrains.kotlin.idea.formatter.isComma import org.jetbrains.kotlin.idea.formatter.isComma
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.function.Predicate import java.util.function.Predicate
class KotlinExpressionMover : AbstractKotlinUpDownMover() { class KotlinExpressionMover : AbstractKotlinUpDownMover() {
@@ -117,9 +120,14 @@ class KotlinExpressionMover : AbstractKotlinUpDownMover() {
val (first, second) = parametersOrArgsToMove ?: return val (first, second) = parametersOrArgsToMove ?: return
val lastElementOnFirstLine = getLastSiblingOfSameTypeInLine(first, editor) val lastElementOnFirstLine = getLastSiblingOfSameTypeInLine(first, editor)
val lastElementOnSecondLine = getLastSiblingOfSameTypeInLine(second, editor) val lastElementOnSecondLine = getLastSiblingOfSameTypeInLine(second, editor)
val withTrailingComma = lastElementOnFirstLine.parent
?.safeAs<KtElement>()
?.let {
TrailingCommaHelper.needComma(it, CodeStyle.getSettings(it.project), true)
} == true
fixCommaIfNeeded(lastElementOnFirstLine, down && isLastOfItsKind(lastElementOnSecondLine, true)) fixCommaIfNeeded(lastElementOnFirstLine, down && isLastOfItsKind(lastElementOnSecondLine, true), withTrailingComma)
fixCommaIfNeeded(lastElementOnSecondLine, !down && isLastOfItsKind(lastElementOnFirstLine, true)) fixCommaIfNeeded(lastElementOnSecondLine, !down && isLastOfItsKind(lastElementOnFirstLine, true),withTrailingComma)
editor.project?.let { PsiDocumentManager.getInstance(it).doPostponedOperationsAndUnblockDocument(editor.document) } editor.project?.let { PsiDocumentManager.getInstance(it).doPostponedOperationsAndUnblockDocument(editor.document) }
} }
} }
@@ -476,15 +484,15 @@ class KotlinExpressionMover : AbstractKotlinUpDownMover() {
predicate = MOVABLE_ELEMENT_CONSTRAINT predicate = MOVABLE_ELEMENT_CONSTRAINT
) ?: return null ) ?: return null
if (isBracelessBlock(movableElement)) { return if (isBracelessBlock(movableElement)) {
return StatementUpDownMover.firstNonWhiteElement( StatementUpDownMover.firstNonWhiteElement(
if (lookRight) if (lookRight)
movableElement.lastChild movableElement.lastChild
else else
movableElement.firstChild, !lookRight movableElement.firstChild, !lookRight
) )
} else { } else {
return movableElement movableElement
} }
} }
@@ -550,9 +558,9 @@ class KotlinExpressionMover : AbstractKotlinUpDownMover() {
private fun getComma(element: PsiElement): PsiElement? = firstNonWhiteSibling(element, true)?.takeIf(PsiElement::isComma) private fun getComma(element: PsiElement): PsiElement? = firstNonWhiteSibling(element, true)?.takeIf(PsiElement::isComma)
private fun fixCommaIfNeeded(element: PsiElement, willBeLast: Boolean) { private fun fixCommaIfNeeded(element: PsiElement, willBeLast: Boolean, withTrailingComma: Boolean) {
val comma = getComma(element) val comma = getComma(element)
if (willBeLast && comma != null) { if (willBeLast && comma != null && !withTrailingComma) {
comma.delete() comma.delete()
} else if (!willBeLast && comma == null) { } else if (!willBeLast && comma == null) {
val parent = element.parent val parent = element.parent
@@ -0,0 +1,6 @@
// MOVE: down
val x = foo(
<caret>a,
b,
c
)
@@ -0,0 +1,6 @@
// MOVE: down
val x = foo(
b,
<caret>a,
c
)
@@ -0,0 +1,6 @@
// MOVE: down
val x = foo(
b,
<caret>a,
c
)
@@ -0,0 +1,6 @@
// MOVE: down
val x = foo(
b,
c,
<caret>a
)
@@ -0,0 +1,7 @@
// MOVE: down
// IS_APPLICABLE: false
val x = foo(
b,
c,
<caret>a
)
@@ -0,0 +1,6 @@
// MOVE: up
val x = foo(
b,
c,
<caret>a
)
@@ -0,0 +1,6 @@
// MOVE: up
val x = foo(
b,
<caret>a,
c
)
@@ -0,0 +1,6 @@
// MOVE: up
val x = foo(
b,
<caret>a,
c
)
@@ -0,0 +1,6 @@
// MOVE: up
val x = foo(
<caret>a,
b,
c
)
@@ -0,0 +1,7 @@
// MOVE: up
// IS_APPLICABLE: false
val x = foo(
<caret>a,
b,
c
)
@@ -0,0 +1,6 @@
// MOVE: down
val x = listOf(
1,
<caret>2, 3,
4
)
@@ -0,0 +1,6 @@
// MOVE: down
val x = listOf(
1,
4,
<caret>2, 3
)
@@ -0,0 +1,6 @@
// MOVE: up
val x = listOf(
1,
4,
<caret>2, 3
)
@@ -0,0 +1,6 @@
// MOVE: up
val x = listOf(
1,
<caret>2, 3,
4
)
@@ -0,0 +1,8 @@
// MOVE: down
class A(
b:<caret> Int,
a: Int,
c: Int
) {
}
@@ -0,0 +1,8 @@
// MOVE: down
class A(
a: Int,
b:<caret> Int,
c: Int
) {
}
@@ -0,0 +1,8 @@
// MOVE: down
class A(
b: Int,
<caret>a: Int,
c: Int
) {
}
@@ -0,0 +1,8 @@
// MOVE: down
class A(
b: Int,
c: Int,
<caret>a: Int,
) {
}
@@ -0,0 +1,8 @@
// MOVE: up
class A(
a: Int,
b:<caret> Int,
c: Int
) {
}
@@ -0,0 +1,8 @@
// MOVE: up
class A(
b:<caret> Int,
a: Int,
c: Int
) {
}
@@ -0,0 +1,8 @@
// MOVE: up
class A(
b: Int,
c: Int,
<caret>a: Int
) {
}
@@ -0,0 +1,8 @@
// MOVE: up
class A(
b: Int,
<caret>a: Int,
c: Int,
) {
}
@@ -0,0 +1,9 @@
// MOVE: down
// IS_APPLICABLE: false
class A(
b: Int,
c: Int,
<caret>a: Int
) {
}
@@ -0,0 +1,9 @@
// MOVE: up
// IS_APPLICABLE: false
class A(
<caret>b: Int,
c: Int,
a: Int
) {
}
@@ -0,0 +1,6 @@
// MOVE: down
class A(
a: Int,
<caret>b: Int, c: Int,
d: Int
)
@@ -0,0 +1,6 @@
// MOVE: down
class A(
a: Int,
d: Int,
<caret>b: Int, c: Int,
)
@@ -0,0 +1,6 @@
// MOVE: up
class A(
a: Int,
d: Int,
<caret>b: Int, c: Int
)
@@ -0,0 +1,6 @@
// MOVE: up
class A(
a: Int,
<caret>b: Int, c: Int,
d: Int,
)
@@ -0,0 +1,13 @@
// MOVE: down
class A {
fun <T, U, W> foo(
b:<caret> Int,
a: Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,13 @@
// MOVE: down
class A {
fun <T, U, W> foo(
a: Int,
b:<caret> Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,13 @@
// MOVE: down
class A {
fun <T, U, W> foo(
b: Int,
<caret>a: Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,13 @@
// MOVE: down
class A {
fun <T, U, W> foo(
b: Int,
c: Int,
<caret>a: Int,
) {
}
class B {
}
}
@@ -0,0 +1,13 @@
// MOVE: up
class A {
fun <T, U, W> foo(
a: Int,
b:<caret> Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,13 @@
// MOVE: up
class A {
fun <T, U, W> foo(
b:<caret> Int,
a: Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,13 @@
// MOVE: up
class A {
fun <T, U, W> foo(
b: Int,
c: Int
<caret>a: Int,
) {
}
class B {
}
}
@@ -0,0 +1,13 @@
// MOVE: up
class A {
fun <T, U, W> foo(
b: Int,
<caret>a: Int,
c: Int
) {
}
class B {
}
}
@@ -0,0 +1,14 @@
// MOVE: down
// IS_APPLICABLE: false
class A {
fun <T, U, W> foo(
b: Int,
c: Int
<caret>a: Int,
) {
}
class B {
}
}
@@ -0,0 +1,14 @@
// MOVE: up
// IS_APPLICABLE: false
class A {
fun <T, U, W> foo(
b: Int<caret>,
c: Int
a: Int,
) {
}
class B {
}
}
@@ -0,0 +1,7 @@
// MOVE: down
fun test(
a: Int,
<caret>b: Int, c: Int,
d: Int,
) {
}
@@ -0,0 +1,7 @@
// MOVE: down
fun test(
a: Int,
d: Int,
<caret>b: Int, c: Int,
) {
}
@@ -0,0 +1,7 @@
// MOVE: up
fun test(
a: Int,
d: Int,
<caret>b: Int, c: Int
) {
}
@@ -0,0 +1,7 @@
// MOVE: up
fun test(
a: Int,
<caret>b: Int, c: Int,
d: Int,
) {
}
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.formatter.FormatSettingsUtil
import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinDeclarationMover import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinDeclarationMover
import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinExpressionMover import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinExpressionMover
import org.jetbrains.kotlin.idea.core.script.isScriptChangesNotifierDisabled import org.jetbrains.kotlin.idea.core.script.isScriptChangesNotifierDisabled
import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightTestCase import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightTestCase
import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
@@ -36,8 +37,12 @@ abstract class AbstractMoveStatementTest : AbstractCodeMoverTest() {
doTest(path, KotlinExpressionMover::class.java) doTest(path, KotlinExpressionMover::class.java)
} }
private fun doTest(path: String, defaultMoverClass: Class<out StatementUpDownMover>) { protected fun doTestExpressionWithTrailingComma(path: String) {
doTest(path) { isApplicableExpected, direction -> doTest(path, KotlinExpressionMover::class.java, true)
}
private fun doTest(path: String, defaultMoverClass: Class<out StatementUpDownMover>, trailingComma: Boolean = false) {
doTest(path, trailingComma) { isApplicableExpected, direction ->
val movers = Extensions.getExtensions(StatementUpDownMover.STATEMENT_UP_DOWN_MOVER_EP) val movers = Extensions.getExtensions(StatementUpDownMover.STATEMENT_UP_DOWN_MOVER_EP)
val info = StatementUpDownMover.MoveInfo() val info = StatementUpDownMover.MoveInfo()
val actualMover = movers.firstOrNull { val actualMover = movers.firstOrNull {
@@ -68,7 +73,11 @@ abstract class AbstractCodeMoverTest : KotlinLightCodeInsightTestCase() {
super.tearDown() super.tearDown()
} }
protected fun doTest(path: String, isApplicableChecker: (isApplicableExpected: Boolean, direction: String) -> Unit) { protected fun doTest(
path: String,
trailingComma: Boolean = false,
isApplicableChecker: (isApplicableExpected: Boolean, direction: String) -> Unit
) {
configureByFile(path) configureByFile(path)
val fileText = FileUtil.loadFile(File(path), true) val fileText = FileUtil.loadFile(File(path), true)
@@ -87,40 +96,39 @@ abstract class AbstractCodeMoverTest : KotlinLightCodeInsightTestCase() {
isApplicableChecker(isApplicableExpected, direction) isApplicableChecker(isApplicableExpected, direction)
invokeAndCheck(fileText, path, action, isApplicableExpected)
}
private fun invokeAndCheck(fileText: String, path: String, action: EditorAction, isApplicableExpected: Boolean) {
val editor = editor_
val project = editor.project!!
val codeStyleSettings = CodeStyle.getSettings(project) val codeStyleSettings = CodeStyle.getSettings(project)
val configurator = FormatSettingsUtil.createConfigurator(fileText, codeStyleSettings)
configurator.configureSettings()
try { try {
val dataContext = currentEditorDataContext_ val configurator = FormatSettingsUtil.createConfigurator(fileText, codeStyleSettings)
configurator.configureSettings()
val before = editor.document.text if (trailingComma) codeStyleSettings.kotlinCustomSettings.ALLOW_TRAILING_COMMA = true
runWriteAction { action.actionPerformed(editor, dataContext) } invokeAndCheck(path, action, isApplicableExpected)
val after = editor.document.text
val actionDoesNothing = after == before
TestCase.assertEquals(isApplicableExpected, !actionDoesNothing)
if (isApplicableExpected) {
val afterFilePath = "$path.after"
try {
checkResultByFile(afterFilePath)
} catch (e: ComparisonFailure) {
KotlinTestUtils.assertEqualsToFile(File(afterFilePath), editor)
}
}
} finally { } finally {
codeStyleSettings.clearCodeStyleSettings() codeStyleSettings.clearCodeStyleSettings()
} }
} }
private fun invokeAndCheck(path: String, action: EditorAction, isApplicableExpected: Boolean) {
val editor = editor_
val dataContext = currentEditorDataContext_
val before = editor.document.text
runWriteAction { action.actionPerformed(editor, dataContext) }
val after = editor.document.text
val actionDoesNothing = after == before
TestCase.assertEquals(isApplicableExpected, !actionDoesNothing)
if (isApplicableExpected) {
val afterFilePath = "$path.after"
try {
checkResultByFile(afterFilePath)
} catch (e: ComparisonFailure) {
KotlinTestUtils.assertEqualsToFile(File(afterFilePath), editor)
}
}
}
override fun getTestDataPath() = "" override fun getTestDataPath() = ""
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.formatter.FormatSettingsUtil
import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinDeclarationMover import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinDeclarationMover
import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinExpressionMover import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinExpressionMover
import org.jetbrains.kotlin.idea.core.script.isScriptChangesNotifierDisabled import org.jetbrains.kotlin.idea.core.script.isScriptChangesNotifierDisabled
import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightTestCase import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightTestCase
import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
@@ -37,8 +38,12 @@ abstract class AbstractMoveStatementTest : AbstractCodeMoverTest() {
doTest(path, KotlinExpressionMover::class.java) doTest(path, KotlinExpressionMover::class.java)
} }
private fun doTest(path: String, defaultMoverClass: Class<out StatementUpDownMover>) { protected fun doTestExpressionWithTrailingComma(path: String) {
doTest(path) { isApplicableExpected, direction -> doTest(path, KotlinExpressionMover::class.java, true)
}
private fun doTest(path: String, defaultMoverClass: Class<out StatementUpDownMover>, trailingComma: Boolean = false) {
doTest(path, trailingComma) { isApplicableExpected, direction ->
val movers = Extensions.getExtensions(StatementUpDownMover.STATEMENT_UP_DOWN_MOVER_EP) val movers = Extensions.getExtensions(StatementUpDownMover.STATEMENT_UP_DOWN_MOVER_EP)
val info = StatementUpDownMover.MoveInfo() val info = StatementUpDownMover.MoveInfo()
val actualMover = movers.firstOrNull { val actualMover = movers.firstOrNull {
@@ -53,7 +58,7 @@ abstract class AbstractMoveStatementTest : AbstractCodeMoverTest() {
abstract class AbstractMoveLeftRightTest : AbstractCodeMoverTest() { abstract class AbstractMoveLeftRightTest : AbstractCodeMoverTest() {
protected fun doTest(path: String) { protected fun doTest(path: String) {
doTest(path) { _, _ -> } doTest(path) { _, _ -> }
} }
} }
@@ -69,12 +74,15 @@ abstract class AbstractCodeMoverTest : KotlinLightCodeInsightTestCase() {
super.tearDown() super.tearDown()
} }
protected fun doTest(path: String, isApplicableChecker: (isApplicableExpected: Boolean, direction: String) -> Unit) { protected fun doTest(
path: String,
trailingComma: Boolean = false,
isApplicableChecker: (isApplicableExpected: Boolean, direction: String) -> Unit
) {
configureByFile(path) configureByFile(path)
val fileText = FileUtil.loadFile(File(path), true) val fileText = FileUtil.loadFile(File(path), true)
val direction = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// MOVE: ") val direction = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// MOVE: ") ?: error("No MOVE directive found")
?: error("No MOVE directive found")
val action = when (direction) { val action = when (direction) {
"up" -> MoveStatementUpAction() "up" -> MoveStatementUpAction()
@@ -89,41 +97,38 @@ abstract class AbstractCodeMoverTest : KotlinLightCodeInsightTestCase() {
isApplicableChecker(isApplicableExpected, direction) isApplicableChecker(isApplicableExpected, direction)
invokeAndCheck(fileText, path, action, isApplicableExpected) val codeStyleSettings = CodeStyle.getSettings(editor_.project!!)
try {
val configurator = FormatSettingsUtil.createConfigurator(fileText, codeStyleSettings)
configurator.configureSettings()
if (trailingComma) codeStyleSettings.kotlinCustomSettings.ALLOW_TRAILING_COMMA = true
invokeAndCheck(path, action, isApplicableExpected)
} finally {
codeStyleSettings.clearCodeStyleSettings()
}
} }
private fun invokeAndCheck(fileText: String, path: String, action: EditorAction, isApplicableExpected: Boolean) { private fun invokeAndCheck(path: String, action: EditorAction, isApplicableExpected: Boolean) {
val editor = editor_ val editor = editor_
val project = editor.project!! val dataContext = currentEditorDataContext_
val codeStyleSettings = CodeStyle.getSettings(project) val before = editor.document.text
val configurator = FormatSettingsUtil.createConfigurator(fileText, codeStyleSettings) runWriteAction { action.actionPerformed(editor, dataContext) }
configurator.configureSettings()
try { val after = editor.document.text
val dataContext = currentEditorDataContext_ val actionDoesNothing = after == before
val before = editor.document.text TestCase.assertEquals(isApplicableExpected, !actionDoesNothing)
runWriteAction { action.actionPerformed(editor, dataContext) }
val after = editor.document.text if (isApplicableExpected) {
val actionDoesNothing = after == before val afterFilePath = "$path.after"
try {
TestCase.assertEquals(isApplicableExpected, !actionDoesNothing) checkResultByFile(afterFilePath)
} catch (e: ComparisonFailure) {
if (isApplicableExpected) { KotlinTestUtils.assertEqualsToFile(File(afterFilePath), editor)
val afterFilePath = path + ".after"
try {
checkResultByFile(afterFilePath)
}
catch (e: ComparisonFailure) {
KotlinTestUtils.assertEqualsToFile(File(afterFilePath), editor)
}
} }
} }
finally {
codeStyleSettings.clearCodeStyleSettings()
}
} }
override fun getTestDataPath() = "" override fun getTestDataPath() = ""
@@ -1,126 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.codeInsight.moveUpDown
import com.intellij.application.options.CodeStyle
import com.intellij.codeInsight.editorActions.moveLeftRight.MoveElementLeftAction
import com.intellij.codeInsight.editorActions.moveLeftRight.MoveElementRightAction
import com.intellij.codeInsight.editorActions.moveUpDown.MoveStatementDownAction
import com.intellij.codeInsight.editorActions.moveUpDown.MoveStatementUpAction
import com.intellij.codeInsight.editorActions.moveUpDown.StatementUpDownMover
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.editor.actionSystem.EditorAction
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.util.io.FileUtil
import junit.framework.ComparisonFailure
import junit.framework.TestCase
import org.jetbrains.kotlin.formatter.FormatSettingsUtil
import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinDeclarationMover
import org.jetbrains.kotlin.idea.codeInsight.upDownMover.KotlinExpressionMover
import org.jetbrains.kotlin.idea.core.script.isScriptChangesNotifierDisabled
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightTestCase
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
abstract class AbstractMoveStatementTest : AbstractCodeMoverTest() {
protected fun doTestClassBodyDeclaration(path: String) {
doTest(path, KotlinDeclarationMover::class.java)
}
protected fun doTestExpression(path: String) {
doTest(path, KotlinExpressionMover::class.java)
}
private fun doTest(path: String, defaultMoverClass: Class<out StatementUpDownMover>) {
doTest(path) { isApplicableExpected, direction ->
val movers = Extensions.getExtensions(StatementUpDownMover.STATEMENT_UP_DOWN_MOVER_EP)
val info = StatementUpDownMover.MoveInfo()
val actualMover = movers.firstOrNull {
it.checkAvailable(editor, file, info, direction == "down")
} ?: error("No mover found")
assertEquals("Unmatched movers", defaultMoverClass.name, actualMover::class.java.name)
assertEquals("Invalid applicability", isApplicableExpected, info.toMove2 != null)
}
}
}
abstract class AbstractMoveLeftRightTest : AbstractCodeMoverTest() {
protected fun doTest(path: String) {
doTest(path) { _, _ -> }
}
}
@Suppress("DEPRECATION")
abstract class AbstractCodeMoverTest : KotlinLightCodeInsightTestCase() {
override fun setUp() {
super.setUp()
ApplicationManager.getApplication().isScriptChangesNotifierDisabled = true
}
override fun tearDown() {
ApplicationManager.getApplication().isScriptChangesNotifierDisabled = false
super.tearDown()
}
protected fun doTest(path: String, isApplicableChecker: (isApplicableExpected: Boolean, direction: String) -> Unit) {
configureByFile(path)
val fileText = FileUtil.loadFile(File(path), true)
val direction = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// MOVE: ") ?: error("No MOVE directive found")
val action = when (direction) {
"up" -> MoveStatementUpAction()
"down" -> MoveStatementDownAction()
"left" -> MoveElementLeftAction()
"right" -> MoveElementRightAction()
else -> error("Unknown direction: $direction")
}
val isApplicableString = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// IS_APPLICABLE: ")
val isApplicableExpected = isApplicableString == null || isApplicableString == "true"
isApplicableChecker(isApplicableExpected, direction)
invokeAndCheck(fileText, path, action, isApplicableExpected)
}
private fun invokeAndCheck(fileText: String, path: String, action: EditorAction, isApplicableExpected: Boolean) {
val editor = editor_
val project = editor.project!!
val codeStyleSettings = CodeStyle.getSettings(project)
val configurator = FormatSettingsUtil.createConfigurator(fileText, codeStyleSettings)
configurator.configureSettings()
try {
val dataContext = currentEditorDataContext_
val before = editor.document.text
runWriteAction { action.actionPerformed(editor, dataContext) }
val after = editor.document.text
val actionDoesNothing = after == before
TestCase.assertEquals(isApplicableExpected, !actionDoesNothing)
if (isApplicableExpected) {
val afterFilePath = "$path.after"
try {
checkResultByFile(afterFilePath)
} catch (e: ComparisonFailure) {
KotlinTestUtils.assertEqualsToFile(File(afterFilePath), editor)
}
}
} finally {
codeStyleSettings.clearCodeStyleSettings()
}
}
override fun getTestDataPath() = ""
}
@@ -1366,4 +1366,137 @@ public class MoveStatementTestGenerated extends AbstractMoveStatementTest {
runTest("idea/testData/codeInsight/moveUpDown/parametersAndArguments/funParams8.kt"); runTest("idea/testData/codeInsight/moveUpDown/parametersAndArguments/funParams8.kt");
} }
} }
@TestMetadata("idea/testData/codeInsight/moveUpDown/trailingComma")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TrailingComma extends AbstractMoveStatementTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTestExpressionWithTrailingComma, this, testDataFilePath);
}
public void testAllFilesPresentInTrailingComma() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/codeInsight/moveUpDown/trailingComma"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("callArgs1.kt")
public void testCallArgs1() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/callArgs1.kt");
}
@TestMetadata("callArgs2.kt")
public void testCallArgs2() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/callArgs2.kt");
}
@TestMetadata("callArgs3.kt")
public void testCallArgs3() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/callArgs3.kt");
}
@TestMetadata("callArgs4.kt")
public void testCallArgs4() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/callArgs4.kt");
}
@TestMetadata("callArgs5.kt")
public void testCallArgs5() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/callArgs5.kt");
}
@TestMetadata("callArgs6.kt")
public void testCallArgs6() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/callArgs6.kt");
}
@TestMetadata("callArgs7.kt")
public void testCallArgs7() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/callArgs7.kt");
}
@TestMetadata("callArgs8.kt")
public void testCallArgs8() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/callArgs8.kt");
}
@TestMetadata("classParams1.kt")
public void testClassParams1() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/classParams1.kt");
}
@TestMetadata("classParams2.kt")
public void testClassParams2() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/classParams2.kt");
}
@TestMetadata("classParams3.kt")
public void testClassParams3() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/classParams3.kt");
}
@TestMetadata("classParams4.kt")
public void testClassParams4() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/classParams4.kt");
}
@TestMetadata("classParams5.kt")
public void testClassParams5() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/classParams5.kt");
}
@TestMetadata("classParams6.kt")
public void testClassParams6() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/classParams6.kt");
}
@TestMetadata("classParams7.kt")
public void testClassParams7() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/classParams7.kt");
}
@TestMetadata("classParams8.kt")
public void testClassParams8() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/classParams8.kt");
}
@TestMetadata("funParams1.kt")
public void testFunParams1() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/funParams1.kt");
}
@TestMetadata("funParams2.kt")
public void testFunParams2() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/funParams2.kt");
}
@TestMetadata("funParams3.kt")
public void testFunParams3() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/funParams3.kt");
}
@TestMetadata("funParams4.kt")
public void testFunParams4() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/funParams4.kt");
}
@TestMetadata("funParams5.kt")
public void testFunParams5() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/funParams5.kt");
}
@TestMetadata("funParams6.kt")
public void testFunParams6() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/funParams6.kt");
}
@TestMetadata("funParams7.kt")
public void testFunParams7() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/funParams7.kt");
}
@TestMetadata("funParams8.kt")
public void testFunParams8() throws Exception {
runTest("idea/testData/codeInsight/moveUpDown/trailingComma/funParams8.kt");
}
}
} }