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/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression")
model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/trailingComma", testMethod = "doTestExpressionWithTrailingComma")
}
testClass<AbstractMoveLeftRightTest> {
@@ -439,6 +439,7 @@ fun main(args: Array<String>) {
model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression")
model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/trailingComma", testMethod = "doTestExpressionWithTrailingComma")
}
testClass<AbstractMoveLeftRightTest> {
@@ -439,6 +439,7 @@ fun main(args: Array<String>) {
model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression")
model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/trailingComma", testMethod = "doTestExpressionWithTrailingComma")
}
testClass<AbstractMoveLeftRightTest> {
@@ -439,6 +439,7 @@ fun main(args: Array<String>) {
model("codeInsight/moveUpDown/closingBraces", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/expressions", pattern = KT_OR_KTS, testMethod = "doTestExpression")
model("codeInsight/moveUpDown/parametersAndArguments", testMethod = "doTestExpression")
model("codeInsight/moveUpDown/trailingComma", testMethod = "doTestExpressionWithTrailingComma")
}
testClass<AbstractMoveLeftRightTest> {
@@ -4,16 +4,19 @@
*/
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.StatementUpDownMover
import com.intellij.openapi.editor.Editor
import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil
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.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.function.Predicate
class KotlinExpressionMover : AbstractKotlinUpDownMover() {
@@ -117,9 +120,14 @@ class KotlinExpressionMover : AbstractKotlinUpDownMover() {
val (first, second) = parametersOrArgsToMove ?: return
val lastElementOnFirstLine = getLastSiblingOfSameTypeInLine(first, 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(lastElementOnSecondLine, !down && isLastOfItsKind(lastElementOnFirstLine, true))
fixCommaIfNeeded(lastElementOnFirstLine, down && isLastOfItsKind(lastElementOnSecondLine, true), withTrailingComma)
fixCommaIfNeeded(lastElementOnSecondLine, !down && isLastOfItsKind(lastElementOnFirstLine, true),withTrailingComma)
editor.project?.let { PsiDocumentManager.getInstance(it).doPostponedOperationsAndUnblockDocument(editor.document) }
}
}
@@ -476,15 +484,15 @@ class KotlinExpressionMover : AbstractKotlinUpDownMover() {
predicate = MOVABLE_ELEMENT_CONSTRAINT
) ?: return null
if (isBracelessBlock(movableElement)) {
return StatementUpDownMover.firstNonWhiteElement(
return if (isBracelessBlock(movableElement)) {
StatementUpDownMover.firstNonWhiteElement(
if (lookRight)
movableElement.lastChild
else
movableElement.firstChild, !lookRight
)
} 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 fixCommaIfNeeded(element: PsiElement, willBeLast: Boolean) {
private fun fixCommaIfNeeded(element: PsiElement, willBeLast: Boolean, withTrailingComma: Boolean) {
val comma = getComma(element)
if (willBeLast && comma != null) {
if (willBeLast && comma != null && !withTrailingComma) {
comma.delete()
} else if (!willBeLast && comma == null) {
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.
*/
@@ -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.KotlinExpressionMover
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.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
@@ -36,8 +37,12 @@ abstract class AbstractMoveStatementTest : AbstractCodeMoverTest() {
doTest(path, KotlinExpressionMover::class.java)
}
private fun doTest(path: String, defaultMoverClass: Class<out StatementUpDownMover>) {
doTest(path) { isApplicableExpected, direction ->
protected fun doTestExpressionWithTrailingComma(path: String) {
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 info = StatementUpDownMover.MoveInfo()
val actualMover = movers.firstOrNull {
@@ -68,7 +73,11 @@ abstract class AbstractCodeMoverTest : KotlinLightCodeInsightTestCase() {
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)
val fileText = FileUtil.loadFile(File(path), true)
@@ -87,40 +96,39 @@ abstract class AbstractCodeMoverTest : KotlinLightCodeInsightTestCase() {
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 configurator = FormatSettingsUtil.createConfigurator(fileText, codeStyleSettings)
configurator.configureSettings()
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)
}
}
if (trailingComma) codeStyleSettings.kotlinCustomSettings.ALLOW_TRAILING_COMMA = true
invokeAndCheck(path, action, isApplicableExpected)
} finally {
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() = ""
}
@@ -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.
*/
@@ -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.KotlinExpressionMover
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.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
@@ -37,8 +38,12 @@ abstract class AbstractMoveStatementTest : AbstractCodeMoverTest() {
doTest(path, KotlinExpressionMover::class.java)
}
private fun doTest(path: String, defaultMoverClass: Class<out StatementUpDownMover>) {
doTest(path) { isApplicableExpected, direction ->
protected fun doTestExpressionWithTrailingComma(path: String) {
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 info = StatementUpDownMover.MoveInfo()
val actualMover = movers.firstOrNull {
@@ -53,7 +58,7 @@ abstract class AbstractMoveStatementTest : AbstractCodeMoverTest() {
abstract class AbstractMoveLeftRightTest : AbstractCodeMoverTest() {
protected fun doTest(path: String) {
doTest(path) { _, _ -> }
doTest(path) { _, _ -> }
}
}
@@ -69,12 +74,15 @@ abstract class AbstractCodeMoverTest : KotlinLightCodeInsightTestCase() {
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)
val fileText = FileUtil.loadFile(File(path), true)
val direction = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// MOVE: ")
?: error("No MOVE directive found")
val direction = InTextDirectivesUtils.findStringWithPrefixes(fileText, "// MOVE: ") ?: error("No MOVE directive found")
val action = when (direction) {
"up" -> MoveStatementUpAction()
@@ -89,41 +97,38 @@ abstract class AbstractCodeMoverTest : KotlinLightCodeInsightTestCase() {
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 project = editor.project!!
val dataContext = currentEditorDataContext_
val codeStyleSettings = CodeStyle.getSettings(project)
val configurator = FormatSettingsUtil.createConfigurator(fileText, codeStyleSettings)
configurator.configureSettings()
val before = editor.document.text
runWriteAction { action.actionPerformed(editor, dataContext) }
try {
val dataContext = currentEditorDataContext_
val after = editor.document.text
val actionDoesNothing = after == before
val before = editor.document.text
runWriteAction { action.actionPerformed(editor, dataContext) }
TestCase.assertEquals(isApplicableExpected, !actionDoesNothing)
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)
}
if (isApplicableExpected) {
val afterFilePath = "$path.after"
try {
checkResultByFile(afterFilePath)
} catch (e: ComparisonFailure) {
KotlinTestUtils.assertEqualsToFile(File(afterFilePath), editor)
}
}
finally {
codeStyleSettings.clearCodeStyleSettings()
}
}
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");
}
}
@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");
}
}
}