Use lazy resolve for counting list of inlined function during step out (KT-14892)

#KT-14892 Fixed
This commit is contained in:
Nikolay Krasko
2016-12-05 20:01:10 +03:00
parent fc5b493fd3
commit fd8d616d35
4 changed files with 33 additions and 44 deletions

View File

@@ -16,13 +16,13 @@
package org.jetbrains.kotlin.idea.debugger
import com.google.common.collect.Sets
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.io.FileUtilRt
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.idea.KotlinFileTypeFactory
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.resolve.CompositeBindingContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
import java.util.*
@@ -101,14 +100,12 @@ object DebuggerUtils {
fun analyzeInlinedFunctions(
resolutionFacadeForFile: ResolutionFacade,
bindingContextForFile: BindingContext,
file: KtFile,
analyzeOnlyReifiedInlineFunctions: Boolean
): Pair<BindingContext, List<KtFile>> {
val analyzedElements = HashSet<KtElement>()
val context = analyzeElementWithInline(
resolutionFacadeForFile,
bindingContextForFile,
file,
1,
analyzedElements,
@@ -127,30 +124,30 @@ object DebuggerUtils {
return Pair<BindingContext, List<KtFile>>(context, ArrayList(toProcess))
}
fun analyzeElementWithInline(
resolutionFacade: ResolutionFacade,
bindingContext: BindingContext,
function: KtNamedFunction,
analyzeInlineFunctions: Boolean): Collection<KtElement> {
fun analyzeElementWithInline(function: KtNamedFunction, analyzeInlineFunctions: Boolean): Collection<KtElement> {
val analyzedElements = HashSet<KtElement>()
analyzeElementWithInline(resolutionFacade, bindingContext, function, 1, analyzedElements, !analyzeInlineFunctions)
analyzeElementWithInline(function.getResolutionFacade(), function, 1, analyzedElements, !analyzeInlineFunctions)
return analyzedElements
}
private fun analyzeElementWithInline(
resolutionFacade: ResolutionFacade,
bindingContext: BindingContext,
element: KtElement,
deep: Int,
analyzedElements: MutableSet<KtElement>,
analyzeInlineFunctions: Boolean): BindingContext {
val project = element.project
val collectedElements = HashSet<KtNamedFunction>()
val inlineFunctions = HashSet<KtNamedFunction>()
val innerContexts = ArrayList<BindingContext>()
element.accept(object : KtTreeVisitorVoid() {
override fun visitExpression(expression: KtExpression) {
super.visitExpression(expression)
val bindingContext = resolutionFacade.analyze(expression)
innerContexts.add(bindingContext)
val call = bindingContext.get(BindingContext.CALL, expression) ?: return
val resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, call)
@@ -160,6 +157,9 @@ object DebuggerUtils {
override fun visitDestructuringDeclaration(destructuringDeclaration: KtDestructuringDeclaration) {
super.visitDestructuringDeclaration(destructuringDeclaration)
val bindingContext = resolutionFacade.analyze(destructuringDeclaration)
innerContexts.add(bindingContext)
for (entry in destructuringDeclaration.entries) {
val resolvedCall = bindingContext.get(BindingContext.COMPONENT_RESOLVED_CALL, entry)
checkResolveCall(resolvedCall)
@@ -169,6 +169,9 @@ object DebuggerUtils {
override fun visitForExpression(expression: KtForExpression) {
super.visitForExpression(expression)
val bindingContext = resolutionFacade.analyze(expression)
innerContexts.add(bindingContext)
checkResolveCall(bindingContext.get(BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL, expression.loopRange))
checkResolveCall(bindingContext.get(BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, expression.loopRange))
checkResolveCall(bindingContext.get(BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL, expression.loopRange))
@@ -183,7 +186,7 @@ object DebuggerUtils {
if (InlineUtil.isInline(descriptor) && (analyzeInlineFunctions || hasReifiedTypeParameters(descriptor))) {
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor)
if (declaration != null && declaration is KtNamedFunction && !analyzedElements.contains(declaration)) {
collectedElements.add(declaration)
inlineFunctions.add(declaration)
}
}
}
@@ -191,24 +194,18 @@ object DebuggerUtils {
analyzedElements.add(element)
if (!collectedElements.isEmpty() && deep < 10) {
val innerContexts = ArrayList<BindingContext>()
for (inlineFunctions in collectedElements) {
val body = inlineFunctions.bodyExpression
if (!inlineFunctions.isEmpty() && deep < 10) {
for (inlineFunction in inlineFunctions) {
val body = inlineFunction.bodyExpression
if (body != null) {
val bindingContextForFunction = resolutionFacade.analyze(body, BodyResolveMode.FULL)
innerContexts.add(analyzeElementWithInline(resolutionFacade, bindingContextForFunction, inlineFunctions, deep + 1,
analyzedElements, analyzeInlineFunctions))
innerContexts.add(analyzeElementWithInline(resolutionFacade, inlineFunction, deep + 1, analyzedElements, analyzeInlineFunctions))
}
}
innerContexts.add(bindingContext)
analyzedElements.addAll(collectedElements)
return CompositeBindingContext.create(innerContexts)
analyzedElements.addAll(inlineFunctions)
}
return bindingContext
return CompositeBindingContext.create(innerContexts)
}
private fun hasReifiedTypeParameters(descriptor: CallableDescriptor): Boolean {

View File

@@ -88,7 +88,7 @@ internal val GENERATED_FUNCTION_NAME = "generated_for_debugger_kotlin_rulezzzz"
private val DEBUG_MODE = false
object KotlinEvaluationBuilder: EvaluatorBuilder {
object KotlinEvaluationBuilder : EvaluatorBuilder {
override fun build(codeFragment: PsiElement, position: SourcePosition?): ExpressionEvaluator {
if (codeFragment !is KtCodeFragment || position == null) {
return EvaluatorBuilderImpl.getInstance()!!.build(codeFragment, position)
@@ -121,7 +121,7 @@ object KotlinEvaluationBuilder: EvaluatorBuilder {
}
}
class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: SourcePosition): Evaluator {
class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: SourcePosition) : Evaluator {
override fun evaluate(context: EvaluationContextImpl): Any? {
if (codeFragment.text.isEmpty()) {
return context.debugProcess.virtualMachineProxy.mirrorOfVoid()
@@ -163,9 +163,9 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
Attachment("context.info", text))
LOG.error(LogMessageEx.createEvent(
"Couldn't evaluate expression",
ExceptionUtil.getThrowableText(e),
mergeAttachments(*attachments)))
"Couldn't evaluate expression",
ExceptionUtil.getThrowableText(e),
mergeAttachments(*attachments)))
val cause = if (e.message != null) ": ${e.message}" else ""
exception("An exception occurs during Evaluate Expression Action $cause")
@@ -195,7 +195,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
codeFragment.checkForErrors()
val extractionResult = getFunctionForExtractedFragment(codeFragment, sourcePosition.file, sourcePosition.line)
?: throw IllegalStateException("Code fragment cannot be extracted to function: ${codeFragment.text}")
?: throw IllegalStateException("Code fragment cannot be extracted to function: ${codeFragment.text}")
val parametersDescriptor = extractionResult.getParametersForDebugger(codeFragment)
val extractedFunction = extractionResult.declaration as KtNamedFunction
@@ -325,7 +325,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
val contextElementFile = fragment.context?.containingFile
if (contextElementFile is KtCodeFragment) {
contextElementFile.accept(object: KtTreeVisitorVoid() {
contextElementFile.accept(object : KtTreeVisitorVoid() {
override fun visitProperty(property: KtProperty) {
val value = property.getUserData(KotlinCodeFragmentFactory.LABEL_VARIABLE_VALUE_KEY)
if (value != null) {
@@ -435,7 +435,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
val declarationDescriptor = paramAnonymousType.constructor.declarationDescriptor
if (declarationDescriptor is ClassDescriptor) {
val localVariable = visitor.findValue(localVariableName, asmType = null, checkType = false, failIfNotFound = false)
?: exception("Couldn't find local variable this in current frame to get classType for anonymous type $paramAnonymousType}")
?: exception("Couldn't find local variable this in current frame to get classType for anonymous type $paramAnonymousType}")
record(CodegenBinding.ASM_TYPE, declarationDescriptor, localVariable.asmType)
if (LOG.isDebugEnabled) {
LOG.debug("Asm type ${localVariable.asmType.className} was recorded for ${declarationDescriptor.name}")
@@ -474,7 +474,7 @@ class KotlinEvaluator(val codeFragment: KtCodeFragment, val sourcePosition: Sour
}
if (analyzeInlineFunctions) {
val (newBindingContext, files) = DebuggerUtils.analyzeInlinedFunctions(resolutionFacade, bindingContext, this, false)
val (newBindingContext, files) = DebuggerUtils.analyzeInlinedFunctions(resolutionFacade, this, false)
ExtendedAnalysisResult(newBindingContext, analysisResult.moduleDescriptor, files)
}
else {

View File

@@ -181,13 +181,7 @@ private fun getInlineFunctionsIfAny(file: KtFile, offset: Int): List<KtNamedFunc
val descriptor = containingFunction.resolveToDescriptor()
if (!InlineUtil.isInline(descriptor)) return emptyList()
val inlineFunctionsCalls = DebuggerUtils.analyzeElementWithInline(
containingFunction.getResolutionFacade(),
containingFunction.analyzeFully(),
containingFunction,
false
).filterIsInstance<KtNamedFunction>()
val inlineFunctionsCalls = DebuggerUtils.analyzeElementWithInline(containingFunction, false).filterIsInstance<KtNamedFunction>()
return inlineFunctionsCalls
}

View File

@@ -292,10 +292,8 @@ public class KotlinBytecodeToolWindow extends JPanel implements Disposable {
) {
ResolutionFacade resolutionFacade = ResolutionUtils.getResolutionFacade(ktFile);
BindingContext bindingContextForFile = resolutionFacade.analyzeFullyAndGetResult(Collections.singletonList(ktFile)).getBindingContext();
kotlin.Pair<BindingContext, List<KtFile>> result = DebuggerUtils.INSTANCE.analyzeInlinedFunctions(
resolutionFacade, bindingContextForFile, ktFile, configuration.getBoolean(CommonConfigurationKeys.DISABLE_INLINE)
resolutionFacade, ktFile, configuration.getBoolean(CommonConfigurationKeys.DISABLE_INLINE)
);
BindingContext bindingContext = result.getFirst();