FIR IDE: add intention to add custom accessor to uninitliazed property
This commit is contained in:
committed by
Ilya Kirillov
parent
78f450a6ef
commit
4d505f4393
@@ -1134,6 +1134,7 @@ fun main(args: Array<String>) {
|
|||||||
model("quickfix/replaceWithSafeCall", pattern = pattern, filenameStartsLowerCase = true)
|
model("quickfix/replaceWithSafeCall", pattern = pattern, filenameStartsLowerCase = true)
|
||||||
model("quickfix/variables/changeMutability", pattern = pattern, filenameStartsLowerCase = true)
|
model("quickfix/variables/changeMutability", pattern = pattern, filenameStartsLowerCase = true)
|
||||||
model("quickfix/addInitializer", pattern = pattern, filenameStartsLowerCase = true)
|
model("quickfix/addInitializer", pattern = pattern, filenameStartsLowerCase = true)
|
||||||
|
model("quickfix/addPropertyAccessors", pattern = pattern, filenameStartsLowerCase = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
testClass<AbstractHLInspectionTest> {
|
testClass<AbstractHLInspectionTest> {
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.intentions.fir
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.intention.PriorityAction
|
||||||
|
import com.intellij.openapi.util.TextRange
|
||||||
|
import org.jetbrains.kotlin.idea.intentions.AbstractAddAccessorsIntention
|
||||||
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
|
|
||||||
|
class AddAccessorsIntention(
|
||||||
|
addGetter: Boolean, addSetter: Boolean,
|
||||||
|
private val priority: PriorityAction.Priority
|
||||||
|
) :
|
||||||
|
AbstractAddAccessorsIntention(addGetter, addSetter), PriorityAction {
|
||||||
|
// FE1.0 logic in org.jetbrains.kotlin.idea.intentions.AddAccessorsIntention has additional defensive checks to ensure the
|
||||||
|
// intention only shows up if the property in question indeed needs initialization or accessors. Those checks are unnecessary
|
||||||
|
// since this factory is coupled with MUST_BE_INITIALIZED_OR_BE_ABSTRACT diagnostic, which has already checked the applicability
|
||||||
|
// of this intention.
|
||||||
|
override fun applicabilityRange(element: KtProperty): TextRange? = element.textRange
|
||||||
|
|
||||||
|
override fun getPriority(): PriorityAction.Priority = priority
|
||||||
|
}
|
||||||
@@ -9,10 +9,8 @@ import org.jetbrains.kotlin.idea.fir.api.fixes.KtQuickFixRegistrar
|
|||||||
import org.jetbrains.kotlin.idea.fir.api.fixes.KtQuickFixesList
|
import org.jetbrains.kotlin.idea.fir.api.fixes.KtQuickFixesList
|
||||||
import org.jetbrains.kotlin.idea.fir.api.fixes.KtQuickFixesListBuilder
|
import org.jetbrains.kotlin.idea.fir.api.fixes.KtQuickFixesListBuilder
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KtFirDiagnostic
|
import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KtFirDiagnostic
|
||||||
import org.jetbrains.kotlin.idea.quickfix.fixes.AddLateInitFactory
|
import org.jetbrains.kotlin.idea.quickfix.fixes.*
|
||||||
import org.jetbrains.kotlin.idea.quickfix.fixes.ChangeTypeQuickFix
|
|
||||||
import org.jetbrains.kotlin.idea.quickfix.fixes.InitializePropertyQuickFixFactory
|
import org.jetbrains.kotlin.idea.quickfix.fixes.InitializePropertyQuickFixFactory
|
||||||
import org.jetbrains.kotlin.idea.quickfix.fixes.ReplaceCallFixFactories
|
|
||||||
|
|
||||||
class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
|
class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
|
||||||
private val modifiers = KtQuickFixesListBuilder.registerPsiQuickFix {
|
private val modifiers = KtQuickFixesListBuilder.registerPsiQuickFix {
|
||||||
@@ -65,6 +63,7 @@ class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
|
|||||||
)
|
)
|
||||||
registerApplicator(InitializePropertyQuickFixFactory.initializePropertyFactory)
|
registerApplicator(InitializePropertyQuickFixFactory.initializePropertyFactory)
|
||||||
registerApplicator(AddLateInitFactory.addLateInitFactory)
|
registerApplicator(AddLateInitFactory.addLateInitFactory)
|
||||||
|
registerApplicator(AddAccessorsFactories.addAccessorsToUninitializedProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val overrides = KtQuickFixesListBuilder.registerPsiQuickFix {
|
private val overrides = KtQuickFixesListBuilder.registerPsiQuickFix {
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.fixes
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.intention.PriorityAction
|
||||||
|
import org.jetbrains.kotlin.idea.fir.api.fixes.diagnosticFixFactory
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KtFirDiagnostic
|
||||||
|
import org.jetbrains.kotlin.idea.intentions.fir.AddAccessorsIntention
|
||||||
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
|
|
||||||
|
object AddAccessorsFactories {
|
||||||
|
val addAccessorsToUninitializedProperty = diagnosticFixFactory<KtFirDiagnostic.MustBeInitializedOrBeAbstract> { diagnostic ->
|
||||||
|
val property: KtProperty = diagnostic.psi
|
||||||
|
val addGetter = property.getter == null
|
||||||
|
val addSetter = property.isVar && property.setter == null
|
||||||
|
if (!addGetter && !addSetter) return@diagnosticFixFactory emptyList()
|
||||||
|
|
||||||
|
listOf(
|
||||||
|
AddAccessorsIntention(
|
||||||
|
addGetter,
|
||||||
|
addSetter,
|
||||||
|
if (addGetter && addSetter) PriorityAction.Priority.LOW else PriorityAction.Priority.NORMAL
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,8 +13,6 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
|||||||
import org.jetbrains.kotlin.psi.KtProperty
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
|
|
||||||
object AddLateInitFactory {
|
object AddLateInitFactory {
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
|
||||||
val addLateInitFactory = diagnosticFixFactory<KtFirDiagnostic.MustBeInitializedOrBeAbstract> { diagnostic ->
|
val addLateInitFactory = diagnosticFixFactory<KtFirDiagnostic.MustBeInitializedOrBeAbstract> { diagnostic ->
|
||||||
val property: KtProperty = diagnostic.psi
|
val property: KtProperty = diagnostic.psi
|
||||||
if (!property.isVar) return@diagnosticFixFactory emptyList()
|
if (!property.isVar) return@diagnosticFixFactory emptyList()
|
||||||
|
|||||||
Generated
+33
@@ -1230,4 +1230,37 @@ public class HighLevelQuickFixTestGenerated extends AbstractHighLevelQuickFixTes
|
|||||||
runTest("idea/testData/quickfix/addInitializer/topLevelPropertyWithGetter.kt");
|
runTest("idea/testData/quickfix/addInitializer/topLevelPropertyWithGetter.kt");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("idea/testData/quickfix/addPropertyAccessors")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class AddPropertyAccessors extends AbstractHighLevelQuickFixTest {
|
||||||
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
|
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllFilesPresentInAddPropertyAccessors() throws Exception {
|
||||||
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/addPropertyAccessors"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("val.kt")
|
||||||
|
public void testVal() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/addPropertyAccessors/val.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("var.kt")
|
||||||
|
public void testVar() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/addPropertyAccessors/var.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("varHasGetter.kt")
|
||||||
|
public void testVarHasGetter() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("varHasSetter.kt")
|
||||||
|
public void testVarHasSetter() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ val KtType.isChar: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.CH
|
|||||||
val KtType.isBoolean: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.BOOLEAN)
|
val KtType.isBoolean: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.BOOLEAN)
|
||||||
val KtType.isString: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.STRING)
|
val KtType.isString: Boolean get() = isClassTypeWithClassId(DefaultTypeClassIds.STRING)
|
||||||
|
|
||||||
|
val KtType.isUInt: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uInt)
|
||||||
|
val KtType.isULong: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uLong)
|
||||||
|
val KtType.isUShort: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uShort)
|
||||||
|
val KtType.isUByte: Boolean get() = isClassTypeWithClassId(StandardNames.FqNames.uByte)
|
||||||
|
|
||||||
|
|
||||||
fun KtType.isClassTypeWithClassId(classId: ClassId): Boolean {
|
fun KtType.isClassTypeWithClassId(classId: ClassId): Boolean {
|
||||||
if (this !is KtClassType) return false
|
if (this !is KtClassType) return false
|
||||||
@@ -57,5 +62,9 @@ val KtType.defaultInitializer: String?
|
|||||||
isBoolean -> "false"
|
isBoolean -> "false"
|
||||||
isUnit -> "Unit"
|
isUnit -> "Unit"
|
||||||
isString -> "\"\""
|
isString -> "\"\""
|
||||||
|
isUInt -> "0.toUInt()"
|
||||||
|
isULong -> "0.toULong()"
|
||||||
|
isUShort -> "0.toUShort()"
|
||||||
|
isUByte -> "0.toUByte()"
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
* Copyright 2010-2021 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.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ class Test {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* IGNORE_FIR */
|
||||||
|
|||||||
@@ -6,3 +6,4 @@ class Test {
|
|||||||
}
|
}
|
||||||
set(value) {<caret>}
|
set(value) {<caret>}
|
||||||
}
|
}
|
||||||
|
/* IGNORE_FIR */
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ class Test {
|
|||||||
var x: Int<caret>
|
var x: Int<caret>
|
||||||
set(value) {}
|
set(value) {}
|
||||||
}
|
}
|
||||||
|
/* IGNORE_FIR */
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ class Test {
|
|||||||
}
|
}
|
||||||
set(value) {}
|
set(value) {}
|
||||||
}
|
}
|
||||||
|
/* IGNORE_FIR */
|
||||||
|
|||||||
Reference in New Issue
Block a user