[kotlin] KTIJ-29028 KotlinApplicatorBasedModCommand, ModCommandBased.ModCommandBased totally replaced with KotlinModCommandAction

GitOrigin-RevId: 17b58dfe86dcf66b10379588a0368c2eb730d988
This commit is contained in:
andrew.kozlov
2024-03-11 21:45:05 +01:00
committed by intellij-monorepo-bot
parent ede7bd81c2
commit 973c16e195
130 changed files with 575 additions and 511 deletions

View File

@@ -1,16 +1,13 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.codeinsight.api.applicators
import com.intellij.codeInsight.intention.FileModifier
import com.intellij.codeInspection.util.IntentionFamilyName
import com.intellij.codeInspection.util.IntentionName
import com.intellij.modcommand.ActionContext
import com.intellij.modcommand.ModPsiUpdater
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
/**
* Applies a fix to the PSI, used as intention/inspection/quickfix action
@@ -60,23 +57,4 @@ sealed interface KotlinApplicator<in PSI : PsiElement, in INPUT : KotlinApplicat
fun startInWriteAction(): Boolean = true
}
interface ModCommandBased<in PSI : PsiElement, in INPUT : KotlinApplicatorInput> : KotlinApplicator<PSI, INPUT> {
/**
* Applies some fix to given [psi], cannot use resolve, so all needed data should be precalculated and stored in [input]
*
* To be invoked on a background thread only.
*
* @param psi a non-physical [PsiElement] to apply fix to
* @param input additional data needed to apply the fix
*/
@RequiresBackgroundThread
fun applyTo(
psi: PSI,
input: INPUT,
context: ActionContext,
updater: ModPsiUpdater,
)
}
}

View File

@@ -1,34 +0,0 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes
import com.intellij.codeInsight.intention.FileModifier
import com.intellij.modcommand.ActionContext
import com.intellij.modcommand.ModPsiUpdater
import com.intellij.modcommand.Presentation
import com.intellij.modcommand.PsiUpdateModCommandAction
import com.intellij.openapi.diagnostic.ReportingClassSubstitutor
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.KotlinApplicator
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.KotlinApplicatorInput
class KotlinApplicatorBasedModCommand<PSI : PsiElement, in INPUT : KotlinApplicatorInput>(
target: PSI,
@FileModifier.SafeFieldForPreview
private val input: INPUT,
@FileModifier.SafeFieldForPreview
private val applicator: KotlinApplicator.ModCommandBased<PSI, INPUT>,
) : PsiUpdateModCommandAction<PSI>(target),
ReportingClassSubstitutor {
override fun getFamilyName(): String =
applicator.getFamilyName()
override fun getPresentation(context: ActionContext, element: PSI): Presentation =
Presentation.of(applicator.getActionName(element, input))
override fun invoke(context: ActionContext, element: PSI, updater: ModPsiUpdater) {
applicator.applyTo(element, input, context, updater)
}
override fun getSubstitutedClass(): Class<*> = applicator.javaClass
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes
@@ -45,7 +45,7 @@ class KotlinApplicatorBasedQuickFix<PSI : PsiElement, in INPUT : KotlinApplicato
return if (input.isValidFor(element)) {
applicator.getActionName(element, input)
} else {
applicator.getFamilyName()
familyName
}
}

View File

@@ -1,10 +1,11 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.KotlinApplicatorInput
@Deprecated("To be totally replaced with actual Intentions/ModCommandActions")
class KotlinApplicatorTargetWithInput<PSI : PsiElement, INPUT : KotlinApplicatorInput>(
val target: PSI,
val input: INPUT,

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes
@@ -23,11 +23,15 @@ sealed class KotlinDiagnosticFixFactory<DIAGNOSTIC : KtDiagnosticWithPsi<*>> {
abstract val diagnosticClass: KClass<DIAGNOSTIC>
}
sealed class KotlinDiagnosticModCommandFixFactory<DIAGNOSTIC : KtDiagnosticWithPsi<*>> {
context(KtAnalysisSession)
abstract fun createModCommandQuickFixes(diagnostic: DIAGNOSTIC): List<ModCommandAction>
// todo make fun interface
// todo common base interface
// todo add second type argument
interface KotlinDiagnosticModCommandFixFactory<DIAGNOSTIC : KtDiagnosticWithPsi<*>> {
abstract val diagnosticClass: KClass<DIAGNOSTIC>
context(KtAnalysisSession)
fun createModCommandQuickFixes(diagnostic: DIAGNOSTIC): List<ModCommandAction>
val diagnosticClass: KClass<DIAGNOSTIC> // todo to be extracted
}
private class KotlinDiagnosticFixFactoryWithFixedApplicator<DIAGNOSTIC : KtDiagnosticWithPsi<*>, TARGET_PSI : PsiElement, INPUT : KotlinApplicatorInput>(
@@ -51,29 +55,6 @@ private class KotlinDiagnosticFixFactoryUsingQuickFixActionBase<DIAGNOSTIC : KtD
}
}
private class KotlinDiagnosticModCommandFixFactoryUsingModCommands<DIAGNOSTIC : KtDiagnosticWithPsi<*>>(
override val diagnosticClass: KClass<DIAGNOSTIC>,
private val createQuickFixes: context(KtAnalysisSession)(DIAGNOSTIC) -> List<ModCommandAction>
) : KotlinDiagnosticModCommandFixFactory<DIAGNOSTIC>() {
context(KtAnalysisSession)
override fun createModCommandQuickFixes(diagnostic: DIAGNOSTIC): List<ModCommandAction> {
return createQuickFixes.invoke(this@KtAnalysisSession, diagnostic)
}
}
private class KotlinDiagnosticModCommandFixFactoryWithFixedApplicator<DIAGNOSTIC : KtDiagnosticWithPsi<*>, TARGET_PSI : PsiElement, INPUT : KotlinApplicatorInput>(
override val diagnosticClass: KClass<DIAGNOSTIC>,
private val applicator: KotlinApplicator.ModCommandBased<TARGET_PSI, INPUT>,
private val createTargets: context(KtAnalysisSession)(DIAGNOSTIC) -> List<KotlinApplicatorTargetWithInput<TARGET_PSI, INPUT>>,
) : KotlinDiagnosticModCommandFixFactory<DIAGNOSTIC>() {
context(KtAnalysisSession)
override fun createModCommandQuickFixes(diagnostic: DIAGNOSTIC): List<ModCommandAction> =
createTargets.invoke(this@KtAnalysisSession, diagnostic)
.map { (target, input) -> KotlinApplicatorBasedModCommand(target, input, applicator) }
}
context(KtAnalysisSession)
internal fun <DIAGNOSTIC : KtDiagnosticWithPsi<PsiElement>> createPlatformQuickFixes(
diagnostic: DIAGNOSTIC,
@@ -97,17 +78,6 @@ fun <DIAGNOSTIC : KtDiagnosticWithPsi<*>, TARGET_PSI : PsiElement, INPUT : Kotli
): KotlinDiagnosticFixFactory<DIAGNOSTIC> =
KotlinDiagnosticFixFactoryWithFixedApplicator(diagnosticClass, applicator, createTargets)
/**
* Returns a [KotlinDiagnosticModCommandFixFactory] that creates targets and inputs ([KotlinApplicatorTargetWithInput]) from a diagnostic.
* The targets and inputs are consumed by the given applicator to apply fixes.
*/
fun <DIAGNOSTIC : KtDiagnosticWithPsi<*>, TARGET_PSI : PsiElement, INPUT : KotlinApplicatorInput> diagnosticModCommandFixFactory(
diagnosticClass: KClass<DIAGNOSTIC>,
applicator: KotlinApplicator.ModCommandBased<TARGET_PSI, INPUT>,
createTargets: context(KtAnalysisSession)(DIAGNOSTIC) -> List<KotlinApplicatorTargetWithInput<TARGET_PSI, INPUT>>
): KotlinDiagnosticModCommandFixFactory<DIAGNOSTIC> =
KotlinDiagnosticModCommandFixFactoryWithFixedApplicator(diagnosticClass, applicator, createTargets)
/**
* Returns a [KotlinDiagnosticFixFactory] that creates [QuickFixActionBase]s from a diagnostic.
*/
@@ -130,21 +100,16 @@ fun <DIAGNOSTIC_PSI : PsiElement, DIAGNOSTIC : KtDiagnosticWithPsi<DIAGNOSTIC_PS
/**
* Returns a [KotlinDiagnosticModCommandFixFactory] that creates [ModCommandAction]s from a diagnostic.
*/
fun <DIAGNOSTIC : KtDiagnosticWithPsi<*>> diagnosticModCommandFixFactory(
diagnosticClass: KClass<DIAGNOSTIC>,
createQuickFixes: context(KtAnalysisSession)(DIAGNOSTIC) -> List<ModCommandAction>
): KotlinDiagnosticModCommandFixFactory<DIAGNOSTIC> =
KotlinDiagnosticModCommandFixFactoryUsingModCommands(diagnosticClass, createQuickFixes)
// todo to be inlined as Kotlin...Factory { ... }
inline fun <reified TARGET_PSI : PsiElement, reified DIAGNOSTIC : KtDiagnosticWithPsi<TARGET_PSI>> diagnosticModCommandFixFactory(
crossinline createTargets: context(KtAnalysisSession)(DIAGNOSTIC) -> List<ModCommandAction>,
): KotlinDiagnosticModCommandFixFactory<DIAGNOSTIC> = object : KotlinDiagnosticModCommandFixFactory<DIAGNOSTIC> {
/**
* Returns a [Collection] of [KotlinDiagnosticModCommandFixFactory] that creates [ModCommandAction]s from a diagnostic that
* have the same type of [PsiElement].
*/
fun <DIAGNOSTIC : KtDiagnosticWithPsi<*>> diagnosticModCommandFixFactories(
vararg diagnosticClasses: KClass<out DIAGNOSTIC>,
createQuickFixes: context(KtAnalysisSession)(DIAGNOSTIC) -> List<ModCommandAction>
): Collection<KotlinDiagnosticModCommandFixFactory<out DIAGNOSTIC>> =
diagnosticClasses.map { KotlinDiagnosticModCommandFixFactoryUsingModCommands(it, createQuickFixes) }
override val diagnosticClass: KClass<DIAGNOSTIC> get() = DIAGNOSTIC::class
context(KtAnalysisSession)
override fun createModCommandQuickFixes(diagnostic: DIAGNOSTIC): List<ModCommandAction> = createTargets(analysisSession, diagnostic)
}
/**
* Returns a [KotlinDiagnosticFixFactory] that creates [IntentionAction]s from a diagnostic.

View File

@@ -0,0 +1,70 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes
import com.intellij.codeInsight.intention.FileModifier
import com.intellij.codeInspection.util.IntentionName
import com.intellij.modcommand.*
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.psi.PsiElement
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
abstract class KotlinModCommandAction<E : PsiElement, C : KotlinModCommandAction.ElementContext>(
element: E,
@FileModifier.SafeFieldForPreview private val elementContext: C,
) : PsiBasedModCommandAction<E>(element) {
interface ElementContext {
fun isValid(context: ActionContext): Boolean = true
}
/**
* @see [PsiUpdateModCommandAction.perform]
*/
@RequiresBackgroundThread
final override fun perform(
context: ActionContext,
element: E,
): ModCommand = try {
val input = getElementContext(context)
if (input != null) {
ModCommand.psiUpdate(element) { e, updater ->
invoke(context, e, input, updater)
}
} else {
ModNothing.NOTHING
}
} catch (e: ProcessCanceledException) {
throw e
} catch (e: RuntimeException) {
throw RuntimeException("When launching $familyName (${javaClass.name})", e)
}
/**
* @see [PsiUpdateModCommandAction.invoke]
*/
@RequiresBackgroundThread
protected abstract fun invoke(
context: ActionContext,
element: E,
elementContext: C,
updater: ModPsiUpdater,
)
protected open fun getActionName(
context: ActionContext,
element: E,
elementContext: C,
): @IntentionName String = familyName
override fun getPresentation(
context: ActionContext,
element: E,
): Presentation? = getElementContext(context)
?.let { getActionName(context, element, it) }
?.let { Presentation.of(it) }
private fun getElementContext(context: ActionContext): C? = elementContext
.takeIf { it.isValid(context) }
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes
@@ -101,12 +101,6 @@ class KtQuickFixesListBuilder private constructor() {
quickFixFactories.forEach(::registerApplicator)
}
fun <DIAGNOSTIC : KtDiagnosticWithPsi<*>> registerModCommandApplicators(
quickFixFactories: Collection<KotlinDiagnosticModCommandFixFactory<out DIAGNOSTIC>>
) {
quickFixFactories.forEach(::registerApplicator)
}
@OptIn(PrivateForInline::class)
fun <DIAGNOSTIC : KtDiagnosticWithPsi<*>> registerApplicator(
quickFixFactory: KotlinDiagnosticFixFactory<out DIAGNOSTIC>