From 4d505f439393207d63c3b7446328fb16a1d009d9 Mon Sep 17 00:00:00 2001 From: Tianyu Geng Date: Sun, 28 Mar 2021 20:32:28 -0700 Subject: [PATCH] FIR IDE: add intention to add custom accessor to uninitliazed property --- .../kotlin/generators/tests/GenerateTests.kt | 1 + .../intentions/fir/AddAccessorsIntention.kt | 25 ++++++++++++++ .../idea/quickfix/MainKtQuickFixRegistrar.kt | 5 ++- .../quickfix/fixes/AddAccessorsFactories.kt | 29 ++++++++++++++++ .../idea/quickfix/fixes/AddLateInitFactory.kt | 2 -- .../HighLevelQuickFixTestGenerated.java | 33 +++++++++++++++++++ .../idea/frontend/api/types/ktTypeUtils.kt | 9 +++++ .../inspections/AbstractKotlinInspection.kt | 2 +- .../quickfix/addPropertyAccessors/val.kt | 2 +- .../addPropertyAccessors/val.kt.after | 2 +- .../quickfix/addPropertyAccessors/var.kt | 2 +- .../addPropertyAccessors/var.kt.after | 2 +- .../addPropertyAccessors/varHasGetter.kt | 3 +- .../varHasGetter.kt.after | 3 +- .../addPropertyAccessors/varHasSetter.kt | 3 +- .../varHasSetter.kt.after | 3 +- 16 files changed, 112 insertions(+), 14 deletions(-) create mode 100644 idea/idea-fir/src/org/jetbrains/kotlin/idea/intentions/fir/AddAccessorsIntention.kt create mode 100644 idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddAccessorsFactories.kt diff --git a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index b77751a416a..95f59a672c3 100644 --- a/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/tests/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -1134,6 +1134,7 @@ fun main(args: Array) { model("quickfix/replaceWithSafeCall", pattern = pattern, filenameStartsLowerCase = true) model("quickfix/variables/changeMutability", pattern = pattern, filenameStartsLowerCase = true) model("quickfix/addInitializer", pattern = pattern, filenameStartsLowerCase = true) + model("quickfix/addPropertyAccessors", pattern = pattern, filenameStartsLowerCase = true) } testClass { diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/intentions/fir/AddAccessorsIntention.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/intentions/fir/AddAccessorsIntention.kt new file mode 100644 index 00000000000..2d83c057785 --- /dev/null +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/intentions/fir/AddAccessorsIntention.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2021 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.intentions.fir + +import com.intellij.codeInsight.intention.PriorityAction +import com.intellij.openapi.util.TextRange +import org.jetbrains.kotlin.idea.intentions.AbstractAddAccessorsIntention +import org.jetbrains.kotlin.psi.KtProperty + +class AddAccessorsIntention( + addGetter: Boolean, addSetter: Boolean, + private val priority: PriorityAction.Priority +) : + AbstractAddAccessorsIntention(addGetter, addSetter), PriorityAction { + // FE1.0 logic in org.jetbrains.kotlin.idea.intentions.AddAccessorsIntention has additional defensive checks to ensure the + // intention only shows up if the property in question indeed needs initialization or accessors. Those checks are unnecessary + // since this factory is coupled with MUST_BE_INITIALIZED_OR_BE_ABSTRACT diagnostic, which has already checked the applicability + // of this intention. + override fun applicabilityRange(element: KtProperty): TextRange? = element.textRange + + override fun getPriority(): PriorityAction.Priority = priority +} \ No newline at end of file diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/MainKtQuickFixRegistrar.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/MainKtQuickFixRegistrar.kt index 3dc52dab2c0..da5216e169d 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/MainKtQuickFixRegistrar.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/MainKtQuickFixRegistrar.kt @@ -9,10 +9,8 @@ import org.jetbrains.kotlin.idea.fir.api.fixes.KtQuickFixRegistrar import org.jetbrains.kotlin.idea.fir.api.fixes.KtQuickFixesList import org.jetbrains.kotlin.idea.fir.api.fixes.KtQuickFixesListBuilder import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KtFirDiagnostic -import org.jetbrains.kotlin.idea.quickfix.fixes.AddLateInitFactory -import org.jetbrains.kotlin.idea.quickfix.fixes.ChangeTypeQuickFix +import org.jetbrains.kotlin.idea.quickfix.fixes.* import org.jetbrains.kotlin.idea.quickfix.fixes.InitializePropertyQuickFixFactory -import org.jetbrains.kotlin.idea.quickfix.fixes.ReplaceCallFixFactories class MainKtQuickFixRegistrar : KtQuickFixRegistrar() { private val modifiers = KtQuickFixesListBuilder.registerPsiQuickFix { @@ -65,6 +63,7 @@ class MainKtQuickFixRegistrar : KtQuickFixRegistrar() { ) registerApplicator(InitializePropertyQuickFixFactory.initializePropertyFactory) registerApplicator(AddLateInitFactory.addLateInitFactory) + registerApplicator(AddAccessorsFactories.addAccessorsToUninitializedProperty) } private val overrides = KtQuickFixesListBuilder.registerPsiQuickFix { diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddAccessorsFactories.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddAccessorsFactories.kt new file mode 100644 index 00000000000..1a411fe498e --- /dev/null +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddAccessorsFactories.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2010-2021 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.quickfix.fixes + +import com.intellij.codeInsight.intention.PriorityAction +import org.jetbrains.kotlin.idea.fir.api.fixes.diagnosticFixFactory +import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KtFirDiagnostic +import org.jetbrains.kotlin.idea.intentions.fir.AddAccessorsIntention +import org.jetbrains.kotlin.psi.KtProperty + +object AddAccessorsFactories { + val addAccessorsToUninitializedProperty = diagnosticFixFactory { diagnostic -> + val property: KtProperty = diagnostic.psi + val addGetter = property.getter == null + val addSetter = property.isVar && property.setter == null + if (!addGetter && !addSetter) return@diagnosticFixFactory emptyList() + + listOf( + AddAccessorsIntention( + addGetter, + addSetter, + if (addGetter && addSetter) PriorityAction.Priority.LOW else PriorityAction.Priority.NORMAL + ) + ) + } +} \ No newline at end of file diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddLateInitFactory.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddLateInitFactory.kt index ea89d08f50f..06d23c29055 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddLateInitFactory.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/quickfix/fixes/AddLateInitFactory.kt @@ -13,8 +13,6 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.KtProperty object AddLateInitFactory { - - @OptIn(ExperimentalStdlibApi::class) val addLateInitFactory = diagnosticFixFactory { diagnostic -> val property: KtProperty = diagnostic.psi if (!property.isVar) return@diagnosticFixFactory emptyList() diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/quickfix/HighLevelQuickFixTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/quickfix/HighLevelQuickFixTestGenerated.java index 28deae162b5..617e02f342d 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/quickfix/HighLevelQuickFixTestGenerated.java +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/quickfix/HighLevelQuickFixTestGenerated.java @@ -1230,4 +1230,37 @@ public class HighLevelQuickFixTestGenerated extends AbstractHighLevelQuickFixTes runTest("idea/testData/quickfix/addInitializer/topLevelPropertyWithGetter.kt"); } } + + @TestMetadata("idea/testData/quickfix/addPropertyAccessors") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddPropertyAccessors extends AbstractHighLevelQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInAddPropertyAccessors() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/addPropertyAccessors"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true); + } + + @TestMetadata("val.kt") + public void testVal() throws Exception { + runTest("idea/testData/quickfix/addPropertyAccessors/val.kt"); + } + + @TestMetadata("var.kt") + public void testVar() throws Exception { + runTest("idea/testData/quickfix/addPropertyAccessors/var.kt"); + } + + @TestMetadata("varHasGetter.kt") + public void testVarHasGetter() throws Exception { + runTest("idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt"); + } + + @TestMetadata("varHasSetter.kt") + public void testVarHasSetter() throws Exception { + runTest("idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt"); + } + } } diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/types/ktTypeUtils.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/types/ktTypeUtils.kt index 0c9cdde392d..fa85d1b6ef3 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/types/ktTypeUtils.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/types/ktTypeUtils.kt @@ -21,6 +21,11 @@ val KtType.isChar: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.CH val KtType.isBoolean: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.BOOLEAN) val KtType.isString: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.STRING) +val KtType.isUInt: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uInt) +val KtType.isULong: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uLong) +val KtType.isUShort: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uShort) +val KtType.isUByte: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uByte) + fun KtType.isClassTypeWithClassId(classId: ClassId): Boolean { if (this !is KtClassType) return false @@ -57,5 +62,9 @@ val KtType.defaultInitializer: String? isBoolean -> "false" isUnit -> "Unit" isString -> "\"\"" + isUInt -> "0.toUInt()" + isULong -> "0.toULong()" + isUShort -> "0.toUShort()" + isUByte -> "0.toUByte()" else -> null } diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/inspections/AbstractKotlinInspection.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/inspections/AbstractKotlinInspection.kt index 2f1923b4053..99a6c4097e9 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/inspections/AbstractKotlinInspection.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/inspections/AbstractKotlinInspection.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2021 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. */ diff --git a/idea/testData/quickfix/addPropertyAccessors/val.kt b/idea/testData/quickfix/addPropertyAccessors/val.kt index 55298cf2540..0d2b985ef51 100644 --- a/idea/testData/quickfix/addPropertyAccessors/val.kt +++ b/idea/testData/quickfix/addPropertyAccessors/val.kt @@ -2,4 +2,4 @@ // WITH_RUNTIME class Test { val x: Int -} \ No newline at end of file +} diff --git a/idea/testData/quickfix/addPropertyAccessors/val.kt.after b/idea/testData/quickfix/addPropertyAccessors/val.kt.after index aafd77339d9..e5aa93a47c3 100644 --- a/idea/testData/quickfix/addPropertyAccessors/val.kt.after +++ b/idea/testData/quickfix/addPropertyAccessors/val.kt.after @@ -5,4 +5,4 @@ class Test { get() { TODO() } -} \ No newline at end of file +} diff --git a/idea/testData/quickfix/addPropertyAccessors/var.kt b/idea/testData/quickfix/addPropertyAccessors/var.kt index c01e53b1150..7962117d0d0 100644 --- a/idea/testData/quickfix/addPropertyAccessors/var.kt +++ b/idea/testData/quickfix/addPropertyAccessors/var.kt @@ -2,4 +2,4 @@ // WITH_RUNTIME class Test { var x: Int -} \ No newline at end of file +} diff --git a/idea/testData/quickfix/addPropertyAccessors/var.kt.after b/idea/testData/quickfix/addPropertyAccessors/var.kt.after index 0cf7def505b..faf9900a9d0 100644 --- a/idea/testData/quickfix/addPropertyAccessors/var.kt.after +++ b/idea/testData/quickfix/addPropertyAccessors/var.kt.after @@ -6,4 +6,4 @@ class Test { TODO() } set(value) {} -} \ No newline at end of file +} diff --git a/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt b/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt index ead42a039e3..d91c32e0687 100644 --- a/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt +++ b/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt @@ -4,4 +4,5 @@ class Test { get() { return 1 } -} \ No newline at end of file +} +/* IGNORE_FIR */ diff --git a/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt.after b/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt.after index 8153f5e1411..d04b7db1c47 100644 --- a/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt.after +++ b/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt.after @@ -5,4 +5,5 @@ class Test { return 1 } set(value) {} -} \ No newline at end of file +} +/* IGNORE_FIR */ diff --git a/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt b/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt index 1b4835daa07..3abcf474b92 100644 --- a/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt +++ b/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt @@ -3,4 +3,5 @@ class Test { var x: Int set(value) {} -} \ No newline at end of file +} +/* IGNORE_FIR */ diff --git a/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt.after b/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt.after index bfc6afd8468..223378051d8 100644 --- a/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt.after +++ b/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt.after @@ -6,4 +6,5 @@ class Test { TODO() } set(value) {} -} \ No newline at end of file +} +/* IGNORE_FIR */