mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[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:
committed by
intellij-monorepo-bot
parent
7c69339b88
commit
43b95d766e
+5
-9
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
+13
-10
@@ -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
|
||||
}
|
||||
|
||||
+28
-14
@@ -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(
|
||||
|
||||
+7
-13
@@ -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]
|
||||
}
|
||||
|
||||
+5
@@ -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
|
||||
}
|
||||
+4
-19
@@ -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()
|
||||
}
|
||||
|
||||
+4
@@ -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)
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+44
-6
@@ -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) {
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+4
-4
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+162
@@ -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() {
|
||||
|
||||
}
|
||||
+65
@@ -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
|
||||
+4
-4
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -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
@@ -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
|
||||
|
||||
+3
-3
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user