From 0aa236d1aca62b3aca59a57ddca704e31d610c8a Mon Sep 17 00:00:00 2001 From: Nicolay Mitropolsky Date: Wed, 18 Apr 2018 15:24:52 +0300 Subject: [PATCH] 182: KotlinElementActionsFactory.createAddFieldActions no more generates private `@JvmField` and `lateinit` `@JvmField` --- .../KotlinElementActionsFactory.kt.182 | 41 ++++++---- .../CommonIntentionActionsTest.kt.182 | 82 +++++++++++++++++++ 2 files changed, 105 insertions(+), 18 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/KotlinElementActionsFactory.kt.182 b/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/KotlinElementActionsFactory.kt.182 index 0a084e793e6..ca74d53ccb3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/KotlinElementActionsFactory.kt.182 +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/crossLanguage/KotlinElementActionsFactory.kt.182 @@ -151,7 +151,7 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() { val info = callableInfos.first() as PropertyInfo return buildString { append("Add '") - if (info.isLateinitPreferred) { + if (info.isLateinitPreferred || info.modifierList?.hasModifier(KtTokens.LATEINIT_KEYWORD) == true) { append("lateinit ") } append(if (info.writable) "var" else "val") @@ -349,30 +349,35 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() { override fun createAddFieldActions(targetClass: JvmClass, request: CreateFieldRequest): List { val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList() - val modifierBuilder = ModifierBuilder(targetContainer, allowJvmStatic = false).apply { - addJvmModifiers(request.modifiers) - addAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) - } - if (!modifierBuilder.isValid) return emptyList() - val resolutionFacade = targetContainer.getResolutionFacade() val typeInfo = request.fieldType.toKotlinTypeInfo(resolutionFacade) val writable = JvmModifier.FINAL !in request.modifiers - val propertyInfo = PropertyInfo( - request.fieldName, - TypeInfo.Empty, - typeInfo, - writable, - listOf(targetContainer), - isForCompanion = JvmModifier.STATIC in request.modifiers, - modifierList = modifierBuilder.modifierList, - withInitializer = true + + fun propertyInfo(lateinit: Boolean) = PropertyInfo( + request.fieldName, + TypeInfo.Empty, + typeInfo, + writable, + listOf(targetContainer), + isLateinitPreferred = false, // Dont set it to `lateinit` because it works via templates that brings issues in batch field adding + isForCompanion = JvmModifier.STATIC in request.modifiers, + modifierList = ModifierBuilder(targetContainer, allowJvmStatic = false).apply { + addJvmModifiers(request.modifiers) + if (modifierList.children.none { it.node.elementType in KtTokens.VISIBILITY_MODIFIERS }) + addJvmModifier(JvmModifier.PUBLIC) + if (lateinit) + modifierList.appendModifier(KtTokens.LATEINIT_KEYWORD) + if (!request.modifiers.contains(JvmModifier.PRIVATE) && !lateinit) + addAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME) + }.modifierList, + withInitializer = !lateinit ) + val propertyInfos = if (writable) { - listOf(propertyInfo, propertyInfo.copyProperty(isLateinitPreferred = true)) + listOf(propertyInfo(false), propertyInfo(true)) } else { - listOf(propertyInfo) + listOf(propertyInfo(false)) } return propertyInfos.map { CreatePropertyFix(targetClass, targetContainer, it) } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsTest.kt.182 b/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsTest.kt.182 index 0cccd1fdcc7..bb6bd1c8bfe 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsTest.kt.182 +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/CommonIntentionActionsTest.kt.182 @@ -403,9 +403,68 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() { """.trim().trimMargin(), true) } + fun testAddStringVarField() { + myFixture.configureByText( + "foo.kt", """ + |class Foo { + | fun bar() {} + |} + """.trim().trimMargin() + ) + myFixture.launchAction( + createFieldActions( + myFixture.atCaret(), + FieldRequest(project, emptyList(), "java.util.Date", "baz") + ).findWithText("Add 'var' property 'baz' to 'Foo'") + ) + myFixture.checkResult( + """ + |import java.util.Date + | + |class Foo { + | @JvmField + | var baz: Date = TODO("initialize me") + | + | fun bar() {} + |} + """.trim().trimMargin(), true + ) + } + + fun testAddLateInitStringVarField() { + myFixture.configureByText( + "foo.kt", """ + |class Foo { + | fun bar() {} + |} + """.trim().trimMargin() + ) + + myFixture.launchAction( + createFieldActions( + myFixture.atCaret(), + FieldRequest(project, listOf(JvmModifier.PRIVATE), "java.lang.String", "baz") + ).findWithText("Add 'lateinit var' property 'baz' to 'Foo'") + ) + myFixture.checkResult( + """ + |class Foo { + | private lateinit var baz: String + | + | fun bar() {} + |} + """.trim().trimMargin(), true + ) + } + + + private fun createPropertyActions(atCaret: JvmClass, property: MemberRequest.Property): List = com.intellij.lang.jvm.actions.EP_NAME.extensions.flatMap { it.createAddPropertyActions(atCaret, property) } + private fun createFieldActions(atCaret: JvmClass, fieldRequest: CreateFieldRequest): List = + com.intellij.lang.jvm.actions.EP_NAME.extensions.flatMap { it.createAddFieldActions(atCaret, fieldRequest) } + fun testAddStringValProperty() { myFixture.configureByText("foo.kt", """ |class Foo { @@ -452,5 +511,28 @@ class CommonIntentionActionsTest : LightPlatformCodeInsightFixtureTestCase() { private fun List.findWithText(text: String): IntentionAction = this.firstOrNull { it.text == text } ?: Assert.fail("intention with text '$text' was not found, only ${this.joinToString { "\"${it.text}\"" }} available") as Nothing + + class FieldRequest( + private val project: Project, + val modifiers: List, + val type: String, + val name: String + ) : CreateFieldRequest { + override fun getTargetSubstitutor(): JvmSubstitutor = PsiJvmSubstitutor(project, PsiSubstitutor.EMPTY) + + override fun getModifiers(): Collection = modifiers + + override fun isConstant(): Boolean = false + + override fun getFieldType(): List = + com.intellij.lang.jvm.actions.expectedTypes(PsiType.getTypeByName(type, project, project.allScope())) + + override fun getFieldName(): String = name + + override fun isValid(): Boolean = true + } + + } +