diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/addRemoveModifier.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/addRemoveModifier.kt index f7ef5a29ddc..037b28c1e61 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/addRemoveModifier.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/addRemoveModifier.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2016 JetBrains s.r.o. + * Copyright 2010-2017 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. @@ -136,6 +136,7 @@ private val MODIFIERS_TO_REPLACE = mapOf( private val MODIFIERS_ORDER = listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD, FINAL_KEYWORD, OPEN_KEYWORD, ABSTRACT_KEYWORD, OVERRIDE_KEYWORD, + LATEINIT_KEYWORD, SUSPEND_KEYWORD, INNER_KEYWORD, ENUM_KEYWORD, COMPANION_KEYWORD, INFIX_KEYWORD, OPERATOR_KEYWORD, DATA_KEYWORD) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddModifierFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddModifierFix.kt index b5893007436..f31836932da 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddModifierFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddModifierFix.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2017 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. @@ -21,8 +21,11 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.psi.PsiFile import com.intellij.psi.PsiNameIdentifierOwner +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil import org.jetbrains.kotlin.idea.refactoring.canRefactor @@ -34,6 +37,7 @@ import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.types.TypeUtils open class AddModifierFix( element: KtModifierListOwner, @@ -116,4 +120,20 @@ open class AddModifierFix( return AddModifierFix(declaration, KtTokens.OPEN_KEYWORD) } } + + object AddLateinitFactory : KotlinSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? { + val property = Errors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT.cast(diagnostic).psiElement + if (!property.isVar) return null + + val context = property.analyze() + val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, property] ?: return null + val type = (descriptor as? PropertyDescriptor)?.type ?: return null + + if (TypeUtils.isNullableType(type)) return null + if (KotlinBuiltIns.isPrimitiveType(type)) return null + + return AddModifierFix(property, KtTokens.LATEINIT_KEYWORD) + } + } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 309ff625f6a..24a40f061b2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -489,5 +489,7 @@ class QuickFixRegistrar : QuickFixContributor { INAPPLICABLE_JVM_FIELD.registerFactory(ReplaceJvmFieldWithConstFix) CONFLICTING_OVERLOADS.registerFactory(ChangeSuspendInHierarchyFix) + + MUST_BE_INITIALIZED_OR_BE_ABSTRACT.registerFactory(AddModifierFix.AddLateinitFactory) } } diff --git a/idea/testData/quickfix/modifiers/addLateinit.kt b/idea/testData/quickfix/modifiers/addLateinit.kt new file mode 100644 index 00000000000..bc85f064751 --- /dev/null +++ b/idea/testData/quickfix/modifiers/addLateinit.kt @@ -0,0 +1,5 @@ +// "Add 'lateinit' modifier" "true" + +class A { + private var a: String +} \ No newline at end of file diff --git a/idea/testData/quickfix/modifiers/addLateinit.kt.after b/idea/testData/quickfix/modifiers/addLateinit.kt.after new file mode 100644 index 00000000000..ff50605306f --- /dev/null +++ b/idea/testData/quickfix/modifiers/addLateinit.kt.after @@ -0,0 +1,5 @@ +// "Add 'lateinit' modifier" "true" + +class A { + private lateinit var a: String +} \ No newline at end of file diff --git a/idea/testData/quickfix/modifiers/noLateinitOnNullable.kt b/idea/testData/quickfix/modifiers/noLateinitOnNullable.kt new file mode 100644 index 00000000000..2f7e5a0398b --- /dev/null +++ b/idea/testData/quickfix/modifiers/noLateinitOnNullable.kt @@ -0,0 +1,10 @@ +// "Add 'lateinit' modifier" "false" +// ACTION: Add initializer +// ACTION: Make 'a' abstract +// ACTION: Move to constructor parameters +// ACTION: Move to constructor +// ERROR: Property must be initialized or be abstract + +class A { + private var a: String? +} \ No newline at end of file diff --git a/idea/testData/quickfix/modifiers/noLateinitOnPrimitive.kt b/idea/testData/quickfix/modifiers/noLateinitOnPrimitive.kt new file mode 100644 index 00000000000..99fad7fc2f5 --- /dev/null +++ b/idea/testData/quickfix/modifiers/noLateinitOnPrimitive.kt @@ -0,0 +1,10 @@ +// "Add 'lateinit' modifier" "false" +// ACTION: Add initializer +// ACTION: Make 'a' abstract +// ACTION: Move to constructor parameters +// ACTION: Move to constructor +// ERROR: Property must be initialized or be abstract + +class A { + private var a: Int +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 312c6006710..622fb7f8c2f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -6613,6 +6613,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("addLateinit.kt") + public void testAddLateinit() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/modifiers/addLateinit.kt"); + doTest(fileName); + } + public void testAllFilesPresentInModifiers() throws Exception { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/modifiers"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); } @@ -6671,6 +6677,18 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("noLateinitOnNullable.kt") + public void testNoLateinitOnNullable() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/modifiers/noLateinitOnNullable.kt"); + doTest(fileName); + } + + @TestMetadata("noLateinitOnPrimitive.kt") + public void testNoLateinitOnPrimitive() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/modifiers/noLateinitOnPrimitive.kt"); + doTest(fileName); + } + @TestMetadata("notAnAnnotationClass.kt") public void testNotAnAnnotationClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/modifiers/notAnAnnotationClass.kt");