Move HLApplicator from fir ide module to frontend-independent

This commit is contained in:
Ilya Kirillov
2021-03-26 18:54:56 +01:00
parent 5cbfb172a4
commit 18ab9c7b25
25 changed files with 217 additions and 35 deletions
@@ -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.api.fe10.impl
import org.jetbrains.kotlin.idea.api.ResolveAllowanceService
class ResolveAllowanceServiceFE10Impl: ResolveAllowanceService() {
override fun switchOnAllowingResolveInEdtInCurrentThread(): SwitchResult {
return SwitchResult.ALREADY_SWITCHED
}
override fun isResolveOnEdtInCurrentThreadAllowed(): Boolean = true
override fun switchOffAllowingResolveInEdtInCurrentThread() {}
override fun switchOnForbidResolveInCurrentThread(actionName: String): SwitchResult {
return SwitchResult.ALREADY_SWITCHED
}
override fun switchOffForbidResolveInCurrentThread() {
}
override fun getResolveInCurrentThreadForbiddenReason(): String? = null
}
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.idea.fir.api
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInputProvider
import org.jetbrains.kotlin.idea.fir.api.applicator.inputProvider
import org.jetbrains.kotlin.idea.frontend.api.components.KtDiagnosticCheckerFilter
@@ -9,6 +9,8 @@ import com.intellij.codeInspection.*
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.api.applicator.HLApplicator
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.fir.api.applicator.*
import org.jetbrains.kotlin.idea.frontend.api.HackToForceAllowRunningAnalyzeOnEDT
import org.jetbrains.kotlin.idea.frontend.api.analyseWithReadAction
@@ -33,7 +35,7 @@ abstract class AbstractHLInspection<PSI : KtElement, INPUT : HLApplicatorInput>(
}
private fun visitTargetElement(element: PSI, holder: ProblemsHolder, isOnTheFly: Boolean) {
if (!applicator.isApplicableByPsi(element)) return
if (!applicator.isApplicableByPsi(element, holder.project)) return
val targets = applicabilityRange.getApplicabilityRanges(element)
if (targets.isEmpty()) return
@@ -101,7 +103,7 @@ private fun <PSI : PsiElement, INPUT : HLApplicatorInput> HLApplicator<PSI, INPU
@Suppress("UNCHECKED_CAST")
val element = descriptor.psiElement as PSI
if (isApplicableByPsi(element) && input.isValidFor(element)) {
if (isApplicableByPsi(element, project) && input.isValidFor(element)) {
applyTo(element, input, project, editor = null)
}
}
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.idea.fir.api
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.idea.api.applicator.HLApplicator
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicabilityRange
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicator
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInputProvider
import org.jetbrains.kotlin.idea.frontend.api.HackToForceAllowRunningAnalyzeOnEDT
import org.jetbrains.kotlin.idea.frontend.api.analyseWithReadAction
@@ -22,7 +22,8 @@ abstract class AbstractHLIntention<PSI : KtElement, INPUT : HLApplicatorInput>(
elementType: KClass<PSI>,
) : SelfTargetingIntention<PSI>(elementType.java, { "" }, { "" }) {
final override fun isApplicableTo(element: PSI, caretOffset: Int): Boolean {
if (!applicator.isApplicableByPsi(element)) return false
val project = element.project// TODO expensive operation, may require traversing the tree up to containing PsiFile
if (!applicator.isApplicableByPsi(element, project)) return false
val ranges = applicabilityRange.getApplicabilityRanges(element)
if (ranges.isEmpty()) return false
val input = getInput(element)
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.idea.fir.api
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnosticWithPsi
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.idea.fir.api.applicator
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
/**
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.idea.fir.api.fixes
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
class HLApplicatorTargetWithInput<PSI : PsiElement, INPUT : HLApplicatorInput>(
val target: PSI,
@@ -7,8 +7,8 @@ package org.jetbrains.kotlin.idea.fir.api.fixes
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicator
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.api.applicator.HLApplicator
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnosticWithPsi
@@ -8,8 +8,8 @@ package org.jetbrains.kotlin.idea.fir.api.fixes
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicator
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.api.applicator.HLApplicator
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
import org.jetbrains.kotlin.psi.KtFile
@@ -20,7 +20,7 @@ class HLQuickFix<PSI : PsiElement, in INPUT : HLApplicatorInput>(
) : KotlinQuickFixAction<PSI>(target) {
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
val element = element ?: return
if (applicator.isApplicableByPsi(element) && input.isValidFor(element)) {
if (applicator.isApplicableByPsi(element, project) && input.isValidFor(element)) {
applicator.applyTo(element, input, project, editor)
}
}
@@ -0,0 +1,44 @@
/*
* 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.fir.api.impl
import org.jetbrains.kotlin.idea.api.ResolveAllowanceService
import org.jetbrains.kotlin.miniStdLib.multithreadings.javaThreadLocal
class ResolveAllowanceServiceFirImpl : ResolveAllowanceService() {
private var allowResolveOnEdt by javaThreadLocal(false)
private var forbidResolve by javaThreadLocal<String?>(null)
override fun switchOnAllowingResolveInEdtInCurrentThread(): SwitchResult {
if (allowResolveOnEdt) {
return SwitchResult.ALREADY_SWITCHED
} else {
allowResolveOnEdt = true
return SwitchResult.SWITCHED
}
}
override fun switchOffAllowingResolveInEdtInCurrentThread() {
allowResolveOnEdt = false
}
override fun isResolveOnEdtInCurrentThreadAllowed(): Boolean = allowResolveOnEdt
override fun switchOnForbidResolveInCurrentThread(actionName: String): SwitchResult {
if (forbidResolve != null) {
return SwitchResult.ALREADY_SWITCHED
} else {
forbidResolve = actionName
return SwitchResult.SWITCHED
}
}
override fun switchOffForbidResolveInCurrentThread() {
forbidResolve = null
}
override fun getResolveInCurrentThreadForbiddenReason(): String? = forbidResolve
}
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.idea.fir.applicators
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.idea.fir.api.applicator.applicabilityTarget
import org.jetbrains.kotlin.idea.refactoring.safeDelete.removeOverrideModifier
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtModifierListOwner
@@ -7,8 +7,8 @@ package org.jetbrains.kotlin.idea.fir.applicators
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.fir.api.applicator.applicator
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.api.applicator.applicator
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeRendererOptions
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
@@ -8,8 +8,8 @@ package org.jetbrains.kotlin.idea.fir.applicators
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.fir.api.applicator.applicator
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.api.applicator.applicator
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
@@ -9,9 +9,9 @@ import com.intellij.codeInspection.CleanupLocalInspectionTool
import com.intellij.codeInspection.ProblemHighlightType
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.fir.api.*
import org.jetbrains.kotlin.idea.api.applicator.with
import org.jetbrains.kotlin.idea.fir.api.applicator.inputProvider
import org.jetbrains.kotlin.idea.fir.api.applicator.presentation
import org.jetbrains.kotlin.idea.fir.api.applicator.with
import org.jetbrains.kotlin.idea.fir.applicators.ApplicabilityRanges
import org.jetbrains.kotlin.idea.fir.applicators.CallableReturnTypeUpdaterApplicator
import org.jetbrains.kotlin.idea.frontend.api.types.isUnit
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.idea.fir.inspections.diagnosticBased
import com.intellij.codeInspection.ProblemHighlightType
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.api.applicator.HLApplicator
import org.jetbrains.kotlin.idea.api.applicator.with
import org.jetbrains.kotlin.idea.fir.api.AbstractHLDiagnosticBasedInspection
import org.jetbrains.kotlin.idea.fir.api.applicator.*
import org.jetbrains.kotlin.idea.fir.api.inputByDiagnosticProvider
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.idea.fir.intentions.declarations
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.fir.api.*
import org.jetbrains.kotlin.idea.api.applicator.with
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicabilityRange
import org.jetbrains.kotlin.idea.fir.api.applicator.inputProvider
import org.jetbrains.kotlin.idea.fir.api.applicator.with
import org.jetbrains.kotlin.idea.fir.applicators.ApplicabilityRanges
import org.jetbrains.kotlin.idea.fir.applicators.CallableReturnTypeUpdaterApplicator
import org.jetbrains.kotlin.psi.*
@@ -7,9 +7,8 @@ package org.jetbrains.kotlin.idea.quickfix.fixes
import com.intellij.psi.PsiElement
import com.intellij.psi.util.parentOfType
import org.jetbrains.kotlin.idea.fir.api.*
import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.fir.api.applicator.applicator
import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput
import org.jetbrains.kotlin.idea.api.applicator.applicator
import org.jetbrains.kotlin.idea.fir.api.fixes.HLApplicatorTargetWithInput
import org.jetbrains.kotlin.idea.fir.api.fixes.diagnosticFixFactory
import org.jetbrains.kotlin.idea.fir.api.fixes.withInput
@@ -0,0 +1,56 @@
/*
* 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.api
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
abstract class ResolveAllowanceService {
abstract fun switchOnAllowingResolveInEdtInCurrentThread(): SwitchResult
abstract fun switchOffAllowingResolveInEdtInCurrentThread()
abstract fun isResolveOnEdtInCurrentThreadAllowed(): Boolean
abstract fun switchOnForbidResolveInCurrentThread(actionName: String): SwitchResult
abstract fun switchOffForbidResolveInCurrentThread()
abstract fun getResolveInCurrentThreadForbiddenReason(): String?
enum class SwitchResult {
SWITCHED,
ALREADY_SWITCHED
}
}
inline fun <T> allowResolveInEdtIn(project: Project, block: () -> T): T {
val resolveAllowanceService = project.service<ResolveAllowanceService>()
return when (resolveAllowanceService.switchOnAllowingResolveInEdtInCurrentThread()) {
ResolveAllowanceService.SwitchResult.SWITCHED -> {
try {
block()
} finally {
resolveAllowanceService.switchOffAllowingResolveInEdtInCurrentThread()
}
}
ResolveAllowanceService.SwitchResult.ALREADY_SWITCHED -> {
block()
}
}
}
inline fun <T> forbidResolveIn(project: Project, actionName: String, block: () -> T): T {
val resolveAllowanceService = project.service<ResolveAllowanceService>()
return when (resolveAllowanceService.switchOnForbidResolveInCurrentThread(actionName)) {
ResolveAllowanceService.SwitchResult.SWITCHED -> {
try {
block()
} finally {
resolveAllowanceService.switchOffForbidResolveInCurrentThread()
}
}
ResolveAllowanceService.SwitchResult.ALREADY_SWITCHED -> {
block()
}
}
}
@@ -3,14 +3,14 @@
* 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.fir.api.applicator
package org.jetbrains.kotlin.idea.api.applicator
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 org.jetbrains.kotlin.idea.api.forbidResolveIn
import org.jetbrains.kotlin.idea.quickfix.KotlinPsiOnlyQuickFixAction
import org.jetbrains.kotlin.miniStdLib.annotations.PrivateForInline
import kotlin.experimental.ExperimentalTypeInference
import kotlin.reflect.KClass
@@ -28,14 +28,14 @@ sealed class HLApplicator<in PSI : PsiElement, in INPUT : HLApplicatorInput> {
* @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") {
fun applyTo(psi: PSI, input: INPUT, project: Project, editor: Editor?) = forbidResolveIn(project, "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") {
fun isApplicableByPsi(psi: PSI, project: Project): Boolean = forbidResolveIn(project, "HLApplicator.isApplicableByPsi") {
isApplicableByPsiImpl(psi)
}
@@ -44,18 +44,16 @@ sealed class HLApplicator<in PSI : PsiElement, in INPUT : HLApplicatorInput> {
*
* @see com.intellij.codeInsight.intention.IntentionAction.getText
*/
fun getActionName(psi: PSI, input: INPUT): String = ForbidKtResolve.forbidResolveIn("HLApplicator.getActionName") {
getActionNameImpl(psi, input)
}
fun getActionName(psi: PSI, input: INPUT): String = 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()
}
fun getFamilyName(): String = getFamilyNameImpl()
protected abstract fun applyToImpl(psi: PSI, input: INPUT, project: Project, editor: Editor?)
protected abstract fun isApplicableByPsiImpl(psi: PSI): Boolean
@@ -3,7 +3,7 @@
* 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.fir.api.applicator
package org.jetbrains.kotlin.idea.api.applicator
import com.intellij.psi.PsiElement
@@ -0,0 +1,13 @@
/*
* 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.miniStdLib.annotations
/**
* This annotation should be used when the declaration is semantically inline
* but cannot be marked as such because it should be used in some inline function
*/
@RequiresOptIn
annotation class PrivateForInline
@@ -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.miniStdLib.multithreadings
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
@JvmInline
value class JavaThreadLocalDelegate<V> internal constructor(private val threadLocal: ThreadLocal<V>): ReadWriteProperty<Any?, V> {
override fun getValue(thisRef: Any?, property: KProperty<*>): V {
return threadLocal.get()
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
threadLocal.set(value)
}
}
fun <T> javaThreadLocal(initialValue: () -> T): JavaThreadLocalDelegate<T> =
JavaThreadLocalDelegate(ThreadLocal.withInitial(initialValue))
fun <T> javaThreadLocal(initialValue: T): JavaThreadLocalDelegate<T> =
JavaThreadLocalDelegate(ThreadLocal.withInitial { initialValue })
@@ -0,0 +1,9 @@
/*
* 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.
*/
/**
* This package should be moved to separate module
*/
package org.jetbrains.kotlin.miniStdLib
@@ -164,6 +164,8 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
<projectService serviceInterface="org.jetbrains.kotlin.trackers.KotlinOutOfBlockModificationTrackerFactory"
serviceImplementation="org.jetbrains.kotlin.trackers.KotlinFE10OutOfBlockModificationTracker"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.api.fe10.impl.ResolveAllowanceServiceFE10Impl"
serviceInterface="org.jetbrains.kotlin.idea.api.ResolveAllowanceService"/>
<statistics.counterUsagesCollector groupId="kotlin.gradle.target" version="2"/>
<statistics.counterUsagesCollector groupId="kotlin.maven.target" version="3"/>
+2
View File
@@ -135,6 +135,8 @@ The Kotlin FIR plugin provides language support in IntelliJ IDEA and Android Stu
<projectService serviceInterface="org.jetbrains.kotlin.trackers.KotlinOutOfBlockModificationTrackerFactory"
serviceImplementation="org.jetbrains.kotlin.idea.fir.low.level.api.trackers.KotlinFirOutOfBlockModificationTrackerFactory"/>
<psi.treeChangePreprocessor implementation="org.jetbrains.kotlin.idea.fir.low.level.api.trackers.KotlinOutOfBlockPsiTreeChangePreprocessor"/>
<projectService serviceImplementation="org.jetbrains.kotlin.idea.fir.api.impl.ResolveAllowanceServiceFirImpl"
serviceInterface="org.jetbrains.kotlin.idea.api.ResolveAllowanceService"/>
</extensions>
<!-- scripts -->