Drop unnecesary logic about additional context for lambda in debugger

This commit is contained in:
Natalia Ukhorskaya
2015-11-30 18:22:16 +03:00
parent f34f7556bc
commit 29778311e8
4 changed files with 8 additions and 105 deletions
@@ -40,9 +40,6 @@ public abstract class KtCodeFragment(
private var viewProvider = super<KtFile>.getViewProvider() as SingleRootFileViewProvider private var viewProvider = super<KtFile>.getViewProvider() as SingleRootFileViewProvider
private var imports = LinkedHashSet<String>() private var imports = LinkedHashSet<String>()
private val additionalContextForLambda: PsiElement? by lazy {
this.getCopyableUserData(ADDITIONAL_CONTEXT_FOR_LAMBDA)?.invoke()
}
init { init {
getViewProvider().forceCachedPsi(this) getViewProvider().forceCachedPsi(this)
@@ -69,7 +66,7 @@ public abstract class KtCodeFragment(
override fun isValid() = true override fun isValid() = true
override fun getContext() = additionalContextForLambda ?: context override fun getContext() = context
override fun getResolveScope() = context?.getResolveScope() ?: super<KtFile>.getResolveScope() override fun getResolveScope() = context?.getResolveScope() ?: super<KtFile>.getResolveScope()
@@ -20,9 +20,7 @@ import com.intellij.debugger.DebuggerManagerEx
import com.intellij.debugger.engine.evaluation.CodeFragmentFactory import com.intellij.debugger.engine.evaluation.CodeFragmentFactory
import com.intellij.debugger.engine.evaluation.CodeFragmentKind import com.intellij.debugger.engine.evaluation.CodeFragmentKind
import com.intellij.debugger.engine.evaluation.TextWithImports import com.intellij.debugger.engine.evaluation.TextWithImports
import com.intellij.debugger.engine.events.DebuggerCommandImpl
import com.intellij.debugger.jdi.StackFrameProxyImpl import com.intellij.debugger.jdi.StackFrameProxyImpl
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
@@ -34,24 +32,21 @@ import com.intellij.util.concurrency.Semaphore
import com.intellij.xdebugger.XDebuggerManager import com.intellij.xdebugger.XDebuggerManager
import com.intellij.xdebugger.impl.XDebugSessionImpl import com.intellij.xdebugger.impl.XDebugSessionImpl
import com.intellij.xdebugger.impl.ui.tree.ValueMarkup import com.intellij.xdebugger.impl.ui.tree.ValueMarkup
import com.sun.jdi.* import com.sun.jdi.ArrayReference
import com.sun.jdi.PrimitiveValue
import com.sun.jdi.Value
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
import org.jetbrains.eval4j.jdi.asValue import org.jetbrains.eval4j.jdi.asValue
import org.jetbrains.kotlin.asJava.KtLightClass import org.jetbrains.kotlin.asJava.KtLightClass
import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
import org.jetbrains.kotlin.idea.core.refactoring.j2kText import org.jetbrains.kotlin.idea.core.refactoring.j2kText
import org.jetbrains.kotlin.idea.core.refactoring.quoteIfNeeded import org.jetbrains.kotlin.idea.core.refactoring.quoteIfNeeded
import org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider import org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.addToStdlib.check
@@ -115,61 +110,6 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
} }
}) })
if (contextElement != null) {
val lambda = getInlineLambdaIfInside(contextElement)
if (lambda != null) {
codeFragment.putCopyableUserData(KtCodeFragment.ADDITIONAL_CONTEXT_FOR_LAMBDA, lamdba@ {
val debuggerContext = DebuggerManagerEx.getInstanceEx(project).context
val semaphore = Semaphore()
semaphore.down()
var visibleVariables: Map<LocalVariable, Value>? = null
val worker = object : DebuggerCommandImpl() {
override fun action() {
try {
val frame = if (ApplicationManager.getApplication().isUnitTestMode)
context?.getCopyableUserData(DEBUG_FRAME_FOR_TESTS)?.stackFrame
else
debuggerContext.frameProxy?.stackFrame
visibleVariables = frame?.let {
f ->
val variables = f.visibleVariables().filter {
!it.name().startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT) &&
!it.name().startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION)
}
f.getValues(variables)
} ?: emptyMap<LocalVariable, Value>()
}
catch(ignored: AbsentInformationException) {
// Debug info unavailable
}
finally {
semaphore.up()
}
}
}
debuggerContext.debugProcess?.managerThread?.invoke(worker)
for (i in 0..50) {
if (semaphore.waitFor(20)) break
}
if (visibleVariables == null) return@lamdba null
val fragmentForVisibleVariables = createCodeFragmentForVisibleVariables(lambda.project, visibleVariables!!)
return@lamdba createWrappingContext(
fragmentForVisibleVariables.first,
fragmentForVisibleVariables.second,
lambda.bodyExpression,
lambda.project)
})
}
}
return codeFragment return codeFragment
} }
@@ -226,19 +166,6 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
private fun KtElement?.check(): Boolean = this != null && this.check { KotlinEditorTextProvider.isAcceptedAsCodeFragmentContext(it) } != null private fun KtElement?.check(): Boolean = this != null && this.check { KotlinEditorTextProvider.isAcceptedAsCodeFragmentContext(it) } != null
private fun getInlineLambdaIfInside(contextElement: KtElement): KtFunction? {
val parentLambda = contextElement.getParentOfType<KtFunction>(false) ?: return null
if (!parentLambda.isLocal) return null
if (KtPsiUtil.getParentCallIfPresent(parentLambda) == null) return null
val bindingContext = contextElement.analyze(BodyResolveMode.PARTIAL)
if (InlineUtil.isInlinedArgument(parentLambda, bindingContext, false)) {
return parentLambda
}
return null
}
//internal for tests //internal for tests
fun createCodeFragmentForLabeledObjects(project: Project, markupMap: Map<*, ValueMarkup>): Pair<String, Map<String, Value>> { fun createCodeFragmentForLabeledObjects(project: Project, markupMap: Map<*, ValueMarkup>): Pair<String, Map<String, Value>> {
val sb = StringBuilder() val sb = StringBuilder()
@@ -259,22 +186,6 @@ class KotlinCodeFragmentFactory: CodeFragmentFactory() {
return sb.toString() to labeledObjects return sb.toString() to labeledObjects
} }
private fun createCodeFragmentForVisibleVariables(project: Project, visibleVariables: Map<LocalVariable, Value>): Pair<String, Map<String, Value>> {
val sb = StringBuilder()
val labeledObjects = HashMap<String, Value>()
for ((variable, value) in visibleVariables) {
val variableName = variable.name()
if (!Name.isValidIdentifier(variableName)) continue
val kotlinProperty = createKotlinProperty(project, variableName, variable.typeName(), value) ?: continue
sb.append("$kotlinProperty\n")
labeledObjects.put(variableName, value)
}
sb.append("val _debug_context_val = 1")
return sb.toString() to labeledObjects
}
private fun createKotlinProperty(project: Project, variableName: String, variableTypeName: String, value: Value): String? { private fun createKotlinProperty(project: Project, variableName: String, variableTypeName: String, value: Value): String? {
val actualClassDescriptor = value.asValue().asmType.getClassDescriptor(project) val actualClassDescriptor = value.asValue().asmType.getClassDescriptor(project)
if (actualClassDescriptor != null && actualClassDescriptor.defaultType.arguments.isEmpty()) { if (actualClassDescriptor != null && actualClassDescriptor.defaultType.arguments.isEmpty()) {
@@ -1,14 +1,12 @@
LineBreakpoint created at parametersOfInlineFun.kt:8 LineBreakpoint created at parametersOfInlineFun.kt:15
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! parametersOfInlineFun.ParametersOfInlineFunKt !JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !OUTPUT_PATH!;!KOTLIN_RUNTIME!;!CUSTOM_LIBRARY!;!RT_JAR! parametersOfInlineFun.ParametersOfInlineFunKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
parametersOfInlineFun.kt:8 parametersOfInlineFun.kt:15
parametersOfInlineFun.kt:8
Compile bytecode for primitive Compile bytecode for primitive
Compile bytecode for it
Compile bytecode for array Compile bytecode for array
Compile bytecode for str Compile bytecode for str
Compile bytecode for list Compile bytecode for list
Compile bytecode for `$receiver`.prop Compile bytecode for this.prop
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0 Process finished with exit code 0
@@ -21,9 +21,6 @@ class A(val prop: Int)
// EXPRESSION: primitive // EXPRESSION: primitive
// RESULT: 1: I // RESULT: 1: I
// EXPRESSION: it
// RESULT: 1: I
// EXPRESSION: array // EXPRESSION: array
// RESULT: instance of java.lang.Integer[1] (id=ID): [Ljava/lang/Integer; // RESULT: instance of java.lang.Integer[1] (id=ID): [Ljava/lang/Integer;
@@ -33,5 +30,5 @@ class A(val prop: Int)
// EXPRESSION: list // EXPRESSION: list
// RESULT: instance of java.util.Collections$SingletonList(id=ID): Ljava/util/Collections$SingletonList; // RESULT: instance of java.util.Collections$SingletonList(id=ID): Ljava/util/Collections$SingletonList;
// EXPRESSION: `$receiver`.prop // EXPRESSION: this.prop
// RESULT: 1: I // RESULT: 1: I