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.PsiFile
|
||||||
import com.intellij.psi.impl.compiled.ClsFileImpl
|
import com.intellij.psi.impl.compiled.ClsFileImpl
|
||||||
import com.intellij.psi.search.searches.ReferencesSearch
|
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.util.ThreeState
|
||||||
import com.intellij.xdebugger.frame.XStackFrame
|
import com.intellij.xdebugger.frame.XStackFrame
|
||||||
import com.sun.jdi.AbsentInformationException
|
import com.sun.jdi.AbsentInformationException
|
||||||
import com.sun.jdi.Location
|
import com.sun.jdi.Location
|
||||||
import com.sun.jdi.ReferenceType
|
import com.sun.jdi.ReferenceType
|
||||||
import com.sun.jdi.request.ClassPrepareRequest
|
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.binding.CodegenBinding
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
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.codegen.state.JetTypeMapper
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
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.NoResolveFileClassesProvider
|
||||||
import org.jetbrains.kotlin.fileClasses.getFileClassInternalName
|
import org.jetbrains.kotlin.fileClasses.getFileClassInternalName
|
||||||
import org.jetbrains.kotlin.fileClasses.internalNameWithoutInnerClasses
|
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.codeInsight.CodeInsightUtils
|
||||||
import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny
|
import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory
|
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() {
|
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? {
|
override fun evaluateCondition(context: EvaluationContext, frame: StackFrameProxyImpl, location: Location, expression: String): ThreeState? {
|
||||||
return ThreeState.UNSURE
|
return ThreeState.UNSURE
|
||||||
}
|
}
|
||||||
@@ -167,10 +160,8 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
|||||||
if (literalsOrFunctions.isEmpty()) return null;
|
if (literalsOrFunctions.isEmpty()) return null;
|
||||||
|
|
||||||
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
||||||
val typeMapper = if (!isInLibrary)
|
val elementAt = file.findElementAt(start) ?: return null
|
||||||
prepareTypeMapper(file)
|
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt)
|
||||||
else
|
|
||||||
createTypeMapperForLibraryFile(file.findElementAt(start), file)
|
|
||||||
|
|
||||||
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName
|
val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName
|
||||||
for (literal in literalsOrFunctions) {
|
for (literal in literalsOrFunctions) {
|
||||||
@@ -274,7 +265,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
|||||||
val file = sourcePosition.file.containingFile as KtFile
|
val file = sourcePosition.file.containingFile as KtFile
|
||||||
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
||||||
lambdas.flatMap {
|
lambdas.flatMap {
|
||||||
val typeMapper = if (!isInLibrary) prepareTypeMapper(file) else createTypeMapperForLibraryFile(it, file)
|
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(it)
|
||||||
getInternalClassNameForElement(it, typeMapper, file, isInLibrary)
|
getInternalClassNameForElement(it, typeMapper, file, isInLibrary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -295,30 +286,14 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
|||||||
element ->
|
element ->
|
||||||
val file = element.containingFile as KtFile
|
val file = element.containingFile as KtFile
|
||||||
val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null
|
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)
|
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> {
|
override fun locationsOfLine(type: ReferenceType, position: SourcePosition): List<Location> {
|
||||||
if (position.file !is KtFile) {
|
if (position.file !is KtFile) {
|
||||||
throw NoDataException.INSTANCE
|
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(
|
private fun getInternalClassNameForElement(
|
||||||
notPositionedElement: PsiElement?,
|
notPositionedElement: PsiElement?,
|
||||||
typeMapper: JetTypeMapper,
|
typeMapper: JetTypeMapper,
|
||||||
@@ -458,9 +426,6 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
|||||||
element is KtPropertyAccessor ||
|
element is KtPropertyAccessor ||
|
||||||
PsiTreeUtil.getParentOfType(element, KtProperty::class.java, KtPropertyAccessor::class.java) 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? {
|
private fun getJvmInternalNameForImpl(typeMapper: JetTypeMapper, ktClass: KtClassOrObject): String? {
|
||||||
val classDescriptor = typeMapper.bindingContext.get<PsiElement, ClassDescriptor>(BindingContext.CLASS, ktClass) ?: return null
|
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
|
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> {
|
private fun findInlinedCalls(function: KtNamedFunction, context: BindingContext): Set<String> {
|
||||||
return runReadAction {
|
return runReadAction {
|
||||||
val result = hashSetOf<String>()
|
val result = hashSetOf<String>()
|
||||||
@@ -589,22 +538,4 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
|
|||||||
private fun ReferenceType.containsKotlinStrata() = availableStrata().contains("Kotlin")
|
private fun ReferenceType.containsKotlinStrata() = availableStrata().contains("Kotlin")
|
||||||
|
|
||||||
private fun String?.toSet() = if (this == null) emptySet() else setOf(this)
|
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.components.ServiceManager
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.libraries.LibraryUtil
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.util.CachedValueProvider
|
import com.intellij.psi.util.CachedValueProvider
|
||||||
import com.intellij.psi.util.CachedValuesManager
|
import com.intellij.psi.util.CachedValuesManager
|
||||||
import com.intellij.psi.util.PsiModificationTracker
|
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.*
|
import java.util.*
|
||||||
|
|
||||||
class KotlinPositionManagerCache(private val project: Project) {
|
class KotlinPositionManagerCache(private val project: Project) {
|
||||||
@@ -32,6 +44,12 @@ class KotlinPositionManagerCache(private val project: Project) {
|
|||||||
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
|
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
|
||||||
}, false)
|
}, false)
|
||||||
|
|
||||||
|
private val cachedTypeMappers = CachedValuesManager.getManager(project).createCachedValue(
|
||||||
|
{
|
||||||
|
CachedValueProvider.Result<HashMap<String, JetTypeMapper>>(
|
||||||
|
hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT)
|
||||||
|
}, false)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getOrComputeClassNames(psiElement: PsiElement, create: (PsiElement) -> Collection<String>): Collection<String> {
|
fun getOrComputeClassNames(psiElement: PsiElement, create: (PsiElement) -> Collection<String>): Collection<String> {
|
||||||
val cache = getInstance(psiElement.project)
|
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 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 {
|
private fun lambdaOrdinalIndex(elementAt: KtFunction): Int {
|
||||||
val typeMapper = KotlinPositionManager.createTypeMapper(elementAt.getContainingKtFile())
|
val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt)
|
||||||
|
|
||||||
val type = CodegenBinding.asmTypeForAnonymousClass(typeMapper.bindingContext, elementAt)
|
val type = CodegenBinding.asmTypeForAnonymousClass(typeMapper.bindingContext, elementAt)
|
||||||
return type.className.substringAfterLast("$").toInt()
|
return type.className.substringAfterLast("$").toInt()
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ public abstract class AbstractPositionManagerTest extends KotlinLightCodeInsight
|
|||||||
assertNotNull(positionManager);
|
assertNotNull(positionManager);
|
||||||
|
|
||||||
for (KtFile file : files) {
|
for (KtFile file : files) {
|
||||||
positionManager.addTypeMapper(file, state.getTypeMapper());
|
KotlinPositionManagerCache.Companion.addTypeMapper(file, state.getTypeMapper());
|
||||||
}
|
}
|
||||||
|
|
||||||
return positionManager;
|
return positionManager;
|
||||||
|
|||||||
Reference in New Issue
Block a user