Add intentions to convert nullable <--> lateinit var #KT-12743 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
9049af3bdf
commit
4cf266e99f
+3
@@ -0,0 +1,3 @@
|
||||
class C {
|
||||
var foo: String? = null
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
class C {
|
||||
lateinit var foo: String
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention converts a lateinit var property / variable to a nullable var property / variable.
|
||||
</body>
|
||||
</html>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
class C {
|
||||
lateinit var foo: String
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
class C {
|
||||
var foo: String? = null
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention converts a nullable var property / variable to a lateinit var property / variable.
|
||||
</body>
|
||||
</html>
|
||||
@@ -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"
|
||||
|
||||
+37
@@ -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)
|
||||
}
|
||||
}
|
||||
+54
@@ -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
|
||||
}
|
||||
+4
@@ -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 = ""
|
||||
}
|
||||
+4
@@ -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
|
||||
}
|
||||
+121
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user