From c442eb89e3533a4f8e468010450c2695a6b370a7 Mon Sep 17 00:00:00 2001 From: Anton Sukhonosenko Date: Mon, 2 Nov 2015 23:53:19 +0300 Subject: [PATCH] #KT-5115 Fixed --- .../org/jetbrains/kotlin/psi/KtPsiFactory.kt | 9 +++ ...ExtensionPropertyInitializerToGetterFix.kt | 65 +++++++++++++++++++ .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 2 + .../baseCase.kt | 2 + .../baseCase.kt.after | 3 + .../baseCaseWithoutTypeAnnotation.kt | 2 + .../baseCaseWithoutTypeAnnotation.kt.after | 3 + .../dontShowQuickfixOnExistingAccessors.kt | 4 ++ .../insertGetterBeforeExistingSetter.kt | 3 + .../insertGetterBeforeExistingSetter.kt.after | 4 ++ .../QuickFixMultiFileTestGenerated.java | 10 +++ .../idea/quickfix/QuickFixTestGenerated.java | 42 ++++++++++++ 12 files changed, 149 insertions(+) create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertExtensionPropertyInitializerToGetterFix.kt create mode 100644 idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCase.kt create mode 100644 idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCase.kt.after create mode 100644 idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCaseWithoutTypeAnnotation.kt create mode 100644 idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCaseWithoutTypeAnnotation.kt.after create mode 100644 idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/dontShowQuickfixOnExistingAccessors.kt create mode 100644 idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/insertGetterBeforeExistingSetter.kt create mode 100644 idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/insertGetterBeforeExistingSetter.kt.after diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt index 64cd682ec18..2efc62da858 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt @@ -180,6 +180,15 @@ public class KtPsiFactory(private val project: Project) { return createDeclaration(text) } + public fun createPropertyGetter(expression: KtExpression): KtPropertyAccessor { + val property = createProperty("val x get() = 1") + val getter = property.getter!! + val bodyExpression = getter.bodyExpression!! + + bodyExpression.replace(expression) + return getter + } + public fun createDeclaration(text: String): TDeclaration { val file = createFile(text) val declarations = file.getDeclarations() diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertExtensionPropertyInitializerToGetterFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertExtensionPropertyInitializerToGetterFix.kt new file mode 100644 index 00000000000..2ba6e5435e2 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertExtensionPropertyInitializerToGetterFix.kt @@ -0,0 +1,65 @@ +/* + * 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.quickfix + +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.intentions.SpecifyTypeExplicitlyIntention +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType + +class ConvertExtensionPropertyInitializerToGetterFix(element: KtExpression) : KotlinQuickFixAction(element) { + override fun getText(): String = "Convert extension property initializer to getter" + + override fun getFamilyName(): String = getText() + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val property = element.getParentOfType(true) ?: return + val type = SpecifyTypeExplicitlyIntention.getTypeForDeclaration(property) + SpecifyTypeExplicitlyIntention.addTypeAnnotation(editor, property, type) + + val getter = KtPsiFactory(element).createPropertyGetter(element) + val setter = property.setter + + if (setter != null) { + property.addBefore(getter, setter) + } + else { + property.add(getter) + } + + property.setInitializer(null) + } + + companion object : KotlinSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val expression = diagnostic.psiElement as? KtExpression ?: return null + val property = expression.getParentOfType(true)!! + + if (property.getter != null) { + return null + } + + return ConvertExtensionPropertyInitializerToGetterFix(expression) + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 7330b57f93f..275dd481599 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -231,6 +231,8 @@ public class QuickFixRegistrar : QuickFixContributor { EXPECTED_PARAMETER_TYPE_MISMATCH.registerFactory(ChangeTypeFix.createFactoryForExpectedParameterTypeMismatch()) + EXTENSION_PROPERTY_WITH_BACKING_FIELD.registerFactory(ConvertExtensionPropertyInitializerToGetterFix) + val changeFunctionLiteralReturnTypeFix = ChangeFunctionLiteralReturnTypeFix.createFactoryForExpectedOrAssignmentTypeMismatch() EXPECTED_TYPE_MISMATCH.registerFactory(changeFunctionLiteralReturnTypeFix) ASSIGNMENT_TYPE_MISMATCH.registerFactory(changeFunctionLiteralReturnTypeFix) diff --git a/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCase.kt b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCase.kt new file mode 100644 index 00000000000..3896d26654a --- /dev/null +++ b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCase.kt @@ -0,0 +1,2 @@ +// "Convert extension property initializer to getter" "true" +val String.foo: Int = 0 \ No newline at end of file diff --git a/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCase.kt.after b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCase.kt.after new file mode 100644 index 00000000000..a367c0a81bd --- /dev/null +++ b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCase.kt.after @@ -0,0 +1,3 @@ +// "Convert extension property initializer to getter" "true" +val String.foo: Int + get() = 0 \ No newline at end of file diff --git a/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCaseWithoutTypeAnnotation.kt b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCaseWithoutTypeAnnotation.kt new file mode 100644 index 00000000000..43f09651915 --- /dev/null +++ b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCaseWithoutTypeAnnotation.kt @@ -0,0 +1,2 @@ +// "Convert extension property initializer to getter" "true" +val String.foo = 0 \ No newline at end of file diff --git a/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCaseWithoutTypeAnnotation.kt.after b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCaseWithoutTypeAnnotation.kt.after new file mode 100644 index 00000000000..a367c0a81bd --- /dev/null +++ b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCaseWithoutTypeAnnotation.kt.after @@ -0,0 +1,3 @@ +// "Convert extension property initializer to getter" "true" +val String.foo: Int + get() = 0 \ No newline at end of file diff --git a/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/dontShowQuickfixOnExistingAccessors.kt b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/dontShowQuickfixOnExistingAccessors.kt new file mode 100644 index 00000000000..83af3415523 --- /dev/null +++ b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/dontShowQuickfixOnExistingAccessors.kt @@ -0,0 +1,4 @@ +// "Convert extension property initializer to getter" "false" +// ERROR: Extension property cannot be initialized because it has no backing field +var String.foo: Int = 0 + get() = 1 diff --git a/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/insertGetterBeforeExistingSetter.kt b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/insertGetterBeforeExistingSetter.kt new file mode 100644 index 00000000000..3a160a984cc --- /dev/null +++ b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/insertGetterBeforeExistingSetter.kt @@ -0,0 +1,3 @@ +// "Convert extension property initializer to getter" "true" +var String.foo: Int = 0 + set(value) {} \ No newline at end of file diff --git a/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/insertGetterBeforeExistingSetter.kt.after b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/insertGetterBeforeExistingSetter.kt.after new file mode 100644 index 00000000000..1778eb241ea --- /dev/null +++ b/idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/insertGetterBeforeExistingSetter.kt.after @@ -0,0 +1,4 @@ +// "Convert extension property initializer to getter" "true" +var String.foo: Int + get() = 0 + set(value) {} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 1b0e96b7c52..a2b2625c5c4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -1506,6 +1506,16 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/properties") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Properties extends AbstractQuickFixMultiFileTest { + public void testAllFilesPresentInProperties() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/properties"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), true); + } + + } + @TestMetadata("idea/testData/quickfix/suppress") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 169eb255fac..c4d453f88a5 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -5278,6 +5278,48 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/properties") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Properties extends AbstractQuickFixTest { + public void testAllFilesPresentInProperties() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/properties"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("idea/testData/quickfix/properties/extensionPropertyInitializerToGetter") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ExtensionPropertyInitializerToGetter extends AbstractQuickFixTest { + public void testAllFilesPresentInExtensionPropertyInitializerToGetter() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/properties/extensionPropertyInitializerToGetter"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("baseCase.kt") + public void testBaseCase() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCase.kt"); + doTest(fileName); + } + + @TestMetadata("baseCaseWithoutTypeAnnotation.kt") + public void testBaseCaseWithoutTypeAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/baseCaseWithoutTypeAnnotation.kt"); + doTest(fileName); + } + + @TestMetadata("dontShowQuickfixOnExistingAccessors.kt") + public void testDontShowQuickfixOnExistingAccessors() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/dontShowQuickfixOnExistingAccessors.kt"); + doTest(fileName); + } + + @TestMetadata("insertGetterBeforeExistingSetter.kt") + public void testInsertGetterBeforeExistingSetter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/properties/extensionPropertyInitializerToGetter/insertGetterBeforeExistingSetter.kt"); + doTest(fileName); + } + } + } + @TestMetadata("idea/testData/quickfix/removeUnused") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)