[kotlin] fix smart step target filtering for functions with lambdas and update tests

KTIJ-19696

(cherry picked from commit b45d5d01721586e65d17ca7be66abca606b37682)

IJ-CR-20727

GitOrigin-RevId: 86f6a3ee5860d93c85dcf79aeaa849be782c5911
This commit is contained in:
Nikita Nazarov
2022-02-11 13:43:51 +00:00
committed by intellij-monorepo-bot
parent 7c69339b88
commit 43b95d766e
19 changed files with 371 additions and 88 deletions
@@ -8,9 +8,10 @@ import com.intellij.debugger.engine.DebugProcessImpl
import com.intellij.psi.util.parentOfType
import com.intellij.util.Range
import com.sun.jdi.Location
import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME
import org.jetbrains.kotlin.idea.core.util.isMultiLine
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils.getMethodNameWithoutMangling
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils.isGeneratedIrBackendLambdaMethodName
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils.trimIfMangledInBytecode
import org.jetbrains.kotlin.idea.debugger.isInsideInlineArgument
import org.jetbrains.kotlin.idea.debugger.safeMethod
import org.jetbrains.kotlin.idea.util.application.runReadAction
@@ -19,7 +20,6 @@ import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.codegen.coroutines.INVOKE_SUSPEND_METHOD_NAME
class KotlinLambdaMethodFilter(
lambda: KtFunction,
@@ -66,14 +66,10 @@ class KotlinLambdaMethodFilter(
if (lambdaInfo.isInline) Range(0, Int.MAX_VALUE) else callingExpressionLines
fun isTargetLambdaName(name: String): Boolean {
val actualName =
if (lambdaInfo.isNameMangledInBytecode)
name.getMethodNameWithoutMangling()
else
name
if (lambdaInfo.isSuspend)
val actualName = name.trimIfMangledInBytecode(lambdaInfo.isNameMangledInBytecode)
if (lambdaInfo.isSuspend) {
return actualName == INVOKE_SUSPEND_METHOD_NAME
}
return actualName == lambdaInfo.methodName || actualName.isGeneratedIrBackendLambdaMethodName()
}
}
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils.getMethodNameWithoutMangling
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils.trimIfMangledInBytecode
import org.jetbrains.kotlin.idea.debugger.getInlineFunctionNamesAndBorders
import org.jetbrains.kotlin.idea.debugger.safeMethod
import org.jetbrains.kotlin.load.java.JvmAbi
@@ -80,16 +80,17 @@ open class KotlinMethodFilter(
private fun nameMatches(location: Location): Boolean {
val method = location.safeMethod() ?: return false
val targetMethodName = methodName
if (methodInfo.isNameMangledInBytecode) {
return method.name().getMethodNameWithoutMangling() == targetMethodName
}
val isNameMangledInBytecode = methodInfo.isNameMangledInBytecode
val actualMethodName = method.name().trimIfMangledInBytecode(isNameMangledInBytecode)
return method.name() == targetMethodName ||
method.name() == "$targetMethodName${JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX}" ||
return actualMethodName == targetMethodName ||
actualMethodName == "$targetMethodName${JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX}" ||
// A correct way here is to memorize the original location (where smart step into was started)
// and filter out ranges that contain that original location.
// Otherwise, nested inline with the same method name will not work correctly.
method.getInlineFunctionNamesAndBorders().filter { location in it.value }.any { it.key.isInlinedFromFunction(targetMethodName) }
method.getInlineFunctionNamesAndBorders()
.filter { location in it.value }
.any { it.key.isInlinedFromFunction(targetMethodName, isNameMangledInBytecode) }
}
}
@@ -110,6 +111,8 @@ private fun getMethodDescriptorAndDeclaration(
}
}
private fun LocalVariable.isInlinedFromFunction(methodName: String) =
name().startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) &&
name().substringAfter(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) == methodName
private fun LocalVariable.isInlinedFromFunction(methodName: String, isNameMangledInBytecode: Boolean): Boolean {
val variableName = name().trimIfMangledInBytecode(isNameMangledInBytecode)
return variableName.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) &&
variableName.substringAfter(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION) == methodName
}
@@ -79,22 +79,11 @@ private fun findSmartStepTargets(position: SourcePosition, session: DebuggerSess
val lines = topmostElement.getLines() ?: return emptyList()
val targets = findSmartStepTargets(topmostElement, lines)
if (session != null) {
return targets.filterAlreadyExecuted(
session.process,
lines.toClosedRange()
)
return calculateSmartStepTargetsToShow(targets, session.process, lines.toClosedRange())
}
return targets
}
private fun List<SmartStepTarget>.filterAlreadyExecuted(debugProcess: DebugProcessImpl, lines: ClosedRange<Int>): List<SmartStepTarget> {
DebuggerManagerThreadImpl.assertIsManagerThread()
if (debugProcess.isDexDebug() || size <= 1) return this
val frameProxy = debugProcess.suspendManager.pausedContext?.frameProxy
val location = frameProxy?.safeLocation() ?: return this
return filterSmartStepTargets(location, lines, this, debugProcess)
}
private fun findSmartStepTargets(topmostElement: KtElement, lines: Range<Int>): List<SmartStepTarget> {
val targets = OrderedSet<SmartStepTarget>()
val visitor = SmartStepTargetVisitor(topmostElement, lines, targets)
@@ -102,6 +91,31 @@ private fun findSmartStepTargets(topmostElement: KtElement, lines: Range<Int>):
return targets
}
private fun calculateSmartStepTargetsToShow(targets: List<SmartStepTarget>, debugProcess: DebugProcessImpl, lines: ClosedRange<Int>): List<SmartStepTarget> {
val lambdaTargets = mutableListOf<SmartStepTarget>()
val methodTargets = mutableListOf<KotlinMethodSmartStepTarget>()
for (target in targets) {
if (target is KotlinMethodSmartStepTarget) {
methodTargets.add(target)
} else {
lambdaTargets.add(target)
}
}
return lambdaTargets + methodTargets.filterAlreadyExecuted(debugProcess, lines)
}
private fun List<KotlinMethodSmartStepTarget>.filterAlreadyExecuted(
debugProcess: DebugProcessImpl,
lines: ClosedRange<Int>
): List<KotlinMethodSmartStepTarget> {
DebuggerManagerThreadImpl.assertIsManagerThread()
if (debugProcess.isDexDebug() || size <= 1) return this
val frameProxy = debugProcess.suspendManager.pausedContext?.frameProxy
val location = frameProxy?.safeLocation() ?: return this
return filterSmartStepTargets(location, lines, this, debugProcess)
}
private fun SourcePosition.getTopmostElement(): KtElement? {
val element = elementAt ?: return null
return getTopmostElementAtOffset(element, element.textRange.startOffset) as? KtElement
@@ -117,9 +131,9 @@ private fun KtElement.getLines(): Range<Int>? {
private fun filterSmartStepTargets(
location: Location,
lines: ClosedRange<Int>,
targets: List<SmartStepTarget>,
targets: List<KotlinMethodSmartStepTarget>,
debugProcess: DebugProcessImpl
): List<SmartStepTarget> {
): List<KotlinMethodSmartStepTarget> {
val method = location.safeMethod() ?: return targets
val targetFilterer = KotlinSmartStepTargetFilterer(targets, debugProcess)
val targetFiltererAdapter = KotlinSmartStepTargetFiltererAdapter(
@@ -1,12 +1,11 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.idea.debugger.stepping.smartStepInto
import com.intellij.debugger.actions.SmartStepTarget
import com.intellij.debugger.engine.DebugProcessImpl
import com.intellij.debugger.impl.DebuggerUtilsEx
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils.getMethodNameWithoutMangling
import org.jetbrains.kotlin.idea.debugger.DebuggerUtils.trimIfMangledInBytecode
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -14,7 +13,7 @@ import org.jetbrains.kotlin.psi.KtPropertyAccessor
import java.util.*
class KotlinSmartStepTargetFilterer(
private val targets: List<SmartStepTarget>,
private val targets: List<KotlinMethodSmartStepTarget>,
private val debugProcess: DebugProcessImpl
) {
private val functionCounter = mutableMapOf<String, Int>()
@@ -24,7 +23,7 @@ class KotlinSmartStepTargetFilterer(
val descriptor = function.descriptor ?: return
val label = KotlinMethodSmartStepTarget.calcLabel(descriptor)
val currentCount = functionCounter.increment(label) - 1
val matchedSteppingTargetIndex = targets.filterIsInstance<KotlinMethodSmartStepTarget>().indexOfFirst {
val matchedSteppingTargetIndex = targets.indexOfFirst {
it.getDeclaration() === function && it.ordinal == currentCount
}
if (matchedSteppingTargetIndex < 0) return
@@ -34,7 +33,7 @@ class KotlinSmartStepTargetFilterer(
fun visitOrdinaryFunction(owner: String, name: String, signature: String) {
val currentCount = functionCounter.increment("$owner.$name$signature") - 1
for ((i, target) in targets.withIndex()) {
if (target is KotlinMethodSmartStepTarget && target.shouldBeVisited(owner, name, signature, currentCount)) {
if (target.shouldBeVisited(owner, name, signature, currentCount)) {
targetWasVisited[i] = true
break
}
@@ -42,12 +41,7 @@ class KotlinSmartStepTargetFilterer(
}
private fun KotlinMethodSmartStepTarget.shouldBeVisited(owner: String, name: String, signature: String, currentCount: Int): Boolean {
val actualName =
if (methodInfo.isNameMangledInBytecode)
name.getMethodNameWithoutMangling()
else
name
val actualName = name.trimIfMangledInBytecode(methodInfo.isNameMangledInBytecode)
if (methodInfo.isInlineClassMember) {
return matches(
owner,
@@ -70,7 +64,7 @@ class KotlinSmartStepTargetFilterer(
return false
}
fun getUnvisitedTargets(): List<SmartStepTarget> =
fun getUnvisitedTargets(): List<KotlinMethodSmartStepTarget> =
targets.filterIndexed { i, _ ->
!targetWasVisited[i]
}
@@ -2,6 +2,11 @@
package org.jetbrains.kotlin.idea.debugger.test
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrKotlinSteppingTest : AbstractKotlinSteppingTest() {
override fun useIrBackend() = true
override fun targetBackend(): TargetBackend =
TargetBackend.JVM_IR
}
@@ -10,11 +10,11 @@ import com.intellij.debugger.engine.evaluation.TextWithImportsImpl
import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl
import com.intellij.debugger.impl.DebuggerContextImpl
import com.intellij.debugger.impl.DebuggerContextImpl.createDebuggerContext
import com.intellij.debugger.impl.OutputChecker
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl
import com.intellij.execution.process.ProcessOutputTypes
import com.intellij.openapi.util.io.FileUtil
import com.intellij.ui.treeStructure.Tree
import com.intellij.xdebugger.impl.frame.XValueMarkers
import com.intellij.xdebugger.impl.ui.tree.ValueMarkup
import com.sun.jdi.ObjectReference
import org.jetbrains.eval4j.ObjectValue
@@ -29,12 +29,10 @@ import org.jetbrains.kotlin.idea.debugger.test.util.FramePrinter
import org.jetbrains.kotlin.idea.debugger.test.util.FramePrinterDelegate
import org.jetbrains.kotlin.idea.debugger.test.util.KotlinOutputChecker
import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstruction
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.test.InTextDirectivesUtils
import org.jetbrains.kotlin.idea.test.InTextDirectivesUtils.findLinesWithPrefixesRemoved
import org.jetbrains.kotlin.idea.test.InTextDirectivesUtils.findStringWithPrefixes
import org.jetbrains.kotlin.idea.test.KotlinBaseTest
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.idea.util.application.runReadAction
import java.io.File
import java.util.concurrent.ConcurrentHashMap
import javax.swing.tree.TreeNode
@@ -190,7 +188,6 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDescriptorTestCaseWi
this@AbstractKotlinEvaluateExpressionTest.project
)
}
?: throw AssertionError("Cannot create an Evaluator for Evaluate Expression")
val value = evaluator.evaluate(evaluationContext)
val actualResult = value.asValue().asString()
@@ -234,22 +231,10 @@ abstract class AbstractKotlinEvaluateExpressionTest : KotlinDescriptorTestCaseWi
}
}
override fun initOutputChecker(): OutputChecker {
return KotlinOutputChecker(
getTestDataPath(),
testAppPath,
appOutputPath,
targetBackend(),
getExpectedOutputFile()
)
}
override fun throwExceptionsIfAny() {
super.throwExceptionsIfAny()
if (exceptions.isNotEmpty()) {
val outputFile = getExpectedOutputFile()
val isIgnored = outputFile.exists() && InTextDirectivesUtils.isIgnoredTarget(targetBackend(), outputFile)
if (!isIgnored) {
if (!isTestIgnored()) {
for (exc in exceptions.values) {
exc.printStackTrace()
}
@@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.debugger.test
import org.jetbrains.kotlin.idea.debugger.test.preference.DebuggerPreferences
import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstruction
import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstructionKind
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractKotlinSteppingTest : KotlinDescriptorTestCaseWithStepping() {
private enum class Category(val instruction: SteppingInstructionKind?) {
@@ -28,6 +29,9 @@ abstract class AbstractKotlinSteppingTest : KotlinDescriptorTestCaseWithStepping
super.tearDown()
}
override fun targetBackend(): TargetBackend =
TargetBackend.JVM_OLD
private fun doTest(path: String, category: Category) {
this.category = category
super.doTest(path)
@@ -1120,6 +1120,11 @@ public abstract class IrKotlinSteppingTestGenerated extends AbstractIrKotlinStep
runTest("testData/stepping/custom/filterChainedFunctionCalls.kt");
}
@TestMetadata("filterChainedFunctionCallsWithLambdas.kt")
public void testFilterChainedFunctionCallsWithLambdas() throws Exception {
runTest("testData/stepping/custom/filterChainedFunctionCallsWithLambdas.kt");
}
@TestMetadata("filterFunctionCallsFromClass.kt")
public void testFilterFunctionCallsFromClass() throws Exception {
runTest("testData/stepping/custom/filterFunctionCallsFromClass.kt");
@@ -113,7 +113,7 @@ abstract class KotlinDescriptorTestCase : DescriptorTestCase() {
open fun fragmentCompilerBackend() = CodeFragmentCompiler.Companion.FragmentCompilerBackend.JVM
protected fun targetBackend(): TargetBackend =
protected open fun targetBackend(): TargetBackend =
when (fragmentCompilerBackend()) {
CodeFragmentCompiler.Companion.FragmentCompilerBackend.JVM ->
if (useIrBackend()) TargetBackend.JVM_IR_WITH_OLD_EVALUATOR else TargetBackend.JVM_WITH_OLD_EVALUATOR
@@ -25,7 +25,7 @@ import com.intellij.psi.PsiElement
import com.intellij.testFramework.runInEdtAndWait
import com.intellij.xdebugger.XDebuggerTestUtil
import com.intellij.xdebugger.frame.XStackFrame
import com.sun.jdi.request.StepRequest
import junit.framework.AssertionFailedError
import org.jetbrains.idea.maven.aether.ArtifactKind
import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor
import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils.getTopmostElementAtOffset
@@ -34,16 +34,21 @@ import org.jetbrains.kotlin.idea.debugger.stackFrame.KotlinStackFrame
import org.jetbrains.kotlin.idea.debugger.stepping.KotlinSteppingCommandProvider
import org.jetbrains.kotlin.idea.debugger.stepping.smartStepInto.KotlinSmartStepIntoHandler
import org.jetbrains.kotlin.idea.debugger.stepping.smartStepInto.KotlinSmartStepTarget
import org.jetbrains.kotlin.idea.debugger.test.util.KotlinOutputChecker
import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstruction
import org.jetbrains.kotlin.idea.debugger.test.util.SteppingInstructionKind
import org.jetbrains.kotlin.idea.debugger.test.util.render
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.idea.test.InTextDirectivesUtils.isIgnoredTarget
import org.jetbrains.kotlin.idea.test.KotlinBaseTest
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import java.nio.charset.StandardCharsets
abstract class KotlinDescriptorTestCaseWithStepping : KotlinDescriptorTestCase() {
companion object {
@@ -68,6 +73,8 @@ abstract class KotlinDescriptorTestCaseWithStepping : KotlinDescriptorTestCase()
private val classPath = mutableListOf<String>()
private val thrownExceptions = mutableListOf<Throwable>()
private fun initContexts(suspendContext: SuspendContextImpl) {
myEvaluationContext = createEvaluationContext(suspendContext)
myDebuggerContext = createDebuggerContext(suspendContext)
@@ -175,17 +182,48 @@ abstract class KotlinDescriptorTestCaseWithStepping : KotlinDescriptorTestCase()
private fun checkNumberOfSmartStepTargets(expectedNumber: Int) {
val smartStepFilters = createSmartStepIntoFilters()
assertEquals(
"Actual and expected numbers of smart step targets do not match",
expectedNumber,
smartStepFilters.size
)
try {
assertEquals(
"Actual and expected numbers of smart step targets do not match",
expectedNumber,
smartStepFilters.size
)
} catch (ex: AssertionFailedError) {
thrownExceptions.add(ex)
}
}
private fun SuspendContextImpl.doSmartStepInto(chooseFromList: Int = 0) {
this.doSmartStepInto(chooseFromList, false)
}
override fun throwExceptionsIfAny() {
if (thrownExceptions.isNotEmpty()) {
if (!isTestIgnored()) {
throw AssertionError(
"Test failed with exceptions:\n${thrownExceptions.renderStackTraces()}"
)
} else {
(checker as? KotlinOutputChecker)?.threwException = true
}
}
}
private fun List<Throwable>.renderStackTraces(): String {
val outputStream = ByteArrayOutputStream()
PrintStream(outputStream, true, StandardCharsets.UTF_8).use {
for (throwable in this) {
throwable.printStackTrace(it)
}
}
return outputStream.toString(StandardCharsets.UTF_8)
}
protected fun isTestIgnored(): Boolean {
val outputFile = getExpectedOutputFile()
return outputFile.exists() && isIgnoredTarget(targetBackend(), outputFile)
}
private fun SuspendContextImpl.printContext() {
runReadAction {
if (this.frameProxy == null) {
@@ -1120,6 +1120,11 @@ public abstract class KotlinSteppingTestGenerated extends AbstractKotlinStepping
runTest("testData/stepping/custom/filterChainedFunctionCalls.kt");
}
@TestMetadata("filterChainedFunctionCallsWithLambdas.kt")
public void testFilterChainedFunctionCallsWithLambdas() throws Exception {
runTest("testData/stepping/custom/filterChainedFunctionCallsWithLambdas.kt");
}
@TestMetadata("filterFunctionCallsFromClass.kt")
public void testFilterFunctionCallsFromClass() throws Exception {
runTest("testData/stepping/custom/filterFunctionCallsFromClass.kt");
@@ -16,19 +16,19 @@ fun Any.baz(): Any {
return this
}
fun Any.inlineFoo(): Any {
inline fun Any.inlineFoo(): Any {
return this
}
fun Any.inlineFoo(i: Int, j: Int): Any {
inline fun Any.inlineFoo(i: Int, j: Int): Any {
return this
}
fun Any.inlineBar(): Any {
inline fun Any.inlineBar(): Any {
return this
}
fun Any.inlineBaz(): Any {
inline fun Any.inlineBaz(): Any {
return this
}
@@ -0,0 +1,162 @@
package filterChainedFunctionCallsWithLambdas
typealias FunT = () -> Unit
fun Any.foo(f: FunT): Any {
return this
}
fun Any.foo(i: Int, j: Int, f: FunT): Any {
return this
}
fun Any.bar(f: FunT): Any {
return this
}
fun Any.baz(f: FunT): Any {
return this
}
inline fun Any.inlineFoo(f: FunT): Any {
return this
}
inline fun Any.inlineFoo(i: Int, j: Int, f: FunT): Any {
return this
}
inline fun Any.inlineBar(f: FunT): Any {
return this
}
inline fun Any.inlineBaz(f: FunT): Any {
return this
}
fun testNoInlineCalls() {
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 1
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 7
1.foo { stopHere() }.bar { stopHere() }.foo (1, 2) { stopHere() }.baz { stopHere() }
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 3
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 6
1.foo { stopHere() }.bar { stopHere() }.foo (1, 2) { stopHere() }.baz { stopHere() }
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 5
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 5
1.foo { stopHere() }.bar { stopHere() }.foo (1, 2) { stopHere() }.baz { stopHere() }
}
fun testFirstCallIsInline() {
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 1
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 7
1.inlineFoo { stopHere() }.bar { stopHere() }.foo (1, 2) { stopHere() }.baz { stopHere() }
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 3
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 6
1.inlineFoo { stopHere() }.bar { stopHere() }.foo (1, 2) { stopHere() }.baz { stopHere() }
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 5
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 5
1.inlineFoo { stopHere() }.bar { stopHere() }.foo (1, 2) { stopHere() }.baz { stopHere() }
}
fun testFirstAndThirdCallsAreInline() {
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 1
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 7
1.inlineFoo { stopHere() }.bar { stopHere() }.inlineFoo (1, 2) { stopHere() }.baz { stopHere() }
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 3
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 6
1.inlineFoo { stopHere() }.bar { stopHere() }.inlineFoo (1, 2) { stopHere() }.baz { stopHere() }
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 5
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 5
1.inlineFoo { stopHere() }.bar { stopHere() }.inlineFoo (1, 2) { stopHere() }.baz { stopHere() }
}
fun testAllCallsAreInline() {
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 1
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 7
1.inlineFoo { stopHere() }.inlineBar { stopHere() }.inlineFoo (1, 2) { stopHere() }.inlineBaz { stopHere() }
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 3
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 6
1.inlineFoo { stopHere() }.inlineBar { stopHere() }.inlineFoo (1, 2) { stopHere() }.inlineBaz { stopHere() }
// STEP_OVER: 1
//Breakpoint!
stopHere()
// SMART_STEP_INTO_BY_INDEX: 5
// STEP_OUT: 1
// SMART_STEP_TARGETS_EXPECTED_NUMBER: 5
1.inlineFoo { stopHere() }.inlineBar { stopHere() }.inlineFoo (1, 2) { stopHere() }.inlineBaz { stopHere() }
}
fun main() {
testNoInlineCalls()
testFirstCallIsInline()
testFirstAndThirdCallsAreInline()
testAllCallsAreInline()
}
fun stopHere() {
}
@@ -0,0 +1,65 @@
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:40
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:49
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:58
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:69
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:78
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:87
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:98
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:107
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:116
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:127
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:136
LineBreakpoint created at filterChainedFunctionCallsWithLambdas.kt:145
Run Java
Connected to the target VM
filterChainedFunctionCallsWithLambdas.kt:40
filterChainedFunctionCallsWithLambdas.kt:45
filterChainedFunctionCallsWithLambdas.kt:6
filterChainedFunctionCallsWithLambdas.kt:45
filterChainedFunctionCallsWithLambdas.kt:49
filterChainedFunctionCallsWithLambdas.kt:54
filterChainedFunctionCallsWithLambdas.kt:14
filterChainedFunctionCallsWithLambdas.kt:54
filterChainedFunctionCallsWithLambdas.kt:58
filterChainedFunctionCallsWithLambdas.kt:63
filterChainedFunctionCallsWithLambdas.kt:10
filterChainedFunctionCallsWithLambdas.kt:63
filterChainedFunctionCallsWithLambdas.kt:69
filterChainedFunctionCallsWithLambdas.kt:74
filterChainedFunctionCallsWithLambdas.kt:22
filterChainedFunctionCallsWithLambdas.kt:74
filterChainedFunctionCallsWithLambdas.kt:78
filterChainedFunctionCallsWithLambdas.kt:83
filterChainedFunctionCallsWithLambdas.kt:14
filterChainedFunctionCallsWithLambdas.kt:83
filterChainedFunctionCallsWithLambdas.kt:87
filterChainedFunctionCallsWithLambdas.kt:92
filterChainedFunctionCallsWithLambdas.kt:10
filterChainedFunctionCallsWithLambdas.kt:92
filterChainedFunctionCallsWithLambdas.kt:98
filterChainedFunctionCallsWithLambdas.kt:103
filterChainedFunctionCallsWithLambdas.kt:22
filterChainedFunctionCallsWithLambdas.kt:103
filterChainedFunctionCallsWithLambdas.kt:107
filterChainedFunctionCallsWithLambdas.kt:112
filterChainedFunctionCallsWithLambdas.kt:14
filterChainedFunctionCallsWithLambdas.kt:112
filterChainedFunctionCallsWithLambdas.kt:116
filterChainedFunctionCallsWithLambdas.kt:121
filterChainedFunctionCallsWithLambdas.kt:26
filterChainedFunctionCallsWithLambdas.kt:121
filterChainedFunctionCallsWithLambdas.kt:127
filterChainedFunctionCallsWithLambdas.kt:132
filterChainedFunctionCallsWithLambdas.kt:22
filterChainedFunctionCallsWithLambdas.kt:132
filterChainedFunctionCallsWithLambdas.kt:136
filterChainedFunctionCallsWithLambdas.kt:141
filterChainedFunctionCallsWithLambdas.kt:30
filterChainedFunctionCallsWithLambdas.kt:141
filterChainedFunctionCallsWithLambdas.kt:145
filterChainedFunctionCallsWithLambdas.kt:150
filterChainedFunctionCallsWithLambdas.kt:26
filterChainedFunctionCallsWithLambdas.kt:150
Disconnected from the target VM
Process finished with exit code 0
@@ -17,19 +17,19 @@ class A {
return this
}
fun inlineFoo(): A {
inline fun inlineFoo(): A {
return this
}
private fun inlineFoo(i: Int, j: Int): A {
private inline fun inlineFoo(i: Int, j: Int): A {
return this
}
fun inlineBar(): A {
inline fun inlineBar(): A {
return this
}
private fun inlineBaz(): A {
private inline fun inlineBaz(): A {
return this
}
@@ -18,19 +18,19 @@ value class A(val str: String) {
return this
}
fun inlineFoo(): A {
inline fun inlineFoo(): A {
return this
}
private fun inlineFoo(i: Int, j: Int): A {
private inline fun inlineFoo(i: Int, j: Int): A {
return this
}
fun inlineBar(): A {
inline fun inlineBar(): A {
return this
}
private fun inlineBaz(): A {
private inline fun inlineBaz(): A {
return this
}
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JVM_OLD
LineBreakpoint created at filterFunctionCallsFromInlineClass.kt:40
LineBreakpoint created at filterFunctionCallsFromInlineClass.kt:49
LineBreakpoint created at filterFunctionCallsFromInlineClass.kt:58
@@ -12,15 +12,15 @@ fun baz(i: Int): Int {
return i
}
fun inlineFoo(i: Int, j: Int): Int {
inline fun inlineFoo(i: Int, j: Int): Int {
return i + j
}
fun inlineBar(i: Int): Int {
inline fun inlineBar(i: Int): Int {
return i
}
fun inlineBaz(i: Int): Int {
inline fun inlineBaz(i: Int): Int {
return i
}
@@ -97,7 +97,13 @@ object DebuggerUtils {
return extension in KotlinFileTypeFactoryUtils.KOTLIN_EXTENSIONS
}
fun String.getMethodNameWithoutMangling() =
fun String.trimIfMangledInBytecode(isMangledInBytecode: Boolean): String =
if (isMangledInBytecode)
getMethodNameWithoutMangling()
else
this
private fun String.getMethodNameWithoutMangling() =
substringBefore('-')
fun isKotlinFakeLineNumber(location: Location): Boolean {