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