Fix step over for inlined functions in Android Studio (KT-14374)

#KT-14374 Fixed
This commit is contained in:
Nikolay Krasko
2016-10-26 20:43:08 +03:00
parent f87779bfb0
commit 623ee316c0
28 changed files with 392 additions and 79 deletions
@@ -101,37 +101,40 @@ class KotlinPositionManager(private val myDebugProcess: DebugProcess) : MultiReq
throw NoDataException.INSTANCE
}
val lineNumber = try {
val sourceLineNumber = try {
location.lineNumber() - 1
}
catch (e: InternalError) {
-1
}
if (lineNumber < 0) {
if (sourceLineNumber < 0) {
throw NoDataException.INSTANCE
}
val lambdaOrFunIfInside = getLambdaOrFunIfInside(location, psiFile as KtFile, lineNumber)
val lambdaOrFunIfInside = getLambdaOrFunIfInside(location, psiFile as KtFile, sourceLineNumber)
if (lambdaOrFunIfInside != null) {
return SourcePosition.createFromElement(lambdaOrFunIfInside.bodyExpression!!)
}
val elementInDeclaration = getElementForDeclarationLine(location, psiFile, lineNumber)
val elementInDeclaration = getElementForDeclarationLine(location, psiFile, sourceLineNumber)
if (elementInDeclaration != null) {
return SourcePosition.createFromElement(elementInDeclaration)
}
if (lineNumber > psiFile.getLineCount() && myDebugProcess.isDexDebug()) {
val inlinePosition = getOriginalPositionOfInlinedLine(
location.lineNumber(), FqName(location.declaringType().name()), location.sourceName(),
myDebugProcess.project, GlobalSearchScope.allScope(myDebugProcess.project))
if (sourceLineNumber > psiFile.getLineCount() && myDebugProcess.isDexDebug()) {
val thisFunLine = getLastLineNumberForLocation(location, myDebugProcess.project)
if (thisFunLine != null && thisFunLine != location.lineNumber()) {
return SourcePosition.createFromLine(psiFile, thisFunLine - 1)
}
val inlinePosition = getOriginalPositionOfInlinedLine(location, myDebugProcess.project)
if (inlinePosition != null) {
return SourcePosition.createFromLine(inlinePosition.first, inlinePosition.second)
}
}
return SourcePosition.createFromLine(psiFile, lineNumber)
return SourcePosition.createFromLine(psiFile, sourceLineNumber)
}
// Returns a property or a constructor if debugger stops at class declaration
@@ -21,9 +21,11 @@ import com.intellij.debugger.engine.DebugProcess
import com.intellij.debugger.jdi.VirtualMachineProxyImpl
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.GlobalSearchScope
import com.sun.jdi.Location
import com.sun.jdi.ReferenceType
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.lexer.KtTokens
@@ -32,9 +34,84 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.utils.getOrPutNullable
import org.jetbrains.org.objectweb.asm.*
import java.util.*
internal fun getOriginalPositionOfInlinedLine(
lineNumber: Int, fqName: FqName, fileName: String, project: Project, searchScope: GlobalSearchScope): Pair<KtFile, Int>? {
// TODO: Don't read same bytecode file again and again
// TODO: Build line mapping for the whole file
// TODO: Quick caching for the same location
fun noStrataLineNumber(location: Location, isDexDebug: Boolean, project: Project, preferInlined: Boolean = false): Int {
if (isDexDebug) {
if (!preferInlined) {
val thisFunLine = runReadAction { getLastLineNumberForLocation(location, project) }
if (thisFunLine != null && thisFunLine != location.lineNumber()) {
// TODO: bad line because of inlining
return thisFunLine
}
}
val inlinePosition = runReadAction { getOriginalPositionOfInlinedLine(location, project) }
if (inlinePosition != null) {
return inlinePosition.second + 1
}
}
return location.lineNumber()
}
fun getLastLineNumberForLocation(location: Location, project: Project, searchScope: GlobalSearchScope = GlobalSearchScope.allScope(project)): Int? {
val lineNumber = location.lineNumber()
val fqName = FqName(location.declaringType().name())
val fileName = location.sourceName()
val method = location.method() ?: return null
val bytes = findAndReadClassFile(fqName, fileName, project, searchScope, { isInlineFunctionLineNumber(it, lineNumber, project) }) ?: return null
fun readLineNumberTableMapping(bytes: ByteArray): Map<String, Set<Int>> {
val labelsToAllStrings = HashMap<String, MutableSet<Int>>()
ClassReader(bytes).accept(object : ClassVisitor(InlineCodegenUtil.API) {
override fun visitMethod(access: Int, name: String?, desc: String?, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
if (!(name == method.name() && desc == method.signature())) {
return null
}
return object : MethodVisitor(Opcodes.ASM5, null) {
override fun visitLineNumber(line: Int, start: Label?) {
if (start != null) {
labelsToAllStrings.getOrPutNullable(start.toString(), { LinkedHashSet<Int>() }).add(line)
}
}
}
}
}, ClassReader.SKIP_FRAMES and ClassReader.SKIP_CODE)
return labelsToAllStrings
}
val lineMapping = readLineNumberTableMapping(bytes)
return lineMapping.values.firstOrNull { it.contains(lineNumber) }?.last()
}
internal fun getOriginalPositionOfInlinedLine(location: Location, project: Project): Pair<KtFile, Int>? {
val lineNumber = location.lineNumber()
val fqName = FqName(location.declaringType().name())
val fileName = location.sourceName()
val searchScope = GlobalSearchScope.allScope(project)
val bytes = findAndReadClassFile(fqName, fileName, project, searchScope, { isInlineFunctionLineNumber(it, lineNumber, project) }) ?: return null
val smapData = readDebugInfo(bytes) ?: return null
return mapStacktraceLineToSource(smapData, lineNumber, project, SourceLineKind.EXECUTED_LINE, searchScope)
}
internal fun findAndReadClassFile(
fqName: FqName, fileName: String, project: Project, searchScope: GlobalSearchScope,
sourceFileFilter: (VirtualFile) -> Boolean = { true },
libFileFilter: (VirtualFile) -> Boolean = { true }): ByteArray? {
val internalName = fqName.asString().replace('.', '/')
val jvmClassName = JvmClassName.byInternalName(internalName)
@@ -42,9 +119,7 @@ internal fun getOriginalPositionOfInlinedLine(
val virtualFile = file.virtualFile ?: return null
val bytes = readClassFile(project, jvmClassName, virtualFile, { isInlineFunctionLineNumber(it, lineNumber, project) }) ?: return null
val smapData = readDebugInfo(bytes) ?: return null
return mapStacktraceLineToSource(smapData, lineNumber, project, SourceLineKind.EXECUTED_LINE, searchScope)
return readClassFile(project, jvmClassName, virtualFile, sourceFileFilter = sourceFileFilter, libFileFilter = libFileFilter)
}
internal fun getLocationsOfInlinedLine(type: ReferenceType, position: SourcePosition, sourceSearchScope: GlobalSearchScope): List<Location> {
@@ -55,12 +55,7 @@ public class DebuggerSteppingHelper {
return debugProcess.new ResumeCommand(suspendContext) {
@Override
public void contextAction() {
// In DEX there's no strata for trying to understand what lines were inlined and no local variables attributes are
// preserved that can be used for fine tuning. So do an ordinal 'step over' instead.
if (NoStrataPositionManagerHelperKt.isDexDebug(suspendContext.getDebugProcess())) {
debugProcess.createStepOverCommand(suspendContext, true).contextAction();
return;
}
boolean isDexDebug = NoStrataPositionManagerHelperKt.isDexDebug(suspendContext.getDebugProcess());
try {
StackFrameProxyImpl frameProxy = suspendContext.getFrameProxy();
@@ -68,7 +63,8 @@ public class DebuggerSteppingHelper {
Action action = KotlinSteppingCommandProviderKt.getStepOverAction(
frameProxy.location(),
kotlinSourcePosition,
frameProxy
frameProxy,
isDexDebug
);
createStepRequest(
@@ -18,19 +18,24 @@ package org.jetbrains.kotlin.idea.debugger.stepping
import com.intellij.debugger.engine.DebugProcessImpl
import com.intellij.debugger.engine.SuspendContextImpl
import com.intellij.openapi.project.Project
import com.intellij.util.Range
import com.sun.jdi.LocalVariable
import com.sun.jdi.Location
import org.jetbrains.kotlin.idea.debugger.noStrataLineNumber
class KotlinStepOverInlineFilter(
val isDexDebug: Boolean,
val project: Project,
val stepOverLines: Set<Int>, val fromLine: Int,
val inlineFunRangeVariables: List<LocalVariable>) : KotlinMethodFilter {
private fun Location.ktLineNumber() = noStrataLineNumber(this, isDexDebug, project)
class KotlinStepOverInlineFilter(val stepOverLines: Set<Int>, val fromLine: Int,
val inlineFunRangeVariables: List<LocalVariable>) : KotlinMethodFilter {
override fun locationMatches(context: SuspendContextImpl, location: Location): Boolean {
val frameProxy = context.frameProxy
if (frameProxy == null) return true
val frameProxy = context.frameProxy ?: return true
val currentLine = location.lineNumber()
if (!(stepOverLines.contains(location.lineNumber()))) {
val currentLine = location.ktLineNumber()
if (!(stepOverLines.contains(currentLine))) {
return currentLine != fromLine
}
@@ -40,6 +40,7 @@ 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.debugger.DebuggerUtils
import org.jetbrains.kotlin.idea.debugger.noStrataLineNumber
import org.jetbrains.kotlin.idea.refactoring.getLineEndOffset
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
@@ -268,12 +269,13 @@ private fun findCallsOnPosition(sourcePosition: SourcePosition, filter: (KtCallE
sealed class Action(val position: XSourcePositionImpl? = null,
val lineNumber: Int? = null,
val stepOverLines: Set<Int>? = null,
val inlineRangeVariables: List<LocalVariable>? = null) {
val inlineRangeVariables: List<LocalVariable>? = null,
val isDexDebug: Boolean = false) {
class STEP_OVER : Action()
class STEP_OUT : Action()
class RUN_TO_CURSOR(position: XSourcePositionImpl) : Action(position)
class STEP_OVER_INLINED(lineNumber: Int, stepOverLines: Set<Int>, inlineVariables: List<LocalVariable>) : Action(
lineNumber = lineNumber, stepOverLines = stepOverLines, inlineRangeVariables = inlineVariables)
class STEP_OVER_INLINED(lineNumber: Int, stepOverLines: Set<Int>, inlineVariables: List<LocalVariable>, isDexDebug: Boolean) : Action(
lineNumber = lineNumber, stepOverLines = stepOverLines, inlineRangeVariables = inlineVariables, isDexDebug = isDexDebug)
fun apply(debugProcess: DebugProcessImpl,
suspendContext: SuspendContextImpl,
@@ -287,26 +289,32 @@ sealed class Action(val position: XSourcePositionImpl? = null,
is Action.STEP_OUT -> debugProcess.createStepOutCommand(suspendContext).contextAction(suspendContext)
is Action.STEP_OVER -> debugProcess.createStepOverCommand(suspendContext, ignoreBreakpoints).contextAction(suspendContext)
is Action.STEP_OVER_INLINED -> KotlinStepActionFactory(debugProcess).createKotlinStepOverInlineAction(
KotlinStepOverInlineFilter(stepOverLines!!, lineNumber ?: -1, inlineRangeVariables!!)).contextAction(suspendContext)
KotlinStepOverInlineFilter(
isDexDebug,
debugProcess.project,
stepOverLines!!,
lineNumber ?: -1,
inlineRangeVariables!!)).contextAction(suspendContext)
}
}
}
interface KotlinMethodFilter: MethodFilter {
interface KotlinMethodFilter : MethodFilter {
fun locationMatches(context: SuspendContextImpl, location: Location): Boolean
}
fun getStepOverAction(
location: Location,
kotlinSourcePosition: KotlinSteppingCommandProvider.KotlinSourcePosition,
frameProxy: StackFrameProxyImpl
frameProxy: StackFrameProxyImpl,
isDexDebug: Boolean
): Action {
val inlineArgumentsToSkip = runReadAction {
getInlineCallFunctionArgumentsIfAny(kotlinSourcePosition.sourcePosition)
}
return getStepOverAction(location, kotlinSourcePosition.file, kotlinSourcePosition.linesRange,
inlineArgumentsToSkip, frameProxy)
inlineArgumentsToSkip, frameProxy, isDexDebug)
}
fun getStepOverAction(
@@ -314,12 +322,21 @@ fun getStepOverAction(
file: KtFile,
range: IntRange,
inlineFunctionArguments: List<KtElement>,
frameProxy: StackFrameProxyImpl
frameProxy: StackFrameProxyImpl,
isDexDebug: Boolean
): Action {
val computedReferenceType = location.declaringType() ?: return Action.STEP_OVER()
val project = file.project
fun Location.ktLineNumber() = noStrataLineNumber(this, isDexDebug, project, true)
fun isLocationSuitable(nextLocation: Location): Boolean {
if (nextLocation.method() != location.method() || nextLocation.lineNumber() !in range) {
if (nextLocation.method() != location.method()) {
return false
}
if (nextLocation.ktLineNumber() !in range) {
return false
}
@@ -336,22 +353,24 @@ fun getStepOverAction(
.dropWhile { it != location }
.drop(1)
.filter(::isLocationSuitable)
.dropWhile { it.lineNumber() == location.lineNumber() }
.dropWhile { it.ktLineNumber() == location.ktLineNumber() }
.firstOrNull()
return previousSuitableLocation != null && previousSuitableLocation.lineNumber() > location.lineNumber()
return previousSuitableLocation != null && previousSuitableLocation.ktLineNumber() > location.ktLineNumber()
}
val patchedLocation = if (isBackEdgeLocation()) {
// Pretend we had already did a backing step
computedReferenceType.allLineLocations()
.filter(::isLocationSuitable)
.first { it.lineNumber() == location.lineNumber() }
.first { it.ktLineNumber() == location.ktLineNumber() }
}
else {
location
}
val patchedLineNumber = patchedLocation.ktLineNumber()
val lambdaArgumentRanges = runReadAction {
inlineFunctionArguments.filterIsInstance<KtElement>().map {
val startLineNumber = it.getLineNumber(true) + 1
@@ -367,21 +386,24 @@ fun getStepOverAction(
// - Lines from other files and from functions that are not in range of current one are definitely inlined
// - Lines in function arguments of inlined functions are inlined too as we found them starting from the position of inlined call.
//
// This heuristic doesn't work for DEX, because of missing strata information (https://code.google.com/p/android/issues/detail?id=82972)
//
// It also thinks that too many lines are inlined when there's a call of function argument or other
// inline function in last statement of inline function. The list of inlineRangeVariables is used to overcome it.
val probablyInlinedLocations = computedReferenceType.allLineLocations()
.dropWhile { it != patchedLocation }
.drop(1)
.dropWhile { it.lineNumber() == patchedLocation.lineNumber() }
.takeWhile { locationAtLine ->
!isLocationSuitable(locationAtLine) || lambdaArgumentRanges.any { locationAtLine.lineNumber() in it }
.dropWhile { it.ktLineNumber() == patchedLineNumber }
.takeWhile { location ->
!isLocationSuitable(location) || lambdaArgumentRanges.any { location.ktLineNumber() in it }
}
.dropWhile { it.lineNumber() == patchedLocation.lineNumber() }
.dropWhile { it.ktLineNumber() == patchedLineNumber }
if (!probablyInlinedLocations.isEmpty()) {
return Action.STEP_OVER_INLINED(patchedLocation.lineNumber(), probablyInlinedLocations.map { it.lineNumber() }.toSet(), inlineRangeVariables)
return Action.STEP_OVER_INLINED(
patchedLineNumber,
probablyInlinedLocations.map { it.ktLineNumber() }.toSet(),
inlineRangeVariables,
isDexDebug
)
}
return Action.STEP_OVER()
@@ -2,7 +2,6 @@ LineBreakpoint created at inlineInIfFalseDex.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! inlineInIfFalseDex.InlineInIfFalseDexKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
inlineInIfFalseDex.kt:6
inlineInIfFalseDex.kt:15
inlineInIfFalseDex.kt:9
inlineInIfFalseDex.kt:10
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
@@ -2,7 +2,6 @@ LineBreakpoint created at inlineInIfTrueDex.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! inlineInIfTrueDex.InlineInIfTrueDexKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
inlineInIfTrueDex.kt:6
inlineInIfTrueDex.kt:14
inlineInIfTrueDex.kt:7
inlineInIfTrueDex.kt:9
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
@@ -3,12 +3,8 @@ LineBreakpoint created at soInlineAnonymousFunctionArgumentDex.kt:5
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
soInlineAnonymousFunctionArgumentDex.kt:5
soInlineAnonymousFunctionArgumentDex.kt:7
soInlineAnonymousFunctionArgumentDex.kt:15
soInlineAnonymousFunctionArgumentDex.kt:8
soInlineAnonymousFunctionArgumentDex.kt:16
soInlineAnonymousFunctionArgumentDex.kt:15
soInlineAnonymousFunctionArgumentDex.kt:11
soInlineAnonymousFunctionArgumentDex.kt:16
soInlineAnonymousFunctionArgumentDex.kt:12
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -3,9 +3,7 @@ LineBreakpoint created at soInlineCallInLastStatementInInlineDex.kt:10
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
soInlineCallInLastStatementInInlineDex.kt:10
soInlineCallInLastStatementInInlineDex.kt:11
soInlineCallInLastStatementInInlineDex.kt:15
soInlineCallInLastStatementInInlineDex.kt:11
soInlineCallInLastStatementInInlineDex.kt:16
soInlineCallInLastStatementInInlineDex.kt:5
soInlineCallInLastStatementInInlineDex.kt:6
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
@@ -2,9 +2,8 @@ LineBreakpoint created at soInlineCallInLastStatementInInlineFunctionArgumentDex
!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! soInlineCallInLastStatementInInlineFunctionArgumentDex.SoInlineCallInLastStatementInInlineFunctionArgumentDexKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:7
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:17
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:18
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:14
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:8
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:9
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
+10
View File
@@ -0,0 +1,10 @@
LineBreakpoint created at soInlineFunDex.kt:7
!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! soInlineFunDex.SoInlineFunDexKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
soInlineFunDex.kt:7
soInlineFunDex.kt:9
soInlineFunDex.kt:11
soInlineFunDex.kt:12
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 soInlineFunOnOneLineFor.kt:17
!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! soInlineFunOnOneLineFor.SoInlineFunOnOneLineForKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
soInlineFunOnOneLineFor.kt:17
soInlineFunOnOneLineFor.kt:18
soInlineFunOnOneLineFor.kt:8
soInlineFunOnOneLineFor.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 soInlineFunOnOneLineForDex.kt:17
!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! soInlineFunOnOneLineForDex.SoInlineFunOnOneLineForDexKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
soInlineFunOnOneLineForDex.kt:17
soInlineFunOnOneLineForDex.kt:18
soInlineFunOnOneLineForDex.kt:8
soInlineFunOnOneLineForDex.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 soInlineFunWithFor.kt:5
!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! soInlineFunWithFor.SoInlineFunWithForKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
soInlineFunWithFor.kt:5
soInlineFunWithFor.kt:7
soInlineFunWithFor.kt:9
soInlineFunWithFor.kt:10
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 soInlineIterableFunDex.kt:5
!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! soInlineIterableFunDex.SoInlineIterableFunDexKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
soInlineIterableFunDex.kt:5
soInlineIterableFunDex.kt:7
soInlineIterableFunDex.kt:9
soInlineIterableFunDex.kt:10
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,11 @@
LineBreakpoint created at soInlineLibFunDex.kt:5
!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! soInlineLibFunDex.SoInlineLibFunDexKt
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
soInlineLibFunDex.kt:5
soInlineLibFunDex.kt:7
soInlineLibFunDex.kt:9
soInlineLibFunDex.kt:10
soInlineLibFunDex.kt:12
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -3,14 +3,8 @@ LineBreakpoint created at soInlineWhileConditionDex.kt:5
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
soInlineWhileConditionDex.kt:5
soInlineWhileConditionDex.kt:7
soInlineWhileConditionDex.kt:18
soInlineWhileConditionDex.kt:7
soInlineWhileConditionDex.kt:8
soInlineWhileConditionDex.kt:7
soInlineWhileConditionDex.kt:18
soInlineWhileConditionDex.kt:7
soInlineWhileConditionDex.kt:12
soInlineWhileConditionDex.kt:18
soInlineWhileConditionDex.kt:12
soInlineWhileConditionDex.kt:15
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
@@ -3,10 +3,10 @@ package inlineInIfTrueDex
fun main(args: Array<String>) {
val bar = ""
//Breakpoint!
if (inlineCall { true }) {
foo()
if (inlineCall { true }) { // 1
foo() // 2
}
}
} // 3
fun foo() {}
@@ -2,14 +2,14 @@ package soInlineAnonymousFunctionArgumentDex
fun main(args: Array<String>) {
//Breakpoint!
val b = 1
val b = 1 // 1
foo(
fun (){ test(1) }
foo( // 2
fun (){ test(1) } //
)
foo(fun (){ test(1) })
}
foo(fun (){ test(1) }) // 3
} // 4
inline fun foo(f: () -> Unit) {
f()
@@ -2,13 +2,13 @@ package soInlineCallInLastStatementInInlineDex
fun main(args: Array<String>) {
bar()
nop()
}
nop() // 3
} // 4
inline fun bar() {
//Breakpoint!
nop()
foo { 42 }
nop() // 1
foo { 42 } // 2
}
inline fun foo(f: () -> Unit) {
@@ -0,0 +1,27 @@
package soInlineFunDex
fun main(args: Array<String>) {
val a = 1
//Breakpoint!
simple() // 1
withParam(1 + a) // 2
withLambda { "hi" } // 3
} // 4
inline fun simple() {
foo()
}
inline fun withParam(i: Int) {
}
inline fun withLambda(a: () -> Unit) {
a()
}
fun foo() {}
// STEP_OVER: 6
@@ -0,0 +1,21 @@
package soInlineFunOnOneLineFor
fun main(args: Array<String>) {
val list = listOf(1, 2, 3)
list.any1 { it > 2 }
foo()
}
fun foo() {
}
inline fun <T> Iterable<T>.any1(predicate: (T) -> Boolean): Boolean {
//Breakpoint!
for (element in this) if (predicate(element)) return true
return false
}
// STEP_OVER: 3
@@ -0,0 +1,21 @@
package soInlineFunOnOneLineForDex
fun main(args: Array<String>) {
val list = listOf(1, 2, 3)
list.any1 { it > 2 }
foo()
}
fun foo() {
}
inline fun <T> Iterable<T>.any1(predicate: (T) -> Boolean): Boolean {
//Breakpoint!
for (element in this) if (predicate(element)) return true
return false
}
// STEP_OVER: 3
@@ -0,0 +1,22 @@
package soInlineFunWithFor
fun main(args: Array<String>) {
//Breakpoint!
foo()
val r = any1 { it > 2 }
foo()
}
fun foo() {}
inline fun any1(predicate: (Int) -> Boolean) {
for (i in 1..2) {
if (predicate(i)) {
return
}
}
}
// STEP_OVER: 5
@@ -0,0 +1,21 @@
package soInlineIterableFunDex
fun main(args: Array<String>) {
//Breakpoint!
val list = listOf(1, 2, 3)
list.any1 { it > 2 }
foo()
}
fun foo() {
}
inline fun <T> Iterable<T>.any1(predicate: (T) -> Boolean): Boolean {
for (element in this) if (predicate(element)) return true
return false
}
// STEP_OVER: 5
@@ -0,0 +1,18 @@
package soInlineLibFunDex
fun main(args: Array<String>) {
//Breakpoint!
var i = 1
listOf(1, 2, 3).any { it > 2 } // Step over goes into 'any' (regression)
if (listOf(1, 2, 3).any { it > 2 }) { // Step over goes into 'any'
i++
}
}
inline fun test(a: () -> Unit) {
a()
}
// STEP_OVER: 7
@@ -9,7 +9,7 @@ fun main(args: Array<String>) {
}
// inline in while condition (false)
while (id { false }) { // 5
while (id { false }) { // 5
bar()
}
} // 6
@@ -518,6 +518,30 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
doStepOverTest(fileName);
}
@TestMetadata("soInlineFunDex.kt")
public void testSoInlineFunDex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineFunDex.kt");
doStepOverTest(fileName);
}
@TestMetadata("soInlineFunOnOneLineFor.kt")
public void testSoInlineFunOnOneLineFor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineFunOnOneLineFor.kt");
doStepOverTest(fileName);
}
@TestMetadata("soInlineFunOnOneLineForDex.kt")
public void testSoInlineFunOnOneLineForDex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineFunOnOneLineForDex.kt");
doStepOverTest(fileName);
}
@TestMetadata("soInlineFunWithFor.kt")
public void testSoInlineFunWithFor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineFunWithFor.kt");
doStepOverTest(fileName);
}
@TestMetadata("soInlineFunWithLastStatementMultilineArgumentCall.kt")
public void testSoInlineFunWithLastStatementMultilineArgumentCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineFunWithLastStatementMultilineArgumentCall.kt");
@@ -542,6 +566,18 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
doStepOverTest(fileName);
}
@TestMetadata("soInlineIterableFunDex.kt")
public void testSoInlineIterableFunDex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineIterableFunDex.kt");
doStepOverTest(fileName);
}
@TestMetadata("soInlineLibFunDex.kt")
public void testSoInlineLibFunDex() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineLibFunDex.kt");
doStepOverTest(fileName);
}
@TestMetadata("soInlineOperatorIterator.kt")
public void testSoInlineOperatorIterator() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineOperatorIterator.kt");