mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-23 15:51:59 +00:00
Use lazy resolve for counting list of inlined function during step out (KT-14892)
#KT-14892 Fixed
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user