Reformat: debugger.stepping
This commit is contained in:
+2
-1
@@ -27,7 +27,8 @@ public class DebugProcessImplHelper {
|
|||||||
public static DebugProcessImpl.StepOverCommand createStepOverCommandWithCustomFilter(
|
public static DebugProcessImpl.StepOverCommand createStepOverCommandWithCustomFilter(
|
||||||
SuspendContextImpl suspendContext,
|
SuspendContextImpl suspendContext,
|
||||||
boolean ignoreBreakpoints,
|
boolean ignoreBreakpoints,
|
||||||
KotlinSuspendCallStepOverFilter methodFilter) {
|
KotlinSuspendCallStepOverFilter methodFilter
|
||||||
|
) {
|
||||||
DebugProcessImpl debugProcess = suspendContext.getDebugProcess();
|
DebugProcessImpl debugProcess = suspendContext.getDebugProcess();
|
||||||
return debugProcess.new StepOverCommand(suspendContext, ignoreBreakpoints, StepRequest.STEP_LINE) {
|
return debugProcess.new StepOverCommand(suspendContext, ignoreBreakpoints, StepRequest.STEP_LINE) {
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
+3
-3
@@ -36,8 +36,8 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypesAndPredicate
|
|||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
|
||||||
class KotlinBasicStepMethodFilter(
|
class KotlinBasicStepMethodFilter(
|
||||||
targetDescriptor: CallableMemberDescriptor,
|
targetDescriptor: CallableMemberDescriptor,
|
||||||
private val myCallingExpressionLines: Range<Int>
|
private val myCallingExpressionLines: Range<Int>
|
||||||
) : NamedMethodFilter {
|
) : NamedMethodFilter {
|
||||||
private val myTargetMethodName: String = when (targetDescriptor) {
|
private val myTargetMethodName: String = when (targetDescriptor) {
|
||||||
is ClassDescriptor, is ConstructorDescriptor -> "<init>"
|
is ClassDescriptor, is ConstructorDescriptor -> "<init>"
|
||||||
@@ -46,7 +46,7 @@ class KotlinBasicStepMethodFilter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val _targetDescriptor = SofterReference(
|
private val _targetDescriptor = SofterReference(
|
||||||
(targetDescriptor as? FunctionDescriptor)?.let { SamCodegenUtil.getOriginalIfSamAdapter(it) } ?: targetDescriptor
|
(targetDescriptor as? FunctionDescriptor)?.let { SamCodegenUtil.getOriginalIfSamAdapter(it) } ?: targetDescriptor
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun getCallingExpressionLines() = myCallingExpressionLines
|
override fun getCallingExpressionLines() = myCallingExpressionLines
|
||||||
|
|||||||
+8
-9
@@ -22,18 +22,18 @@ import com.intellij.debugger.engine.DebugProcessImpl
|
|||||||
import com.intellij.util.Range
|
import com.intellij.util.Range
|
||||||
import com.sun.jdi.Location
|
import com.sun.jdi.Location
|
||||||
import org.jetbrains.kotlin.codegen.coroutines.DO_RESUME_METHOD_NAME
|
import org.jetbrains.kotlin.codegen.coroutines.DO_RESUME_METHOD_NAME
|
||||||
import org.jetbrains.kotlin.idea.refactoring.isMultiLine
|
|
||||||
import org.jetbrains.kotlin.idea.debugger.isInsideInlineArgument
|
import org.jetbrains.kotlin.idea.debugger.isInsideInlineArgument
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.isMultiLine
|
||||||
import org.jetbrains.kotlin.psi.KtBlockExpression
|
import org.jetbrains.kotlin.psi.KtBlockExpression
|
||||||
import org.jetbrains.kotlin.psi.KtFunction
|
import org.jetbrains.kotlin.psi.KtFunction
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
class KotlinLambdaMethodFilter(
|
class KotlinLambdaMethodFilter(
|
||||||
private val lambda: KtFunction,
|
private val lambda: KtFunction,
|
||||||
private val myCallingExpressionLines: Range<Int>,
|
private val myCallingExpressionLines: Range<Int>,
|
||||||
private val isInline: Boolean,
|
private val isInline: Boolean,
|
||||||
private val isSuspend: Boolean
|
private val isSuspend: Boolean
|
||||||
): BreakpointStepMethodFilter {
|
) : BreakpointStepMethodFilter {
|
||||||
private val myFirstStatementPosition: SourcePosition?
|
private val myFirstStatementPosition: SourcePosition?
|
||||||
private val myLastStatementLine: Int
|
private val myLastStatementLine: Int
|
||||||
|
|
||||||
@@ -52,8 +52,7 @@ class KotlinLambdaMethodFilter(
|
|||||||
}
|
}
|
||||||
myFirstStatementPosition = firstStatementPosition
|
myFirstStatementPosition = firstStatementPosition
|
||||||
myLastStatementLine = if (lastStatementPosition != null) lastStatementPosition.line else -1
|
myLastStatementLine = if (lastStatementPosition != null) lastStatementPosition.line else -1
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
myFirstStatementPosition = SourcePosition.createFromElement(lambda)
|
myFirstStatementPosition = SourcePosition.createFromElement(lambda)
|
||||||
myLastStatementLine = myFirstStatementPosition!!.line
|
myLastStatementLine = myFirstStatementPosition!!.line
|
||||||
}
|
}
|
||||||
@@ -78,7 +77,7 @@ class KotlinLambdaMethodFilter(
|
|||||||
if (isSuspend) {
|
if (isSuspend) {
|
||||||
return name == DO_RESUME_METHOD_NAME
|
return name == DO_RESUME_METHOD_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
return name == OperatorNameConventions.INVOKE.asString()
|
return name == OperatorNameConventions.INVOKE.asString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -26,12 +26,12 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
|||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
class KotlinLambdaSmartStepTarget(
|
class KotlinLambdaSmartStepTarget(
|
||||||
label: String,
|
label: String,
|
||||||
highlightElement: KtFunction,
|
highlightElement: KtFunction,
|
||||||
lines: Range<Int>,
|
lines: Range<Int>,
|
||||||
val isInline: Boolean,
|
val isInline: Boolean,
|
||||||
val isSuspend: Boolean
|
val isSuspend: Boolean
|
||||||
): SmartStepTarget(label, highlightElement, true, lines) {
|
) : SmartStepTarget(label, highlightElement, true, lines) {
|
||||||
override fun getIcon(): Icon = KotlinIcons.LAMBDA
|
override fun getIcon(): Icon = KotlinIcons.LAMBDA
|
||||||
|
|
||||||
fun getLambda() = highlightElement as KtFunction
|
fun getLambda() = highlightElement as KtFunction
|
||||||
|
|||||||
+5
-5
@@ -13,11 +13,11 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
|||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
class KotlinMethodSmartStepTarget(
|
class KotlinMethodSmartStepTarget(
|
||||||
val descriptor: CallableMemberDescriptor,
|
val descriptor: CallableMemberDescriptor,
|
||||||
label: String,
|
label: String,
|
||||||
highlightElement: PsiElement,
|
highlightElement: PsiElement,
|
||||||
lines: Range<Int>
|
lines: Range<Int>
|
||||||
): SmartStepTarget(label, highlightElement, false, lines) {
|
) : SmartStepTarget(label, highlightElement, false, lines) {
|
||||||
override fun getIcon(): Icon? {
|
override fun getIcon(): Icon? {
|
||||||
return when {
|
return when {
|
||||||
descriptor.isExtension -> KotlinIcons.EXTENSION_FUNCTION
|
descriptor.isExtension -> KotlinIcons.EXTENSION_FUNCTION
|
||||||
|
|||||||
+2
-3
@@ -32,13 +32,12 @@ class KotlinSimpleGetterProvider : SimplePropertyGetterProvider {
|
|||||||
if (accessor != null && accessor.isGetter) {
|
if (accessor != null && accessor.isGetter) {
|
||||||
val body = accessor.bodyExpression
|
val body = accessor.bodyExpression
|
||||||
return when (body) {
|
return when (body) {
|
||||||
// val a: Int get() { return field }
|
|
||||||
is KtBlockExpression -> {
|
is KtBlockExpression -> {
|
||||||
|
// val a: Int get() { return field }
|
||||||
val returnedExpression = (body.statements.singleOrNull() as? KtReturnExpression)?.returnedExpression ?: return false
|
val returnedExpression = (body.statements.singleOrNull() as? KtReturnExpression)?.returnedExpression ?: return false
|
||||||
returnedExpression.textMatches("field")
|
returnedExpression.textMatches("field")
|
||||||
}
|
}
|
||||||
// val a: Int get() = field
|
is KtExpression -> body.textMatches("field") // val a: Int get() = field
|
||||||
is KtExpression -> body.textMatches("field")
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-12
@@ -54,8 +54,8 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
|
|||||||
|
|
||||||
val elementAtOffset = position.elementAt ?: return emptyList()
|
val elementAtOffset = position.elementAt ?: return emptyList()
|
||||||
|
|
||||||
val element = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, elementAtOffset.textRange.startOffset) as? KtElement ?:
|
val element = CodeInsightUtils.getTopmostElementAtOffset(elementAtOffset, elementAtOffset.textRange.startOffset) as? KtElement
|
||||||
return emptyList()
|
?: return emptyList()
|
||||||
|
|
||||||
val elementTextRange = element.textRange ?: return emptyList()
|
val elementTextRange = element.textRange ?: return emptyList()
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
|
|||||||
val result = OrderedSet<SmartStepTarget>()
|
val result = OrderedSet<SmartStepTarget>()
|
||||||
|
|
||||||
// TODO support class initializers, local functions, delegated properties with specified type, setter for properties
|
// TODO support class initializers, local functions, delegated properties with specified type, setter for properties
|
||||||
element.accept(object: KtTreeVisitorVoid() {
|
element.accept(object : KtTreeVisitorVoid() {
|
||||||
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
|
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
|
||||||
recordFunctionLiteral(lambdaExpression.functionLiteral)
|
recordFunctionLiteral(lambdaExpression.functionLiteral)
|
||||||
}
|
}
|
||||||
@@ -87,8 +87,11 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
|
|||||||
if (argument.arguments.any { getArgumentExpression(it) == function }) {
|
if (argument.arguments.any { getArgumentExpression(it) == function }) {
|
||||||
val resultingDescriptor = resolvedCall.resultingDescriptor
|
val resultingDescriptor = resolvedCall.resultingDescriptor
|
||||||
val label = KotlinLambdaSmartStepTarget.calcLabel(resultingDescriptor, param.name)
|
val label = KotlinLambdaSmartStepTarget.calcLabel(resultingDescriptor, param.name)
|
||||||
result.add(KotlinLambdaSmartStepTarget(
|
result.add(
|
||||||
label, function, lines, InlineUtil.isInline(resultingDescriptor), param.type.isSuspendFunctionType))
|
KotlinLambdaSmartStepTarget(
|
||||||
|
label, function, lines, InlineUtil.isInline(resultingDescriptor), param.type.isSuspendFunctionType
|
||||||
|
)
|
||||||
|
)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,7 +99,8 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getArgumentExpression(it: ValueArgument) = (it.getArgumentExpression() as? KtLambdaExpression)?.functionLiteral ?: it.getArgumentExpression()
|
private fun getArgumentExpression(it: ValueArgument) =
|
||||||
|
(it.getArgumentExpression() as? KtLambdaExpression)?.functionLiteral ?: it.getArgumentExpression()
|
||||||
|
|
||||||
override fun visitObjectLiteralExpression(expression: KtObjectLiteralExpression) {
|
override fun visitObjectLiteralExpression(expression: KtObjectLiteralExpression) {
|
||||||
// skip calls in object declarations
|
// skip calls in object declarations
|
||||||
@@ -159,10 +163,10 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
|
|||||||
val label = KotlinMethodSmartStepTarget.calcLabel(getterDescriptor)
|
val label = KotlinMethodSmartStepTarget.calcLabel(getterDescriptor)
|
||||||
result.add(KotlinMethodSmartStepTarget(getterDescriptor, label, expression, lines))
|
result.add(KotlinMethodSmartStepTarget(getterDescriptor, label, expression, lines))
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val delegatedPropertyGetterDescriptor = delegatedResolvedCall.resultingDescriptor
|
val delegatedPropertyGetterDescriptor = delegatedResolvedCall.resultingDescriptor
|
||||||
val label = "${propertyDescriptor.name}." + KotlinMethodSmartStepTarget.calcLabel(delegatedPropertyGetterDescriptor)
|
val label =
|
||||||
|
"${propertyDescriptor.name}." + KotlinMethodSmartStepTarget.calcLabel(delegatedPropertyGetterDescriptor)
|
||||||
result.add(KotlinMethodSmartStepTarget(delegatedPropertyGetterDescriptor, label, expression, lines))
|
result.add(KotlinMethodSmartStepTarget(delegatedPropertyGetterDescriptor, label, expression, lines))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,8 +184,7 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
|
|||||||
(DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor) as? PsiMethod)?.let {
|
(DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor) as? PsiMethod)?.let {
|
||||||
result.add(MethodSmartStepTarget(it, null, expression, false, lines))
|
result.add(MethodSmartStepTarget(it, null, expression, false, lines))
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (descriptor is ConstructorDescriptor && descriptor.isPrimary) {
|
if (descriptor is ConstructorDescriptor && descriptor.isPrimary) {
|
||||||
val psiElement = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor)
|
val psiElement = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, descriptor)
|
||||||
if (psiElement is KtClass && psiElement.getAnonymousInitializers().isEmpty()) {
|
if (psiElement is KtClass && psiElement.getAnonymousInitializers().isEmpty()) {
|
||||||
@@ -216,7 +219,8 @@ class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
|
|||||||
KotlinBasicStepMethodFilter(stepTarget.descriptor, stepTarget.callingExpressionLines!!)
|
KotlinBasicStepMethodFilter(stepTarget.descriptor, stepTarget.callingExpressionLines!!)
|
||||||
is KotlinLambdaSmartStepTarget ->
|
is KotlinLambdaSmartStepTarget ->
|
||||||
KotlinLambdaMethodFilter(
|
KotlinLambdaMethodFilter(
|
||||||
stepTarget.getLambda(), stepTarget.callingExpressionLines!!, stepTarget.isInline, stepTarget.isSuspend)
|
stepTarget.getLambda(), stepTarget.callingExpressionLines!!, stepTarget.isInline, stepTarget.isSuspend
|
||||||
|
)
|
||||||
else -> super.createMethodFilter(stepTarget)
|
else -> super.createMethodFilter(stepTarget)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-11
@@ -61,13 +61,15 @@ class KotlinStepActionFactory(private val debuggerProcess: DebugProcessImpl) {
|
|||||||
// TODO: ask for better API
|
// TODO: ask for better API
|
||||||
// Should be safe to use reflection as method is protected and not obfuscated
|
// Should be safe to use reflection as method is protected and not obfuscated
|
||||||
private fun doStep(
|
private fun doStep(
|
||||||
suspendContext: SuspendContextImpl,
|
suspendContext: SuspendContextImpl,
|
||||||
stepThread: ThreadReferenceProxyImpl,
|
stepThread: ThreadReferenceProxyImpl,
|
||||||
size: Int, depth: Int, hint: RequestHint) {
|
size: Int, depth: Int, hint: RequestHint
|
||||||
|
) {
|
||||||
val doStepMethod = DebugProcessImpl::class.java.getDeclaredMethod(
|
val doStepMethod = DebugProcessImpl::class.java.getDeclaredMethod(
|
||||||
"doStep",
|
"doStep",
|
||||||
SuspendContextImpl::class.java, ThreadReferenceProxyImpl::class.java,
|
SuspendContextImpl::class.java, ThreadReferenceProxyImpl::class.java,
|
||||||
Integer.TYPE, Integer.TYPE, RequestHint::class.java)
|
Integer.TYPE, Integer.TYPE, RequestHint::class.java
|
||||||
|
)
|
||||||
|
|
||||||
doStepMethod.isAccessible = true
|
doStepMethod.isAccessible = true
|
||||||
|
|
||||||
@@ -89,7 +91,8 @@ class KotlinStepActionFactory(private val debuggerProcess: DebugProcessImpl) {
|
|||||||
return field.get(debuggerProcess) as T
|
return field.get(debuggerProcess) as T
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class StepOverInlineCommand(private val mySmartStepFilter: KotlinMethodFilter, private val myStepSize: Int) : KotlinStepAction() {
|
private inner class StepOverInlineCommand(private val mySmartStepFilter: KotlinMethodFilter, private val myStepSize: Int) :
|
||||||
|
KotlinStepAction() {
|
||||||
private fun getContextThread(suspendContext: SuspendContextImpl): ThreadReferenceProxyImpl? {
|
private fun getContextThread(suspendContext: SuspendContextImpl): ThreadReferenceProxyImpl? {
|
||||||
val contextThread = debuggerContext.threadProxy
|
val contextThread = debuggerContext.threadProxy
|
||||||
return contextThread ?: suspendContext.thread
|
return contextThread ?: suspendContext.thread
|
||||||
@@ -114,8 +117,7 @@ class KotlinStepActionFactory(private val debuggerProcess: DebugProcessImpl) {
|
|||||||
}
|
}
|
||||||
if (isResumeOnlyCurrentThread && suspendContext.suspendPolicy == EventRequest.SUSPEND_ALL) {
|
if (isResumeOnlyCurrentThread && suspendContext.suspendPolicy == EventRequest.SUSPEND_ALL) {
|
||||||
suspendManager.resumeThread(suspendContext, thread)
|
suspendManager.resumeThread(suspendContext, thread)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
suspendManager.resume(suspendContext)
|
suspendManager.resume(suspendContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,8 +138,7 @@ class KotlinStepActionFactory(private val debuggerProcess: DebugProcessImpl) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
session.setIgnoreStepFiltersFlag(stepThread.frameCount())
|
session.setIgnoreStepFiltersFlag(stepThread.frameCount())
|
||||||
}
|
} catch (e: EvaluateException) {
|
||||||
catch (e: EvaluateException) {
|
|
||||||
LOG.info(e)
|
LOG.info(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -25,11 +25,11 @@ import com.sun.jdi.Location
|
|||||||
import org.jetbrains.kotlin.idea.debugger.ktLocationInfo
|
import org.jetbrains.kotlin.idea.debugger.ktLocationInfo
|
||||||
|
|
||||||
class StepOverFilterData(
|
class StepOverFilterData(
|
||||||
val lineNumber: Int,
|
val lineNumber: Int,
|
||||||
val stepOverLines: Set<Int>,
|
val stepOverLines: Set<Int>,
|
||||||
val inlineRangeVariables: List<LocalVariable>,
|
val inlineRangeVariables: List<LocalVariable>,
|
||||||
val isDexDebug: Boolean,
|
val isDexDebug: Boolean,
|
||||||
val skipAfterCodeIndex: Long = -1
|
val skipAfterCodeIndex: Long = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
class KotlinStepOverInlineFilter(val project: Project, val data: StepOverFilterData) : KotlinMethodFilter {
|
class KotlinStepOverInlineFilter(val project: Project, val data: StepOverFilterData) : KotlinMethodFilter {
|
||||||
|
|||||||
+9
-14
@@ -16,22 +16,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.debugger.stepping
|
package org.jetbrains.kotlin.idea.debugger.stepping
|
||||||
|
|
||||||
import com.intellij.debugger.SourcePosition
|
import com.intellij.debugger.engine.RequestHint
|
||||||
import com.intellij.debugger.engine.*
|
import com.intellij.debugger.engine.SuspendContextImpl
|
||||||
import com.intellij.debugger.engine.evaluation.EvaluateException
|
import com.intellij.debugger.engine.evaluation.EvaluateException
|
||||||
import com.intellij.debugger.engine.jdi.StackFrameProxy
|
|
||||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl
|
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.diagnostic.Logger
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
import com.intellij.openapi.util.Computable
|
|
||||||
import com.sun.jdi.VMDisconnectedException
|
import com.sun.jdi.VMDisconnectedException
|
||||||
import com.sun.jdi.request.StepRequest
|
import com.sun.jdi.request.StepRequest
|
||||||
|
|
||||||
// Originally copied from RequestHint
|
// Originally copied from RequestHint
|
||||||
class KotlinStepOverInlinedLinesHint(
|
class KotlinStepOverInlinedLinesHint(
|
||||||
stepThread: ThreadReferenceProxyImpl,
|
stepThread: ThreadReferenceProxyImpl,
|
||||||
suspendContext: SuspendContextImpl,
|
suspendContext: SuspendContextImpl,
|
||||||
methodFilter: KotlinMethodFilter) : RequestHint(stepThread, suspendContext, methodFilter) {
|
methodFilter: KotlinMethodFilter
|
||||||
|
) : RequestHint(stepThread, suspendContext, methodFilter) {
|
||||||
|
|
||||||
private val LOG = Logger.getInstance(KotlinStepOverInlinedLinesHint::class.java)
|
private val LOG = Logger.getInstance(KotlinStepOverInlinedLinesHint::class.java)
|
||||||
|
|
||||||
@@ -46,8 +44,7 @@ class KotlinStepOverInlinedLinesHint(
|
|||||||
if (isTheSameFrame(context)) {
|
if (isTheSameFrame(context)) {
|
||||||
return if (filter.locationMatches(context, frameProxy.location())) {
|
return if (filter.locationMatches(context, frameProxy.location())) {
|
||||||
STOP
|
STOP
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
StepRequest.STEP_OVER
|
StepRequest.STEP_OVER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,10 +55,8 @@ class KotlinStepOverInlinedLinesHint(
|
|||||||
|
|
||||||
return StepRequest.STEP_OUT
|
return StepRequest.STEP_OUT
|
||||||
}
|
}
|
||||||
}
|
} catch (ignored: VMDisconnectedException) {
|
||||||
catch (ignored: VMDisconnectedException) {
|
} catch (e: EvaluateException) {
|
||||||
}
|
|
||||||
catch (e: EvaluateException) {
|
|
||||||
LOG.error(e)
|
LOG.error(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+104
-97
@@ -62,9 +62,9 @@ import org.jetbrains.kotlin.utils.keysToMap
|
|||||||
|
|
||||||
class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
||||||
override fun getStepOverCommand(
|
override fun getStepOverCommand(
|
||||||
suspendContext: SuspendContextImpl?,
|
suspendContext: SuspendContextImpl?,
|
||||||
ignoreBreakpoints: Boolean,
|
ignoreBreakpoints: Boolean,
|
||||||
stepSize: Int
|
stepSize: Int
|
||||||
): DebugProcessImpl.ResumeCommand? {
|
): DebugProcessImpl.ResumeCommand? {
|
||||||
if (suspendContext == null || suspendContext.isResumed) return null
|
if (suspendContext == null || suspendContext.isResumed) return null
|
||||||
|
|
||||||
@@ -74,17 +74,18 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
|||||||
|
|
||||||
@TestOnly
|
@TestOnly
|
||||||
fun getStepOverCommand(
|
fun getStepOverCommand(
|
||||||
suspendContext: SuspendContextImpl,
|
suspendContext: SuspendContextImpl,
|
||||||
ignoreBreakpoints: Boolean,
|
ignoreBreakpoints: Boolean,
|
||||||
debuggerContext: DebuggerContextImpl
|
debuggerContext: DebuggerContextImpl
|
||||||
): DebugProcessImpl.ResumeCommand? {
|
): DebugProcessImpl.ResumeCommand? {
|
||||||
return getStepOverCommand(suspendContext, ignoreBreakpoints, debuggerContext.sourcePosition)
|
return getStepOverCommand(suspendContext, ignoreBreakpoints, debuggerContext.sourcePosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getStepOverCommand(
|
private fun getStepOverCommand(
|
||||||
suspendContext: SuspendContextImpl,
|
suspendContext: SuspendContextImpl,
|
||||||
ignoreBreakpoints: Boolean,
|
ignoreBreakpoints: Boolean,
|
||||||
sourcePosition: SourcePosition): DebugProcessImpl.ResumeCommand? {
|
sourcePosition: SourcePosition
|
||||||
|
): DebugProcessImpl.ResumeCommand? {
|
||||||
val kotlinSourcePosition = KotlinSourcePosition.create(sourcePosition) ?: return null
|
val kotlinSourcePosition = KotlinSourcePosition.create(sourcePosition) ?: return null
|
||||||
|
|
||||||
if (isSpecialStepOverNeeded(kotlinSourcePosition)) {
|
if (isSpecialStepOverNeeded(kotlinSourcePosition)) {
|
||||||
@@ -95,14 +96,17 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
|||||||
val location = suspendContext.debugProcess.invokeInManagerThread { suspendContext.frameProxy?.location() } ?: return null
|
val location = suspendContext.debugProcess.invokeInManagerThread { suspendContext.frameProxy?.location() } ?: return null
|
||||||
if (isInSuspendMethod(location) && !isOnSuspendReturnOrReenter(location) && !isLastLineLocationInMethod(location)) {
|
if (isInSuspendMethod(location) && !isOnSuspendReturnOrReenter(location) && !isLastLineLocationInMethod(location)) {
|
||||||
return DebugProcessImplHelper.createStepOverCommandWithCustomFilter(
|
return DebugProcessImplHelper.createStepOverCommandWithCustomFilter(
|
||||||
suspendContext, ignoreBreakpoints, KotlinSuspendCallStepOverFilter(sourcePosition.line, file, ignoreBreakpoints))
|
suspendContext, ignoreBreakpoints, KotlinSuspendCallStepOverFilter(sourcePosition.line, file, ignoreBreakpoints)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
data class KotlinSourcePosition(val file: KtFile, val function: KtNamedFunction,
|
data class KotlinSourcePosition(
|
||||||
val linesRange: IntRange, val sourcePosition: SourcePosition) {
|
val file: KtFile, val function: KtNamedFunction,
|
||||||
|
val linesRange: IntRange, val sourcePosition: SourcePosition
|
||||||
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun create(sourcePosition: SourcePosition): KotlinSourcePosition? {
|
fun create(sourcePosition: SourcePosition): KotlinSourcePosition? {
|
||||||
val file = sourcePosition.file as? KtFile ?: return null
|
val file = sourcePosition.file as? KtFile ?: return null
|
||||||
@@ -110,8 +114,8 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
|||||||
|
|
||||||
val elementAt = sourcePosition.elementAt ?: return null
|
val elementAt = sourcePosition.elementAt ?: return null
|
||||||
val containingFunction = elementAt.parents
|
val containingFunction = elementAt.parents
|
||||||
.filterIsInstance<KtNamedFunction>()
|
.filterIsInstance<KtNamedFunction>()
|
||||||
.firstOrNull { !it.isLocal } ?: return null
|
.firstOrNull { !it.isLocal } ?: return null
|
||||||
|
|
||||||
val startLineNumber = containingFunction.getLineNumber(true) + 1
|
val startLineNumber = containingFunction.getLineNumber(true) + 1
|
||||||
val endLineNumber = containingFunction.getLineNumber(false) + 1
|
val endLineNumber = containingFunction.getLineNumber(false) + 1
|
||||||
@@ -193,14 +197,18 @@ private fun getInlineFunctionsIfAny(file: KtFile, offset: Int): List<KtNamedFunc
|
|||||||
private fun getInlineArgumentsIfAny(inlineFunctionCalls: List<KtCallExpression>): List<KtFunction> {
|
private fun getInlineArgumentsIfAny(inlineFunctionCalls: List<KtCallExpression>): List<KtFunction> {
|
||||||
return inlineFunctionCalls.flatMap {
|
return inlineFunctionCalls.flatMap {
|
||||||
it.valueArguments
|
it.valueArguments
|
||||||
.map(::getArgumentExpression)
|
.map(::getArgumentExpression)
|
||||||
.filterIsInstance<KtFunction>()
|
.filterIsInstance<KtFunction>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getArgumentExpression(it: ValueArgument) = (it.getArgumentExpression() as? KtLambdaExpression)?.functionLiteral ?: it.getArgumentExpression()
|
private fun getArgumentExpression(it: ValueArgument) =
|
||||||
|
(it.getArgumentExpression() as? KtLambdaExpression)?.functionLiteral ?: it.getArgumentExpression()
|
||||||
|
|
||||||
private fun getInlineArgumentsCallsIfAny(sourcePosition: SourcePosition, declarationDescriptor: DeclarationDescriptor): List<KtCallExpression>? {
|
private fun getInlineArgumentsCallsIfAny(
|
||||||
|
sourcePosition: SourcePosition,
|
||||||
|
declarationDescriptor: DeclarationDescriptor
|
||||||
|
): List<KtCallExpression>? {
|
||||||
if (declarationDescriptor !is CallableDescriptor) return null
|
if (declarationDescriptor !is CallableDescriptor) return null
|
||||||
|
|
||||||
val valueParameters = declarationDescriptor.valueParameters.filter { it.type.isFunctionType }.toSet()
|
val valueParameters = declarationDescriptor.valueParameters.filter { it.type.isFunctionType }.toSet()
|
||||||
@@ -249,12 +257,11 @@ private fun findCallsOnPosition(sourcePosition: SourcePosition, filter: (KtCallE
|
|||||||
val start = lineElement.startOffset
|
val start = lineElement.startOffset
|
||||||
val end = lineElement.endOffset
|
val end = lineElement.endOffset
|
||||||
|
|
||||||
val allFilteredCalls = CodeInsightUtils.
|
val allFilteredCalls = CodeInsightUtils.findElementsOfClassInRange(file, start, end, KtExpression::class.java)
|
||||||
findElementsOfClassInRange(file, start, end, KtExpression::class.java)
|
.map { KtPsiUtil.getParentCallIfPresent(it as KtExpression) }
|
||||||
.map { KtPsiUtil.getParentCallIfPresent(it as KtExpression) }
|
.filterIsInstance<KtCallExpression>()
|
||||||
.filterIsInstance<KtCallExpression>()
|
.filter { filter(it) }
|
||||||
.filter { filter(it) }
|
.toSet()
|
||||||
.toSet()
|
|
||||||
|
|
||||||
// It is necessary to check range because of multiline assign
|
// It is necessary to check range because of multiline assign
|
||||||
var linesRange = lineNumber..lineNumber
|
var linesRange = lineNumber..lineNumber
|
||||||
@@ -267,16 +274,20 @@ private fun findCallsOnPosition(sourcePosition: SourcePosition, filter: (KtCallE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class Action(val position: XSourcePositionImpl? = null,
|
sealed class Action(
|
||||||
val stepOverInlineData: StepOverFilterData? = null) {
|
val position: XSourcePositionImpl? = null,
|
||||||
|
val stepOverInlineData: StepOverFilterData? = null
|
||||||
|
) {
|
||||||
class STEP_OVER : Action() {
|
class STEP_OVER : Action() {
|
||||||
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) =
|
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) =
|
||||||
debugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints).contextAction(suspendContext)
|
debugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints).contextAction(suspendContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
class STEP_OUT : Action() {
|
class STEP_OUT : Action() {
|
||||||
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) =
|
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) =
|
||||||
debugProcess.createStepOutCommand(suspendContext).contextAction(suspendContext)
|
debugProcess.createStepOutCommand(suspendContext).contextAction(suspendContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
class RUN_TO_CURSOR(position: XSourcePositionImpl) : Action(position) {
|
class RUN_TO_CURSOR(position: XSourcePositionImpl) : Action(position) {
|
||||||
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) {
|
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) {
|
||||||
return runReadAction {
|
return runReadAction {
|
||||||
@@ -284,10 +295,12 @@ sealed class Action(val position: XSourcePositionImpl? = null,
|
|||||||
}.contextAction(suspendContext)
|
}.contextAction(suspendContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class STEP_OVER_INLINED(stepOverInlineData: StepOverFilterData) : Action(stepOverInlineData = stepOverInlineData) {
|
class STEP_OVER_INLINED(stepOverInlineData: StepOverFilterData) : Action(stepOverInlineData = stepOverInlineData) {
|
||||||
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) {
|
override fun apply(debugProcess: DebugProcessImpl, suspendContext: SuspendContextImpl, ignoreBreakpoints: Boolean) {
|
||||||
return KotlinStepActionFactory(debugProcess).createKotlinStepOverInlineAction(
|
return KotlinStepActionFactory(debugProcess).createKotlinStepOverInlineAction(
|
||||||
KotlinStepOverInlineFilter(debugProcess.project, stepOverInlineData!!)).contextAction(suspendContext)
|
KotlinStepOverInlineFilter(debugProcess.project, stepOverInlineData!!)
|
||||||
|
).contextAction(suspendContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,26 +312,28 @@ interface KotlinMethodFilter : MethodFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getStepOverAction(
|
fun getStepOverAction(
|
||||||
location: Location,
|
location: Location,
|
||||||
kotlinSourcePosition: KotlinSteppingCommandProvider.KotlinSourcePosition,
|
kotlinSourcePosition: KotlinSteppingCommandProvider.KotlinSourcePosition,
|
||||||
frameProxy: StackFrameProxyImpl,
|
frameProxy: StackFrameProxyImpl,
|
||||||
isDexDebug: Boolean
|
isDexDebug: Boolean
|
||||||
): Action {
|
): Action {
|
||||||
val inlineArgumentsToSkip = runReadAction {
|
val inlineArgumentsToSkip = runReadAction {
|
||||||
getInlineCallFunctionArgumentsIfAny(kotlinSourcePosition.sourcePosition)
|
getInlineCallFunctionArgumentsIfAny(kotlinSourcePosition.sourcePosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
return getStepOverAction(location, kotlinSourcePosition.file, kotlinSourcePosition.linesRange,
|
return getStepOverAction(
|
||||||
inlineArgumentsToSkip, frameProxy, isDexDebug)
|
location, kotlinSourcePosition.file, kotlinSourcePosition.linesRange,
|
||||||
|
inlineArgumentsToSkip, frameProxy, isDexDebug
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getStepOverAction(
|
fun getStepOverAction(
|
||||||
location: Location,
|
location: Location,
|
||||||
sourceFile: KtFile,
|
sourceFile: KtFile,
|
||||||
range: IntRange,
|
range: IntRange,
|
||||||
inlineFunctionArguments: List<KtElement>,
|
inlineFunctionArguments: List<KtElement>,
|
||||||
frameProxy: StackFrameProxyImpl,
|
frameProxy: StackFrameProxyImpl,
|
||||||
isDexDebug: Boolean
|
isDexDebug: Boolean
|
||||||
): Action {
|
): Action {
|
||||||
location.declaringType() ?: return Action.STEP_OVER()
|
location.declaringType() ?: return Action.STEP_OVER()
|
||||||
|
|
||||||
@@ -346,19 +361,18 @@ fun getStepOverAction(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
return nextLocation.ktFileName() == sourceFile.name
|
return nextLocation.ktFileName() == sourceFile.name
|
||||||
}
|
} catch (e: AbsentInformationException) {
|
||||||
catch(e: AbsentInformationException) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isBackEdgeLocation(): Boolean {
|
fun isBackEdgeLocation(): Boolean {
|
||||||
val previousSuitableLocation = methodLocations.reversed()
|
val previousSuitableLocation = methodLocations.reversed()
|
||||||
.dropWhile { it != location }
|
.dropWhile { it != location }
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.filter(::isThisMethodLocation)
|
.filter(::isThisMethodLocation)
|
||||||
.dropWhile { it.ktLineNumber() == location.ktLineNumber() }
|
.dropWhile { it.ktLineNumber() == location.ktLineNumber() }
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
|
|
||||||
return previousSuitableLocation != null && previousSuitableLocation.ktLineNumber() > location.ktLineNumber()
|
return previousSuitableLocation != null && previousSuitableLocation.ktLineNumber() > location.ktLineNumber()
|
||||||
}
|
}
|
||||||
@@ -366,10 +380,9 @@ fun getStepOverAction(
|
|||||||
val patchedLocation = if (isBackEdgeLocation()) {
|
val patchedLocation = if (isBackEdgeLocation()) {
|
||||||
// Pretend we had already done a backing step
|
// Pretend we had already done a backing step
|
||||||
methodLocations
|
methodLocations
|
||||||
.filter(::isThisMethodLocation)
|
.filter(::isThisMethodLocation)
|
||||||
.firstOrNull { it.ktLineNumber() == location.ktLineNumber() } ?: location
|
.firstOrNull { it.ktLineNumber() == location.ktLineNumber() } ?: location
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
location
|
location
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,12 +407,12 @@ fun getStepOverAction(
|
|||||||
// We might erroneously extend this range too much when there's a call of function argument or other
|
// We might erroneously extend this range too much when there's a call of function argument or other
|
||||||
// inline function in last statement of inline function. The list of inlineRangeVariables will be used later to overcome it.
|
// inline function in last statement of inline function. The list of inlineRangeVariables will be used later to overcome it.
|
||||||
val stepOverLocations = methodLocations
|
val stepOverLocations = methodLocations
|
||||||
.dropWhile { it != patchedLocation }
|
.dropWhile { it != patchedLocation }
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.dropWhile { it.ktLineNumber() == patchedLineNumber }
|
.dropWhile { it.ktLineNumber() == patchedLineNumber }
|
||||||
.takeWhile { loc ->
|
.takeWhile { loc ->
|
||||||
!isThisMethodLocation(loc) || lambdaArgumentRanges.any { loc.ktLineNumber() in it } || loc.ktLineNumber() == patchedLineNumber
|
!isThisMethodLocation(loc) || lambdaArgumentRanges.any { loc.ktLineNumber() in it } || loc.ktLineNumber() == patchedLineNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stepOverLocations.isEmpty()) {
|
if (!stepOverLocations.isEmpty()) {
|
||||||
// Some Kotlin inlined methods with 'for' (and maybe others) generates bytecode that after dexing have a strange artifact.
|
// Some Kotlin inlined methods with 'for' (and maybe others) generates bytecode that after dexing have a strange artifact.
|
||||||
@@ -412,39 +425,39 @@ fun getStepOverAction(
|
|||||||
val locationsOfLine = method.safeLocationsOfLine(range.last)
|
val locationsOfLine = method.safeLocationsOfLine(range.last)
|
||||||
if (locationsOfLine.isNotEmpty()) {
|
if (locationsOfLine.isNotEmpty()) {
|
||||||
locationsOfLine.map { it.codeIndex() }.max() ?: -1L
|
locationsOfLine.map { it.codeIndex() }.max() ?: -1L
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
findReturnFromDexBytecode(location.method())
|
findReturnFromDexBytecode(location.method())
|
||||||
}
|
}
|
||||||
}
|
} else -1L
|
||||||
else -1L
|
|
||||||
|
|
||||||
return Action.STEP_OVER_INLINED(StepOverFilterData(
|
return Action.STEP_OVER_INLINED(
|
||||||
|
StepOverFilterData(
|
||||||
patchedLineNumber,
|
patchedLineNumber,
|
||||||
stepOverLocations.map { it.ktLineNumber() }.toSet(),
|
stepOverLocations.map { it.ktLineNumber() }.toSet(),
|
||||||
inlineRangeVariables,
|
inlineRangeVariables,
|
||||||
isDexDebug,
|
isDexDebug,
|
||||||
returnCodeIndex
|
returnCodeIndex
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Action.STEP_OVER()
|
return Action.STEP_OVER()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getStepOutAction(
|
fun getStepOutAction(
|
||||||
location: Location,
|
location: Location,
|
||||||
suspendContext: SuspendContextImpl,
|
suspendContext: SuspendContextImpl,
|
||||||
inlineFunctions: List<KtNamedFunction>,
|
inlineFunctions: List<KtNamedFunction>,
|
||||||
inlinedArgument: KtFunctionLiteral?
|
inlinedArgument: KtFunctionLiteral?
|
||||||
): Action {
|
): Action {
|
||||||
val computedReferenceType = location.declaringType() ?: return Action.STEP_OUT()
|
val computedReferenceType = location.declaringType() ?: return Action.STEP_OUT()
|
||||||
|
|
||||||
val locations = computedReferenceType.safeAllLineLocations()
|
val locations = computedReferenceType.safeAllLineLocations()
|
||||||
val nextLineLocations = locations
|
val nextLineLocations = locations
|
||||||
.dropWhile { it != location }
|
.dropWhile { it != location }
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.filter { it.method() == location.method() }
|
.filter { it.method() == location.method() }
|
||||||
.dropWhile { it.lineNumber() == location.lineNumber() }
|
.dropWhile { it.lineNumber() == location.lineNumber() }
|
||||||
|
|
||||||
if (inlineFunctions.isNotEmpty()) {
|
if (inlineFunctions.isNotEmpty()) {
|
||||||
val position = suspendContext.getXPositionForStepOutFromInlineFunction(nextLineLocations, inlineFunctions)
|
val position = suspendContext.getXPositionForStepOutFromInlineFunction(nextLineLocations, inlineFunctions)
|
||||||
@@ -460,11 +473,10 @@ fun getStepOutAction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun SuspendContextImpl.getXPositionForStepOutFromInlineFunction(
|
private fun SuspendContextImpl.getXPositionForStepOutFromInlineFunction(
|
||||||
locations: List<Location>,
|
locations: List<Location>,
|
||||||
inlineFunctionsToSkip: List<KtNamedFunction>
|
inlineFunctionsToSkip: List<KtNamedFunction>
|
||||||
): XSourcePositionImpl? {
|
): XSourcePositionImpl? {
|
||||||
return getNextPositionWithFilter(locations) {
|
return getNextPositionWithFilter(locations) { offset, elementAt ->
|
||||||
offset, elementAt ->
|
|
||||||
if (inlineFunctionsToSkip.any { it.textRange.contains(offset) }) {
|
if (inlineFunctionsToSkip.any { it.textRange.contains(offset) }) {
|
||||||
return@getNextPositionWithFilter true
|
return@getNextPositionWithFilter true
|
||||||
}
|
}
|
||||||
@@ -474,27 +486,25 @@ private fun SuspendContextImpl.getXPositionForStepOutFromInlineFunction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun SuspendContextImpl.getXPositionForStepOutFromInlinedArgument(
|
private fun SuspendContextImpl.getXPositionForStepOutFromInlinedArgument(
|
||||||
locations: List<Location>,
|
locations: List<Location>,
|
||||||
inlinedArgumentToSkip: KtFunctionLiteral
|
inlinedArgumentToSkip: KtFunctionLiteral
|
||||||
): XSourcePositionImpl? {
|
): XSourcePositionImpl? {
|
||||||
return getNextPositionWithFilter(locations) {
|
return getNextPositionWithFilter(locations) { offset, _ ->
|
||||||
offset, _ ->
|
|
||||||
inlinedArgumentToSkip.textRange.contains(offset)
|
inlinedArgumentToSkip.textRange.contains(offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun SuspendContextImpl.getNextPositionWithFilter(
|
private fun SuspendContextImpl.getNextPositionWithFilter(
|
||||||
locations: List<Location>,
|
locations: List<Location>,
|
||||||
skip: (Int, PsiElement) -> Boolean
|
skip: (Int, PsiElement) -> Boolean
|
||||||
): XSourcePositionImpl? {
|
): XSourcePositionImpl? {
|
||||||
for (location in locations) {
|
for (location in locations) {
|
||||||
val position = runReadAction l@ {
|
val position = runReadAction l@{
|
||||||
val sourcePosition = try {
|
val sourcePosition = try {
|
||||||
this.debugProcess.positionManager.getSourcePosition(location)
|
this.debugProcess.positionManager.getSourcePosition(location)
|
||||||
}
|
} catch (e: NoDataException) {
|
||||||
catch(e: NoDataException) {
|
null
|
||||||
null
|
} ?: return@l null
|
||||||
} ?: return@l null
|
|
||||||
|
|
||||||
val file = sourcePosition.file as? KtFile ?: return@l null
|
val file = sourcePosition.file as? KtFile ?: return@l null
|
||||||
val elementAt = sourcePosition.elementAt ?: return@l null
|
val elementAt = sourcePosition.elementAt ?: return@l null
|
||||||
@@ -514,11 +524,11 @@ private fun SuspendContextImpl.getNextPositionWithFilter(
|
|||||||
|
|
||||||
fun getInlineRangeLocalVariables(stackFrame: StackFrameProxyImpl): List<LocalVariable> {
|
fun getInlineRangeLocalVariables(stackFrame: StackFrameProxyImpl): List<LocalVariable> {
|
||||||
return stackFrame.visibleVariables()
|
return stackFrame.visibleVariables()
|
||||||
.filter {
|
.filter {
|
||||||
val name = it.name()
|
val name = it.name()
|
||||||
name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION)
|
name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION)
|
||||||
}
|
}
|
||||||
.map { it.variable }
|
.map { it.variable }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInlineArgumentIfAny(elementAt: PsiElement?): KtFunctionLiteral? {
|
private fun getInlineArgumentIfAny(elementAt: PsiElement?): KtFunctionLiteral? {
|
||||||
@@ -541,8 +551,7 @@ private fun findReturnFromDexBytecode(method: Method): Long {
|
|||||||
while (true) {
|
while (true) {
|
||||||
if (method.locationOfCodeIndex(lastMethodCodeIndex + 1) != null) {
|
if (method.locationOfCodeIndex(lastMethodCodeIndex + 1) != null) {
|
||||||
lastMethodCodeIndex++
|
lastMethodCodeIndex++
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -562,11 +571,9 @@ private fun findReturnFromDexBytecode(method: Method): Long {
|
|||||||
if (instruction == RETURN_VOID || instruction == RETURN || instruction == RETURN_WIDE || instruction == RETURN_OBJECT) {
|
if (instruction == RETURN_VOID || instruction == RETURN || instruction == RETURN_WIDE || instruction == RETURN_OBJECT) {
|
||||||
// Instruction found
|
// Instruction found
|
||||||
return returnIndex
|
return returnIndex
|
||||||
}
|
} else if (instruction == MOVE || instruction == GOTO) {
|
||||||
else if (instruction == MOVE || instruction == GOTO) {
|
|
||||||
// proceed
|
// proceed
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Don't know the instruction and it's length. Abort.
|
// Don't know the instruction and it's length. Abort.
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-7
@@ -33,9 +33,10 @@ import org.jetbrains.kotlin.idea.debugger.suspendFunctionFirstLineLocation
|
|||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
|
|
||||||
class KotlinSuspendCallStepOverFilter(
|
class KotlinSuspendCallStepOverFilter(
|
||||||
private val line: Int,
|
private val line: Int,
|
||||||
private val file: PsiFile,
|
private val file: PsiFile,
|
||||||
private val ignoreBreakpoints: Boolean) : MethodFilter {
|
private val ignoreBreakpoints: Boolean
|
||||||
|
) : MethodFilter {
|
||||||
override fun getCallingExpressionLines(): Range<Int>? = Range(line, line)
|
override fun getCallingExpressionLines(): Range<Int>? = Range(line, line)
|
||||||
|
|
||||||
override fun locationMatches(process: DebugProcessImpl, location: Location?): Boolean {
|
override fun locationMatches(process: DebugProcessImpl, location: Location?): Boolean {
|
||||||
@@ -66,10 +67,9 @@ private fun createRunToCursorBreakpoint(context: SuspendContextImpl, line: Int,
|
|||||||
}
|
}
|
||||||
|
|
||||||
val runToCursorBreakpoint =
|
val runToCursorBreakpoint =
|
||||||
runReadAction {
|
runReadAction {
|
||||||
DebuggerManagerEx.getInstanceEx(process.project).breakpointManager.addRunToCursorBreakpoint(position, ignoreBreakpoints)
|
DebuggerManagerEx.getInstanceEx(process.project).breakpointManager.addRunToCursorBreakpoint(position, ignoreBreakpoints)
|
||||||
} ?:
|
} ?: return
|
||||||
return
|
|
||||||
|
|
||||||
runToCursorBreakpoint.suspendPolicy = when {
|
runToCursorBreakpoint.suspendPolicy = when {
|
||||||
context.suspendPolicy == EventRequest.SUSPEND_EVENT_THREAD -> DebuggerSettings.SUSPEND_THREAD
|
context.suspendPolicy == EventRequest.SUSPEND_EVENT_THREAD -> DebuggerSettings.SUSPEND_THREAD
|
||||||
|
|||||||
+12
-11
@@ -29,13 +29,16 @@ import org.intellij.lang.annotations.MagicConstant
|
|||||||
import java.lang.reflect.Field
|
import java.lang.reflect.Field
|
||||||
|
|
||||||
internal class RequestHintWithMethodFilter(
|
internal class RequestHintWithMethodFilter(
|
||||||
stepThread: ThreadReferenceProxyImpl,
|
stepThread: ThreadReferenceProxyImpl,
|
||||||
suspendContext: SuspendContextImpl,
|
suspendContext: SuspendContextImpl,
|
||||||
@MagicConstant(intValues = longArrayOf(
|
@MagicConstant(
|
||||||
StepRequest.STEP_INTO.toLong(),
|
intValues = longArrayOf(
|
||||||
StepRequest.STEP_OVER.toLong(),
|
StepRequest.STEP_INTO.toLong(),
|
||||||
StepRequest.STEP_OUT.toLong())) depth: Int,
|
StepRequest.STEP_OVER.toLong(),
|
||||||
methodFilter: MethodFilter
|
StepRequest.STEP_OUT.toLong()
|
||||||
|
)
|
||||||
|
) depth: Int,
|
||||||
|
methodFilter: MethodFilter
|
||||||
) : RequestHint(stepThread, suspendContext, methodFilter) {
|
) : RequestHint(stepThread, suspendContext, methodFilter) {
|
||||||
private var targetMethodMatched = false
|
private var targetMethodMatched = false
|
||||||
|
|
||||||
@@ -71,11 +74,9 @@ internal class RequestHintWithMethodFilter(
|
|||||||
return filter.onReached(context, this)
|
return filter.onReached(context, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} catch (ignored: VMDisconnectedException) {
|
||||||
catch (ignored: VMDisconnectedException) {
|
|
||||||
return STOP
|
return STOP
|
||||||
}
|
} catch (e: EvaluateException) {
|
||||||
catch (e: EvaluateException) {
|
|
||||||
LOG.error(e)
|
LOG.error(e)
|
||||||
return STOP
|
return STOP
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user