diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml index 752959e569a..bc772b6624a 100644 --- a/idea/resources/META-INF/plugin-common.xml +++ b/idea/resources/META-INF/plugin-common.xml @@ -1381,6 +1381,11 @@ Kotlin + + org.jetbrains.kotlin.idea.intentions.ConvertSnakeCaseTestFunctionToSpacedIntention + Kotlin + + org.jetbrains.kotlin.idea.intentions.ReplaceSingleLineLetIntention Kotlin diff --git a/idea/resources/intentionDescriptions/ConvertSnakeCaseTestFunctionToSpacedIntention/after.kt.template b/idea/resources/intentionDescriptions/ConvertSnakeCaseTestFunctionToSpacedIntention/after.kt.template new file mode 100644 index 00000000000..306191852a9 --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertSnakeCaseTestFunctionToSpacedIntention/after.kt.template @@ -0,0 +1,5 @@ +class MyTest { + @Test fun `test two plus two equals four`() { + + } +} diff --git a/idea/resources/intentionDescriptions/ConvertSnakeCaseTestFunctionToSpacedIntention/before.kt.template b/idea/resources/intentionDescriptions/ConvertSnakeCaseTestFunctionToSpacedIntention/before.kt.template new file mode 100644 index 00000000000..d21da9a8ff5 --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertSnakeCaseTestFunctionToSpacedIntention/before.kt.template @@ -0,0 +1,5 @@ +class MyTest { + @Test fun test_two_plus_two_equals_four() { + + } +} diff --git a/idea/resources/intentionDescriptions/ConvertSnakeCaseTestFunctionToSpacedIntention/description.html b/idea/resources/intentionDescriptions/ConvertSnakeCaseTestFunctionToSpacedIntention/description.html new file mode 100644 index 00000000000..4b912cd5300 --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertSnakeCaseTestFunctionToSpacedIntention/description.html @@ -0,0 +1,5 @@ + + +This intention changes a snake case name of the given test function to a space-separated one. + + \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertCamelCaseTestFunctionToSpacedIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertTestFunctionToSpacedIntention.kt similarity index 62% rename from idea/src/org/jetbrains/kotlin/idea/intentions/ConvertCamelCaseTestFunctionToSpacedIntention.kt rename to idea/src/org/jetbrains/kotlin/idea/intentions/ConvertTestFunctionToSpacedIntention.kt index bfdb3041252..2ca87f1ef6a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertCamelCaseTestFunctionToSpacedIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertTestFunctionToSpacedIntention.kt @@ -37,16 +37,29 @@ import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart import org.jetbrains.kotlin.utils.SmartList -class ConvertCamelCaseTestFunctionToSpacedIntention : SelfTargetingRangeIntention( - KtNamedFunction::class.java, "Replace camel-case name with spaces" +sealed class ConvertTestFunctionToSpacedIntention(case: String) : SelfTargetingRangeIntention( + KtNamedFunction::class.java, "Replace $case name with spaces" ) { + companion object { + private val SNAKE_CASE_REGEX = ".+_.+".toRegex() + } + + abstract fun split(name: String): List + + abstract fun isApplicableName(name: String): Boolean + + protected fun isSnakeCase(name: String): Boolean { + return name.contains(SNAKE_CASE_REGEX) + } + override fun applicabilityRange(element: KtNamedFunction): TextRange? { val platform = element.platform if (platform is CommonPlatform || platform is JsPlatform) return null val range = element.nameIdentifier?.textRange ?: return null val name = element.name ?: return null - val newName = decamelize(name) + if (!isApplicableName(name)) return null + val newName = convert(name) if (newName == name.quoteIfNeeded()) return null val lightMethod = element.toLightMethods().firstOrNull() ?: return null @@ -57,11 +70,67 @@ class ConvertCamelCaseTestFunctionToSpacedIntention : SelfTargetingRangeIntentio return range } + private fun convert(name: String) = split(name).joinToString(separator = " ") { it.decapitalizeSmart().trim() }.quoteIfNeeded() + + private fun startRename(element: KtNamedFunction, newName: String) { + RenameProcessor(element.project, element, newName, false, false).run() + } + + override fun startInWriteAction() = false + + override fun applyTo(element: KtNamedFunction, editor: Editor?) { + val nameIdentifier = element.nameIdentifier ?: return + val oldName = element.name ?: return + val oldId = oldName.quoteIfNeeded() + val newId = convert(oldName) + + if (editor != null) { + val builder = TemplateBuilderImpl(nameIdentifier) + builder.replaceElement(nameIdentifier, newId) + val template = runWriteAction { builder.buildInlineTemplate() } + TemplateManager.getInstance(element.project).startTemplate( + editor, + template, + object : TemplateEditingAdapter() { + private var chosenId: String = newId + private var range: TextRange? = null + + override fun beforeTemplateFinished(state: TemplateState, template: Template?) { + val varName = (template as? TemplateImpl)?.getVariableNameAt(0) ?: return + chosenId = state.getVariableValue(varName)?.text?.quoteIfNeeded() ?: return + range = state.getVariableRange(varName) + } + + override fun templateFinished(template: Template, brokenOff: Boolean) { + range?.let { + val doc = editor.document + runWriteAction { doc.replaceString(it.startOffset, it.endOffset, oldId) } + PsiDocumentManager.getInstance(element.project).commitDocument(doc) + } + + if (!brokenOff && chosenId != oldId) { + startRename(element, chosenId) + } + } + } + ) + } else { + startRename(element, newId) + } + } +} + + +class ConvertCamelCaseTestFunctionToSpacedIntention : ConvertTestFunctionToSpacedIntention("camel-case") { + override fun isApplicableName(name: String): Boolean { + return !isSnakeCase(name) + } + enum class Case { LOWER, UPPER, OTHER } - private fun splitCamelName(name: String): List { + override fun split(name: String): List { if (name === "") return emptyList() val result = SmartList() @@ -88,54 +157,14 @@ class ConvertCamelCaseTestFunctionToSpacedIntention : SelfTargetingRangeIntentio return result } +} - private fun decamelize(name: String) = splitCamelName(name).joinToString(separator = " ") { it.decapitalizeSmart().trim() }.quoteIfNeeded() - - private fun startRename(element: KtNamedFunction, newName: String) { - RenameProcessor(element.project, element, newName, false, false).run() +class ConvertSnakeCaseTestFunctionToSpacedIntention : ConvertTestFunctionToSpacedIntention("snake_case") { + override fun isApplicableName(name: String): Boolean { + return isSnakeCase(name) } - override fun startInWriteAction() = false - - override fun applyTo(element: KtNamedFunction, editor: Editor?) { - val nameIdentifier = element.nameIdentifier ?: return - val oldName = element.name ?: return - val oldId = oldName.quoteIfNeeded() - val newId = decamelize(oldName) - - if (editor != null) { - val builder = TemplateBuilderImpl(nameIdentifier) - builder.replaceElement(nameIdentifier, newId) - val template = runWriteAction { builder.buildInlineTemplate() } - TemplateManager.getInstance(element.project).startTemplate( - editor, - template, - object : TemplateEditingAdapter() { - private var chosenId: String = newId - private var range: TextRange? = null - - override fun beforeTemplateFinished(state: TemplateState, template: Template?) { - val varName = (template as? TemplateImpl)?.getVariableNameAt(0) ?: return - chosenId = state?.getVariableValue(varName)?.text?.quoteIfNeeded() ?: return - range = state.getVariableRange(varName) - } - - override fun templateFinished(template: Template, brokenOff: Boolean) { - range?.let { - val doc = editor.document - runWriteAction { doc.replaceString(it.startOffset, it.endOffset, oldId) } - PsiDocumentManager.getInstance(element.project).commitDocument(doc) - } - - if (!brokenOff && chosenId != oldId) { - startRename(element, chosenId) - } - } - } - ) - } - else { - startRename(element, newId) - } + override fun split(name: String): List { + return name.split("_").filter { it.isNotBlank() } } } \ No newline at end of file diff --git a/idea/testData/intentions/convertCamelCaseTestFunctionToSpaced/snake.kt b/idea/testData/intentions/convertCamelCaseTestFunctionToSpaced/snake.kt new file mode 100644 index 00000000000..0f1e16b57dd --- /dev/null +++ b/idea/testData/intentions/convertCamelCaseTestFunctionToSpaced/snake.kt @@ -0,0 +1,12 @@ +// CONFIGURE_LIBRARY: JUnit@lib/junit-4.12.jar +// IS_APPLICABLE: false + +import org.junit.Test + +class A { + @Test fun test_two_plus_two_equals_four() {} +} + +fun test() { + A().test_two_plus_two_equals_four() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/.intention b/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/.intention new file mode 100644 index 00000000000..ed522d9135b --- /dev/null +++ b/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.ConvertSnakeCaseTestFunctionToSpacedIntention diff --git a/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/camel.kt b/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/camel.kt new file mode 100644 index 00000000000..dda9357766d --- /dev/null +++ b/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/camel.kt @@ -0,0 +1,8 @@ +// CONFIGURE_LIBRARY: JUnit@lib/junit-4.12.jar +// IS_APPLICABLE: false + +import org.junit.Test + +class A { + @Test fun testTwoPlusTwoEqualsFour() {} +} \ No newline at end of file diff --git a/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/snake.kt b/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/snake.kt new file mode 100644 index 00000000000..a9e3ef79d29 --- /dev/null +++ b/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/snake.kt @@ -0,0 +1,10 @@ +// CONFIGURE_LIBRARY: JUnit@lib/junit-4.12.jar +import org.junit.Test + +class A { + @Test fun test_two_plus_two_equals_four() {} +} + +fun test() { + A().test_two_plus_two_equals_four() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/snake.kt.after b/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/snake.kt.after new file mode 100644 index 00000000000..bf442c2cb5b --- /dev/null +++ b/idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/snake.kt.after @@ -0,0 +1,10 @@ +// CONFIGURE_LIBRARY: JUnit@lib/junit-4.12.jar +import org.junit.Test + +class A { + @Test fun `test two plus two equals four`() {} +} + +fun test() { + A().`test two plus two equals four`() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 086e019311e..febfb26c42f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -4804,6 +4804,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest { runTest("idea/testData/intentions/convertCamelCaseTestFunctionToSpaced/notTestFunction.kt"); } + @TestMetadata("snake.kt") + public void testSnake() throws Exception { + runTest("idea/testData/intentions/convertCamelCaseTestFunctionToSpaced/snake.kt"); + } + @TestMetadata("unchanged.kt") public void testUnchanged() throws Exception { runTest("idea/testData/intentions/convertCamelCaseTestFunctionToSpaced/unchanged.kt"); @@ -7014,6 +7019,29 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } } + @TestMetadata("idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ConvertSnakeCaseTestFunctionToSpaced extends AbstractIntentionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInConvertSnakeCaseTestFunctionToSpaced() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true); + } + + @TestMetadata("camel.kt") + public void testCamel() throws Exception { + runTest("idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/camel.kt"); + } + + @TestMetadata("snake.kt") + public void testSnake() throws Exception { + runTest("idea/testData/intentions/convertSnakeCaseTestFunctionToSpaced/snake.kt"); + } + } + @TestMetadata("idea/testData/intentions/convertToAlso") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)