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/variables/changeMutability", pattern = pattern, filenameStartsLowerCase = true)
|
||||
model("quickfix/addInitializer", pattern = pattern, filenameStartsLowerCase = true)
|
||||
model("quickfix/addPropertyAccessors", pattern = pattern, filenameStartsLowerCase = true)
|
||||
}
|
||||
|
||||
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.KtQuickFixesListBuilder
|
||||
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.ChangeTypeQuickFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.fixes.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.fixes.InitializePropertyQuickFixFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.fixes.ReplaceCallFixFactories
|
||||
|
||||
class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
|
||||
private val modifiers = KtQuickFixesListBuilder.registerPsiQuickFix {
|
||||
@@ -65,6 +63,7 @@ class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
|
||||
)
|
||||
registerApplicator(InitializePropertyQuickFixFactory.initializePropertyFactory)
|
||||
registerApplicator(AddLateInitFactory.addLateInitFactory)
|
||||
registerApplicator(AddAccessorsFactories.addAccessorsToUninitializedProperty)
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
object AddLateInitFactory {
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
val addLateInitFactory = diagnosticFixFactory<KtFirDiagnostic.MustBeInitializedOrBeAbstract> { diagnostic ->
|
||||
val property: KtProperty = diagnostic.psi
|
||||
if (!property.isVar) return@diagnosticFixFactory emptyList()
|
||||
|
||||
Generated
+33
@@ -1230,4 +1230,37 @@ public class HighLevelQuickFixTestGenerated extends AbstractHighLevelQuickFixTes
|
||||
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.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 {
|
||||
if (this !is KtClassType) return false
|
||||
@@ -57,5 +62,9 @@ val KtType.defaultInitializer: String?
|
||||
isBoolean -> "false"
|
||||
isUnit -> "Unit"
|
||||
isString -> "\"\""
|
||||
isUInt -> "0.toUInt()"
|
||||
isULong -> "0.toULong()"
|
||||
isUShort -> "0.toUShort()"
|
||||
isUByte -> "0.toUByte()"
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
// WITH_RUNTIME
|
||||
class Test {
|
||||
val x: Int<caret>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@ class Test {
|
||||
get() {
|
||||
<caret>TODO()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
// WITH_RUNTIME
|
||||
class Test {
|
||||
var x: Int<caret>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ class Test {
|
||||
<caret>TODO()
|
||||
}
|
||||
set(value) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,5 @@ class Test {
|
||||
get() {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
/* IGNORE_FIR */
|
||||
|
||||
@@ -5,4 +5,5 @@ class Test {
|
||||
return 1
|
||||
}
|
||||
set(value) {<caret>}
|
||||
}
|
||||
}
|
||||
/* IGNORE_FIR */
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
class Test {
|
||||
var x: Int<caret>
|
||||
set(value) {}
|
||||
}
|
||||
}
|
||||
/* IGNORE_FIR */
|
||||
|
||||
@@ -6,4 +6,5 @@ class Test {
|
||||
<caret>TODO()
|
||||
}
|
||||
set(value) {}
|
||||
}
|
||||
}
|
||||
/* IGNORE_FIR */
|
||||
|
||||
Reference in New Issue
Block a user