Add intentions to convert nullable <--> lateinit var #KT-12743 Fixed

This commit is contained in:
Toshiaki Kameyama
2018-11-21 10:50:15 +03:00
committed by Mikhail Glukhikh
parent 9049af3bdf
commit 4cf266e99f
33 changed files with 343 additions and 0 deletions
@@ -0,0 +1,3 @@
class C {
var foo: String? = null
}
@@ -0,0 +1,3 @@
class C {
lateinit var foo: String
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts a lateinit var property / variable to a nullable var property / variable.
</body>
</html>
@@ -0,0 +1,3 @@
class C {
lateinit var foo: String
}
@@ -0,0 +1,3 @@
class C {
var foo: String? = null
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention converts a nullable var property / variable to a lateinit var property / variable.
</body>
</html>
+10
View File
@@ -1670,6 +1670,16 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertNullablePropertyToLateinitIntention</className>
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ConvertLateinitPropertyToNullableIntention</className>
<category>Kotlin</category>
</intentionAction>
<lang.inspectionSuppressor language="kotlin" implementationClass="org.jetbrains.kotlin.idea.inspections.KotlinInspectionSuppressor"/>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.setType
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtNullableType
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.typeUtil.makeNullable
class ConvertLateinitPropertyToNullableIntention : SelfTargetingIntention<KtProperty>(
KtProperty::class.java, "Convert to nullable var"
) {
override fun isApplicableTo(element: KtProperty, caretOffset: Int): Boolean {
return element.hasModifier(KtTokens.LATEINIT_KEYWORD)
&& element.isVar
&& element.typeReference?.typeElement !is KtNullableType
&& element.initializer == null
}
override fun applyTo(element: KtProperty, editor: Editor?) {
val typeReference: KtTypeReference = element.typeReference ?: return
val nullableType = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, typeReference]?.makeNullable() ?: return
element.removeModifier(KtTokens.LATEINIT_KEYWORD)
element.setType(nullableType)
element.initializer = KtPsiFactory(element).createExpression(KtTokens.NULL_KEYWORD.value)
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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
import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.setType
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtNullableType
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
class ConvertNullablePropertyToLateinitIntention : SelfTargetingIntention<KtProperty>(
KtProperty::class.java, "Convert to lateinit var"
) {
override fun isApplicableTo(element: KtProperty, caretOffset: Int): Boolean {
if (element.hasModifier(KtTokens.LATEINIT_KEYWORD) || element.hasModifier(KtTokens.ABSTRACT_KEYWORD)) return false
if (!element.isVar) return false
if (element.isLocal || element.isTopLevel) return false
if (element.getter?.hasBody() != null || element.setter?.hasBody() != null) return false
if (!element.initializer.isNullExpression()) return false
val typeReference = element.typeReference
if (typeReference?.typeElement !is KtNullableType) return false
val context = element.analyze(BodyResolveMode.PARTIAL)
val type = context[BindingContext.TYPE, typeReference]?.makeNotNullable() ?: return false
if (KotlinBuiltIns.isPrimitiveType(type) || type.isInlineClassType() || TypeUtils.isNullableType(type)) return false
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? PropertyDescriptor ?: return false
if (context[BindingContext.BACKING_FIELD_REQUIRED, descriptor] == false) return false
if (descriptor.extensionReceiverParameter != null) return false
return true
}
override fun applyTo(element: KtProperty, editor: Editor?) {
val typeReference: KtTypeReference = element.typeReference ?: return
val notNullableType = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, typeReference]?.makeNotNullable() ?: return
element.addModifier(KtTokens.LATEINIT_KEYWORD)
element.setType(notNullableType)
element.initializer = null
}
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.ConvertLateinitPropertyToNullableIntention
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// DISABLE-ERRORS
class C {
<caret>private lateinit var bar: String = ""
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// DISABLE-ERRORS
class C {
<caret>private lateinit var bar: String?
}
@@ -0,0 +1,3 @@
class C {
<caret>private lateinit var bar: String
}
@@ -0,0 +1,3 @@
class C {
private var bar: String? = null
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// DISABLE-ERRORS
class C {
<caret>private lateinit val bar: String
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.ConvertNullablePropertyToLateinitIntention
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// DISABLE-ERRORS
abstract class C {
abstract var <caret>foo: String? = null
}
@@ -0,0 +1,11 @@
// IS_APPLICABLE: false
import kotlin.reflect.KProperty
class C {
<caret>var foo by Delegate
}
object Delegate {
operator fun getValue(instance: Any?, property: KProperty<*>): String = ""
operator fun setValue(instance: Any?, property: KProperty<*>, value: String) {}
}
@@ -0,0 +1,7 @@
// IS_APPLICABLE: false
// DISABLE-ERRORS
class C {
<caret>var Foo.foo: String? = null
}
class Foo
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
class C {
<caret>var foo: String? = null
get() = ""
}
@@ -0,0 +1,6 @@
// IS_APPLICABLE: false
class C {
<caret>var foo: Foo? = null
}
inline class Foo(val value: String)
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
class C {
<caret>var foo: Int? = null
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
fun test() {
<caret>var foo: String? = null
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
class C {
<caret>private var foo: String? = ""
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
class C {
<caret>private var foo: String = ""
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
class C<V> {
<caret>var foo: V? = null
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
class C {
<caret>var foo: String? = null
private set
}
@@ -0,0 +1,3 @@
class C {
<caret>private var foo: String? = null
}
@@ -0,0 +1,3 @@
class C {
private lateinit var foo: String
}
@@ -0,0 +1,2 @@
// IS_APPLICABLE: false
<caret>var foo: String? = null
@@ -0,0 +1,5 @@
// WITH_RUNTIME
// IS_APPLICABLE: false
class C {
<caret>var foo: UInt? = null
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
class C {
<caret>private val foo: String? = null
}
@@ -5714,6 +5714,39 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
@TestMetadata("idea/testData/intentions/convertLateinitPropertyToNullable")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ConvertLateinitPropertyToNullable extends AbstractIntentionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInConvertLateinitPropertyToNullable() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertLateinitPropertyToNullable"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("initializer.kt")
public void testInitializer() throws Exception {
runTest("idea/testData/intentions/convertLateinitPropertyToNullable/initializer.kt");
}
@TestMetadata("nullable.kt")
public void testNullable() throws Exception {
runTest("idea/testData/intentions/convertLateinitPropertyToNullable/nullable.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("idea/testData/intentions/convertLateinitPropertyToNullable/simple.kt");
}
@TestMetadata("val.kt")
public void testVal() throws Exception {
runTest("idea/testData/intentions/convertLateinitPropertyToNullable/val.kt");
}
}
@TestMetadata("idea/testData/intentions/convertLineCommentToBlockComment")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -5830,6 +5863,94 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
@TestMetadata("idea/testData/intentions/convertNullablePropertyToLateinit")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ConvertNullablePropertyToLateinit extends AbstractIntentionTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
}
@TestMetadata("abstract.kt")
public void testAbstract() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/abstract.kt");
}
public void testAllFilesPresentInConvertNullablePropertyToLateinit() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertNullablePropertyToLateinit"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), TargetBackend.ANY, true);
}
@TestMetadata("delegate.kt")
public void testDelegate() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/delegate.kt");
}
@TestMetadata("extension.kt")
public void testExtension() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/extension.kt");
}
@TestMetadata("getter.kt")
public void testGetter() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/getter.kt");
}
@TestMetadata("inlineClass.kt")
public void testInlineClass() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/inlineClass.kt");
}
@TestMetadata("int.kt")
public void testInt() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/int.kt");
}
@TestMetadata("local.kt")
public void testLocal() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/local.kt");
}
@TestMetadata("nonNullInitializer.kt")
public void testNonNullInitializer() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/nonNullInitializer.kt");
}
@TestMetadata("nonNullable.kt")
public void testNonNullable() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/nonNullable.kt");
}
@TestMetadata("nullableUpperBound.kt")
public void testNullableUpperBound() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/nullableUpperBound.kt");
}
@TestMetadata("setter.kt")
public void testSetter() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/setter.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/simple.kt");
}
@TestMetadata("topLevel.kt")
public void testTopLevel() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/topLevel.kt");
}
@TestMetadata("unsignedInt.kt")
public void testUnsignedInt() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/unsignedInt.kt");
}
@TestMetadata("val.kt")
public void testVal() throws Exception {
runTest("idea/testData/intentions/convertNullablePropertyToLateinit/val.kt");
}
}
@TestMetadata("idea/testData/intentions/convertObjectLiteralToClass")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)