diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 787596664ec..8bda6606404 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -258,9 +258,6 @@ - - diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt index 608f8fbd6f3..95ba3528fc0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt @@ -51,6 +51,7 @@ import org.jetbrains.kotlin.fileClasses.internalNameWithoutInnerClasses import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils import org.jetbrains.kotlin.idea.debugger.breakpoints.getLambdasAtLineIfAny import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinCodeFragmentFactory +import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset import org.jetbrains.kotlin.idea.search.usagesSearch.isImportUsage @@ -67,7 +68,6 @@ import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.source.getPsi import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull -import org.jetbrains.kotlin.utils.toReadOnlyList import java.util.* import com.intellij.debugger.engine.DebuggerUtils as JDebuggerUtils @@ -160,7 +160,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq if (literalsOrFunctions.isEmpty()) return null; val elementAt = file.findElementAt(start) ?: return null - val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt) + val typeMapper = KotlinDebuggerCaches.getOrCreateTypeMapper(elementAt) val currentLocationClassName = JvmClassName.byFqNameWithoutInnerClasses(FqName(currentLocationFqName)).internalName for (literal in literalsOrFunctions) { @@ -269,11 +269,11 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq emptyList() } else { - KotlinPositionManagerCache.getOrComputeClassNames(element) { + KotlinDebuggerCaches.getOrComputeClassNames(element) { element -> val file = element.containingFile as KtFile val isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null - val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(element) + val typeMapper = KotlinDebuggerCaches.getOrCreateTypeMapper(element) getInternalClassNameForElement(element, typeMapper, file, isInLibrary) } diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManagerCache.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManagerCache.kt deleted file mode 100644 index 1f16b7667f7..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManagerCache.kt +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -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.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) { - - private val cachedClassNames = CachedValuesManager.getManager(project).createCachedValue( - { - CachedValueProvider.Result>>( - hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT) - }, false) - - private val cachedTypeMappers = CachedValuesManager.getManager(project).createCachedValue( - { - CachedValueProvider.Result>( - hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT) - }, false) - - companion object { - fun getOrComputeClassNames(psiElement: PsiElement, create: (PsiElement) -> List): List { - val cache = getInstance(psiElement.project) - synchronized(cache.cachedClassNames) { - val classNamesCache = cache.cachedClassNames.value - - val cachedValue = classNamesCache[psiElement] - if (cachedValue != null) return cachedValue - - val newValue = create(psiElement) - - classNamesCache[psiElement] = newValue - return newValue - } - } - - 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 isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null - - if (!isInLibrary) { - // Key = file - val cachedValue = typeMappersCache[file] - if (cachedValue != null) return cachedValue - - val newValue = createTypeMapperForSourceFile(file) - typeMappersCache[file] = newValue - return newValue - } - else { - // key = KtElement - val element = getElementToCreateTypeMapperForLibraryFile(psiElement) - val cachedValue = typeMappersCache[psiElement] - if (cachedValue != null) return cachedValue - - val newValue = createTypeMapperForLibraryFile(element, file) - typeMappersCache[psiElement] = newValue - return newValue - } - } - } - - private fun getInstance(project: Project) = ServiceManager.getService(project, KotlinPositionManagerCache::class.java)!! - - private fun createTypeMapperForLibraryFile(element: KtElement, file: KtFile): JetTypeMapper { - 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) { - getInstance(file.project).cachedTypeMappers.value[file] = typeMapper - } - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/debuggerUtil.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/debuggerUtil.kt index 1cd8f2e00b9..ff0248cede6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/debuggerUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/debuggerUtil.kt @@ -20,6 +20,7 @@ import com.intellij.debugger.engine.DebugProcessImpl import com.sun.jdi.* import com.sun.tools.jdi.LocalVariableImpl import org.jetbrains.kotlin.codegen.binding.CodegenBinding +import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.psi.KtFunction @@ -41,7 +42,7 @@ fun isInsideInlineArgument(inlineArgument: KtFunction, location: Location, debug } private fun lambdaOrdinalIndex(elementAt: KtFunction): Int { - val typeMapper = KotlinPositionManagerCache.getOrCreateTypeMapper(elementAt) + val typeMapper = KotlinDebuggerCaches.getOrCreateTypeMapper(elementAt) val type = CodegenBinding.asmTypeForAnonymousClass(typeMapper.bindingContext, elementAt) return type.className.substringAfterLast("$").toInt() diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinDebuggerCaches.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinDebuggerCaches.kt index 649e36c44f9..40df2c8c574 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinDebuggerCaches.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinDebuggerCaches.kt @@ -20,15 +20,26 @@ import com.intellij.debugger.SourcePosition import com.intellij.debugger.engine.evaluation.EvaluationContextImpl 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 com.intellij.util.containers.MultiMap import org.apache.log4j.Logger +import org.jetbrains.annotations.TestOnly import org.jetbrains.eval4j.Value +import org.jetbrains.kotlin.codegen.ClassBuilderFactories +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.codegen.state.JetTypeMapper import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult +import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.psi.KtCodeFragment +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.types.KotlinType import java.util.* @@ -41,6 +52,18 @@ class KotlinDebuggerCaches(private val project: Project) { MultiMap.create(), PsiModificationTracker.MODIFICATION_COUNT) }, false) + private val cachedClassNames = CachedValuesManager.getManager(project).createCachedValue( + { + CachedValueProvider.Result>>( + hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT) + }, false) + + private val cachedTypeMappers = CachedValuesManager.getManager(project).createCachedValue( + { + CachedValueProvider.Result>( + hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT) + }, false) + companion object { private val LOG = Logger.getLogger(KotlinDebuggerCaches::class.java)!! @@ -70,6 +93,85 @@ class KotlinDebuggerCaches(private val project: Project) { return@synchronized newCompiledData } } + + fun getOrComputeClassNames(psiElement: PsiElement, create: (PsiElement) -> List): List { + val cache = getInstance(psiElement.project) + synchronized(cache.cachedClassNames) { + val classNamesCache = cache.cachedClassNames.value + + val cachedValue = classNamesCache[psiElement] + if (cachedValue != null) return cachedValue + + val newValue = create(psiElement) + + classNamesCache[psiElement] = newValue + return newValue + } + } + + 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 isInLibrary = LibraryUtil.findLibraryEntry(file.virtualFile, file.project) != null + + if (!isInLibrary) { + // Key = file + val cachedValue = typeMappersCache[file] + if (cachedValue != null) return cachedValue + + val newValue = createTypeMapperForSourceFile(file) + typeMappersCache[file] = newValue + return newValue + } + else { + // key = KtElement + val element = getElementToCreateTypeMapperForLibraryFile(psiElement) + val cachedValue = typeMappersCache[psiElement] + if (cachedValue != null) return cachedValue + + val newValue = createTypeMapperForLibraryFile(element, file) + typeMappersCache[psiElement] = newValue + return newValue + } + } + } + + private fun createTypeMapperForLibraryFile(element: KtElement, file: KtFile): JetTypeMapper { + 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) { + getInstance(file.project).cachedTypeMappers.value[file] = typeMapper + } } private fun canBeEvaluatedInThisContext(compiledData: CompiledDataDescriptor, context: EvaluationContextImpl): Boolean { diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/AbstractPositionManagerTest.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/AbstractPositionManagerTest.java index bac6ff681a3..c135d05885d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/AbstractPositionManagerTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/AbstractPositionManagerTest.java @@ -32,16 +32,17 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.testFramework.LightProjectDescriptor; import com.sun.jdi.Location; import com.sun.jdi.ReferenceType; -import kotlin.sequences.SequencesKt; -import kotlin.text.StringsKt; import kotlin.Unit; import kotlin.io.FilesKt; import kotlin.jvm.functions.Function1; +import kotlin.sequences.SequencesKt; +import kotlin.text.StringsKt; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.backend.common.output.OutputFile; import org.jetbrains.kotlin.backend.common.output.OutputFileCollection; import org.jetbrains.kotlin.codegen.GenerationUtils; import org.jetbrains.kotlin.codegen.state.GenerationState; +import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches; import org.jetbrains.kotlin.idea.project.PluginJetFilesProvider; import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase; import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor; @@ -93,7 +94,7 @@ public abstract class AbstractPositionManagerTest extends KotlinLightCodeInsight assertNotNull(positionManager); for (KtFile file : files) { - KotlinPositionManagerCache.Companion.addTypeMapper(file, state.getTypeMapper()); + KotlinDebuggerCaches.Companion.addTypeMapper(file, state.getTypeMapper()); } return positionManager;