Move typeMappers cache to KotlinPositionManagerCache
This commit is contained in:
@@ -31,18 +31,15 @@ import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.impl.compiled.ClsFileImpl
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.psi.util.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.ThreeState
|
||||
import com.intellij.xdebugger.frame.XStackFrame
|
||||
import com.sun.jdi.AbsentInformationException
|
||||
import com.sun.jdi.Location
|
||||
import com.sun.jdi.ReferenceType
|
||||
import com.sun.jdi.request.ClassPrepareRequest
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
@@ -51,8 +48,6 @@ import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
|
||||
import org.jetbrains.kotlin.fileClasses.getFileClassInternalName
|
||||
import org.jetbrains.kotlin.fileClasses.internalNameWithoutInnerClasses
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||
import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny
|
||||
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory
|
||||
@@ -78,8 +73,6 @@ import com.intellij.debugger.engine.DebuggerUtils as JDebuggerUtils
|
||||
|
||||
class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiRequestPositionManager, PositionManagerEx() {
|
||||
|
||||
private val myTypeMappers = WeakHashMap<String, CachedValue<JetTypeMapper>>()
|
||||
|
||||
override fun evaluateCondition(context: EvaluationContext, frame: StackFrameProxyImpl, location: Location, expression: String): ThreeState? {
|
||||
return ThreeState.UNSURE
|
||||
}
|
||||
@@ -167,10 +160,8 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
||||
if (literalsOrFunctions.isEmpty()) return null;
|
||||
|
||||
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
||||
val typeMapper = if (!isInLibrary)
|
||||
prepareTypeMapper(file)
|
||||
else
|
||||
createTypeMapperForLibraryFile(file.findElementAt(start), file)
|
||||
val elementAt = file.findElementAt(start) ?: return null
|
||||
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt)
|
||||
|
||||
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName
|
||||
for (literal in literalsOrFunctions) {
|
||||
@@ -274,7 +265,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
||||
val file = sourcePosition.file.containingFile as KtFile
|
||||
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
||||
lambdas.flatMap {
|
||||
val typeMapper = if (!isInLibrary) prepareTypeMapper(file) else createTypeMapperForLibraryFile(it, file)
|
||||
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(it)
|
||||
getInternalClassNameForElement(it, typeMapper, file, isInLibrary)
|
||||
}
|
||||
}
|
||||
@@ -295,30 +286,14 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
||||
element ->
|
||||
val file = element.containingFile as KtFile
|
||||
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
||||
val typeMapper = if (!isInLibrary) prepareTypeMapper(file) else createTypeMapperForLibraryFile(element, file)
|
||||
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(element)
|
||||
|
||||
getInternalClassNameForElement(element, typeMapper, file, isInLibrary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareTypeMapper(file: KtFile): JetTypeMapper {
|
||||
val key = createKeyForTypeMapper(file)
|
||||
|
||||
var value: CachedValue<JetTypeMapper>? = myTypeMappers.get(key)
|
||||
if (value == null) {
|
||||
value = CachedValuesManager.getManager(file.project).createCachedValue<JetTypeMapper>(
|
||||
{
|
||||
val typeMapper = createTypeMapper(file)
|
||||
CachedValueProvider.Result(typeMapper, PsiModificationTracker.MODIFICATION_COUNT)
|
||||
}, false)
|
||||
|
||||
myTypeMappers.put(key, value)
|
||||
}
|
||||
|
||||
return value.value
|
||||
}
|
||||
|
||||
override fun locationsOfLine(type: ReferenceType, position: SourcePosition): List<Location> {
|
||||
if (position.file !is KtFile) {
|
||||
throw NoDataException.INSTANCE
|
||||
@@ -352,13 +327,6 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly fun addTypeMapper(file: KtFile, typeMapper: JetTypeMapper) {
|
||||
val value = CachedValuesManager.getManager(file.project).createCachedValue<JetTypeMapper>(
|
||||
{ CachedValueProvider.Result(typeMapper, PsiModificationTracker.MODIFICATION_COUNT) }, false)
|
||||
val key = createKeyForTypeMapper(file)
|
||||
myTypeMappers.put(key, value)
|
||||
}
|
||||
|
||||
private fun getInternalClassNameForElement(
|
||||
notPositionedElement: PsiElement?,
|
||||
typeMapper: JetTypeMapper,
|
||||
@@ -458,9 +426,6 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
||||
element is KtPropertyAccessor ||
|
||||
PsiTreeUtil.getParentOfType(element, KtProperty::class.java, KtPropertyAccessor::class.java) is KtPropertyAccessor
|
||||
|
||||
private fun getElementToCreateTypeMapperForLibraryFile(element: PsiElement?) =
|
||||
if (element is KtElement) element else PsiTreeUtil.getParentOfType(element, KtElement::class.java)
|
||||
|
||||
private fun getJvmInternalNameForImpl(typeMapper: JetTypeMapper, ktClass: KtClassOrObject): String? {
|
||||
val classDescriptor = typeMapper.bindingContext.get<PsiElement, ClassDescriptor>(BindingContext.CLASS, ktClass) ?: return null
|
||||
|
||||
@@ -471,22 +436,6 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
||||
return typeMapper.mapClass(classDescriptor).internalName
|
||||
}
|
||||
|
||||
private fun createTypeMapperForLibraryFile(notPositionedElement: PsiElement?, file: KtFile): JetTypeMapper {
|
||||
val element = getElementToCreateTypeMapperForLibraryFile(notPositionedElement)
|
||||
val analysisResult = element!!.analyzeAndGetResult()
|
||||
|
||||
val state = GenerationState(file.project, ClassBuilderFactories.THROW_EXCEPTION,
|
||||
analysisResult.moduleDescriptor, analysisResult.bindingContext, listOf(file))
|
||||
state.beforeCompile()
|
||||
return state.typeMapper
|
||||
}
|
||||
|
||||
fun isInlinedLambda(functionLiteral: KtFunction, context: BindingContext): Boolean {
|
||||
return InlineUtil.isInlinedArgument(functionLiteral, context, false)
|
||||
}
|
||||
|
||||
private fun createKeyForTypeMapper(file: KtFile) = NoResolveFileClassesProvider.getFileClassInternalName(file)
|
||||
|
||||
private fun findInlinedCalls(function: KtNamedFunction, context: BindingContext): Set<String> {
|
||||
return runReadAction {
|
||||
val result = hashSetOf<String>()
|
||||
@@ -589,22 +538,4 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
||||
private fun ReferenceType.containsKotlinStrata() = availableStrata().contains("Kotlin")
|
||||
|
||||
private fun String?.toSet() = if (this == null) emptySet() else setOf(this)
|
||||
|
||||
companion object {
|
||||
fun createTypeMapper(file: KtFile): JetTypeMapper {
|
||||
val project = file.project
|
||||
|
||||
val analysisResult = file.analyzeFullyAndGetResult()
|
||||
analysisResult.throwIfError()
|
||||
|
||||
val state = GenerationState(
|
||||
project,
|
||||
ClassBuilderFactories.THROW_EXCEPTION,
|
||||
analysisResult.moduleDescriptor,
|
||||
analysisResult.bindingContext,
|
||||
listOf(file))
|
||||
state.beforeCompile()
|
||||
return state.typeMapper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,22 @@ package org.jetbrains.kotlin.idea.debugger
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.libraries.LibraryUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.util.CachedValuesManager
|
||||
import com.intellij.psi.util.PsiModificationTracker
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper
|
||||
import org.jetbrains.kotlin.fileClasses.NoResolveFileClassesProvider
|
||||
import org.jetbrains.kotlin.fileClasses.getFileClassInternalName
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.util.*
|
||||
|
||||
class KotlinPositionManagerCache(private val project: Project) {
|
||||
@@ -32,6 +44,12 @@ class KotlinPositionManagerCache(private val project: Project) {
|
||||
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
|
||||
}, false)
|
||||
|
||||
private val cachedTypeMappers = CachedValuesManager.getManager(project).createCachedValue(
|
||||
{
|
||||
CachedValueProvider.Result<HashMap<String, JetTypeMapper>>(
|
||||
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
|
||||
}, false)
|
||||
|
||||
companion object {
|
||||
fun getOrComputeClassNames(psiElement: PsiElement, create: (PsiElement) -> Collection<String>): Collection<String> {
|
||||
val cache = getInstance(psiElement.project)
|
||||
@@ -48,6 +66,68 @@ class KotlinPositionManagerCache(private val project: Project) {
|
||||
}
|
||||
}
|
||||
|
||||
fun getOrCreateTypeMapper(psiElement: PsiElement): JetTypeMapper {
|
||||
val cache = getInstance(psiElement.project)
|
||||
synchronized(cache.cachedTypeMappers) {
|
||||
val typeMappersCache = cache.cachedTypeMappers.value
|
||||
|
||||
val file = psiElement.containingFile as KtFile
|
||||
val key = createKeyForTypeMapper(file)
|
||||
|
||||
val cachedValue = typeMappersCache[key]
|
||||
if (cachedValue != null) return cachedValue
|
||||
|
||||
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
||||
if (!isInLibrary) {
|
||||
val newValue = createTypeMapperForSourceFile(file)
|
||||
typeMappersCache[key] = newValue
|
||||
return newValue
|
||||
}
|
||||
else {
|
||||
return createTypeMapperForLibraryFile(psiElement, file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getInstance(project: Project) = ServiceManager.getService(project, KotlinPositionManagerCache::class.java)!!
|
||||
|
||||
private fun createKeyForTypeMapper(file: KtFile) = NoResolveFileClassesProvider.getFileClassInternalName(file)
|
||||
|
||||
private fun createTypeMapperForLibraryFile(notPositionedElement: PsiElement?, file: KtFile): JetTypeMapper {
|
||||
val element = getElementToCreateTypeMapperForLibraryFile(notPositionedElement)
|
||||
val analysisResult = element.analyzeAndGetResult()
|
||||
|
||||
val state = GenerationState(
|
||||
file.project,
|
||||
ClassBuilderFactories.THROW_EXCEPTION,
|
||||
analysisResult.moduleDescriptor,
|
||||
analysisResult.bindingContext,
|
||||
listOf(file))
|
||||
state.beforeCompile()
|
||||
return state.typeMapper
|
||||
}
|
||||
|
||||
private fun getElementToCreateTypeMapperForLibraryFile(element: PsiElement?) =
|
||||
if (element is KtElement) element else PsiTreeUtil.getParentOfType(element, KtElement::class.java)!!
|
||||
|
||||
private fun createTypeMapperForSourceFile(file: KtFile): JetTypeMapper {
|
||||
val analysisResult = file.analyzeFullyAndGetResult()
|
||||
analysisResult.throwIfError()
|
||||
|
||||
val state = GenerationState(
|
||||
file.project,
|
||||
ClassBuilderFactories.THROW_EXCEPTION,
|
||||
analysisResult.moduleDescriptor,
|
||||
analysisResult.bindingContext,
|
||||
listOf(file))
|
||||
state.beforeCompile()
|
||||
return state.typeMapper
|
||||
}
|
||||
|
||||
@TestOnly fun addTypeMapper(file: KtFile, typeMapper: JetTypeMapper) {
|
||||
val cache = getInstance(file.project)
|
||||
val key = createKeyForTypeMapper(file)
|
||||
cache.cachedTypeMappers.value[key] = typeMapper
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ fun isInsideInlineArgument(inlineArgument: KtFunction, location: Location, debug
|
||||
}
|
||||
|
||||
private fun lambdaOrdinalIndex(elementAt: KtFunction): Int {
|
||||
val typeMapper = KotlinPositionManager.createTypeMapper(elementAt.getContainingKtFile())
|
||||
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt)
|
||||
|
||||
val type = CodegenBinding.asmTypeForAnonymousClass(typeMapper.bindingContext, elementAt)
|
||||
return type.className.substringAfterLast("$").toInt()
|
||||
|
||||
@@ -93,7 +93,7 @@ public abstract class AbstractPositionManagerTest extends KotlinLightCodeInsight
|
||||
assertNotNull(positionManager);
|
||||
|
||||
for (KtFile file : files) {
|
||||
positionManager.addTypeMapper(file, state.getTypeMapper());
|
||||
KotlinPositionManagerCache.Companion.addTypeMapper(file, state.getTypeMapper());
|
||||
}
|
||||
|
||||
return positionManager;
|
||||
|
||||
Reference in New Issue
Block a user