diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 089cecb811d..b14d1e65d40 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -258,6 +258,9 @@ + + diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt index 26554531c37..1020340e79e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManager.kt @@ -259,7 +259,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq private fun classNamesForPositionAndInlinedOnes(sourcePosition: SourcePosition): List { val result = hashSetOf() - val names = classNamesForPosition(sourcePosition, true) + val names = classNamesForPosition(sourcePosition) result.addAll(names) val lambdas = findLambdas(sourcePosition) @@ -280,21 +280,24 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq } } - fun classNamesForPosition(sourcePosition: SourcePosition, withInlines: Boolean): Collection { + fun classNamesForPosition(sourcePosition: SourcePosition): Collection { val psiElement = runReadAction { sourcePosition.elementAt } ?: return emptyList() - return classNamesForPosition(psiElement, withInlines) + return classNamesForPosition(psiElement) } - private fun classNamesForPosition(element: PsiElement, withInlines: Boolean): Collection { + private fun classNamesForPosition(element: PsiElement): Collection { return runReadAction { if (DumbService.getInstance(element.project).isDumb) { emptySet() } else { - 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) - getInternalClassNameForElement(element, typeMapper, file, isInLibrary, withInlines) + KotlinPositionManagerCache.getOrComputeClassNames(element) { + 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) + getInternalClassNameForElement(element, typeMapper, file, isInLibrary) + } } } } @@ -360,8 +363,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq notPositionedElement: PsiElement?, typeMapper: JetTypeMapper, file: KtFile, - isInLibrary: Boolean, - withInlines: Boolean = true + isInLibrary: Boolean ): Collection { val element = getElementToCalculateClassName(notPositionedElement) @@ -370,7 +372,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq is KtFunction -> { val descriptor = InlineUtil.getInlineArgumentDescriptor(element, typeMapper.bindingContext) if (descriptor != null) { - val classNamesForParent = getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary, withInlines) + val classNamesForParent = getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary) if (descriptor.isCrossinline) { return findCrossInlineArguments(element, descriptor, typeMapper.bindingContext) + classNamesForParent } @@ -393,9 +395,9 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq val parent = getElementToCalculateClassName(element.parent) // Class-object initializer if (parent is KtObjectDeclaration && parent.isCompanion()) { - return getInternalClassNameForElement(parent.parent, typeMapper, file, isInLibrary, withInlines) + return getInternalClassNameForElement(parent.parent, typeMapper, file, isInLibrary) } - return getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary, withInlines) + return getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary) } element is KtProperty && (!element.isTopLevel || !isInLibrary) -> { if (isInPropertyAccessor(notPositionedElement)) { @@ -407,7 +409,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq val descriptor = typeMapper.bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element) if (descriptor !is PropertyDescriptor) { - return getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary, withInlines) + return getInternalClassNameForElement(element.parent, typeMapper, file, isInLibrary) } return getJvmInternalNameForPropertyOwner(typeMapper, descriptor).toSet() @@ -425,8 +427,6 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq NoResolveFileClassesProvider.getFileClassInternalName(file) } - if (!withInlines) return parentInternalName.toSet() - val inlinedCalls = findInlinedCalls(element, typeMapper.bindingContext) return inlinedCalls + parentInternalName.toSet() } @@ -497,7 +497,7 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq val usage = it.element if (usage is KtElement) { //TODO recursive search - val names = classNamesForPosition(usage, false) + val names = classNamesForPosition(usage) result.addAll(names) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManagerCache.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManagerCache.kt new file mode 100644 index 00000000000..d555d06307b --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/KotlinPositionManagerCache.kt @@ -0,0 +1,53 @@ +/* + * 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.psi.PsiElement +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.psi.util.PsiModificationTracker +import java.util.* + +class KotlinPositionManagerCache(private val project: Project) { + + private val cachedClassNames = CachedValuesManager.getManager(project).createCachedValue( + { + CachedValueProvider.Result>>( + hashMapOf(), PsiModificationTracker.MODIFICATION_COUNT) + }, false) + + companion object { + fun getOrComputeClassNames(psiElement: PsiElement, create: (PsiElement) -> Collection): Collection { + 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 + } + } + + private fun getInstance(project: Project) = ServiceManager.getService(project, KotlinPositionManagerCache::class.java)!! + } +}