FIR IDE: Add quickfix for INAPPLICABLE_LATEINIT_MODIFIER.

Also changed FE1.0 checker and all related fix factories to report error
on the declaration instead of the lateinit modifier. This is consistent
with the direction of all checkers in FIR (no reporting on modifiers).
This commit is contained in:
Mark Punzalan
2021-02-12 21:56:39 +00:00
committed by Ilya Kirillov
parent b1ab64e854
commit 4e44804c77
18 changed files with 78 additions and 32 deletions
@@ -37,6 +37,7 @@ class MainKtQuickFixRegistrar : KtQuickFixRegistrar() {
private val mutability = KtQuickFixesListBuilder.registerPsiQuickFix {
registerPsiQuickFix<PsiElement, KtFirDiagnostic.VarOverriddenByVal>(ChangeVariableMutabilityFix.VAR_OVERRIDDEN_BY_VAL_FACTORY)
registerPsiQuickFix<KtModifierListOwner, KtFirDiagnostic.InapplicableLateinitModifier>(ChangeVariableMutabilityFix.LATEINIT_VAL_FACTORY)
}
override val list: KtQuickFixesList = KtQuickFixesList.createCombined(
@@ -19,6 +19,49 @@ import java.util.regex.Pattern;
@SuppressWarnings("all")
@RunWith(JUnit3RunnerWithInners.class)
public class HighLevelQuickFixTestGenerated extends AbstractHighLevelQuickFixTest {
@TestMetadata("idea/testData/quickfix/lateinit")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Lateinit extends AbstractHighLevelQuickFixTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInLateinit() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/lateinit"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
}
@TestMetadata("nullable.kt")
public void testNullable() throws Exception {
runTest("idea/testData/quickfix/lateinit/nullable.kt");
}
@TestMetadata("val.kt")
public void testVal() throws Exception {
runTest("idea/testData/quickfix/lateinit/val.kt");
}
@TestMetadata("withGetter.kt")
public void testWithGetter() throws Exception {
runTest("idea/testData/quickfix/lateinit/withGetter.kt");
}
@TestMetadata("withGetterSetter.kt")
public void testWithGetterSetter() throws Exception {
runTest("idea/testData/quickfix/lateinit/withGetterSetter.kt");
}
@TestMetadata("withInitializer.kt")
public void testWithInitializer() throws Exception {
runTest("idea/testData/quickfix/lateinit/withInitializer.kt");
}
@TestMetadata("withSetter.kt")
public void testWithSetter() throws Exception {
runTest("idea/testData/quickfix/lateinit/withSetter.kt");
}
}
@TestMetadata("idea/testData/quickfix/modifiers")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -372,7 +372,7 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val candidate: KtSymbol
}
abstract class InapplicableLateinitModifier : KtFirDiagnostic<PsiElement>() {
abstract class InapplicableLateinitModifier : KtFirDiagnostic<KtModifierListOwner>() {
override val diagnosticClass get() = InapplicableLateinitModifier::class
abstract val reason: String
}
@@ -596,7 +596,7 @@ internal class InapplicableLateinitModifierImpl(
override val reason: String,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.InapplicableLateinitModifier(), KtAbstractFirDiagnostic<PsiElement> {
) : KtFirDiagnostic.InapplicableLateinitModifier(), KtAbstractFirDiagnostic<KtModifierListOwner> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
@@ -64,9 +64,9 @@ class ChangeVariableMutabilityFix(
listOf(ChangeVariableMutabilityFix(psiElement, false))
}
val LATEINIT_VAL_FACTORY: QuickFixesPsiBasedFactory<PsiElement> =
quickFixesPsiBasedFactory { psiElement: PsiElement ->
val property = psiElement.getStrictParentOfType<KtProperty>() ?: return@quickFixesPsiBasedFactory emptyList()
val LATEINIT_VAL_FACTORY: QuickFixesPsiBasedFactory<KtModifierListOwner> =
quickFixesPsiBasedFactory { psiElement: KtModifierListOwner ->
val property = psiElement as? KtProperty ?: return@quickFixesPsiBasedFactory emptyList()
if (property.valOrVarKeyword.text != "val") {
emptyList()
} else {
@@ -121,8 +121,7 @@ class RemoveModifierFix(
fun createRemoveLateinitFactory(): QuickFixesPsiBasedFactory<PsiElement> {
return quickFixesPsiBasedFactory { psiElement: PsiElement ->
val modifierList = psiElement.parent as? KtDeclarationModifierList ?: return@quickFixesPsiBasedFactory emptyList()
val property = modifierList.parent as? KtProperty ?: return@quickFixesPsiBasedFactory emptyList()
val property = psiElement as? KtProperty ?: return@quickFixesPsiBasedFactory emptyList()
if (!property.hasModifier(KtTokens.LATEINIT_KEYWORD)) return@quickFixesPsiBasedFactory emptyList()
listOf(RemoveModifierFix(property, KtTokens.LATEINIT_KEYWORD, isRedundant = false))
}
@@ -40,8 +40,7 @@ class ConvertLateinitPropertyToNotNullDelegateFix(
companion object : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtProperty>? {
val modifierList = diagnostic.psiElement.parent as? KtDeclarationModifierList ?: return null
val property = modifierList.parent as? KtProperty ?: return null
val property = diagnostic.psiElement as? KtProperty ?: return null
if (!property.hasModifier(KtTokens.LATEINIT_KEYWORD) || !property.isVar || property.hasInitializer()) return null
val typeReference = property.typeReference ?: return null
val type = property.analyze(BodyResolveMode.PARTIAL)[BindingContext.TYPE, typeReference] ?: return null
@@ -58,8 +58,7 @@ class RemoveNullableFix(
object LATEINIT_FACTORY : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtNullableType>? {
val lateinitElement = Errors.INAPPLICABLE_LATEINIT_MODIFIER.cast(diagnostic).psiElement
val property = lateinitElement.getStrictParentOfType<KtProperty>() ?: return null
val property = Errors.INAPPLICABLE_LATEINIT_MODIFIER.cast(diagnostic).psiElement as? KtProperty ?: return null
val typeReference = property.typeReference ?: return null
val typeElement = (typeReference.typeElement ?: return null) as? KtNullableType ?: return null
if (typeElement.innerType == null) return null
@@ -118,8 +118,7 @@ open class RemovePartsFromPropertyFix(
object LateInitFactory : KotlinSingleIntentionActionFactory() {
public override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtProperty>? {
val element = Errors.INAPPLICABLE_LATEINIT_MODIFIER.cast(diagnostic).psiElement
val property = PsiTreeUtil.getParentOfType(element, KtProperty::class.java) ?: return null
val property = Errors.INAPPLICABLE_LATEINIT_MODIFIER.cast(diagnostic).psiElement as? KtProperty ?: return null
val hasInitializer = property.hasInitializer()
val hasGetter = property.getter?.bodyExpression != null
val hasSetter = property.setter?.bodyExpression != null
@@ -1,3 +1,5 @@
// FIR_COMPARISON
class C<V>() {
<error descr="[INAPPLICABLE_LATEINIT_MODIFIER] 'lateinit' modifier is not allowed on properties of a type with nullable upper bound">lateinit</error> var item: V
}
+2 -1
View File
@@ -2,4 +2,5 @@
class A() {
<caret>lateinit val foo: String
}
}
/* FIR_COMPARISON */
+2 -1
View File
@@ -2,4 +2,5 @@
class A() {
<caret>lateinit var foo: String
}
}
/* FIR_COMPARISON */