FIR IDE: add more KDoc to HLApplicator stuff
This commit is contained in:
@@ -84,6 +84,7 @@ abstract class AbstractHLInspection<PSI : KtElement, INPUT : HLApplicatorInput>(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract val presentation: HLPresentation<PSI>
|
||||
abstract val applicabilityRange: HLApplicabilityRange<PSI>
|
||||
abstract val inputProvider: HLApplicatorInputProvider<PSI, INPUT>
|
||||
@@ -96,7 +97,6 @@ private fun <PSI : PsiElement, INPUT : HLApplicatorInput> HLApplicator<PSI, INPU
|
||||
): LocalQuickFix = object : LocalQuickFix {
|
||||
override fun startInWriteAction() = false
|
||||
|
||||
@OptIn(HackToForceAllowRunningAnalyzeOnEDT::class)
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val element = descriptor.psiElement as PSI
|
||||
|
||||
@@ -13,19 +13,45 @@ import org.jetbrains.kotlin.idea.frontend.api.ForbidKtResolve
|
||||
import kotlin.experimental.ExperimentalTypeInference
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Applies a fix to the PSI, used as intention/inspection/quickfix action
|
||||
* Also, knows if a fix is applicable by [isApplicableByPsi]
|
||||
*
|
||||
* Uses some additional information from [INPUT] to apply the element
|
||||
*/
|
||||
sealed class HLApplicator<in PSI : PsiElement, in INPUT : HLApplicatorInput> {
|
||||
|
||||
/**
|
||||
* Applies some fix to given [psi], can not use resolve, so all needed data should be precalculated and stored in [input]
|
||||
*
|
||||
* @param psi a [PsiElement] to apply fix to
|
||||
* @param input additional data needed to apply the fix, the [input] can be collected by [HLApplicatorInputProvider
|
||||
*/
|
||||
fun applyTo(psi: PSI, input: INPUT, project: Project?, editor: Editor?) = ForbidKtResolve.forbidResolveIn("HLApplicator.applyTo") {
|
||||
applyToImpl(psi, input, project, editor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if applicator is applicable to specific element, can not use resolve inside
|
||||
*/
|
||||
fun isApplicableByPsi(psi: PSI): Boolean = ForbidKtResolve.forbidResolveIn("HLApplicator.isApplicableByPsi") {
|
||||
isApplicableByPsiImpl(psi)
|
||||
}
|
||||
|
||||
/**
|
||||
* Action name which will be as text in inspections/intentions
|
||||
*
|
||||
* @see com.intellij.codeInsight.intention.IntentionAction.getText
|
||||
*/
|
||||
fun getActionName(psi: PSI, input: INPUT): String = ForbidKtResolve.forbidResolveIn("HLApplicator.getActionName") {
|
||||
getActionNameImpl(psi, input)
|
||||
}
|
||||
|
||||
/**
|
||||
* Family name which will be used in inspections/intentions
|
||||
*
|
||||
* @see com.intellij.codeInsight.intention.IntentionAction.getFamilyName
|
||||
*/
|
||||
fun getFamilyName(): String = ForbidKtResolve.forbidResolveIn("HLApplicator.getFamilyName") {
|
||||
getFamilyNameImpl()
|
||||
}
|
||||
@@ -36,6 +62,9 @@ sealed class HLApplicator<in PSI : PsiElement, in INPUT : HLApplicatorInput> {
|
||||
protected abstract fun getFamilyNameImpl(): String
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of an applicator with some components replaced
|
||||
*/
|
||||
fun <PSI : PsiElement, NEW_PSI : PSI, INPUT : HLApplicatorInput> HLApplicator<PSI, INPUT>.with(
|
||||
init: HLApplicatorBuilder<NEW_PSI, INPUT>.(olApplicator: HLApplicator<PSI, INPUT>) -> Unit
|
||||
): HLApplicator<NEW_PSI, INPUT> = when (this@with) {
|
||||
@@ -47,8 +76,12 @@ fun <PSI : PsiElement, NEW_PSI : PSI, INPUT : HLApplicatorInput> HLApplicator<PS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of an applicator with some components replaced
|
||||
* The PSI type of a new applicator will be a class passed in [newPsiTypeTag]
|
||||
*/
|
||||
fun <PSI : PsiElement, NEW_PSI : PSI, INPUT : HLApplicatorInput> HLApplicator<PSI, INPUT>.with(
|
||||
newPsiTypeTag: KClass<NEW_PSI>,
|
||||
@Suppress("UNUSED_PARAMETER") newPsiTypeTag: KClass<NEW_PSI>,
|
||||
init: HLApplicatorBuilder<NEW_PSI, INPUT>.(olApplicator: HLApplicator<PSI, INPUT>) -> Unit
|
||||
): HLApplicator<NEW_PSI, INPUT> = when (this@with) {
|
||||
is HLApplicatorImpl -> {
|
||||
@@ -128,15 +161,31 @@ class HLApplicatorBuilder<PSI : PsiElement, INPUT : HLApplicatorInput> internal
|
||||
|
||||
|
||||
@OptIn(PrivateForInline::class)
|
||||
fun build(): HLApplicator<PSI, INPUT> = HLApplicatorImpl(
|
||||
applyTo = applyTo!!,
|
||||
isApplicableByPsi = isApplicableByPsi ?: { true },
|
||||
getActionName = getActionName ?: getFamilyName?.let { familyName -> { _, _ -> familyName.invoke() } }!!,
|
||||
getFamilyName = getFamilyName!!
|
||||
)
|
||||
fun build(): HLApplicator<PSI, INPUT> {
|
||||
val applyTo = applyTo
|
||||
?: error("Please, specify applyTo")
|
||||
val getActionName = getActionName
|
||||
?: error("Please, specify actionName or familyName via either of: actionName,familyAndActionName")
|
||||
val isApplicableByPsi = isApplicableByPsi ?: { true }
|
||||
val getFamilyName = getFamilyName
|
||||
?: error("Please, specify or familyName via either of: familyName, familyAndActionName")
|
||||
return HLApplicatorImpl(
|
||||
applyTo = applyTo,
|
||||
isApplicableByPsi = isApplicableByPsi,
|
||||
getActionName = getActionName,
|
||||
getFamilyName = getFamilyName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds a new applicator with HLApplicatorBuilder
|
||||
*
|
||||
* Should specify at least applyTo and familyAndActionName
|
||||
*
|
||||
* @see HLApplicatorBuilder
|
||||
*/
|
||||
fun <PSI : PsiElement, INPUT : HLApplicatorInput> applicator(
|
||||
init: HLApplicatorBuilder<PSI, INPUT>.() -> Unit,
|
||||
): HLApplicator<PSI, INPUT> =
|
||||
|
||||
@@ -7,6 +7,20 @@ package org.jetbrains.kotlin.idea.fir.api.applicator
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
|
||||
/**
|
||||
* Data which [HLApplicator] is needed to perform the fix
|
||||
*
|
||||
* Created by [HLApplicatorInputProvider] or via [org.jetbrains.kotlin.idea.fir.api.fixes.HLDiagnosticFixFactory]
|
||||
*
|
||||
* Should not store inside
|
||||
* - Everything that came from [org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession] like :
|
||||
* - [org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol] consider using [org.jetbrains.kotlin.idea.frontend.api.symbols.pointers.KtSymbolPointer] instead
|
||||
* - [org.jetbrains.kotlin.idea.frontend.api.types.KtType]
|
||||
* - [org.jetbrains.kotlin.idea.frontend.api.calls.KtCall]
|
||||
* - [org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession] instance itself
|
||||
* - [PsiElement] consider using [com.intellij.psi.SmartPsiElementPointer] instead
|
||||
*
|
||||
*/
|
||||
interface HLApplicatorInput {
|
||||
fun isValidFor(psi: PsiElement): Boolean = true
|
||||
}
|
||||
|
||||
+11
@@ -8,7 +8,14 @@ package org.jetbrains.kotlin.idea.fir.api.applicator
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||
|
||||
/**
|
||||
* Resolves the code to provide [HLApplicator] some input
|
||||
*/
|
||||
abstract class HLApplicatorInputProvider<PSI : PsiElement, out INPUT : HLApplicatorInput> {
|
||||
/**
|
||||
* Provide input to the applicator, if returns `null` then the applicator is not applicable and will not be called
|
||||
* Guaranteed to be executed from read action, should not be called from EDT thread
|
||||
*/
|
||||
abstract fun KtAnalysisSession.provideInput(element: PSI): INPUT?
|
||||
}
|
||||
|
||||
@@ -18,6 +25,10 @@ private class HLApplicatorInputProviderImpl<PSI : PsiElement, out INPUT : HLAppl
|
||||
override fun KtAnalysisSession.provideInput(element: PSI): INPUT? = provideInput.invoke(this, element)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates [HLApplicatorInputProvider]
|
||||
* The [provideInput] is guaranteed to be executed from read action, should not be called from EDT thread
|
||||
*/
|
||||
fun <PSI : PsiElement, INPUT : HLApplicatorInput> inputProvider(
|
||||
provideInput: KtAnalysisSession.(PSI) -> INPUT?
|
||||
): HLApplicatorInputProvider<PSI, INPUT> =
|
||||
|
||||
@@ -9,7 +9,11 @@ import com.intellij.codeInspection.ProblemHighlightType
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.frontend.api.ForbidKtResolve
|
||||
|
||||
abstract class HLPresentation<PSI : PsiElement> internal constructor() {
|
||||
/**
|
||||
* Provides a presentation to display an message in the editor which may be latter fixed by [HLApplicator]
|
||||
* Used by [org.jetbrains.kotlin.idea.fir.api.AbstractHLInspection] to provide higlighting message and type
|
||||
*/
|
||||
sealed class HLPresentation<PSI : PsiElement> {
|
||||
fun getHighlightType(element: PSI): ProblemHighlightType = ForbidKtResolve.forbidResolveIn("HLPresentation.getHighlightType") {
|
||||
getHighlightTypeImpl(element)
|
||||
}
|
||||
@@ -54,9 +58,13 @@ class HLInspectionPresentationProviderBuilder<PSI : PsiElement> internal constru
|
||||
getMessage = { text }
|
||||
}
|
||||
|
||||
|
||||
internal fun build(): HLPresentation<PSI> =
|
||||
HLPresentationImpl(getHighlightType!!, getMessage!!)
|
||||
internal fun build(): HLPresentation<PSI> {
|
||||
val getHighlightType = getHighlightType
|
||||
?: error("Please, provide highlightType")
|
||||
val getMessage = getMessage
|
||||
?: error("Please, provide getMessage")
|
||||
return HLPresentationImpl(getHighlightType, getMessage)
|
||||
}
|
||||
}
|
||||
|
||||
fun <PSI : PsiElement> presentation(
|
||||
|
||||
+2
-2
@@ -20,11 +20,11 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
|
||||
object CallableReturnTypeUpdaterApplicator {
|
||||
val applicator = applicator<KtCallableDeclaration, Type> {
|
||||
familyName(KotlinBundle.message("fix.change.return.type.family"))
|
||||
familyAndActionName(KotlinBundle.lazyMessage("fix.change.return.type.family"))
|
||||
|
||||
applyTo { declaration, type, project ->
|
||||
val newTypeRef = if (!declaration.isProcedure(type)) {
|
||||
// TODO use longTypeRepresentation and the shorten
|
||||
// TODO use longTypeRepresentation and then shorten
|
||||
KtPsiFactory(project ?: declaration.project).createType(type.shortTypeRepresentation)
|
||||
} else null
|
||||
runWriteAction {
|
||||
|
||||
Reference in New Issue
Block a user