FIR IDE: forbid resolve in HLApplicator/HLApplicabilityRange/HLPresentation
This commit is contained in:
+7
-2
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.fir.api.applicator
|
||||
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.frontend.api.ForbidKtResolve
|
||||
import org.jetbrains.kotlin.idea.util.textRangeIn
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
|
||||
@@ -28,13 +29,17 @@ sealed class HLApplicabilityRange<in ELEMENT : PsiElement> {
|
||||
* The ranges are relative to [element]
|
||||
* i.e. if range covers the whole element when it should return `[0, element.length)`
|
||||
*/
|
||||
abstract fun getApplicabilityRanges(element: ELEMENT): List<TextRange>
|
||||
fun getApplicabilityRanges(element: ELEMENT): List<TextRange> = ForbidKtResolve.forbidResolveIn("getApplicabilityRanges") {
|
||||
getApplicabilityRangesImpl(element)
|
||||
}
|
||||
|
||||
protected abstract fun getApplicabilityRangesImpl(element: ELEMENT): List<TextRange>
|
||||
}
|
||||
|
||||
private class HLApplicabilityRangeImpl<ELEMENT : PsiElement>(
|
||||
private val getApplicabilityRanges: (ELEMENT) -> List<TextRange>,
|
||||
) : HLApplicabilityRange<ELEMENT>() {
|
||||
override fun getApplicabilityRanges(element: ELEMENT): List<TextRange> =
|
||||
override fun getApplicabilityRangesImpl(element: ELEMENT): List<TextRange> =
|
||||
getApplicabilityRanges.invoke(element)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,16 +9,31 @@ import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.fir.low.level.api.annotations.PrivateForInline
|
||||
import org.jetbrains.kotlin.idea.frontend.api.ForbidKtResolve
|
||||
import kotlin.experimental.ExperimentalTypeInference
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
sealed class HLApplicator<in PSI : PsiElement, in INPUT : HLApplicatorInput> {
|
||||
abstract fun applyTo(psi: PSI, input: INPUT, project: Project?, editor: Editor?)
|
||||
fun applyTo(psi: PSI, input: INPUT, project: Project?, editor: Editor?) = ForbidKtResolve.forbidResolveIn("HLApplicator.applyTo") {
|
||||
applyToImpl(psi, input, project, editor)
|
||||
}
|
||||
|
||||
abstract fun isApplicableByPsi(psi: PSI): Boolean
|
||||
fun isApplicableByPsi(psi: PSI): Boolean = ForbidKtResolve.forbidResolveIn("HLApplicator.isApplicableByPsi") {
|
||||
isApplicableByPsiImpl(psi)
|
||||
}
|
||||
|
||||
abstract fun getActionName(psi: PSI, input: INPUT): String
|
||||
abstract fun getFamilyName(): String
|
||||
fun getActionName(psi: PSI, input: INPUT): String = ForbidKtResolve.forbidResolveIn("HLApplicator.getActionName") {
|
||||
getActionNameImpl(psi, input)
|
||||
}
|
||||
|
||||
fun getFamilyName(): String = ForbidKtResolve.forbidResolveIn("HLApplicator.getFamilyName") {
|
||||
getFamilyNameImpl()
|
||||
}
|
||||
|
||||
protected abstract fun applyToImpl(psi: PSI, input: INPUT, project: Project?, editor: Editor?)
|
||||
protected abstract fun isApplicableByPsiImpl(psi: PSI): Boolean
|
||||
protected abstract fun getActionNameImpl(psi: PSI, input: INPUT): String
|
||||
protected abstract fun getFamilyNameImpl(): String
|
||||
}
|
||||
|
||||
fun <PSI : PsiElement, NEW_PSI : PSI, INPUT : HLApplicatorInput> HLApplicator<PSI, INPUT>.with(
|
||||
@@ -51,17 +66,17 @@ internal class HLApplicatorImpl<PSI : PsiElement, INPUT : HLApplicatorInput>(
|
||||
val getActionName: (PSI, INPUT) -> String,
|
||||
val getFamilyName: () -> String,
|
||||
) : HLApplicator<PSI, INPUT>() {
|
||||
override fun applyTo(psi: PSI, input: INPUT, project: Project?, editor: Editor?) {
|
||||
override fun applyToImpl(psi: PSI, input: INPUT, project: Project?, editor: Editor?) {
|
||||
applyTo.invoke(psi, input, project, editor)
|
||||
}
|
||||
|
||||
override fun isApplicableByPsi(psi: PSI): Boolean =
|
||||
override fun isApplicableByPsiImpl(psi: PSI): Boolean =
|
||||
isApplicableByPsi.invoke(psi)
|
||||
|
||||
override fun getActionName(psi: PSI, input: INPUT): String =
|
||||
override fun getActionNameImpl(psi: PSI, input: INPUT): String =
|
||||
getActionName.invoke(psi, input)
|
||||
|
||||
override fun getFamilyName(): String =
|
||||
override fun getFamilyNameImpl(): String =
|
||||
getFamilyName.invoke()
|
||||
}
|
||||
|
||||
|
||||
@@ -7,25 +7,34 @@ package org.jetbrains.kotlin.idea.fir.api.applicator
|
||||
|
||||
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() {
|
||||
abstract fun getHighlightType(element: PSI): ProblemHighlightType
|
||||
abstract fun getMessage(element: PSI): String
|
||||
abstract class HLPresentation<PSI : PsiElement> internal constructor() {
|
||||
fun getHighlightType(element: PSI): ProblemHighlightType = ForbidKtResolve.forbidResolveIn("HLPresentation.getHighlightType") {
|
||||
getHighlightTypeImpl(element)
|
||||
}
|
||||
|
||||
fun getMessage(element: PSI): String = ForbidKtResolve.forbidResolveIn("HLPresentation.getMessage") {
|
||||
getMessageImpl(element)
|
||||
}
|
||||
|
||||
abstract fun getMessageImpl(element: PSI): String
|
||||
abstract fun getHighlightTypeImpl(element: PSI): ProblemHighlightType
|
||||
}
|
||||
|
||||
private class HLPresentationImpl<PSI: PsiElement>(
|
||||
private class HLPresentationImpl<PSI : PsiElement>(
|
||||
private val getHighlightType: (element: PSI) -> ProblemHighlightType,
|
||||
private val getMessage: (element: PSI) -> String,
|
||||
) : HLPresentation<PSI>() {
|
||||
override fun getHighlightType(element: PSI): ProblemHighlightType =
|
||||
override fun getHighlightTypeImpl(element: PSI): ProblemHighlightType =
|
||||
getHighlightType.invoke(element)
|
||||
|
||||
override fun getMessage(element: PSI): String =
|
||||
override fun getMessageImpl(element: PSI): String =
|
||||
getMessage.invoke(element)
|
||||
}
|
||||
|
||||
|
||||
class HLInspectionPresentationProviderBuilder<PSI: PsiElement> internal constructor() {
|
||||
class HLInspectionPresentationProviderBuilder<PSI : PsiElement> internal constructor() {
|
||||
private var getHighlightType: ((element: PSI) -> ProblemHighlightType)? = null
|
||||
private var getMessage: ((element: PSI) -> String)? = null
|
||||
|
||||
@@ -50,7 +59,7 @@ class HLInspectionPresentationProviderBuilder<PSI: PsiElement> internal construc
|
||||
HLPresentationImpl(getHighlightType!!, getMessage!!)
|
||||
}
|
||||
|
||||
fun <PSI: PsiElement> presentation(
|
||||
fun <PSI : PsiElement> presentation(
|
||||
init: HLInspectionPresentationProviderBuilder<PSI>.() -> Unit
|
||||
): HLPresentation<PSI> =
|
||||
HLInspectionPresentationProviderBuilder<PSI>().apply(init).build()
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.frontend.api
|
||||
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
@RequiresOptIn
|
||||
annotation class ForbidKtResolveInternals
|
||||
|
||||
object ForbidKtResolve {
|
||||
@OptIn(ForbidKtResolveInternals::class)
|
||||
inline fun <R> forbidResolveIn(actionName: String, action: () -> R): R {
|
||||
if (resovleIsForbidenInActionWithName.get() != null) return action()
|
||||
resovleIsForbidenInActionWithName.set(actionName)
|
||||
return try {
|
||||
action()
|
||||
} finally {
|
||||
resovleIsForbidenInActionWithName.set(null)
|
||||
}
|
||||
}
|
||||
|
||||
@ForbidKtResolveInternals
|
||||
val resovleIsForbidenInActionWithName: ThreadLocal<String?> = ThreadLocal.withInitial { null }
|
||||
}
|
||||
+7
-2
@@ -23,22 +23,27 @@ class ReadActionConfinementValidityToken(project: Project) : ValidityToken() {
|
||||
error("Getting invalidation reason for valid validity token")
|
||||
}
|
||||
|
||||
@OptIn(HackToForceAllowRunningAnalyzeOnEDT::class)
|
||||
@OptIn(HackToForceAllowRunningAnalyzeOnEDT::class, ForbidKtResolveInternals::class)
|
||||
override fun isAccessible(): Boolean {
|
||||
val application = ApplicationManager.getApplication()
|
||||
if (application.isDispatchThread && !allowOnEdt.get()) return false
|
||||
if (ForbidKtResolve.resovleIsForbidenInActionWithName.get() != null) return false
|
||||
if (!application.isReadAccessAllowed) return false
|
||||
return true
|
||||
}
|
||||
|
||||
@OptIn(HackToForceAllowRunningAnalyzeOnEDT::class)
|
||||
@OptIn(HackToForceAllowRunningAnalyzeOnEDT::class, ForbidKtResolveInternals::class)
|
||||
override fun getInaccessibilityReason(): String {
|
||||
val application = ApplicationManager.getApplication()
|
||||
if (application.isDispatchThread && !allowOnEdt.get()) return "Called in EDT thread"
|
||||
if (!application.isReadAccessAllowed) return "Called outside read action"
|
||||
ForbidKtResolve.resovleIsForbidenInActionWithName.get()?.let { actionName ->
|
||||
return "Resolve is forbidden in $actionName"
|
||||
}
|
||||
error("Getting inaccessibility reason for validity token when it is accessible")
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
@HackToForceAllowRunningAnalyzeOnEDT
|
||||
val allowOnEdt: ThreadLocal<Boolean> = ThreadLocal.withInitial { false }
|
||||
|
||||
Reference in New Issue
Block a user