FIR IDE: remove type parameter TARGET_PSI and INPUT

The factory does not need to care about what target PSI and input a
quick fix should need. We only need to ensure these two types match when
an `HLQuickfix` is created. With this constraint loosened, now one
factory can register multiple quickfixes applied on different targets
and different input. This makes it much more flexible when implementing
quickfixes.
This commit is contained in:
Tianyu Geng
2021-03-22 16:56:28 -07:00
committed by Ilya Kirillov
parent a5e445492f
commit 6c52d95342
3 changed files with 20 additions and 20 deletions
@@ -12,28 +12,28 @@ import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnosticWithPsi
sealed class HLDiagnosticFixFactory<DIAGNOSTIC_PSI : PsiElement, in DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>, TARGET_PSI : PsiElement, INPUT : HLApplicatorInput> {
abstract fun KtAnalysisSession.createQuickFixes(diagnostic: DIAGNOSTIC): List<HLQuickFix<TARGET_PSI, INPUT>>
sealed class HLDiagnosticFixFactory<DIAGNOSTIC_PSI : PsiElement, in DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>> {
abstract fun KtAnalysisSession.createQuickFixes(diagnostic: DIAGNOSTIC): List<HLQuickFix<*, *>>
}
private class HLDiagnosticFixFactoryWithFixedApplicator<DIAGNOSTIC_PSI : PsiElement, DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>, TARGET_PSI : PsiElement, INPUT : HLApplicatorInput>(
private val applicator: HLApplicator<TARGET_PSI, INPUT>,
private val createTargets: KtAnalysisSession.(DIAGNOSTIC) -> List<HLApplicatorTargetWithInput<TARGET_PSI, INPUT>>
) : HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC, TARGET_PSI, INPUT>() {
) : HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC>() {
override fun KtAnalysisSession.createQuickFixes(diagnostic: DIAGNOSTIC): List<HLQuickFix<TARGET_PSI, INPUT>> =
createTargets.invoke(this, diagnostic).map { (target, input) -> HLQuickFix(target, input, applicator) }
}
private class HLDiagnosticFixFactoryWithVariableApplicator<DIAGNOSTIC_PSI : PsiElement, DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>, TARGET_PSI : PsiElement, INPUT : HLApplicatorInput>(
private val createQuickFixes: KtAnalysisSession.(DIAGNOSTIC) -> List<HLQuickFix<TARGET_PSI, INPUT>>
) : HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC, TARGET_PSI, INPUT>() {
override fun KtAnalysisSession.createQuickFixes(diagnostic: DIAGNOSTIC): List<HLQuickFix<TARGET_PSI, INPUT>> =
private class HLDiagnosticFixFactoryWithVariableApplicator<DIAGNOSTIC_PSI : PsiElement, DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>>(
private val createQuickFixes: KtAnalysisSession.(DIAGNOSTIC) -> List<HLQuickFix<*, *>>
) : HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC>() {
override fun KtAnalysisSession.createQuickFixes(diagnostic: DIAGNOSTIC): List<HLQuickFix<*, *>> =
createQuickFixes.invoke(this, diagnostic)
}
internal fun <DIAGNOSTIC : KtDiagnosticWithPsi<PsiElement>> KtAnalysisSession.createPlatformQuickFixes(
diagnostic: DIAGNOSTIC,
factory: HLDiagnosticFixFactory<PsiElement, DIAGNOSTIC, PsiElement, HLApplicatorInput>
factory: HLDiagnosticFixFactory<PsiElement, DIAGNOSTIC>
): List<IntentionAction> = with(factory) { createQuickFixes(diagnostic) }
/**
@@ -43,13 +43,13 @@ internal fun <DIAGNOSTIC : KtDiagnosticWithPsi<PsiElement>> KtAnalysisSession.cr
fun <DIAGNOSTIC_PSI : PsiElement, DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>, TARGET_PSI : PsiElement, INPUT : HLApplicatorInput> diagnosticFixFactory(
applicator: HLApplicator<TARGET_PSI, INPUT>,
createTargets: KtAnalysisSession.(DIAGNOSTIC) -> List<HLApplicatorTargetWithInput<TARGET_PSI, INPUT>>
): HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC, TARGET_PSI, INPUT> =
): HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC> =
HLDiagnosticFixFactoryWithFixedApplicator(applicator, createTargets)
/**
* Returns a [HLDiagnosticFixFactory] that creates [HLQuickFix]es from a diagnostic.
*/
fun <DIAGNOSTIC_PSI : PsiElement, DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>, TARGET_PSI : PsiElement, INPUT : HLApplicatorInput> diagnosticFixFactory(
createQuickFixes: KtAnalysisSession.(DIAGNOSTIC) -> List<HLQuickFix<TARGET_PSI, INPUT>>
): HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC, TARGET_PSI, INPUT> =
fun <DIAGNOSTIC_PSI : PsiElement, DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>> diagnosticFixFactory(
createQuickFixes: KtAnalysisSession.(DIAGNOSTIC) -> List<HLQuickFix<*, *>>
): HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC> =
HLDiagnosticFixFactoryWithVariableApplicator(createQuickFixes)
@@ -30,7 +30,7 @@ class KtQuickFixesList @ForKtQuickFixesListBuilder @OptIn(PrivateForInline::clas
is HLQuickFixFactory.HLApplicatorBasedFactory -> {
@Suppress("UNCHECKED_CAST")
val factory = quickFixFactory.applicatorFactory
as HLDiagnosticFixFactory<PsiElement, KtDiagnosticWithPsi<PsiElement>, PsiElement, HLApplicatorInput>
as HLDiagnosticFixFactory<PsiElement, KtDiagnosticWithPsi<PsiElement>>
createPlatformQuickFixes(diagnostic, factory)
}
is HLQuickFixFactory.HLQuickFixesPsiBasedFactory -> quickFixFactory.psiFactory.createQuickFix(diagnostic.psi)
@@ -66,8 +66,8 @@ class KtQuickFixesListBuilder private constructor() {
}
@OptIn(PrivateForInline::class)
inline fun <DIAGNOSTIC_PSI : PsiElement, reified DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>, TARGET_PSI : PsiElement, INPUT : HLApplicatorInput> registerApplicator(
quickFixFactory: HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC, TARGET_PSI, INPUT>
inline fun <DIAGNOSTIC_PSI : PsiElement, reified DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>> registerApplicator(
quickFixFactory: HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC>
) {
registerApplicator(DIAGNOSTIC::class, quickFixFactory)
}
@@ -82,9 +82,9 @@ class KtQuickFixesListBuilder private constructor() {
@PrivateForInline
fun <DIAGNOSTIC_PSI : PsiElement, DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>, TARGET_PSI : PsiElement, INPUT : HLApplicatorInput> registerApplicator(
fun <DIAGNOSTIC_PSI : PsiElement, DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PSI>> registerApplicator(
diagnosticClass: KClass<DIAGNOSTIC>,
quickFixFactory: HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC, TARGET_PSI, INPUT>
quickFixFactory: HLDiagnosticFixFactory<DIAGNOSTIC_PSI, DIAGNOSTIC>
) {
quickFixes.getOrPut(diagnosticClass) { mutableListOf() }
.add(HLQuickFixFactory.HLApplicatorBasedFactory(quickFixFactory))
@@ -105,7 +105,7 @@ sealed class HLQuickFixFactory {
) : HLQuickFixFactory()
class HLApplicatorBasedFactory(
val applicatorFactory: HLDiagnosticFixFactory<*, *, *, *>
val applicatorFactory: HLDiagnosticFixFactory<*, *>
) : HLQuickFixFactory()
}
@@ -121,4 +121,4 @@ private fun <K, V> List<Map<K, List<V>>>.merge(): Map<K, List<V>> {
}
@RequiresOptIn
annotation class ForKtQuickFixesListBuilder()
annotation class ForKtQuickFixesListBuilder
@@ -40,7 +40,7 @@ object ReplaceCallFixFactories {
class Input(val notNullNeeded: Boolean) : HLApplicatorInput
val unsafeCallFactory =
diagnosticFixFactory<PsiElement, KtFirDiagnostic.UnsafeCall, KtExpression, Input> { diagnostic ->
diagnosticFixFactory<PsiElement, KtFirDiagnostic.UnsafeCall> { diagnostic ->
fun KtExpression.shouldHaveNotNullType(): Boolean {
// This function is used to determine if we may need to add an elvis operator after the safe call. For example, to replace
// `s.length` in `val x: Int = s.length` with a safe call, it should be replaced with `s.length ?: <caret>`.