Debugger: support stepping out inline function
This commit is contained in:
+113
-8
@@ -24,14 +24,20 @@ import com.intellij.debugger.engine.events.DebuggerCommandImpl
|
||||
import com.intellij.debugger.impl.JvmSteppingCommandProvider
|
||||
import com.intellij.util.concurrency.Semaphore
|
||||
import com.intellij.xdebugger.impl.XSourcePositionImpl
|
||||
import com.sun.jdi.Location
|
||||
import com.sun.jdi.ReferenceType
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.getLineCount
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.getLineStartOffset
|
||||
import org.jetbrains.kotlin.idea.util.DebuggerUtils
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
@@ -44,16 +50,13 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
|
||||
): DebugProcessImpl.ResumeCommand? {
|
||||
if (suspendContext == null) return null
|
||||
|
||||
if (!isKotlinStrataPresent(suspendContext)) return null
|
||||
|
||||
val result: Pair<SourcePosition, List<ReferenceType>>? = computeInManagerThread(suspendContext) {
|
||||
val result: Pair<SourcePosition, ReferenceType>? = computeInManagerThread(suspendContext) {
|
||||
val sp = runReadAction { ContextUtil.getSourcePosition(it) } ?: return@computeInManagerThread null
|
||||
val cl = it.debugProcess.positionManager.getAllClasses(sp)
|
||||
val cl = it.frameProxy?.location()?.declaringType() ?: return@computeInManagerThread null
|
||||
sp to cl
|
||||
}
|
||||
|
||||
val (sourcePosition, allClasses) = result ?: return null
|
||||
val computedReferenceType = allClasses.firstOrNull() ?: return null
|
||||
val (sourcePosition, computedReferenceType) = result ?: return null
|
||||
|
||||
val file = sourcePosition.file as? JetFile ?: return null
|
||||
|
||||
@@ -80,7 +83,107 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
|
||||
return null
|
||||
}
|
||||
|
||||
private fun isKotlinStrataPresent(suspendContext: SuspendContextImpl): Boolean {
|
||||
override fun getStepOutCommand(suspendContext: SuspendContextImpl?, stepSize: Int): DebugProcessImpl.ResumeCommand? {
|
||||
if (suspendContext == null) return null
|
||||
|
||||
val location = computeInManagerThread(suspendContext) {
|
||||
it.frameProxy?.location()
|
||||
} ?: return null
|
||||
|
||||
val sourcePosition = suspendContext.debugProcess.positionManager.getSourcePosition(location) ?: return null
|
||||
val computedReferenceType = location.declaringType() ?: return null
|
||||
|
||||
val locations = computedReferenceType.allLineLocations()
|
||||
|
||||
val file = sourcePosition.file as? JetFile ?: return null
|
||||
val lineStartOffset = file.getLineStartOffset(sourcePosition.line) ?: return null
|
||||
val nextLineLocations = locations.dropWhile { it.lineNumber() != location.lineNumber() }.filter { it.method() == location.method() }
|
||||
|
||||
val inlineFunction = getInlineFunctionsIfAny(file, lineStartOffset)
|
||||
if (inlineFunction != null) {
|
||||
val xPosition = suspendContext.getXPositionForStepOutFromInlineFunction(nextLineLocations, inlineFunction) ?: return null
|
||||
return suspendContext.debugProcess.createRunToCursorCommand(suspendContext, xPosition, true)
|
||||
}
|
||||
|
||||
val inlinedArgument = getInlineArgumentIfAny(file, lineStartOffset)
|
||||
if (inlinedArgument != null) {
|
||||
val xPosition = suspendContext.getXPositionForStepOutFromInlinedArgument(nextLineLocations, inlinedArgument) ?: return null
|
||||
return suspendContext.debugProcess.createRunToCursorCommand(suspendContext, xPosition, true)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun SuspendContextImpl.getXPositionForStepOutFromInlineFunction(
|
||||
locations: List<Location>,
|
||||
inlineFunctionsToSkip: List<JetNamedFunction>
|
||||
): XSourcePositionImpl? {
|
||||
return getNextPositionWithFilter(locations) {
|
||||
file, offset ->
|
||||
if (inlineFunctionsToSkip.any { it.textRange.contains(offset) }) {
|
||||
return@getNextPositionWithFilter true
|
||||
}
|
||||
|
||||
val inlinedArgument = getInlineArgumentIfAny(file, offset)
|
||||
inlinedArgument != null && inlinedArgument.textRange.contains(offset)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SuspendContextImpl.getXPositionForStepOutFromInlinedArgument(
|
||||
locations: List<Location>,
|
||||
inlinedArgumentToSkip: JetFunctionLiteral
|
||||
): XSourcePositionImpl? {
|
||||
return getNextPositionWithFilter(locations) {
|
||||
file, offset ->
|
||||
inlinedArgumentToSkip.textRange.contains(offset)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SuspendContextImpl.getNextPositionWithFilter(
|
||||
locations: List<Location>,
|
||||
skip: (JetFile, Int) -> Boolean
|
||||
): XSourcePositionImpl? {
|
||||
for (location in locations) {
|
||||
val file = this.debugProcess.positionManager.getSourcePosition(location)?.file as? JetFile ?: continue
|
||||
val currentLine = location.lineNumber() - 1
|
||||
val lineStartOffset = file.getLineStartOffset(currentLine) ?: continue
|
||||
if (skip(file, lineStartOffset)) continue
|
||||
|
||||
val elementAt = file.findElementAt(lineStartOffset) ?: continue
|
||||
return XSourcePositionImpl.createByElement(elementAt)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getInlineFunctionsIfAny(file: JetFile, offset: Int): List<JetNamedFunction>? {
|
||||
val elementAt = file.findElementAt(offset) ?: return null
|
||||
val containingFunction = elementAt.getParentOfType<JetNamedFunction>(false) ?: return null
|
||||
|
||||
val descriptor = containingFunction.resolveToDescriptor()
|
||||
if (!InlineUtil.isInline(descriptor)) return null
|
||||
|
||||
val inlineFunctionsCalls = DebuggerUtils.analyzeElementWithInline(
|
||||
containingFunction.getResolutionFacade(),
|
||||
containingFunction.analyzeFully(),
|
||||
containingFunction,
|
||||
false
|
||||
).filterIsInstance<JetNamedFunction>()
|
||||
|
||||
return inlineFunctionsCalls
|
||||
}
|
||||
|
||||
private fun getInlineArgumentIfAny(file: JetFile, offset: Int): JetFunctionLiteral? {
|
||||
val elementAt = file.findElementAt(offset) ?: return null
|
||||
val functionLiteralExpression = elementAt.getParentOfType<JetFunctionLiteralExpression>(false) ?: return null
|
||||
|
||||
val context = functionLiteralExpression.analyze(BodyResolveMode.PARTIAL)
|
||||
if (!InlineUtil.isInlinedArgument(functionLiteralExpression.functionLiteral, context, false)) return null
|
||||
|
||||
return functionLiteralExpression.functionLiteral
|
||||
}
|
||||
|
||||
private fun isKotlinStrataAvailable(suspendContext: SuspendContextImpl): Boolean {
|
||||
val availableStrata = suspendContext.frameProxy?.location()?.declaringType()?.availableStrata() ?: return false
|
||||
return availableStrata.contains("Kotlin")
|
||||
}
|
||||
@@ -93,7 +196,9 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
|
||||
val worker = object : DebuggerCommandImpl() {
|
||||
override fun action() {
|
||||
try {
|
||||
result = action(suspendContext)
|
||||
if (isKotlinStrataAvailable(suspendContext)) {
|
||||
result = action(suspendContext)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
semaphore.up()
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.idea.resolve.ResolutionFacade;
|
||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils;
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde;
|
||||
import org.jetbrains.kotlin.idea.debugger.DebuggerPackage;
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolvePackage;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
@@ -177,6 +178,18 @@ public class DebuggerUtils {
|
||||
return new Pair<BindingContext, List<JetFile>>(context, new ArrayList<JetFile>(toProcess));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Collection<JetElement> analyzeElementWithInline(
|
||||
@NotNull ResolutionFacade resolutionFacade,
|
||||
@NotNull BindingContext bindingContext,
|
||||
@NotNull JetNamedFunction function,
|
||||
boolean analyzeInlineFunctions
|
||||
) {
|
||||
Set<JetElement> analyzedElements = new HashSet<JetElement>();
|
||||
analyzeElementWithInline(resolutionFacade, bindingContext, function, 1, analyzedElements, !analyzeInlineFunctions);
|
||||
return analyzedElements;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static BindingContext analyzeElementWithInline(
|
||||
@NotNull ResolutionFacade resolutionFacade,
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at stepOutInlineFunction.kt:12
|
||||
!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! stepOutInlineFunction.StepOutInlineFunctionPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
stepOutInlineFunction.kt:12
|
||||
stepOutInlineFunction.kt:7
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at stepOutInlineFunctionStdlib.kt:6
|
||||
!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! stepOutInlineFunctionStdlib.StepOutInlineFunctionStdlibPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
stepOutInlineFunctionStdlib.kt:6
|
||||
_Elements.!EXT!
|
||||
stepOutInlineFunctionStdlib.kt:9
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at stepOutInlinedLambdaArgument.kt:6
|
||||
!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! stepOutInlinedLambdaArgument.StepOutInlinedLambdaArgumentPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
stepOutInlinedLambdaArgument.kt:6
|
||||
stepOutInlinedLambdaArgument.kt:15
|
||||
stepOutInlinedLambdaArgument.kt:9
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,10 @@
|
||||
LineBreakpoint created at stepOutSeveralInlineArgumentDeepest.kt:6
|
||||
!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! stepOutSeveralInlineArgumentDeepest.StepOutSeveralInlineArgumentDeepestPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
stepOutSeveralInlineArgumentDeepest.kt:6
|
||||
stepOutSeveralInlineArgumentDeepest.kt:22
|
||||
stepOutSeveralInlineArgumentDeepest.kt:16
|
||||
stepOutSeveralInlineArgumentDeepest.kt:8
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at stepOutSeveralInlineFunctions.kt:12
|
||||
!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! stepOutSeveralInlineFunctions.StepOutSeveralInlineFunctionsPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
stepOutSeveralInlineFunctions.kt:12
|
||||
stepOutSeveralInlineFunctions.kt:7
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at stepOutSeveralInlineFunctionsDeepest.kt:20
|
||||
!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! stepOutSeveralInlineFunctionsDeepest.StepOutSeveralInlineFunctionsDeepestPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
stepOutSeveralInlineFunctionsDeepest.kt:20
|
||||
stepOutSeveralInlineFunctionsDeepest.kt:15
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package stepOutInlineFunctionStdlib
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = listOf(1, 2, 3)
|
||||
//Breakpoint!
|
||||
a.firstOrNull {
|
||||
it > 1
|
||||
}
|
||||
}
|
||||
|
||||
fun test(i: Int) = 1
|
||||
|
||||
// TRACING_FILTERS_ENABLED: false
|
||||
// STEP_INTO: 1
|
||||
// STEP_OUT: 1
|
||||
@@ -0,0 +1,19 @@
|
||||
package stepOutInlineFunction
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
foo {
|
||||
test(2)
|
||||
}
|
||||
test(3)
|
||||
}
|
||||
|
||||
inline fun foo(f: () -> Unit) {
|
||||
//Breakpoint!
|
||||
val a = 1
|
||||
f()
|
||||
val b = 2
|
||||
}
|
||||
|
||||
fun test(i: Int) = 1
|
||||
|
||||
// STEP_OUT: 2
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package stepOutInlinedLambdaArgument
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
foo {
|
||||
//Breakpoint!
|
||||
test(1)
|
||||
test(2)
|
||||
}
|
||||
test(3)
|
||||
}
|
||||
|
||||
inline fun foo(f: () -> Unit) {
|
||||
val a = 1
|
||||
f()
|
||||
val b = 2
|
||||
}
|
||||
|
||||
fun test(i: Int) = 1
|
||||
|
||||
// STEP_OUT: 2
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package stepOutSeveralInlineArgumentDeepest
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
f1 {
|
||||
//Breakpoint!
|
||||
test(2)
|
||||
}
|
||||
test(3)
|
||||
}
|
||||
|
||||
inline fun f1(f: () -> Unit) {
|
||||
val a = 1
|
||||
f2 {
|
||||
f()
|
||||
}
|
||||
val b = 2
|
||||
}
|
||||
|
||||
inline fun f2(f: () -> Unit) {
|
||||
val a = 1
|
||||
f()
|
||||
val b = 2
|
||||
}
|
||||
|
||||
fun test(i: Int) = 1
|
||||
|
||||
// STEP_OUT: 4
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package stepOutSeveralInlineFunctions
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
f1 {
|
||||
test(2)
|
||||
}
|
||||
test(3)
|
||||
}
|
||||
|
||||
inline fun f1(f: () -> Unit) {
|
||||
//Breakpoint!
|
||||
val a = 1
|
||||
f2 {
|
||||
f()
|
||||
}
|
||||
val b = 2
|
||||
}
|
||||
|
||||
inline fun f2(f: () -> Unit) {
|
||||
val a = 1
|
||||
f()
|
||||
val b = 2
|
||||
}
|
||||
|
||||
fun test(i: Int) = 1
|
||||
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
package stepOutSeveralInlineFunctionsDeepest
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
f1 {
|
||||
test(2)
|
||||
}
|
||||
test(3)
|
||||
}
|
||||
|
||||
inline fun f1(f: () -> Unit) {
|
||||
val a = 1
|
||||
f2 {
|
||||
f()
|
||||
}
|
||||
val b = 2
|
||||
}
|
||||
|
||||
inline fun f2(f: () -> Unit) {
|
||||
//Breakpoint!
|
||||
val a = 1
|
||||
f()
|
||||
val b = 2
|
||||
}
|
||||
|
||||
fun test(i: Int) = 1
|
||||
@@ -136,7 +136,9 @@ abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() {
|
||||
}
|
||||
|
||||
protected fun SuspendContextImpl.stepOut() {
|
||||
dp.getManagerThread()!!.schedule(dp.createStepOutCommand(this))
|
||||
val stepOutCommand = runReadAction { KotlinSteppingCommandProvider().getStepOutCommand(this, StepRequest.STEP_LINE) }
|
||||
?: dp.createStepOutCommand(this)
|
||||
dp.getManagerThread()!!.schedule(stepOutCommand)
|
||||
}
|
||||
|
||||
protected fun SuspendContextImpl.stepOver() {
|
||||
|
||||
@@ -297,6 +297,36 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/inapplicableFieldWatchpoints.kt");
|
||||
doStepOutTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stepOutInlineFunction.kt")
|
||||
public void testStepOutInlineFunction() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlineFunction.kt");
|
||||
doStepOutTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stepOutInlinedLambdaArgument.kt")
|
||||
public void testStepOutInlinedLambdaArgument() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutInlinedLambdaArgument.kt");
|
||||
doStepOutTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stepOutSeveralInlineArgumentDeepest.kt")
|
||||
public void testStepOutSeveralInlineArgumentDeepest() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineArgumentDeepest.kt");
|
||||
doStepOutTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stepOutSeveralInlineFunctions.kt")
|
||||
public void testStepOutSeveralInlineFunctions() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctions.kt");
|
||||
doStepOutTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stepOutSeveralInlineFunctionsDeepest.kt")
|
||||
public void testStepOutSeveralInlineFunctionsDeepest() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOut/stepOutSeveralInlineFunctionsDeepest.kt");
|
||||
doStepOutTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver")
|
||||
@@ -444,5 +474,11 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/stepIntoStdlibInlineFun2step.kt");
|
||||
doCustomTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stepOutInlineFunctionStdlib.kt")
|
||||
public void testStepOutInlineFunctionStdlib() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/custom/stepOutInlineFunctionStdlib.kt");
|
||||
doCustomTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user