From e3c91349043a96d7bbef41031558a07dfacfb46e Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Tue, 18 Jun 2019 11:52:51 +0900 Subject: [PATCH] Add "Convert to notNull delegate" quick fix for INAPPLICABLE_LATEINIT_MODIFIER #KT-12515 Fixed --- ...ertLateinitPropertyToNotNullDelegateFix.kt | 51 +++++++++++++++++++ .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 1 + .../basic.kt | 3 ++ .../basic.kt.after | 5 ++ .../basic2.kt | 3 ++ .../basic2.kt.after | 5 ++ .../hasInitializer.kt | 8 +++ .../noType.kt | 7 +++ .../notPrimitive.kt | 5 ++ .../nullablePrimitive.kt | 7 +++ .../val.kt | 7 +++ .../QuickFixMultiFileTestGenerated.java | 13 +++++ .../idea/quickfix/QuickFixTestGenerated.java | 48 +++++++++++++++++ 13 files changed, 163 insertions(+) create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertLateinitPropertyToNotNullDelegateFix.kt create mode 100644 idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic.kt create mode 100644 idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic.kt.after create mode 100644 idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic2.kt create mode 100644 idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic2.kt.after create mode 100644 idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/hasInitializer.kt create mode 100644 idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/noType.kt create mode 100644 idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/notPrimitive.kt create mode 100644 idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/nullablePrimitive.kt create mode 100644 idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/val.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertLateinitPropertyToNotNullDelegateFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertLateinitPropertyToNotNullDelegateFix.kt new file mode 100644 index 00000000000..be8003daa38 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ConvertLateinitPropertyToNotNullDelegateFix.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2019 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 + +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.core.ShortenReferences +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode + +class ConvertLateinitPropertyToNotNullDelegateFix( + property: KtProperty, + private val type: String +) : KotlinQuickFixAction(property) { + override fun getText() = "Convert to notNull delegate" + + override fun getFamilyName() = text + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val property = element ?: return + val typeReference = property.typeReference ?: return + val psiFactory = KtPsiFactory(property) + property.removeModifier(KtTokens.LATEINIT_KEYWORD) + val propertyDelegate = psiFactory.createPropertyDelegate( + psiFactory.createExpression("kotlin.properties.Delegates.notNull<$type>()") + ) + property.addAfter(propertyDelegate, typeReference) + property.typeReference = null + ShortenReferences.DEFAULT.process(property) + } + + companion object : KotlinSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { + val modifierList = diagnostic.psiElement.parent as? KtDeclarationModifierList ?: return null + val property = modifierList.parent as? KtProperty ?: return null + if (!property.hasModifier(KtTokens.LATEINIT_KEYWORD) || !property.isVar || property.hasInitializer()) return null + val typeReference = property.typeReference ?: return null + val type = property.analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, typeReference] ?: return null + if (!KotlinBuiltIns.isPrimitiveType(type)) return null + return ConvertLateinitPropertyToNotNullDelegateFix(property, type.toString()) + } + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 4334ca2d8c8..1b64e2622b6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -512,6 +512,7 @@ class QuickFixRegistrar : QuickFixContributor { INAPPLICABLE_LATEINIT_MODIFIER.registerFactory(RemoveNullableFix.LATEINIT_FACTORY) INAPPLICABLE_LATEINIT_MODIFIER.registerFactory(RemovePartsFromPropertyFix.LateInitFactory) INAPPLICABLE_LATEINIT_MODIFIER.registerFactory(RemoveModifierFix.createRemoveLateinitFactory()) + INAPPLICABLE_LATEINIT_MODIFIER.registerFactory(ConvertLateinitPropertyToNotNullDelegateFix) VARIABLE_WITH_REDUNDANT_INITIALIZER.registerFactory(RemoveRedundantInitializerFix) diff --git a/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic.kt b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic.kt new file mode 100644 index 00000000000..b0fccf7baea --- /dev/null +++ b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic.kt @@ -0,0 +1,3 @@ +// "Convert to notNull delegate" "true" +// WITH_RUNTIME +lateinit var x: Boolean \ No newline at end of file diff --git a/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic.kt.after b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic.kt.after new file mode 100644 index 00000000000..92db4c3fb1f --- /dev/null +++ b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic.kt.after @@ -0,0 +1,5 @@ +import kotlin.properties.Delegates + +// "Convert to notNull delegate" "true" +// WITH_RUNTIME +var x by Delegates.notNull() \ No newline at end of file diff --git a/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic2.kt b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic2.kt new file mode 100644 index 00000000000..58f64a88225 --- /dev/null +++ b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic2.kt @@ -0,0 +1,3 @@ +// "Convert to notNull delegate" "true" +// WITH_RUNTIME +lateinit var x: Int \ No newline at end of file diff --git a/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic2.kt.after b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic2.kt.after new file mode 100644 index 00000000000..ec2a5438b22 --- /dev/null +++ b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic2.kt.after @@ -0,0 +1,5 @@ +import kotlin.properties.Delegates + +// "Convert to notNull delegate" "true" +// WITH_RUNTIME +var x by Delegates.notNull() \ No newline at end of file diff --git a/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/hasInitializer.kt b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/hasInitializer.kt new file mode 100644 index 00000000000..8b1ce62c770 --- /dev/null +++ b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/hasInitializer.kt @@ -0,0 +1,8 @@ +// "Convert to notNull delegate" "false" +// DISABLE-ERRORS +// ACTION: Make internal +// ACTION: Make private +// ACTION: Remove 'lateinit' modifier +// ACTION: Remove explicit type specification +// ACTION: Remove initializer from property +lateinit var x: Boolean = true \ No newline at end of file diff --git a/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/noType.kt b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/noType.kt new file mode 100644 index 00000000000..9570223993e --- /dev/null +++ b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/noType.kt @@ -0,0 +1,7 @@ +// "Convert to notNull delegate" "false" +// DISABLE-ERRORS +// ACTION: Convert to nullable var +// ACTION: Make internal +// ACTION: Make private +// ACTION: Specify type explicitly +lateinit var x \ No newline at end of file diff --git a/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/notPrimitive.kt b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/notPrimitive.kt new file mode 100644 index 00000000000..714b31a7cb7 --- /dev/null +++ b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/notPrimitive.kt @@ -0,0 +1,5 @@ +// "Convert to notNull delegate" "false" +// ACTION: Convert to nullable var +// ACTION: Make internal +// ACTION: Make private +lateinit var x: String \ No newline at end of file diff --git a/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/nullablePrimitive.kt b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/nullablePrimitive.kt new file mode 100644 index 00000000000..b6e5019ada9 --- /dev/null +++ b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/nullablePrimitive.kt @@ -0,0 +1,7 @@ +// "Convert to notNull delegate" "false" +// DISABLE-ERRORS +// ACTION: Make internal +// ACTION: Make not-nullable +// ACTION: Make private +// ACTION: Remove 'lateinit' modifier +lateinit var x: Boolean? \ No newline at end of file diff --git a/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/val.kt b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/val.kt new file mode 100644 index 00000000000..1b9bb86b77e --- /dev/null +++ b/idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/val.kt @@ -0,0 +1,7 @@ +// "Convert to notNull delegate" "false" +// DISABLE-ERRORS +// ACTION: Change to var +// ACTION: Make internal +// ACTION: Make private +// ACTION: Remove 'lateinit' modifier +lateinit val x: Boolean \ 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 0cba1818ede..4d6717f24b8 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -1399,6 +1399,19 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes } } + @TestMetadata("idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ConvertLateinitPropertyToNotNullDelegate extends AbstractQuickFixMultiFileTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestWithExtraFile, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInConvertLateinitPropertyToNotNullDelegate() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), TargetBackend.ANY, true); + } + } + @TestMetadata("idea/testData/quickfix/convertPropertyInitializerToGetter") @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 aebdc229cc7..63665778c12 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -2449,6 +2449,54 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ConvertLateinitPropertyToNotNullDelegate extends AbstractQuickFixTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInConvertLateinitPropertyToNotNullDelegate() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + runTest("idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic.kt"); + } + + @TestMetadata("basic2.kt") + public void testBasic2() throws Exception { + runTest("idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/basic2.kt"); + } + + @TestMetadata("hasInitializer.kt") + public void testHasInitializer() throws Exception { + runTest("idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/hasInitializer.kt"); + } + + @TestMetadata("noType.kt") + public void testNoType() throws Exception { + runTest("idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/noType.kt"); + } + + @TestMetadata("notPrimitive.kt") + public void testNotPrimitive() throws Exception { + runTest("idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/notPrimitive.kt"); + } + + @TestMetadata("nullablePrimitive.kt") + public void testNullablePrimitive() throws Exception { + runTest("idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/nullablePrimitive.kt"); + } + + @TestMetadata("val.kt") + public void testVal() throws Exception { + runTest("idea/testData/quickfix/convertLateinitPropertyToNotNullDelegate/val.kt"); + } + } + @TestMetadata("idea/testData/quickfix/convertPropertyInitializerToGetter") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)