From fbd7bc8a46673017082053a3c169de5565d89da4 Mon Sep 17 00:00:00 2001 From: "Konstantin.Nisht" Date: Wed, 25 Sep 2019 18:33:50 +0300 Subject: [PATCH] IDEA-221863 SOE in type inlay hint: fix endless recreation of DFA for single method GitOrigin-RevId: 3eca8237078e4524bed5593ccd5704ce006f95ba --- .../inference/MethodParameterAugmenter.kt | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/inference/MethodParameterAugmenter.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/inference/MethodParameterAugmenter.kt index b5b63b84afbe..23fb4a659552 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/inference/MethodParameterAugmenter.kt +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/inference/MethodParameterAugmenter.kt @@ -8,6 +8,8 @@ import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.util.CachedValueProvider import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.parentOfType +import org.jetbrains.plugins.groovy.intentions.style.inference.MethodParameterAugmenter.Companion.VisitState.NOT_VISITED +import org.jetbrains.plugins.groovy.intentions.style.inference.MethodParameterAugmenter.Companion.VisitState.VISITED_MANY import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod @@ -19,6 +21,9 @@ class MethodParameterAugmenter : TypeAugmenter() { const val GROOVY_COLLECT_METHOD_CALLS_FOR_INFERENCE = "groovy.collect.method.calls.for.inference" + private val methodRegistry: ThreadLocal> = + ThreadLocal.withInitial { mutableMapOf() } + internal fun createInferenceResult(method: GrMethod): InferenceResult? { if (!Registry.`is`(GROOVY_COLLECT_METHOD_CALLS_FOR_INFERENCE, false)) { return null @@ -27,13 +32,45 @@ class MethodParameterAugmenter : TypeAugmenter() { val scope = with(originalMethod.containingFile?.virtualFile) { if (this == null) return null else GlobalSearchScope.fileScope(originalMethod.project, this) } - return CachedValuesManager.getCachedValue(method) { + val involvedMethods = methodRegistry.get() + if (involvedMethods.getOrDefault(method, NOT_VISITED) == VISITED_MANY) { + return InferenceResult(method, PsiSubstitutor.EMPTY) + } + else { + involvedMethods[method] = involvedMethods.getOrDefault(method, NOT_VISITED).nextState() + try { + return computeInferredMethod(method, scope) + } + finally { + involvedMethods[method] = involvedMethods[method]!!.prevState() + } + } + } + + private fun computeInferredMethod(method: GrMethod, scope: GlobalSearchScope): InferenceResult = + CachedValuesManager.getCachedValue(method) { val typedMethod = runInferenceProcess(method, scope) val typeParameterSubstitutor = createVirtualToActualSubstitutor(typedMethod, method) CachedValueProvider.Result(InferenceResult(typedMethod, typeParameterSubstitutor), method) } - } + private enum class VisitState { + NOT_VISITED { + override fun nextState(): VisitState = VISITED_ONCE + override fun prevState(): VisitState = NOT_VISITED + }, + VISITED_ONCE { + override fun nextState(): VisitState = VISITED_MANY + override fun prevState(): VisitState = NOT_VISITED + }, + VISITED_MANY { + override fun nextState(): VisitState = VISITED_MANY + override fun prevState(): VisitState = VISITED_ONCE + }; + + abstract fun nextState(): VisitState + abstract fun prevState(): VisitState + } } data class InferenceResult(val virtualMethod: GrMethod?, val typeParameterSubstitutor: PsiSubstitutor)