Fix step over for inlined functions in Android Studio (KT-14374)
#KT-14374 Fixed
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+41
-19
@@ -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'
|
||||
|
||||
+1
-5
@@ -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
|
||||
|
||||
+1
-3
@@ -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'
|
||||
|
||||
|
||||
Vendored
+2
-3
@@ -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
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
|
||||
Vendored
+5
-5
@@ -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()
|
||||
|
||||
Vendored
+4
-4
@@ -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
|
||||
+21
@@ -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
|
||||
+21
@@ -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
|
||||
+21
@@ -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
|
||||
+1
-1
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user