From 6978d842fbeae8d5585cff087fb6aec1a93598d3 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Wed, 23 Dec 2015 15:03:19 +0300 Subject: [PATCH] Intentions: Implement 'Add val/var to primary constructor parameter' intention #KT-4038 In Progress --- .../after.kt.template | 1 + .../before.kt.template | 1 + .../description.html | 5 ++ idea/src/META-INF/plugin.xml | 5 ++ ...ddValVarToConstructorParameterIntention.kt | 56 +++++++++++++++++++ .../callableBuilder/templateExpressions.kt | 10 ---- .../idea/refactoring/ValVarExpression.kt | 34 +++++++++++ .../intentions/addValOrVar/.intention | 1 + .../testData/intentions/addValOrVar/addVal.kt | 3 + .../intentions/addValOrVar/addVal.kt.after | 3 + .../intentions/addValOrVar/funParameter.kt | 4 ++ .../testData/intentions/addValOrVar/hasVal.kt | 4 ++ .../testData/intentions/addValOrVar/hasVar.kt | 4 ++ .../intentions/addValOrVar/outOfRange.kt | 4 ++ .../secondaryConstructorParameter.kt | 4 ++ .../intentions/IntentionTestGenerated.java | 45 +++++++++++++++ 16 files changed, 174 insertions(+), 10 deletions(-) create mode 100644 idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/after.kt.template create mode 100644 idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/before.kt.template create mode 100644 idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/description.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/intentions/AddValVarToConstructorParameterIntention.kt create mode 100644 idea/src/org/jetbrains/kotlin/idea/refactoring/ValVarExpression.kt create mode 100644 idea/testData/intentions/addValOrVar/.intention create mode 100644 idea/testData/intentions/addValOrVar/addVal.kt create mode 100644 idea/testData/intentions/addValOrVar/addVal.kt.after create mode 100644 idea/testData/intentions/addValOrVar/funParameter.kt create mode 100644 idea/testData/intentions/addValOrVar/hasVal.kt create mode 100644 idea/testData/intentions/addValOrVar/hasVar.kt create mode 100644 idea/testData/intentions/addValOrVar/outOfRange.kt create mode 100644 idea/testData/intentions/addValOrVar/secondaryConstructorParameter.kt diff --git a/idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/after.kt.template b/idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/after.kt.template new file mode 100644 index 00000000000..3d79bccf651 --- /dev/null +++ b/idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/after.kt.template @@ -0,0 +1 @@ +class Foo(n: Int, val s: String) diff --git a/idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/before.kt.template b/idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/before.kt.template new file mode 100644 index 00000000000..35b4b19e713 --- /dev/null +++ b/idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/before.kt.template @@ -0,0 +1 @@ +class Foo(n: Int, s: String) diff --git a/idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/description.html b/idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/description.html new file mode 100644 index 00000000000..b2c8931c243 --- /dev/null +++ b/idea/resources/intentionDescriptions/AddValVarToConstructorParameterIntention/description.html @@ -0,0 +1,5 @@ + + +This intention adds val/var keyword to the primary constructor parameter effectively making it a property. + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index f4a68f12db9..581fbf9950e 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -1115,6 +1115,11 @@ Kotlin + + org.jetbrains.kotlin.idea.intentions.AddValVarToConstructorParameterIntention + Kotlin + + (KtParameter::class.java, + "Add val/var to primary constructor parameter") { + override fun applicabilityRange(element: KtParameter): TextRange? { + if (element.valOrVarKeyword != null) return null + if ((element.parent as? KtParameterList)?.parent !is KtPrimaryConstructor) return null + text = "Add val/var to parameter '${element.name ?: ""}'" + return element.nameIdentifier?.textRange + } + + override fun applyTo(element: KtParameter, editor: Editor) { + val project = element.project + + element.addAfter(KtPsiFactory(project).createValKeyword(), null) + + val parameter = element.createSmartPointer().let { + PsiDocumentManager.getInstance(project).commitAllDocuments() + PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document) + it.element + } ?: return + + TemplateBuilderImpl(parameter) + .apply { replaceElement(parameter.valOrVarKeyword!!, ValVarExpression) } + .buildInlineTemplate() + .let { TemplateManager.getInstance(project).startTemplate(editor, it) } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/templateExpressions.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/templateExpressions.kt index d25f64563c7..ecc938aca16 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/templateExpressions.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/templateExpressions.kt @@ -184,13 +184,3 @@ internal class TypeParameterListExpression(private val mandatoryTypeParameters: // do not offer the user any choices override fun calculateLookupItems(context: ExpressionContext?) = arrayOf() } - -internal object ValVarExpression: Expression() { - private val cachedLookupElements = listOf("val", "var").map { LookupElementBuilder.create(it) }.toTypedArray() - - override fun calculateResult(context: ExpressionContext?): Result? = TextResult("val") - - override fun calculateQuickResult(context: ExpressionContext?): Result? = calculateResult(context) - - override fun calculateLookupItems(context: ExpressionContext?): Array? = cachedLookupElements -} diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/ValVarExpression.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/ValVarExpression.kt new file mode 100644 index 00000000000..c75bc92512b --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/ValVarExpression.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.refactoring + +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.codeInsight.template.Expression +import com.intellij.codeInsight.template.ExpressionContext +import com.intellij.codeInsight.template.Result +import com.intellij.codeInsight.template.TextResult + +object ValVarExpression: Expression() { + private val cachedLookupElements = listOf("val", "var").map { LookupElementBuilder.create(it) }.toTypedArray() + + override fun calculateResult(context: ExpressionContext?): Result? = TextResult("val") + + override fun calculateQuickResult(context: ExpressionContext?): Result? = calculateResult(context) + + override fun calculateLookupItems(context: ExpressionContext?): Array? = cachedLookupElements +} \ No newline at end of file diff --git a/idea/testData/intentions/addValOrVar/.intention b/idea/testData/intentions/addValOrVar/.intention new file mode 100644 index 00000000000..6c3841003d3 --- /dev/null +++ b/idea/testData/intentions/addValOrVar/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.AddValVarToConstructorParameterIntention \ No newline at end of file diff --git a/idea/testData/intentions/addValOrVar/addVal.kt b/idea/testData/intentions/addValOrVar/addVal.kt new file mode 100644 index 00000000000..9564cb999da --- /dev/null +++ b/idea/testData/intentions/addValOrVar/addVal.kt @@ -0,0 +1,3 @@ +class Foo(x: Int, y: Int) { + +} \ No newline at end of file diff --git a/idea/testData/intentions/addValOrVar/addVal.kt.after b/idea/testData/intentions/addValOrVar/addVal.kt.after new file mode 100644 index 00000000000..693e712d9ee --- /dev/null +++ b/idea/testData/intentions/addValOrVar/addVal.kt.after @@ -0,0 +1,3 @@ +class Foo(val x: Int, y: Int) { + +} \ No newline at end of file diff --git a/idea/testData/intentions/addValOrVar/funParameter.kt b/idea/testData/intentions/addValOrVar/funParameter.kt new file mode 100644 index 00000000000..7df2d98fa7d --- /dev/null +++ b/idea/testData/intentions/addValOrVar/funParameter.kt @@ -0,0 +1,4 @@ +// IS_APPLICABLE: false +fun foo(x: Int, y: Int) { + +} \ No newline at end of file diff --git a/idea/testData/intentions/addValOrVar/hasVal.kt b/idea/testData/intentions/addValOrVar/hasVal.kt new file mode 100644 index 00000000000..c6053b0afc0 --- /dev/null +++ b/idea/testData/intentions/addValOrVar/hasVal.kt @@ -0,0 +1,4 @@ +// IS_APPLICABLE: false +class Foo(val x: Int, y: Int) { + +} \ No newline at end of file diff --git a/idea/testData/intentions/addValOrVar/hasVar.kt b/idea/testData/intentions/addValOrVar/hasVar.kt new file mode 100644 index 00000000000..8505d727e87 --- /dev/null +++ b/idea/testData/intentions/addValOrVar/hasVar.kt @@ -0,0 +1,4 @@ +// IS_APPLICABLE: false +class Foo(var x: Int, y: Int) { + +} \ No newline at end of file diff --git a/idea/testData/intentions/addValOrVar/outOfRange.kt b/idea/testData/intentions/addValOrVar/outOfRange.kt new file mode 100644 index 00000000000..09d01128610 --- /dev/null +++ b/idea/testData/intentions/addValOrVar/outOfRange.kt @@ -0,0 +1,4 @@ +// IS_APPLICABLE: false +class Foo(x: Int, y: Int) { + +} \ No newline at end of file diff --git a/idea/testData/intentions/addValOrVar/secondaryConstructorParameter.kt b/idea/testData/intentions/addValOrVar/secondaryConstructorParameter.kt new file mode 100644 index 00000000000..c2ad4a12c10 --- /dev/null +++ b/idea/testData/intentions/addValOrVar/secondaryConstructorParameter.kt @@ -0,0 +1,4 @@ +// IS_APPLICABLE: false +class Foo { + constructor(x: Int, y: Int) +} \ 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 bf7eab21b2a..693d390a789 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -362,6 +362,51 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } } + @TestMetadata("idea/testData/intentions/addValOrVar") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddValOrVar extends AbstractIntentionTest { + @TestMetadata("addVal.kt") + public void testAddVal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addValOrVar/addVal.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInAddValOrVar() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/addValOrVar"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("funParameter.kt") + public void testFunParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addValOrVar/funParameter.kt"); + doTest(fileName); + } + + @TestMetadata("hasVal.kt") + public void testHasVal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addValOrVar/hasVal.kt"); + doTest(fileName); + } + + @TestMetadata("hasVar.kt") + public void testHasVar() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addValOrVar/hasVar.kt"); + doTest(fileName); + } + + @TestMetadata("outOfRange.kt") + public void testOutOfRange() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addValOrVar/outOfRange.kt"); + doTest(fileName); + } + + @TestMetadata("secondaryConstructorParameter.kt") + public void testSecondaryConstructorParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/addValOrVar/secondaryConstructorParameter.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/intentions/anonymousFunctionToLambda") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)