From 8d425a6f945c71a49625f771883165717c2ea56d Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Fri, 17 Feb 2017 17:09:41 +0100 Subject: [PATCH] Add intention to add missing components to destructuring assignment #KT-16258 Fixed --- .../after.kt.template | 5 ++ .../before.kt.template | 5 ++ .../description.html | 5 ++ idea/src/META-INF/plugin.xml | 5 ++ .../AddMissingDestructuringIntention.kt | 67 +++++++++++++++++++ .../addMissingDestructuring/.intention | 1 + .../addMissingDestructuring/notAvailable.kt | 6 ++ .../addMissingDestructuring/sameName.kt | 5 ++ .../addMissingDestructuring/sameName.kt.after | 5 ++ .../addMissingDestructuring/simple.kt | 5 ++ .../addMissingDestructuring/simple.kt.after | 5 ++ .../intentions/addMissingDestructuring/var.kt | 5 ++ .../addMissingDestructuring/var.kt.after | 5 ++ .../intentions/IntentionTestGenerated.java | 33 +++++++++ 14 files changed, 157 insertions(+) create mode 100644 idea/resources/intentionDescriptions/AddMissingDestructuringIntention/after.kt.template create mode 100644 idea/resources/intentionDescriptions/AddMissingDestructuringIntention/before.kt.template create mode 100644 idea/resources/intentionDescriptions/AddMissingDestructuringIntention/description.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/intentions/AddMissingDestructuringIntention.kt create mode 100644 idea/testData/intentions/addMissingDestructuring/.intention create mode 100644 idea/testData/intentions/addMissingDestructuring/notAvailable.kt create mode 100644 idea/testData/intentions/addMissingDestructuring/sameName.kt create mode 100644 idea/testData/intentions/addMissingDestructuring/sameName.kt.after create mode 100644 idea/testData/intentions/addMissingDestructuring/simple.kt create mode 100644 idea/testData/intentions/addMissingDestructuring/simple.kt.after create mode 100644 idea/testData/intentions/addMissingDestructuring/var.kt create mode 100644 idea/testData/intentions/addMissingDestructuring/var.kt.after diff --git a/idea/resources/intentionDescriptions/AddMissingDestructuringIntention/after.kt.template b/idea/resources/intentionDescriptions/AddMissingDestructuringIntention/after.kt.template new file mode 100644 index 00000000000..204af264eff --- /dev/null +++ b/idea/resources/intentionDescriptions/AddMissingDestructuringIntention/after.kt.template @@ -0,0 +1,5 @@ +data class Foo(val a: String, val b: String, val c: String) + +fun bar(f: Foo) { + val (a, b, c) = f +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/AddMissingDestructuringIntention/before.kt.template b/idea/resources/intentionDescriptions/AddMissingDestructuringIntention/before.kt.template new file mode 100644 index 00000000000..54ef02e07dd --- /dev/null +++ b/idea/resources/intentionDescriptions/AddMissingDestructuringIntention/before.kt.template @@ -0,0 +1,5 @@ +data class Foo(val a: String, val b: String, val c: String) + +fun bar(f: Foo) { + val (a, b) = f +} diff --git a/idea/resources/intentionDescriptions/AddMissingDestructuringIntention/description.html b/idea/resources/intentionDescriptions/AddMissingDestructuringIntention/description.html new file mode 100644 index 00000000000..5daaaaff005 --- /dev/null +++ b/idea/resources/intentionDescriptions/AddMissingDestructuringIntention/description.html @@ -0,0 +1,5 @@ + + +This intention adds missing components in a destructuring declaration. + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 6bc213d46ac..a86729baee0 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -1507,6 +1507,11 @@ Kotlin + + org.jetbrains.kotlin.idea.intentions.AddMissingDestructuringIntention + Kotlin + + (KtDestructuringDeclaration::class.java, "Add missing component") { + override fun isApplicableTo(element: KtDestructuringDeclaration, caretOffset: Int): Boolean { + val entriesCount = element.entries.size + + val classDescriptor = element.classDescriptor() ?: return false + if (!classDescriptor.isData) return false + + val primaryParameters = classDescriptor.primaryParameters() ?: return false + return primaryParameters.size > entriesCount + } + + override fun applyTo(element: KtDestructuringDeclaration, editor: Editor?) { + val entries = element.entries + val primaryParameters = element.classDescriptor()?.primaryParameters() ?: return + + val factory = KtPsiFactory(element) + val nameValidator = CollectingNameValidator( + filter = NewDeclarationNameValidator(element.parent.parent, null, NewDeclarationNameValidator.Target.VARIABLES) + ) + + val newEntries = entries.joinToString(postfix = ", ") { it.text } + + primaryParameters.drop(entries.size).joinToString { + KotlinNameSuggester.suggestNameByName(it.name.asString(), nameValidator) + } + val initializer = element.initializer ?: return + + val newDestructuringDeclaration = factory.createDestructuringDeclarationByPattern( + if (element.isVar) "var ($0) = $1" else "val ($0) = $1", + newEntries, initializer) + element.replace(newDestructuringDeclaration) + } + + private fun KtDestructuringDeclaration.classDescriptor(): ClassDescriptor? { + val type = initializer?.let { it.analyze().getType(it) } ?: return null + return type.constructor.declarationDescriptor as? ClassDescriptor ?: return null + } + + private fun ClassDescriptor.primaryParameters() = constructors.firstOrNull { it.isPrimary }?.valueParameters +} \ No newline at end of file diff --git a/idea/testData/intentions/addMissingDestructuring/.intention b/idea/testData/intentions/addMissingDestructuring/.intention new file mode 100644 index 00000000000..e389eaed098 --- /dev/null +++ b/idea/testData/intentions/addMissingDestructuring/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.AddMissingDestructuringIntention diff --git a/idea/testData/intentions/addMissingDestructuring/notAvailable.kt b/idea/testData/intentions/addMissingDestructuring/notAvailable.kt new file mode 100644 index 00000000000..f3ea71f9c8d --- /dev/null +++ b/idea/testData/intentions/addMissingDestructuring/notAvailable.kt @@ -0,0 +1,6 @@ +// IS_APPLICABLE: false +data class Foo(val a: String, val b: String, val c: String) + +fun bar(f: Foo) { + val (a, b, c) = f +} diff --git a/idea/testData/intentions/addMissingDestructuring/sameName.kt b/idea/testData/intentions/addMissingDestructuring/sameName.kt new file mode 100644 index 00000000000..f4358be18be --- /dev/null +++ b/idea/testData/intentions/addMissingDestructuring/sameName.kt @@ -0,0 +1,5 @@ +data class Foo(val a: String, val b: String, val c: String) + +fun bar(f: Foo) { + val (a, c) = f +} diff --git a/idea/testData/intentions/addMissingDestructuring/sameName.kt.after b/idea/testData/intentions/addMissingDestructuring/sameName.kt.after new file mode 100644 index 00000000000..cbca3b82cc9 --- /dev/null +++ b/idea/testData/intentions/addMissingDestructuring/sameName.kt.after @@ -0,0 +1,5 @@ +data class Foo(val a: String, val b: String, val c: String) + +fun bar(f: Foo) { + val (a, c, c1) = f +} diff --git a/idea/testData/intentions/addMissingDestructuring/simple.kt b/idea/testData/intentions/addMissingDestructuring/simple.kt new file mode 100644 index 00000000000..9fbe4a5f0a1 --- /dev/null +++ b/idea/testData/intentions/addMissingDestructuring/simple.kt @@ -0,0 +1,5 @@ +data class Foo(val a: String, val b: String, val c: String) + +fun bar(f: Foo) { + val (a, b) = f +} diff --git a/idea/testData/intentions/addMissingDestructuring/simple.kt.after b/idea/testData/intentions/addMissingDestructuring/simple.kt.after new file mode 100644 index 00000000000..88a69c77a68 --- /dev/null +++ b/idea/testData/intentions/addMissingDestructuring/simple.kt.after @@ -0,0 +1,5 @@ +data class Foo(val a: String, val b: String, val c: String) + +fun bar(f: Foo) { + val (a, b, c) = f +} diff --git a/idea/testData/intentions/addMissingDestructuring/var.kt b/idea/testData/intentions/addMissingDestructuring/var.kt new file mode 100644 index 00000000000..1e13a6f65b1 --- /dev/null +++ b/idea/testData/intentions/addMissingDestructuring/var.kt @@ -0,0 +1,5 @@ +data class Foo(val a: String, val b: String, val c: String) + +fun bar(f: Foo) { + var (a, b) = f +} diff --git a/idea/testData/intentions/addMissingDestructuring/var.kt.after b/idea/testData/intentions/addMissingDestructuring/var.kt.after new file mode 100644 index 00000000000..2a343387b09 --- /dev/null +++ b/idea/testData/intentions/addMissingDestructuring/var.kt.after @@ -0,0 +1,5 @@ +data class Foo(val a: String, val b: String, val c: String) + +fun bar(f: Foo) { + var (a, b, c) = f +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 29bc234162a..6f56077b1ae 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -288,6 +288,39 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } } + @TestMetadata("idea/testData/intentions/addMissingDestructuring") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddMissingDestructuring extends AbstractIntentionTest { + public void testAllFilesPresentInAddMissingDestructuring() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/addMissingDestructuring"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("notAvailable.kt") + public void testNotAvailable() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addMissingDestructuring/notAvailable.kt"); + doTest(fileName); + } + + @TestMetadata("sameName.kt") + public void testSameName() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addMissingDestructuring/sameName.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addMissingDestructuring/simple.kt"); + doTest(fileName); + } + + @TestMetadata("var.kt") + public void testVar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addMissingDestructuring/var.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/intentions/addNameToArgument") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)