Run full resolve in debugger with write action priority (KT-14602)

#KT-14602 Fixed
This commit is contained in:
Nikolay Krasko
2016-12-06 13:36:08 +03:00
parent 45532e480f
commit fc5b493fd3
5 changed files with 52 additions and 22 deletions
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.idea.util.application
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.command.CommandProcessor import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
fun <T> runReadAction(action: () -> T): T { fun <T> runReadAction(action: () -> T): T {
@@ -0,0 +1,33 @@
/*
* 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
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.util.ProgressIndicatorUtils
fun <T : Any> runInReadActionWithWriteActionPriority(f: () -> T): T {
var r: T? = null
val complete = ProgressIndicatorUtils.runInReadActionWithWriteActionPriority {
r = f()
}
// There is a write action in progress or pending, so no point in counting the result
if (!complete) throw ProcessCanceledException()
return r!!
}
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
import org.jetbrains.kotlin.idea.debugger.BinaryCacheKey import org.jetbrains.kotlin.idea.debugger.BinaryCacheKey
import org.jetbrains.kotlin.idea.debugger.BytecodeDebugInfo import org.jetbrains.kotlin.idea.debugger.BytecodeDebugInfo
import org.jetbrains.kotlin.idea.debugger.WeakBytecodeDebugInfoStorage import org.jetbrains.kotlin.idea.debugger.WeakBytecodeDebugInfoStorage
import org.jetbrains.kotlin.idea.runInReadActionWithWriteActionPriority
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.KtCodeFragment import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
@@ -119,7 +120,7 @@ class KotlinDebuggerCaches(project: Project) {
return newCompiledData return newCompiledData
} }
fun <T: PsiElement> getOrComputeClassNames(psiElement: T, create: (T) -> ComputedClassNames): List<String> { fun <T : PsiElement> getOrComputeClassNames(psiElement: T, create: (T) -> ComputedClassNames): List<String> {
val cache = getInstance(runReadAction { psiElement.project }) val cache = getInstance(runReadAction { psiElement.project })
val classNamesCache = cache.cachedClassNames.value val classNamesCache = cache.cachedClassNames.value
@@ -149,21 +150,16 @@ class KotlinDebuggerCaches(project: Project) {
val cachedValue = typeMappersCache[key] val cachedValue = typeMappersCache[key]
if (cachedValue != null) return cachedValue if (cachedValue != null) return cachedValue
if (!isInLibrary) { val newValue = if (!isInLibrary) {
val newValue = createTypeMapperForSourceFile(file) createTypeMapperForSourceFile(file)
typeMappersCache[file] = newValue
return newValue
} }
else { else {
val element = getElementToCreateTypeMapperForLibraryFile(psiElement) val element = getElementToCreateTypeMapperForLibraryFile(psiElement)
val newValue = createTypeMapperForLibraryFile(element, file) createTypeMapperForLibraryFile(element, file)
typeMappersCache[psiElement] = newValue
return newValue
} }
typeMappersCache[key] = newValue
return newValue
} }
fun getOrReadDebugInfoFromBytecode( fun getOrReadDebugInfoFromBytecode(
@@ -178,12 +174,12 @@ class KotlinDebuggerCaches(project: Project) {
runReadAction { element as? KtElement ?: PsiTreeUtil.getParentOfType(element, KtElement::class.java)!! } runReadAction { element as? KtElement ?: PsiTreeUtil.getParentOfType(element, KtElement::class.java)!! }
private fun createTypeMapperForLibraryFile(element: KtElement, file: KtFile): KotlinTypeMapper = private fun createTypeMapperForLibraryFile(element: KtElement, file: KtFile): KotlinTypeMapper =
runReadAction { runInReadActionWithWriteActionPriority {
createTypeMapper(file, element.analyzeAndGetResult()) createTypeMapper(file, element.analyzeAndGetResult())
} }
private fun createTypeMapperForSourceFile(file: KtFile): KotlinTypeMapper = private fun createTypeMapperForSourceFile(file: KtFile): KotlinTypeMapper =
runReadAction { runInReadActionWithWriteActionPriority {
createTypeMapper(file, file.analyzeFullyAndGetResult().apply(AnalysisResult::throwIfError)) createTypeMapper(file, file.analyzeFullyAndGetResult().apply(AnalysisResult::throwIfError))
} }
@@ -238,14 +234,14 @@ class KotlinDebuggerCaches(project: Project) {
data class Parameter(val callText: String, val type: KotlinType, val value: Value? = null) data class Parameter(val callText: String, val type: KotlinType, val value: Value? = null)
sealed class ComputedClassNames(val classNames: List<String>, val shouldBeCached: Boolean) { sealed class ComputedClassNames(val classNames: List<String>, val shouldBeCached: Boolean) {
class CachedClassNames(classNames: List<String>): ComputedClassNames(classNames, true) { class CachedClassNames(classNames: List<String>) : ComputedClassNames(classNames, true) {
constructor(className: String?): this(className.toList()) constructor(className: String?) : this(className.toList())
} }
class NonCachedClassNames(classNames: List<String>): ComputedClassNames(classNames, false) { class NonCachedClassNames(classNames: List<String>) : ComputedClassNames(classNames, false) {
constructor(className: String?): this(className.toList()) constructor(className: String?) : this(className.toList())
} }
} }
} }
private fun String?.toList() = if (this == null) emptyList() else listOf(this) private fun String?.toList() = if (this == null) emptyList() else listOf(this)
@@ -62,6 +62,7 @@ import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.Compiled
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.ParametersDescriptor import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches.ParametersDescriptor
import org.jetbrains.kotlin.idea.debugger.evaluate.compilingEvaluator.loadClasses import org.jetbrains.kotlin.idea.debugger.evaluate.compilingEvaluator.loadClasses
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.ExtractionResult import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.ExtractionResult
import org.jetbrains.kotlin.idea.runInReadActionWithWriteActionPriority
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.attachment.attachmentByPsiFile import org.jetbrains.kotlin.idea.util.attachment.attachmentByPsiFile
import org.jetbrains.kotlin.idea.util.attachment.mergeAttachments import org.jetbrains.kotlin.idea.util.attachment.mergeAttachments
@@ -449,7 +450,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
// contextFile must be NotNull when analyzeInlineFunctions = true // contextFile must be NotNull when analyzeInlineFunctions = true
private fun KtFile.checkForErrors(analyzeInlineFunctions: Boolean = false, contextFile: KtFile? = null): ExtendedAnalysisResult { private fun KtFile.checkForErrors(analyzeInlineFunctions: Boolean = false, contextFile: KtFile? = null): ExtendedAnalysisResult {
return runReadAction { return runInReadActionWithWriteActionPriority {
try { try {
AnalyzingUtils.checkForSyntacticErrors(this) AnalyzingUtils.checkForSyntacticErrors(this)
} }
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.* import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.AnalysisResult.ErrorMessage import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.AnalysisResult.ErrorMessage
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.AnalysisResult.Status import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.AnalysisResult.Status
import org.jetbrains.kotlin.idea.runInReadActionWithWriteActionPriority
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.attachment.attachmentByPsiFile import org.jetbrains.kotlin.idea.util.attachment.attachmentByPsiFile
import org.jetbrains.kotlin.idea.util.attachment.mergeAttachments import org.jetbrains.kotlin.idea.util.attachment.mergeAttachments
@@ -156,7 +157,7 @@ private fun KtFile.findContextElement(): KtElement? {
private var PsiElement.DEBUG_SMART_CAST: PsiElement? by CopyableUserDataProperty(Key.create("DEBUG_SMART_CAST")) private var PsiElement.DEBUG_SMART_CAST: PsiElement? by CopyableUserDataProperty(Key.create("DEBUG_SMART_CAST"))
private fun KtCodeFragment.markSmartCasts() { private fun KtCodeFragment.markSmartCasts() {
val bindingContext = analyzeFullyAndGetResult().bindingContext val bindingContext = runInReadActionWithWriteActionPriority { analyzeFullyAndGetResult() }.bindingContext
val factory = KtPsiFactory(project) val factory = KtPsiFactory(project)
getContentElement()?.forEachDescendantOfType<KtExpression> { expression -> getContentElement()?.forEachDescendantOfType<KtExpression> { expression ->