Introduce QuickFixesPsiBasedFactory for quickfixes which can be created only by PSI
This commit is contained in:
@@ -23,8 +23,8 @@ class QuickFixes {
|
||||
Extensions.getExtensions(QuickFixContributor.EP_NAME).forEach { it.registerQuickFixes(this) }
|
||||
}
|
||||
|
||||
fun register(diagnosticFactory: DiagnosticFactory<*>, vararg factory: KotlinIntentionActionsFactory) {
|
||||
factories.putAll(diagnosticFactory, factory.toList())
|
||||
fun register(diagnosticFactory: DiagnosticFactory<*>, vararg factory: QuickFixFactory) {
|
||||
factories.putAll(diagnosticFactory, factory.map { it.asKotlinIntentionActionsFactory() })
|
||||
}
|
||||
|
||||
fun register(diagnosticFactory: DiagnosticFactory<*>, vararg action: IntentionAction) {
|
||||
|
||||
+3
-1
@@ -9,7 +9,9 @@ import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.psi.KtCodeFragment
|
||||
|
||||
abstract class KotlinIntentionActionsFactory: QuickFixFactory {
|
||||
abstract class KotlinIntentionActionsFactory : QuickFixFactory {
|
||||
override fun asKotlinIntentionActionsFactory(): KotlinIntentionActionsFactory = this
|
||||
|
||||
protected open fun isApplicableForCodeFragment(): Boolean = false
|
||||
|
||||
protected abstract fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction>
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
|
||||
fun interface PsiElementSuitabilityChecker<in PSI: PsiElement> {
|
||||
fun isSupported(psiElement: PSI): Boolean
|
||||
}
|
||||
|
||||
object PsiElementSuitabilityCheckers {
|
||||
val ALWAYS_SUITABLE = PsiElementSuitabilityChecker<PsiElement> { true }
|
||||
|
||||
val MODIFIER = PsiElementSuitabilityChecker<LeafPsiElement> { psiElement ->
|
||||
psiElement.elementType is KtModifierKeywordToken
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
interface QuickFixFactory {
|
||||
fun asKotlinIntentionActionsFactory(): KotlinIntentionActionsFactory
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
|
||||
abstract class QuickFixesPsiBasedFactory<PSI : PsiElement>(
|
||||
private val classTag: KClass<PSI>,
|
||||
private val suitabilityChecker: PsiElementSuitabilityChecker<PSI>,
|
||||
) : QuickFixFactory {
|
||||
final override fun asKotlinIntentionActionsFactory(): KotlinIntentionActionsFactory =
|
||||
object : KotlinIntentionActionsFactory() {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||
val psiElement = diagnostic.psiElement as PSI
|
||||
return createQuickFix(psiElement)
|
||||
}
|
||||
}
|
||||
|
||||
fun createQuickFix(psiElement: PsiElement): List<IntentionAction> {
|
||||
checkIfPsiElementIsSupported(psiElement)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return doCreateQuickFix(psiElement as PSI)
|
||||
}
|
||||
|
||||
private fun checkIfPsiElementIsSupported(psiElement: PsiElement) {
|
||||
if (!psiElement::class.isSubclassOf(classTag)) {
|
||||
throw InvalidPsiElementTypeException(
|
||||
expectedPsiType = psiElement::class,
|
||||
actualPsiType = classTag,
|
||||
factoryName = this::class.toString()
|
||||
)
|
||||
}
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
if (!suitabilityChecker.isSupported(psiElement as PSI)) {
|
||||
throw UnsupportedPsiElementException(psiElement, this::class.toString())
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract fun doCreateQuickFix(psiElement: PSI): List<IntentionAction>
|
||||
}
|
||||
|
||||
inline fun <reified PSI : PsiElement> quickFixesPsiBasedFactory(
|
||||
suitabilityChecker: PsiElementSuitabilityChecker<PSI> = PsiElementSuitabilityCheckers.ALWAYS_SUITABLE,
|
||||
crossinline createQuickFix: (PSI) -> List<IntentionAction>,
|
||||
) = object : QuickFixesPsiBasedFactory<PSI>(PSI::class, suitabilityChecker) {
|
||||
override fun doCreateQuickFix(psiElement: PSI): List<IntentionAction> = createQuickFix(psiElement)
|
||||
}
|
||||
|
||||
inline fun <reified PSI : PsiElement, reified PSI2 : PsiElement> QuickFixesPsiBasedFactory<PSI>.coMap(
|
||||
suitabilityChecker: PsiElementSuitabilityChecker<PSI2> = PsiElementSuitabilityCheckers.ALWAYS_SUITABLE,
|
||||
crossinline map: (PSI2) -> PSI?
|
||||
) = quickFixesPsiBasedFactory(suitabilityChecker) { psiElement ->
|
||||
val newPsi = map(psiElement) ?: return@quickFixesPsiBasedFactory emptyList()
|
||||
createQuickFix(newPsi)
|
||||
}
|
||||
|
||||
|
||||
class InvalidPsiElementTypeException(
|
||||
expectedPsiType: KClass<out PsiElement>,
|
||||
actualPsiType: KClass<out PsiElement>,
|
||||
factoryName: String,
|
||||
) : Exception("PsiElement with type $expectedPsiType is expected but $actualPsiType found for $factoryName")
|
||||
|
||||
|
||||
class UnsupportedPsiElementException(
|
||||
psiElement: PsiElement,
|
||||
factoryName: String
|
||||
) : Exception("PsiElement $psiElement is unsopported for $factoryName")
|
||||
@@ -104,7 +104,9 @@ object J2KPostProcessingRegistrarImpl : J2KPostProcessingRegistrar {
|
||||
}
|
||||
|
||||
registerDiagnosticBasedProcessing<KtTypeProjection>(Errors.REDUNDANT_PROJECTION) { _, diagnostic ->
|
||||
val fix = RemoveModifierFix.createRemoveProjectionFactory(true).createActions(diagnostic).single() as RemoveModifierFix
|
||||
val fix = RemoveModifierFix.createRemoveProjectionFactory(true)
|
||||
.asKotlinIntentionActionsFactory()
|
||||
.createActions(diagnostic).single() as RemoveModifierFix
|
||||
fix.invoke()
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ import org.jetbrains.kotlin.resolve.konan.diagnostics.ErrorsNative.THROWS_LIST_E
|
||||
|
||||
class QuickFixRegistrar : QuickFixContributor {
|
||||
override fun registerQuickFixes(quickFixes: QuickFixes) {
|
||||
fun DiagnosticFactory<*>.registerFactory(vararg factory: KotlinIntentionActionsFactory) {
|
||||
fun DiagnosticFactory<*>.registerFactory(vararg factory: QuickFixFactory) {
|
||||
quickFixes.register(this, *factory)
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.idea.core.util.range
|
||||
import org.jetbrains.kotlin.idea.quickfix.AddExclExclCallFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.idea.quickfix.QuickFixFactory
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.nj2k.NewJ2kConverterContext
|
||||
@@ -86,11 +87,12 @@ inline fun <reified T : PsiElement> diagnosticBasedProcessing(
|
||||
}
|
||||
}
|
||||
|
||||
fun diagnosticBasedProcessing(fixFactory: KotlinIntentionActionsFactory, vararg diagnosticFactory: DiagnosticFactory<*>) =
|
||||
fun diagnosticBasedProcessing(fixFactory: QuickFixFactory, vararg diagnosticFactory: DiagnosticFactory<*>) =
|
||||
object : DiagnosticBasedProcessing {
|
||||
override val diagnosticFactories = diagnosticFactory.toList()
|
||||
override fun fix(diagnostic: Diagnostic) {
|
||||
val fix = runReadAction { fixFactory.createActions(diagnostic).singleOrNull() } ?: return
|
||||
val actionFactory = fixFactory.asKotlinIntentionActionsFactory()
|
||||
val fix = runReadAction { actionFactory.createActions(diagnostic).singleOrNull() } ?: return
|
||||
runUndoTransparentActionInEdt(inWriteAction = true) {
|
||||
fix.invoke(diagnostic.psiElement.project, null, diagnostic.psiFile)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user