diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLApplicabilityRange.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLApplicabilityRange.kt index e0d962f0e13..2b4292c62f3 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLApplicabilityRange.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLApplicabilityRange.kt @@ -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 { * 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 + fun getApplicabilityRanges(element: ELEMENT): List = ForbidKtResolve.forbidResolveIn("getApplicabilityRanges") { + getApplicabilityRangesImpl(element) + } + + protected abstract fun getApplicabilityRangesImpl(element: ELEMENT): List } private class HLApplicabilityRangeImpl( private val getApplicabilityRanges: (ELEMENT) -> List, ) : HLApplicabilityRange() { - override fun getApplicabilityRanges(element: ELEMENT): List = + override fun getApplicabilityRangesImpl(element: ELEMENT): List = getApplicabilityRanges.invoke(element) } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLApplicator.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLApplicator.kt index ebd053ac4e7..0aae6c28bce 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLApplicator.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLApplicator.kt @@ -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 { - 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 HLApplicator.with( @@ -51,17 +66,17 @@ internal class HLApplicatorImpl( val getActionName: (PSI, INPUT) -> String, val getFamilyName: () -> String, ) : HLApplicator() { - 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() } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLPresentation.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLPresentation.kt index 215b0fefb4d..baa316640fd 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLPresentation.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/api/applicator/HLPresentation.kt @@ -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 internal constructor() { - abstract fun getHighlightType(element: PSI): ProblemHighlightType - abstract fun getMessage(element: PSI): String +abstract class HLPresentation 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( +private class HLPresentationImpl( private val getHighlightType: (element: PSI) -> ProblemHighlightType, private val getMessage: (element: PSI) -> String, ) : HLPresentation() { - 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 internal constructor() { +class HLInspectionPresentationProviderBuilder internal constructor() { private var getHighlightType: ((element: PSI) -> ProblemHighlightType)? = null private var getMessage: ((element: PSI) -> String)? = null @@ -50,7 +59,7 @@ class HLInspectionPresentationProviderBuilder internal construc HLPresentationImpl(getHighlightType!!, getMessage!!) } -fun presentation( +fun presentation( init: HLInspectionPresentationProviderBuilder.() -> Unit ): HLPresentation = HLInspectionPresentationProviderBuilder().apply(init).build() diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ForbidKtResolve.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ForbidKtResolve.kt new file mode 100644 index 00000000000..82583a946c4 --- /dev/null +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ForbidKtResolve.kt @@ -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 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 = ThreadLocal.withInitial { null } +} \ No newline at end of file diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ReadActionConfinementValidityToken.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ReadActionConfinementValidityToken.kt index 12097480415..7df85d4aa8a 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ReadActionConfinementValidityToken.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ReadActionConfinementValidityToken.kt @@ -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 = ThreadLocal.withInitial { false }