Change the way 'step over' over inline calls works (KT-13751)
Previously it worked by invoking 'Run To Cursor' for the last position of inline function. As there's only one 'run to cursor' breakpoint available in Idea framework, it couldn't work when inline function call was was used in conditions of control flow statements. A new approach works through multiple step over operation and controlling stop position. In other words we try to "step over" inlined lines. Same thing is actually done in "Smart Step Into" action. (cherry picked from commit 2e8775d) #KT-13751 Fixed
This commit is contained in:
committed by
Nikolay Krasko
parent
9594316b0a
commit
7992df7b93
@@ -58,7 +58,8 @@ public class DebuggerSteppingHelper {
|
||||
if (frameProxy != null) {
|
||||
Action action = KotlinSteppingCommandProviderKt.getStepOverAction(
|
||||
frameProxy.location(),
|
||||
kotlinSourcePosition
|
||||
kotlinSourcePosition,
|
||||
frameProxy
|
||||
);
|
||||
|
||||
createStepRequest(
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.stepping
|
||||
|
||||
import com.intellij.debugger.DebuggerManagerEx
|
||||
import com.intellij.debugger.engine.*
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl
|
||||
import com.intellij.debugger.impl.DebuggerSession
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl
|
||||
import com.intellij.debugger.settings.DebuggerSettings
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.util.EventDispatcher
|
||||
import com.sun.jdi.request.EventRequest
|
||||
import com.sun.jdi.request.StepRequest
|
||||
|
||||
// Mass-copy-paste code for commands behaviour from com.intellij.debugger.engine.DebugProcessImpl
|
||||
@SuppressWarnings("UnnecessaryFinalOnLocalVariableOrParameter")
|
||||
class KotlinStepActionFactory(private val debuggerProcess: DebugProcessImpl) {
|
||||
abstract class KotlinStepAction {
|
||||
abstract fun contextAction(suspendContext: SuspendContextImpl)
|
||||
}
|
||||
|
||||
fun createKotlinStepOverInlineAction(smartStepFilter: KotlinMethodFilter): KotlinStepAction {
|
||||
return StepOverInlineCommand(smartStepFilter, StepRequest.STEP_LINE)
|
||||
}
|
||||
|
||||
private val debuggerContext: DebuggerContextImpl get() = debuggerProcess.debuggerContext
|
||||
private val suspendManager: SuspendManager get() = debuggerProcess.suspendManager
|
||||
private val project: Project get() = debuggerProcess.project
|
||||
private val session: DebuggerSession get() = debuggerProcess.session
|
||||
|
||||
// TODO: ask for better API
|
||||
private val debugProcessDispatcher: EventDispatcher<DebugProcessListener>
|
||||
// Should be safe to use reflection as field is protected and not obfuscated
|
||||
get() = getFromField("myDebugProcessDispatcher")
|
||||
|
||||
// TODO: ask for better API
|
||||
private val threadBlockedMonitor: ThreadBlockedMonitor
|
||||
// FIXME: obfuscated in ULTIMATE. Absent in old AS
|
||||
get() = getFromField("myThreadBlockedMonitor")
|
||||
|
||||
private fun showStatusText(message: String) {
|
||||
debuggerProcess.showStatusText(message)
|
||||
}
|
||||
|
||||
// TODO: ask for better API
|
||||
private fun doStep(
|
||||
suspendContext: SuspendContextImpl,
|
||||
stepThread: ThreadReferenceProxyImpl,
|
||||
size: Int, depth: Int, hint: RequestHint) {
|
||||
// Should be safe to use reflection as field is protected and not obfuscated
|
||||
val doStepMethod = DebugProcessImpl::class.java.getDeclaredMethod(
|
||||
"doStep",
|
||||
SuspendContextImpl::class.java, ThreadReferenceProxyImpl::class.java,
|
||||
Integer.TYPE, Integer.TYPE, RequestHint::class.java)
|
||||
|
||||
doStepMethod.isAccessible = true
|
||||
|
||||
doStepMethod.invoke(debuggerProcess, suspendContext, stepThread, size, depth, hint)
|
||||
}
|
||||
|
||||
private fun <T> getFromField(fieldName: String): T {
|
||||
val field = DebugProcessImpl::class.java.getDeclaredField(fieldName)
|
||||
field.isAccessible = true
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return field.get(debuggerProcess) as T
|
||||
}
|
||||
|
||||
private inner class StepOverInlineCommand(private val mySmartStepFilter: KotlinMethodFilter, private val myStepSize: Int) : KotlinStepAction() {
|
||||
private fun getContextThread(suspendContext: SuspendContextImpl): ThreadReferenceProxyImpl? {
|
||||
val contextThread = debuggerContext.threadProxy
|
||||
return contextThread ?: suspendContext.thread
|
||||
}
|
||||
|
||||
// See: ResumeCommand.applyThreadFilter()
|
||||
private fun applyThreadFilter(suspendContext: SuspendContextImpl, thread: ThreadReferenceProxyImpl) {
|
||||
if (suspendContext.suspendPolicy == EventRequest.SUSPEND_ALL) {
|
||||
// there could be explicit resume as a result of call to voteSuspend()
|
||||
// e.g. when breakpoint was considered invalid, in that case the filter will be applied _after_
|
||||
// resuming and all breakpoints in other threads will be ignored.
|
||||
// As resume() implicitly cleares the filter, the filter must be always applied _before_ any resume() action happens
|
||||
val breakpointManager = DebuggerManagerEx.getInstanceEx(project).breakpointManager
|
||||
breakpointManager.applyThreadFilter(debuggerProcess, thread.threadReference)
|
||||
}
|
||||
}
|
||||
|
||||
// See: StepCommand.resumeAction()
|
||||
private fun resumeAction(suspendContext: SuspendContextImpl, thread: ThreadReferenceProxyImpl) {
|
||||
if (suspendContext.suspendPolicy == EventRequest.SUSPEND_EVENT_THREAD || isResumeOnlyCurrentThread) {
|
||||
threadBlockedMonitor.startWatching(thread)
|
||||
}
|
||||
if (isResumeOnlyCurrentThread && suspendContext.suspendPolicy == EventRequest.SUSPEND_ALL) {
|
||||
suspendManager.resumeThread(suspendContext, thread)
|
||||
}
|
||||
else {
|
||||
suspendManager.resume(suspendContext)
|
||||
}
|
||||
}
|
||||
|
||||
// See: StepIntoCommand.contextAction()
|
||||
override fun contextAction(suspendContext: SuspendContextImpl) {
|
||||
showStatusText("Stepping over inline")
|
||||
val stepThread = getContextThread(suspendContext)
|
||||
|
||||
if (stepThread == null) {
|
||||
// TODO: Intellij code doesn't bother to check thread for null, so probably it's not-null actually
|
||||
debuggerProcess.createStepOverCommand(suspendContext, true).contextAction(suspendContext)
|
||||
return
|
||||
}
|
||||
|
||||
val hint = KotlinStepOverInlinedLinesHint(stepThread, suspendContext, mySmartStepFilter)
|
||||
hint.isResetIgnoreFilters = !session.shouldIgnoreSteppingFilters()
|
||||
|
||||
try {
|
||||
session.setIgnoreStepFiltersFlag(stepThread.frameCount())
|
||||
}
|
||||
catch (e: EvaluateException) {
|
||||
LOG.info(e)
|
||||
}
|
||||
|
||||
hint.isIgnoreFilters = true
|
||||
applyThreadFilter(suspendContext, stepThread)
|
||||
|
||||
doStep(suspendContext, stepThread, myStepSize, StepRequest.STEP_OVER, hint)
|
||||
|
||||
showStatusText("Process resumed")
|
||||
resumeAction(suspendContext, stepThread)
|
||||
debugProcessDispatcher.multicaster.resumed(suspendContext)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(KotlinStepActionFactory::class.java)
|
||||
|
||||
private val isResumeOnlyCurrentThread: Boolean
|
||||
get() = DebuggerSettings.getInstance().RESUME_ONLY_CURRENT_THREAD
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger.stepping
|
||||
|
||||
import com.intellij.debugger.SourcePosition
|
||||
import com.intellij.debugger.engine.*
|
||||
import com.intellij.debugger.engine.evaluation.EvaluateException
|
||||
import com.intellij.debugger.engine.jdi.StackFrameProxy
|
||||
import com.intellij.debugger.jdi.ThreadReferenceProxyImpl
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.Computable
|
||||
import com.sun.jdi.VMDisconnectedException
|
||||
import com.sun.jdi.request.StepRequest
|
||||
|
||||
// Originally copied from RequestHint
|
||||
class KotlinStepOverInlinedLinesHint(
|
||||
stepThread: ThreadReferenceProxyImpl,
|
||||
suspendContext: SuspendContextImpl,
|
||||
methodFilter: KotlinMethodFilter) : RequestHint(stepThread, suspendContext, methodFilter) {
|
||||
|
||||
private val LOG = Logger.getInstance(KotlinStepOverInlinedLinesHint::class.java)
|
||||
|
||||
private var mySteppedOut = false
|
||||
|
||||
private var myFrameCount: Int
|
||||
private var myPosition: SourcePosition?
|
||||
|
||||
// TODO: Copied from RequestHint constructor. But can't reused code because of private fields.
|
||||
init {
|
||||
var frameCount = 0
|
||||
var position: SourcePosition? = null
|
||||
try {
|
||||
frameCount = stepThread.frameCount()
|
||||
|
||||
position = ApplicationManager.getApplication().runReadAction(Computable<com.intellij.debugger.SourcePosition> {
|
||||
ContextUtil.getSourcePosition(object : StackFrameContext {
|
||||
override fun getFrameProxy(): StackFrameProxy? {
|
||||
try {
|
||||
return stepThread.frame(0)
|
||||
}
|
||||
catch (e: EvaluateException) {
|
||||
LOG.debug(e)
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun getDebugProcess(): DebugProcess {
|
||||
return suspendContext.debugProcess
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.info(e)
|
||||
}
|
||||
finally {
|
||||
myFrameCount = frameCount
|
||||
myPosition = position
|
||||
}
|
||||
}
|
||||
|
||||
private val filter = methodFilter
|
||||
|
||||
override fun getDepth(): Int = StepRequest.STEP_OVER
|
||||
|
||||
// TODO: Copy of RequestHint.isTheSameFrame()
|
||||
private fun isTheSameFrame(context: SuspendContextImpl): Boolean {
|
||||
if (mySteppedOut) return false
|
||||
|
||||
val contextThread = context.thread
|
||||
if (contextThread != null) {
|
||||
try {
|
||||
val currentDepth = contextThread.frameCount()
|
||||
if (currentDepth < myFrameCount) {
|
||||
mySteppedOut = true
|
||||
}
|
||||
return currentDepth == myFrameCount
|
||||
}
|
||||
catch (ignored: EvaluateException) {
|
||||
}
|
||||
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun getNextStepDepth(context: SuspendContextImpl): Int {
|
||||
try {
|
||||
val frameProxy = context.frameProxy
|
||||
if (frameProxy != null) {
|
||||
if (isTheSameFrame(context)) {
|
||||
if (filter.locationMatches(context, frameProxy.location())) {
|
||||
return STOP
|
||||
}
|
||||
else {
|
||||
return StepRequest.STEP_OVER
|
||||
}
|
||||
}
|
||||
|
||||
if (mySteppedOut) {
|
||||
return STOP
|
||||
}
|
||||
|
||||
return StepRequest.STEP_OUT
|
||||
}
|
||||
}
|
||||
catch (ignored: VMDisconnectedException) {
|
||||
}
|
||||
catch (e: EvaluateException) {
|
||||
LOG.error(e)
|
||||
}
|
||||
|
||||
return STOP
|
||||
}
|
||||
}
|
||||
+163
-165
@@ -19,15 +19,21 @@ package org.jetbrains.kotlin.idea.debugger.stepping
|
||||
import com.intellij.debugger.NoDataException
|
||||
import com.intellij.debugger.SourcePosition
|
||||
import com.intellij.debugger.engine.DebugProcessImpl
|
||||
import com.intellij.debugger.engine.MethodFilter
|
||||
import com.intellij.debugger.engine.SuspendContextImpl
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl
|
||||
import com.intellij.debugger.impl.JvmSteppingCommandProvider
|
||||
import com.intellij.debugger.jdi.StackFrameProxyImpl
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.xdebugger.impl.XSourcePositionImpl
|
||||
import com.sun.jdi.AbsentInformationException
|
||||
import com.sun.jdi.LocalVariable
|
||||
import com.sun.jdi.Location
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.codegen.inline.KOTLIN_STRATA_NAME
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
@@ -38,12 +44,14 @@ import org.jetbrains.kotlin.idea.refactoring.getLineEndOffset
|
||||
import org.jetbrains.kotlin.idea.refactoring.getLineNumber
|
||||
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCallImpl
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
@@ -102,7 +110,23 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
||||
}
|
||||
|
||||
private fun isSpecialStepOverNeeded(kotlinSourcePosition: KotlinSourcePosition): Boolean {
|
||||
return getElementsToSkip(kotlinSourcePosition.function, kotlinSourcePosition.sourcePosition) != null
|
||||
val sourcePosition = kotlinSourcePosition.sourcePosition
|
||||
|
||||
val hasInlineCallsOnLine = getInlineFunctionCallsIfAny(sourcePosition).isNotEmpty()
|
||||
if (hasInlineCallsOnLine) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Step over calls to lambda arguments in inline function while execution is already in that function
|
||||
val containingFunctionDescriptor = kotlinSourcePosition.function.resolveToDescriptor()
|
||||
if (InlineUtil.isInline(containingFunctionDescriptor)) {
|
||||
val inlineArgumentsCallsIfAny = getInlineArgumentsCallsIfAny(sourcePosition, containingFunctionDescriptor)
|
||||
if (inlineArgumentsCallsIfAny != null && inlineArgumentsCallsIfAny.isNotEmpty()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
@@ -132,123 +156,15 @@ class KotlinSteppingCommandProvider : JvmSteppingCommandProvider() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getElementsToSkip(containingFunction: KtNamedFunction, sourcePosition: SourcePosition): List<KtFunction>? {
|
||||
val inlineFunctionCalls = getInlineFunctionCallsIfAny(sourcePosition)
|
||||
if (!inlineFunctionCalls.isEmpty()) {
|
||||
val inlineArguments = getInlineArgumentsIfAny(inlineFunctionCalls)
|
||||
if (inlineArguments.isNotEmpty() && inlineArguments.all { !it.shouldNotUseStepOver(sourcePosition.elementAt) }) {
|
||||
return inlineArguments
|
||||
}
|
||||
|
||||
if (inlineArguments.isEmpty() && inlineFunctionCalls.all { !it.shouldNotUseStepOver(sourcePosition.elementAt) }) {
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
// Step over calls to lambda arguments in inline function while execution is already in that function
|
||||
if (InlineUtil.isInline(containingFunction.resolveToDescriptor())) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun PsiElement.getAdditionalElementsToSkip(): List<PsiElement> {
|
||||
val result = arrayListOf<PsiElement>()
|
||||
val ifParent = getParentOfType<KtIfExpression>(false)
|
||||
if (ifParent != null) {
|
||||
if (ifParent.then.contains(this)) {
|
||||
ifParent.elseKeyword?.let { result.add(it) }
|
||||
ifParent.`else`?.let { result.add(it) }
|
||||
}
|
||||
}
|
||||
val tryParent = getParentOfType<KtTryExpression>(false)
|
||||
if (tryParent != null) {
|
||||
val catchClause = getParentOfType<KtCatchClause>(false)
|
||||
if (catchClause != null) {
|
||||
result.addAll(tryParent.catchClauses.filter { it != catchClause })
|
||||
}
|
||||
}
|
||||
|
||||
val whenEntry = getParentOfType<KtWhenEntry>(false)
|
||||
if (whenEntry != null) {
|
||||
if (whenEntry.expression.contains(this)) {
|
||||
val whenParent = whenEntry.getParentOfType<KtWhenExpression>(false)
|
||||
if (whenParent != null) {
|
||||
result.addAll(whenParent.entries.filter { it != whenEntry })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun PsiElement.shouldNotUseStepOver(elementAt: PsiElement): Boolean {
|
||||
val ifParent = getParentOfType<KtIfExpression>(false)
|
||||
if (ifParent != null) {
|
||||
// if (inlineFunCall()) {...}
|
||||
if (ifParent.condition.contains(this)) {
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
<caret>if (...) inlineFunCall()
|
||||
else inlineFunCall()
|
||||
*/
|
||||
val ifParentElementAt = elementAt.getParentOfType<KtIfExpression>(false)
|
||||
if (ifParentElementAt == null) {
|
||||
if (ifParent.then.contains(this)) {
|
||||
return true
|
||||
}
|
||||
if (ifParent.`else`.contains(this)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val tryParent = getParentOfType<KtTryExpression>(false)
|
||||
if (tryParent != null) {
|
||||
/* try { inlineFunCall() }
|
||||
catch()...
|
||||
*/
|
||||
if (tryParent.tryBlock.contains(this)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
val whenEntry = getParentOfType<KtWhenEntry>(false)
|
||||
if (whenEntry != null) {
|
||||
// <caret>inlineFunCall -> ...
|
||||
if (whenEntry.conditions.any { it.contains(this) } ) {
|
||||
return true
|
||||
}
|
||||
|
||||
// <caret>1 == 2 -> inlineFunCall()
|
||||
if (whenEntry.expression.contains(this)) {
|
||||
val parentEntryElementAt = elementAt.getParentOfType<KtWhenEntry>(false) ?: return true
|
||||
return parentEntryElementAt == whenEntry &&
|
||||
whenEntry.conditions.any { it.contains(elementAt) }
|
||||
}
|
||||
}
|
||||
|
||||
val whileParent = getParentOfType<KtWhileExpression>(false)
|
||||
if (whileParent != null) {
|
||||
// while (inlineFunCall()) {...}
|
||||
if (whileParent.condition.contains(this)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// last statement in while
|
||||
return (whileParent.body as? KtBlockExpression)?.statements?.lastOrNull()?.getLineNumber() == elementAt.getLineNumber()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun PsiElement?.contains(element: PsiElement): Boolean {
|
||||
return this?.textRange?.contains(element.textRange) ?: false
|
||||
}
|
||||
|
||||
private fun getInlineCallFunctionArgumentsIfAny(sourcePosition: SourcePosition): List<KtFunction> {
|
||||
val inlineFunctionCalls = getInlineFunctionCallsIfAny(sourcePosition)
|
||||
return getInlineArgumentsIfAny(inlineFunctionCalls)
|
||||
}
|
||||
|
||||
private fun getInlineFunctionsIfAny(file: KtFile, offset: Int): List<KtNamedFunction> {
|
||||
val elementAt = file.findElementAt(offset) ?: return emptyList()
|
||||
val containingFunction = elementAt.getParentOfType<KtNamedFunction>(false) ?: return emptyList()
|
||||
@@ -269,14 +185,46 @@ private fun getInlineFunctionsIfAny(file: KtFile, offset: Int): List<KtNamedFunc
|
||||
private fun getInlineArgumentsIfAny(inlineFunctionCalls: List<KtCallExpression>): List<KtFunction> {
|
||||
return inlineFunctionCalls.flatMap {
|
||||
it.valueArguments
|
||||
.map { getArgumentExpression(it) }
|
||||
.map { getArgumentExpression(it) }
|
||||
.filterIsInstance<KtFunction>()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getArgumentExpression(it: ValueArgument) = (it.getArgumentExpression() as? KtLambdaExpression)?.functionLiteral ?: it.getArgumentExpression()
|
||||
|
||||
private fun getInlineArgumentsCallsIfAny(sourcePosition: SourcePosition, declarationDescriptor: DeclarationDescriptor): List<KtCallExpression>? {
|
||||
if (declarationDescriptor !is CallableDescriptor) return null
|
||||
|
||||
val valueParameters = declarationDescriptor.valueParameters.filter { it.type.isFunctionType }.toSet()
|
||||
|
||||
if (valueParameters.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
fun isCallOfArgument(ktCallExpression: KtCallExpression): Boolean {
|
||||
val context = ktCallExpression.analyze(BodyResolveMode.PARTIAL)
|
||||
val resolvedCall = ktCallExpression.getResolvedCall(context) ?: return false
|
||||
|
||||
if (resolvedCall !is VariableAsFunctionResolvedCallImpl) return false
|
||||
val candidateDescriptor = resolvedCall.variableCall.candidateDescriptor
|
||||
|
||||
return candidateDescriptor in valueParameters
|
||||
}
|
||||
|
||||
return findCallsOnPosition(sourcePosition, ::isCallOfArgument)
|
||||
}
|
||||
|
||||
private fun getInlineFunctionCallsIfAny(sourcePosition: SourcePosition): List<KtCallExpression> {
|
||||
fun isInlineCall(expr: KtCallExpression): Boolean {
|
||||
val context = expr.analyze(BodyResolveMode.PARTIAL)
|
||||
val resolvedCall = expr.getResolvedCall(context) ?: return false
|
||||
return InlineUtil.isInline(resolvedCall.resultingDescriptor)
|
||||
}
|
||||
|
||||
return findCallsOnPosition(sourcePosition, ::isInlineCall)
|
||||
}
|
||||
|
||||
private fun findCallsOnPosition(sourcePosition: SourcePosition, filter: (KtCallExpression) -> Boolean): List<KtCallExpression> {
|
||||
val file = sourcePosition.file as? KtFile ?: return emptyList()
|
||||
val lineNumber = sourcePosition.line
|
||||
var elementAt = sourcePosition.elementAt
|
||||
@@ -298,22 +246,16 @@ private fun getInlineFunctionCallsIfAny(sourcePosition: SourcePosition): List<Kt
|
||||
val start = topMostElement.startOffset
|
||||
val end = topMostElement.endOffset
|
||||
|
||||
fun isInlineCall(expr: KtExpression): Boolean {
|
||||
val context = expr.analyze(BodyResolveMode.PARTIAL)
|
||||
val resolvedCall = expr.getResolvedCall(context) ?: return false
|
||||
return InlineUtil.isInline(resolvedCall.resultingDescriptor)
|
||||
}
|
||||
|
||||
val allInlineFunctionCalls = CodeInsightUtils.
|
||||
val allFilteredCalls = CodeInsightUtils.
|
||||
findElementsOfClassInRange(file, start, end, KtExpression::class.java)
|
||||
.map { KtPsiUtil.getParentCallIfPresent(it as KtExpression) }
|
||||
.filterIsInstance<KtCallExpression>()
|
||||
.filter { isInlineCall(it) }
|
||||
.filter { filter(it) }
|
||||
.toSet()
|
||||
|
||||
// It is necessary to check range because of multiline assign
|
||||
var linesRange = lineNumber..lineNumber
|
||||
return allInlineFunctionCalls.filter {
|
||||
return allFilteredCalls.filter {
|
||||
val shouldInclude = it.getLineNumber() in linesRange
|
||||
if (shouldInclude) {
|
||||
linesRange = Math.min(linesRange.start, it.getLineNumber())..Math.max(linesRange.endInclusive, it.getLineNumber(false))
|
||||
@@ -322,10 +264,16 @@ private fun getInlineFunctionCallsIfAny(sourcePosition: SourcePosition): List<Kt
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Action(val position: XSourcePositionImpl?) {
|
||||
class STEP_OVER: Action(null)
|
||||
class STEP_OUT: Action(null)
|
||||
class RUN_TO_CURSOR(position: XSourcePositionImpl): Action(position)
|
||||
|
||||
sealed class Action(val position: XSourcePositionImpl? = null,
|
||||
val lineNumber: Int? = null,
|
||||
val stepOverLines: Set<Int>? = null,
|
||||
val inlineRangeVariables: List<LocalVariable>? = null) {
|
||||
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)
|
||||
|
||||
fun apply(debugProcess: DebugProcessImpl,
|
||||
suspendContext: SuspendContextImpl,
|
||||
@@ -338,30 +286,63 @@ sealed class Action(val position: XSourcePositionImpl?) {
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface KotlinMethodFilter: MethodFilter {
|
||||
fun locationMatches(context: SuspendContextImpl, location: Location): Boolean
|
||||
}
|
||||
|
||||
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 currentLine = location.lineNumber()
|
||||
|
||||
if (!(stepOverLines.contains(location.lineNumber()))) {
|
||||
return currentLine != fromLine
|
||||
}
|
||||
|
||||
val visibleInlineVariables = getInlineRangeLocalVariables(frameProxy)
|
||||
|
||||
// Our ranges check missed exit from inline function. This is when breakpoint was in last statement of inline functions.
|
||||
// This can be observed by inline local range-variables. Absence of any means step out was done.
|
||||
return inlineFunRangeVariables.any { !visibleInlineVariables.contains(it) }
|
||||
}
|
||||
|
||||
override fun locationMatches(process: DebugProcessImpl, location: Location): Boolean {
|
||||
throw IllegalStateException() // Should not be called from Kotlin hint
|
||||
}
|
||||
|
||||
override fun getCallingExpressionLines(): Range<Int>? {
|
||||
throw IllegalStateException() // Should not be called from Kotlin hint
|
||||
}
|
||||
}
|
||||
|
||||
fun getStepOverAction(
|
||||
location: Location,
|
||||
kotlinSourcePosition: KotlinSteppingCommandProvider.KotlinSourcePosition
|
||||
kotlinSourcePosition: KotlinSteppingCommandProvider.KotlinSourcePosition,
|
||||
frameProxy: StackFrameProxyImpl
|
||||
): Action {
|
||||
val (inlineArgumentsToSkip, additionalElementsToSkip) = runReadAction {
|
||||
val inlineArgumentsToSkip = getElementsToSkip(kotlinSourcePosition.function, kotlinSourcePosition.sourcePosition)!!
|
||||
val additionalElementsToSkip = kotlinSourcePosition.sourcePosition.elementAt.getAdditionalElementsToSkip()
|
||||
|
||||
Pair(inlineArgumentsToSkip, additionalElementsToSkip)
|
||||
val inlineArgumentsToSkip = runReadAction {
|
||||
getInlineCallFunctionArgumentsIfAny(kotlinSourcePosition.sourcePosition)
|
||||
}
|
||||
|
||||
return getStepOverAction(location, kotlinSourcePosition.file, kotlinSourcePosition.linesRange, inlineArgumentsToSkip, additionalElementsToSkip)
|
||||
return getStepOverAction(location, kotlinSourcePosition.file, kotlinSourcePosition.linesRange,
|
||||
inlineArgumentsToSkip, frameProxy)
|
||||
}
|
||||
|
||||
fun getStepOverAction(
|
||||
location: Location,
|
||||
file: KtFile,
|
||||
range: IntRange,
|
||||
inlinedArguments: List<KtElement>,
|
||||
elementsToSkip: List<PsiElement>
|
||||
inlineFunctionArguments: List<KtElement>,
|
||||
frameProxy: StackFrameProxyImpl
|
||||
): Action {
|
||||
val computedReferenceType = location.declaringType() ?: return Action.STEP_OVER()
|
||||
|
||||
@@ -389,38 +370,46 @@ fun getStepOverAction(
|
||||
return previousSuitableLocation != null && previousSuitableLocation.lineNumber() > location.lineNumber()
|
||||
}
|
||||
|
||||
if (isBackEdgeLocation()) {
|
||||
return Action.STEP_OVER()
|
||||
val patchedLocation = if (isBackEdgeLocation()) {
|
||||
// Pretend we had already did a backing step
|
||||
computedReferenceType.allLineLocations()
|
||||
.filter(::isLocationSuitable)
|
||||
.first { it.lineNumber() == location.lineNumber() }
|
||||
}
|
||||
else {
|
||||
location
|
||||
}
|
||||
|
||||
// Predict step over location by assuming that it will be next valid location in the range of current function.
|
||||
// This prediction doesn't work in branching position when there're several valid location after current position.
|
||||
val locations = computedReferenceType.allLineLocations()
|
||||
.dropWhile { it != location }
|
||||
val lambdaArgumentRanges = runReadAction {
|
||||
inlineFunctionArguments.filterIsInstance<KtElement>().map {
|
||||
val startLineNumber = it.getLineNumber(true) + 1
|
||||
val endLineNumber = it.getLineNumber(false) + 1
|
||||
|
||||
startLineNumber..endLineNumber
|
||||
}
|
||||
}
|
||||
|
||||
val inlineRangeVariables = getInlineRangeLocalVariables(frameProxy)
|
||||
|
||||
// Try to find the range of inlined lines:
|
||||
// - 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)
|
||||
.filter(::isLocationSuitable)
|
||||
.dropWhile { it.lineNumber() == location.lineNumber() }
|
||||
.dropWhile { it.lineNumber() == patchedLocation.lineNumber() }
|
||||
.takeWhile { locationAtLine ->
|
||||
!isLocationSuitable(locationAtLine) || lambdaArgumentRanges.any { locationAtLine.lineNumber() in it }
|
||||
}
|
||||
.dropWhile { it.lineNumber() == patchedLocation.lineNumber() }
|
||||
|
||||
for (locationAtLine in locations) {
|
||||
val xPosition = runReadAction l@ {
|
||||
val lineNumber = locationAtLine.lineNumber()
|
||||
val lineStartOffset = file.getLineStartOffset(lineNumber - 1) ?: return@l null
|
||||
if (inlinedArguments.any { it.textRange.contains(lineStartOffset) }) return@l null
|
||||
if (elementsToSkip.any { it.textRange.contains(lineStartOffset) }) return@l null
|
||||
|
||||
if (locationAtLine.lineNumber() == location.lineNumber()) return@l null
|
||||
|
||||
val elementAt = file.findElementAt(lineStartOffset) ?: return@l null
|
||||
XSourcePositionImpl.createByElement(elementAt)
|
||||
}
|
||||
|
||||
if (xPosition != null) {
|
||||
return Action.RUN_TO_CURSOR(xPosition)
|
||||
}
|
||||
}
|
||||
|
||||
if (locations.isNotEmpty()) {
|
||||
return Action.STEP_OUT()
|
||||
if (!probablyInlinedLocations.isEmpty()) {
|
||||
return Action.STEP_OVER_INLINED(patchedLocation.lineNumber(), probablyInlinedLocations.map { it.lineNumber() }.toSet(), inlineRangeVariables)
|
||||
}
|
||||
|
||||
return Action.STEP_OVER()
|
||||
@@ -507,6 +496,15 @@ private fun SuspendContextImpl.getNextPositionWithFilter(
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getInlineRangeLocalVariables(stackFrame: StackFrameProxyImpl): List<LocalVariable> {
|
||||
return stackFrame.visibleVariables()
|
||||
.filter {
|
||||
val name = it.name()
|
||||
name.startsWith(JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION)
|
||||
}
|
||||
.map { it.variable }
|
||||
}
|
||||
|
||||
private fun getInlineArgumentIfAny(elementAt: PsiElement?): KtFunctionLiteral? {
|
||||
val functionLiteralExpression = elementAt?.getParentOfType<KtLambdaExpression>(false) ?: return null
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at inlineInIfFalse.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! inlineInIfFalse.InlineInIfFalseKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
inlineInIfFalse.kt:6
|
||||
inlineInIfFalse.kt:9
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at inlineInIfTrue.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! inlineInIfTrue.InlineInIfTrueKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
inlineInIfTrue.kt:6
|
||||
inlineInIfTrue.kt:7
|
||||
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 soInlineAnonymousFunctionArgument.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! soInlineAnonymousFunctionArgument.SoInlineAnonymousFunctionArgumentKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
soInlineAnonymousFunctionArgument.kt:5
|
||||
soInlineAnonymousFunctionArgument.kt:7
|
||||
soInlineAnonymousFunctionArgument.kt:11
|
||||
soInlineAnonymousFunctionArgument.kt:12
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at soInlineCallInLastStatementInInline.kt:9
|
||||
!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! soInlineCallInLastStatementInInline.SoInlineCallInLastStatementInInlineKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
soInlineCallInLastStatementInInline.kt:9
|
||||
soInlineCallInLastStatementInInline.kt:10
|
||||
soInlineCallInLastStatementInInline.kt:5
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at soInlineCallInLastStatementInInlineInInline.kt:15
|
||||
!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! soInlineCallInLastStatementInInlineInInline.SoInlineCallInLastStatementInInlineInInlineKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
soInlineCallInLastStatementInInlineInInline.kt:15
|
||||
soInlineCallInLastStatementInInlineInInline.kt:5
|
||||
soInlineCallInLastStatementInInlineInInline.kt:6
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn.kt:11 lambdaOrdinal = -1
|
||||
!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! soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn.SoInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwnKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn.kt:11
|
||||
soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn.kt:7
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at soInlineFunWithLastStatementMultilineArgumentCall.kt:14
|
||||
!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! soInlineFunWithLastStatementMultilineArgumentCall.SoInlineFunWithLastStatementMultilineArgumentCallKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
soInlineFunWithLastStatementMultilineArgumentCall.kt:14
|
||||
soInlineFunWithLastStatementMultilineArgumentCall.kt:9
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
LineBreakpoint created at soInlineFunWithLastStatementOneLineArgumentCall.kt:11
|
||||
!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! soInlineFunWithLastStatementOneLineArgumentCall.SoInlineFunWithLastStatementOneLineArgumentCallKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
soInlineFunWithLastStatementOneLineArgumentCall.kt:11
|
||||
soInlineFunWithLastStatementOneLineArgumentCall.kt:6
|
||||
soInlineFunWithLastStatementOneLineArgumentCall.kt:7
|
||||
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 soInlineIfConditionLambdaFalse.kt:11
|
||||
!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! soInlineIfConditionLambdaFalse.SoInlineIfConditionLambdaFalseKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
soInlineIfConditionLambdaFalse.kt:11
|
||||
soInlineIfConditionLambdaFalse.kt:15
|
||||
soInlineIfConditionLambdaFalse.kt:18
|
||||
soInlineIfConditionLambdaFalse.kt:7
|
||||
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 soInlineIfConditionLambdaTrue.kt:11
|
||||
!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! soInlineIfConditionLambdaTrue.SoInlineIfConditionLambdaTrueKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
soInlineIfConditionLambdaTrue.kt:11
|
||||
soInlineIfConditionLambdaTrue.kt:12
|
||||
soInlineIfConditionLambdaTrue.kt:18
|
||||
soInlineIfConditionLambdaTrue.kt:7
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,12 @@
|
||||
LineBreakpoint created at soInlineWhileCondition.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! soInlineWhileCondition.SoInlineWhileConditionKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
soInlineWhileCondition.kt:5
|
||||
soInlineWhileCondition.kt:7
|
||||
soInlineWhileCondition.kt:8
|
||||
soInlineWhileCondition.kt:7
|
||||
soInlineWhileCondition.kt:12
|
||||
soInlineWhileCondition.kt:15
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at soReifiedInlineIfConditionFalse.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! soReifiedInlineIfConditionFalse.SoReifiedInlineIfConditionFalseKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
soReifiedInlineIfConditionFalse.kt:6
|
||||
soReifiedInlineIfConditionFalse.kt:9
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at soSimpleInlineIfCondition.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! soSimpleInlineIfCondition.SoSimpleInlineIfConditionKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
soSimpleInlineIfCondition.kt:5
|
||||
soSimpleInlineIfCondition.kt:8
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,8 @@
|
||||
LineBreakpoint created at stepOverDeclarationInInlineFun.kt:9
|
||||
!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! stepOverDeclarationInInlineFun.StepOverDeclarationInInlineFunKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
stepOverDeclarationInInlineFun.kt:9
|
||||
stepOverDeclarationInInlineFun.kt:10
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -9,23 +9,14 @@ stepOverIfWithInline.kt:15
|
||||
stepOverIfWithInline.kt:18
|
||||
stepOverIfWithInline.kt:15
|
||||
stepOverIfWithInline.kt:21
|
||||
stepOverIfWithInline.kt:46
|
||||
stepOverIfWithInline.kt:21
|
||||
stepOverIfWithInline.kt:24
|
||||
stepOverIfWithInline.kt:25
|
||||
stepOverIfWithInline.kt:24
|
||||
stepOverIfWithInline.kt:28
|
||||
stepOverIfWithInline.kt:46
|
||||
stepOverIfWithInline.kt:28
|
||||
stepOverIfWithInline.kt:32
|
||||
stepOverIfWithInline.kt:46
|
||||
stepOverIfWithInline.kt:32
|
||||
stepOverIfWithInline.kt:36
|
||||
stepOverIfWithInline.kt:32
|
||||
stepOverIfWithInline.kt:40
|
||||
stepOverIfWithInline.kt:53
|
||||
stepOverIfWithInline.kt:54
|
||||
stepOverIfWithInline.kt:43
|
||||
stepOverIfWithInline.kt:38
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
LineBreakpoint created at stepOverInlinedLambda.kt:6
|
||||
LineBreakpoint created at stepOverInlinedLambda.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! stepOverInlinedLambda.StepOverInlinedLambdaKt
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
stepOverInlinedLambda.kt:5
|
||||
stepOverInlinedLambda.kt:6
|
||||
stepOverInlinedLambda.kt:7
|
||||
stepOverInlinedLambda.kt:10
|
||||
@@ -11,8 +12,7 @@ stepOverInlinedLambda.kt:19
|
||||
stepOverInlinedLambda.kt:20
|
||||
stepOverInlinedLambda.kt:23
|
||||
stepOverInlinedLambda.kt:29
|
||||
stepOverInlinedLambda.kt:31
|
||||
stepOverInlinedLambda.kt:32
|
||||
stepOverInlinedLambda.kt:30
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -4,6 +4,7 @@ Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socke
|
||||
stepOverInsideInlineFun.kt:11
|
||||
stepOverInsideInlineFun.kt:12
|
||||
stepOverInsideInlineFun.kt:13
|
||||
stepOverInsideInlineFun.kt:14
|
||||
stepOverInsideInlineFun.kt:7
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ stepOverNonLocalReturnInLambda.kt:35
|
||||
stepOverNonLocalReturnInLambda.kt:7
|
||||
stepOverNonLocalReturnInLambda.kt:52
|
||||
stepOverNonLocalReturnInLambda.kt:53
|
||||
stepOverNonLocalReturnInLambda.kt:10
|
||||
stepOverNonLocalReturnInLambda.kt:9
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -4,21 +4,15 @@ Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socke
|
||||
stepOverTryCatchWithInline.kt:14
|
||||
stepOverTryCatchWithInline.kt:16
|
||||
stepOverTryCatchWithInline.kt:17
|
||||
stepOverTryCatchWithInline.kt:48
|
||||
stepOverTryCatchWithInline.kt:17
|
||||
stepOverTryCatchWithInline.kt:24
|
||||
stepOverTryCatchWithInline.kt:25
|
||||
stepOverTryCatchWithInline.kt:27
|
||||
stepOverTryCatchWithInline.kt:28
|
||||
stepOverTryCatchWithInline.kt:35
|
||||
stepOverTryCatchWithInline.kt:36
|
||||
stepOverTryCatchWithInline.kt:48
|
||||
stepOverTryCatchWithInline.kt:36
|
||||
stepOverTryCatchWithInline.kt:38
|
||||
stepOverTryCatchWithInline.kt:39
|
||||
stepOverTryCatchWithInline.kt:43
|
||||
stepOverTryCatchWithInline.kt:48
|
||||
stepOverTryCatchWithInline.kt:43
|
||||
stepOverTryCatchWithInline.kt:7
|
||||
stepOverTryCatchWithInline.kt:8
|
||||
stepOverTryCatchWithInline.kt:10
|
||||
|
||||
@@ -3,8 +3,6 @@ LineBreakpoint created at stepOverWhenInReturn.kt:10
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
stepOverWhenInReturn.kt:10
|
||||
stepOverWhenInReturn.kt:11
|
||||
stepOverWhenInReturn.kt:17
|
||||
stepOverWhenInReturn.kt:11
|
||||
stepOverWhenInReturn.kt:10
|
||||
stepOverWhenInReturn.kt:4
|
||||
stepOverWhenInReturn.kt:5
|
||||
|
||||
@@ -4,43 +4,29 @@ Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socke
|
||||
stepOverWhenWithInline.kt:5
|
||||
stepOverWhenWithInline.kt:8
|
||||
stepOverWhenWithInline.kt:9
|
||||
stepOverWhenWithInline.kt:83
|
||||
stepOverWhenWithInline.kt:9
|
||||
stepOverWhenWithInline.kt:7
|
||||
stepOverWhenWithInline.kt:14
|
||||
stepOverWhenWithInline.kt:17
|
||||
stepOverWhenWithInline.kt:18
|
||||
stepOverWhenWithInline.kt:13
|
||||
stepOverWhenWithInline.kt:26
|
||||
stepOverWhenWithInline.kt:83
|
||||
stepOverWhenWithInline.kt:26
|
||||
stepOverWhenWithInline.kt:27
|
||||
stepOverWhenWithInline.kt:83
|
||||
stepOverWhenWithInline.kt:27
|
||||
stepOverWhenWithInline.kt:25
|
||||
stepOverWhenWithInline.kt:32
|
||||
stepOverWhenWithInline.kt:34
|
||||
stepOverWhenWithInline.kt:83
|
||||
stepOverWhenWithInline.kt:34
|
||||
stepOverWhenWithInline.kt:32
|
||||
stepOverWhenWithInline.kt:38
|
||||
stepOverWhenWithInline.kt:43
|
||||
stepOverWhenWithInline.kt:38
|
||||
stepOverWhenWithInline.kt:51
|
||||
stepOverWhenWithInline.kt:52
|
||||
stepOverWhenWithInline.kt:83
|
||||
stepOverWhenWithInline.kt:52
|
||||
stepOverWhenWithInline.kt:51
|
||||
stepOverWhenWithInline.kt:58
|
||||
stepOverWhenWithInline.kt:83
|
||||
stepOverWhenWithInline.kt:58
|
||||
stepOverWhenWithInline.kt:57
|
||||
stepOverWhenWithInline.kt:64
|
||||
stepOverWhenWithInline.kt:65
|
||||
stepOverWhenWithInline.kt:63
|
||||
stepOverWhenWithInline.kt:76
|
||||
stepOverWhenWithInline.kt:83
|
||||
stepOverWhenWithInline.kt:76
|
||||
stepOverWhenWithInline.kt:75
|
||||
stepOverWhenWithInline.kt:80
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
@@ -5,8 +5,6 @@ stepOverWhileWithInline.kt:5
|
||||
stepOverWhileWithInline.kt:7
|
||||
stepOverWhileWithInline.kt:8
|
||||
stepOverWhileWithInline.kt:9
|
||||
stepOverWhileWithInline.kt:41
|
||||
stepOverWhileWithInline.kt:9
|
||||
stepOverWhileWithInline.kt:7
|
||||
stepOverWhileWithInline.kt:13
|
||||
stepOverWhileWithInline.kt:14
|
||||
@@ -18,18 +16,7 @@ stepOverWhileWithInline.kt:21
|
||||
stepOverWhileWithInline.kt:24
|
||||
stepOverWhileWithInline.kt:25
|
||||
stepOverWhileWithInline.kt:26
|
||||
stepOverWhileWithInline.kt:28
|
||||
stepOverWhileWithInline.kt:30
|
||||
stepOverWhileWithInline.kt:41
|
||||
stepOverWhileWithInline.kt:30
|
||||
stepOverWhileWithInline.kt:31
|
||||
stepOverWhileWithInline.kt:30
|
||||
stepOverWhileWithInline.kt:41
|
||||
stepOverWhileWithInline.kt:30
|
||||
stepOverWhileWithInline.kt:35
|
||||
stepOverWhileWithInline.kt:41
|
||||
stepOverWhileWithInline.kt:35
|
||||
stepOverWhileWithInline.kt:38
|
||||
stepOverWhileWithInline.kt:27
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package inlineInIfFalse
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val bar = ""
|
||||
//Breakpoint!
|
||||
if (inlineCall { true }) {
|
||||
foo()
|
||||
}
|
||||
foo()
|
||||
}
|
||||
|
||||
fun foo() {}
|
||||
|
||||
inline fun inlineCall(predicate: (String?) -> Boolean): Boolean {
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package inlineInIfTrue
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val bar = ""
|
||||
//Breakpoint!
|
||||
if (inlineCall { true }) {
|
||||
foo()
|
||||
}
|
||||
}
|
||||
|
||||
fun foo() {}
|
||||
|
||||
inline fun inlineCall(predicate: (String?) -> Boolean): Boolean {
|
||||
return true
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package soInlineAnonymousFunctionArgument
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
//Breakpoint!
|
||||
val b = 1 // 1
|
||||
|
||||
foo( // 2
|
||||
fun (){ test(1) }
|
||||
)
|
||||
|
||||
foo(fun (){ test(1) }) // 3
|
||||
} // 4
|
||||
|
||||
inline fun foo(f: () -> Unit) {
|
||||
f()
|
||||
}
|
||||
|
||||
fun test(i: Int) = 1
|
||||
|
||||
// STEP_OVER: 6
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
package soInlineCallInLastStatementInInline
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
bar()
|
||||
}
|
||||
|
||||
inline fun bar() {
|
||||
//Breakpoint!
|
||||
val a = 1
|
||||
foo { 42 }
|
||||
}
|
||||
|
||||
inline fun foo(f: () -> Unit) {
|
||||
f()
|
||||
}
|
||||
|
||||
// STEP_OVER: 2
|
||||
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
package soInlineCallInLastStatementInInlineInInline
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
bar()
|
||||
val i = 45
|
||||
}
|
||||
|
||||
inline fun bar() {
|
||||
val a = 1
|
||||
foo { 42 }
|
||||
}
|
||||
|
||||
inline fun foo(f: () -> Unit) {
|
||||
//Breakpoint!
|
||||
f()
|
||||
}
|
||||
|
||||
// STEP_OVER: 4
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
bar {
|
||||
println("")
|
||||
}
|
||||
}
|
||||
|
||||
inline fun bar(f2: () -> Unit) {
|
||||
//Breakpoint! (lambdaOrdinal = -1)
|
||||
foo({ 42 },
|
||||
f2)
|
||||
}
|
||||
|
||||
inline fun foo(f1: () -> Unit, f2: () -> Unit) {
|
||||
f1()
|
||||
f2()
|
||||
}
|
||||
|
||||
// STEP_OVER 5
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package soInlineFunWithLastStatementMultilineArgumentCall
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
var k = 444
|
||||
bar {
|
||||
val b = 1
|
||||
}
|
||||
|
||||
k++
|
||||
}
|
||||
|
||||
inline fun bar(f: (Int) -> Unit) {
|
||||
//Breakpoint!
|
||||
f(1)
|
||||
}
|
||||
|
||||
// STEP_OVER: 1
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package soInlineFunWithLastStatementOneLineArgumentCall
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
var k = 444
|
||||
bar { val b = 1 }
|
||||
k++
|
||||
}
|
||||
|
||||
inline fun bar(f: (Int) -> Unit) {
|
||||
//Breakpoint!
|
||||
f(1)
|
||||
}
|
||||
|
||||
// STEP_OVER: 4
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package soInlineIfConditionLambdaFalse
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
bar {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
inline fun bar(f: (Int) -> Boolean) {
|
||||
//Breakpoint!
|
||||
if (f(42)) {
|
||||
foo()
|
||||
}
|
||||
else {
|
||||
foo()
|
||||
}
|
||||
|
||||
foo()
|
||||
}
|
||||
|
||||
fun foo() {}
|
||||
|
||||
// STEP_OVER: 4
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package soInlineIfConditionLambdaTrue
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
bar {
|
||||
true
|
||||
}
|
||||
} // 4
|
||||
|
||||
inline fun bar(f: (Int) -> Boolean) {
|
||||
//Breakpoint!
|
||||
if (f(42)) { // 1
|
||||
foo() // 2
|
||||
}
|
||||
else {
|
||||
foo()
|
||||
}
|
||||
|
||||
foo() // 3
|
||||
}
|
||||
|
||||
fun foo() {}
|
||||
|
||||
// STEP_OVER: 4
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package soInlineWhileCondition
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
//Breakpoint!
|
||||
var i = 1 // 1
|
||||
// inline in while condition (true)
|
||||
while (id { i < 2 }) { // 2 4
|
||||
i++ // 3
|
||||
}
|
||||
|
||||
// inline in while condition (false)
|
||||
while (id { false }) { // 5
|
||||
bar()
|
||||
}
|
||||
} // 6
|
||||
|
||||
inline fun id(f: () -> Boolean): Boolean {
|
||||
return f()
|
||||
}
|
||||
|
||||
fun bar() {}
|
||||
|
||||
// STEP_OVER: 6
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package soReifiedInlineIfConditionFalse
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
// Reified function call in if condition
|
||||
//Breakpoint!
|
||||
if (reified(11) != 11) { // 1
|
||||
val a = 22
|
||||
}
|
||||
} // 2
|
||||
|
||||
inline fun <reified T> reified(f: T): T {
|
||||
val a = 33
|
||||
return f
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package soSimpleInlineIfCondition
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
//Breakpoint!
|
||||
if (foo {
|
||||
test(2)
|
||||
}) {
|
||||
bar()
|
||||
}
|
||||
|
||||
bar()
|
||||
}
|
||||
|
||||
inline fun foo(f: () -> Boolean): Boolean = f()
|
||||
|
||||
fun test(i: Int): Boolean = true
|
||||
|
||||
fun bar() {}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package stepOverDeclarationInInlineFun
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
foo { 1 }
|
||||
}
|
||||
|
||||
inline fun foo(f: () -> Int): Int {
|
||||
//Breakpoint!
|
||||
val a = 15
|
||||
return f()
|
||||
}
|
||||
+13
-23
@@ -2,45 +2,40 @@ package stepOverIfWithInline
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
//Breakpoint!
|
||||
val prop = 1
|
||||
val prop = 1 // 1
|
||||
// False with braces
|
||||
val a = if (1 > 2) {
|
||||
val a = if (1 > 2) { // 2 4(?)
|
||||
foo { test(1) }
|
||||
}
|
||||
else {
|
||||
foo { test(1) }
|
||||
foo { test(1) } // 3
|
||||
}
|
||||
|
||||
// False without braces
|
||||
val b = if (1 > 2)
|
||||
val b = if (1 > 2) // 5 7(?)
|
||||
foo { test(1) }
|
||||
else
|
||||
foo { test(1) }
|
||||
foo { test(1) } // 6
|
||||
|
||||
// One line
|
||||
val c = if (1 > 2) foo { test(1) } else foo { test(1) }
|
||||
val c = if (1 > 2) foo { test(1) } else foo { test(1) } // 8
|
||||
|
||||
// Else on next line, false
|
||||
val d = if (1 > 2) foo { test(1) }
|
||||
else foo { test(1) }
|
||||
val d = if (1 > 2) foo { test(1) } // 9 11
|
||||
else foo { test(1) } // 10
|
||||
|
||||
// Else on next line, true
|
||||
val e = if (1 < 2) foo { test(1) }
|
||||
val e = if (1 < 2) foo { test(1) } // 12
|
||||
else foo { test(1) }
|
||||
|
||||
// Inline function call in condition
|
||||
val f = if (foo { test(1) } > 2) {
|
||||
val f = if (foo { test(1) } > 2) { // 13 15(?)
|
||||
foo { test(1) }
|
||||
}
|
||||
else {
|
||||
foo { test(1) }
|
||||
foo { test(1) } // 14
|
||||
}
|
||||
|
||||
// Reified function call in if condition
|
||||
if (reified(1) != 1) {
|
||||
val a = 1
|
||||
}
|
||||
}
|
||||
} // 16
|
||||
|
||||
inline fun foo(f: () -> Int): Int {
|
||||
val a = 1
|
||||
@@ -49,9 +44,4 @@ inline fun foo(f: () -> Int): Int {
|
||||
|
||||
fun test(i: Int) = 1
|
||||
|
||||
inline fun <reified T> reified(f: T): Int {
|
||||
val a = 1
|
||||
return 1
|
||||
}
|
||||
|
||||
// STEP_OVER: 25
|
||||
// STEP_OVER: 17
|
||||
+2
-4
@@ -1,8 +1,8 @@
|
||||
package stepOverInlinedLambda
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val a = A()
|
||||
//Breakpoint!
|
||||
val a = A()
|
||||
foo { test(1) }
|
||||
foo {
|
||||
test(2)
|
||||
@@ -27,8 +27,6 @@ fun main(args: Array<String>) {
|
||||
})
|
||||
|
||||
val b = foo { test(1) }
|
||||
|
||||
foo(fun (){ test(1) })
|
||||
}
|
||||
|
||||
inline fun foo(f: () -> Unit) {
|
||||
@@ -49,4 +47,4 @@ class A {
|
||||
|
||||
fun test(i: Int) = 1
|
||||
|
||||
// STEP_OVER: 11
|
||||
// STEP_OVER: 12
|
||||
+4
-4
@@ -3,16 +3,16 @@ package stepOverInlinedLambdaStdlib
|
||||
fun main(args: Array<String>) {
|
||||
//Breakpoint!
|
||||
val a = listOf(1, 2, 3)
|
||||
a.filter { it > 1 }
|
||||
a.filter { it > 1 } /*!*/
|
||||
|
||||
a.filter { it > 1 }.map { it * 2 }
|
||||
a.filter { it > 1 }.map { it * 2 } /*!*/
|
||||
|
||||
a.filter {
|
||||
a.filter { /*!*/
|
||||
it > 1
|
||||
}.map {
|
||||
it * 2
|
||||
}
|
||||
}
|
||||
} /*!*/
|
||||
|
||||
// TRACING_FILTERS_ENABLED: false
|
||||
// STEP_OVER: 4
|
||||
+4
-1
@@ -9,8 +9,11 @@ fun main(args: Array<String>) {
|
||||
inline fun bar(f: (Int) -> Unit) {
|
||||
//Breakpoint!
|
||||
val a = 1
|
||||
foo()
|
||||
val f = f(1)
|
||||
val c = 1
|
||||
}
|
||||
|
||||
// STEP_OVER: 3
|
||||
fun foo() {}
|
||||
|
||||
// STEP_OVER: 4
|
||||
+16
-16
@@ -4,43 +4,43 @@ fun main(args: Array<String>) {
|
||||
try {
|
||||
bar()
|
||||
}
|
||||
catch(e: Exception) {
|
||||
val a = 1
|
||||
catch(e: Exception) { // 13
|
||||
val a = 1 // 14
|
||||
}
|
||||
}
|
||||
} // 15
|
||||
|
||||
fun bar() {
|
||||
//Breakpoint!
|
||||
val prop = 1
|
||||
val prop = 1 // 1
|
||||
// Try
|
||||
try {
|
||||
foo { test(1) }
|
||||
try { // 2
|
||||
foo { test(1) } // 3
|
||||
}
|
||||
catch(e: Exception) {
|
||||
foo { test(1) }
|
||||
}
|
||||
|
||||
// Many catch clauses
|
||||
try {
|
||||
throw IllegalStateException()
|
||||
try { // 4
|
||||
throw IllegalStateException() // 5
|
||||
}
|
||||
catch(e: IllegalStateException) {
|
||||
foo { test(1) }
|
||||
catch(e: IllegalStateException) { // 6
|
||||
foo { test(1) } // 7
|
||||
}
|
||||
catch(e: Exception) {
|
||||
foo { test(1) }
|
||||
}
|
||||
|
||||
// exception in lambda
|
||||
try {
|
||||
foo { throw IllegalStateException() }
|
||||
try { // 8
|
||||
foo { throw IllegalStateException() } // 9
|
||||
}
|
||||
catch(e: Exception) {
|
||||
foo { test(1) }
|
||||
catch(e: Exception) { // 10
|
||||
foo { test(1) } // 11
|
||||
}
|
||||
|
||||
// Exception without catch
|
||||
foo { throw IllegalStateException() }
|
||||
foo { throw IllegalStateException() } // 12
|
||||
val prop2 = 1
|
||||
}
|
||||
|
||||
@@ -51,4 +51,4 @@ inline fun foo(f: () -> Int): Int {
|
||||
|
||||
fun test(i: Int) = 1
|
||||
|
||||
// STEP_OVER: 20
|
||||
// STEP_OVER: 15
|
||||
+6
-6
@@ -1,23 +1,23 @@
|
||||
package stepOverWhenInReturn
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
whenInReturn()
|
||||
}
|
||||
whenInReturn() // 4?
|
||||
} // 5
|
||||
|
||||
fun whenInReturn(): Int {
|
||||
val a = 1
|
||||
//Breakpoint!
|
||||
return when(a) {
|
||||
1 -> foo { 1 }
|
||||
return when(a) { // 1 3?
|
||||
1 -> foo { 1 } // 2
|
||||
else -> 3
|
||||
}
|
||||
}
|
||||
|
||||
inline fun foo(f: () -> Int): Int {
|
||||
val a = 1
|
||||
val a = 15
|
||||
return f()
|
||||
}
|
||||
|
||||
fun test(i: Int) = 1
|
||||
fun test(i: Int) = 42
|
||||
|
||||
// STEP_OVER: 6
|
||||
+26
-26
@@ -2,45 +2,45 @@ package stepOverWhenWithInline
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
//Breakpoint!
|
||||
val prop = 1
|
||||
val prop = 1 // 1
|
||||
// Break after second
|
||||
val a = when {
|
||||
1 > 2 -> foo { test(1) }
|
||||
2 > 1 -> foo { test(1) }
|
||||
val a = when { // 4
|
||||
1 > 2 -> foo { test(1) } // 2
|
||||
2 > 1 -> foo { test(1) } // 3
|
||||
else -> foo { test(1) }
|
||||
}
|
||||
|
||||
val b = when {
|
||||
1 > 2 -> {
|
||||
val b = when { // 8
|
||||
1 > 2 -> { // 5
|
||||
foo { test(1) }
|
||||
}
|
||||
2 > 1 -> {
|
||||
foo { test(1) }
|
||||
2 > 1 -> { // 6
|
||||
foo { test(1) } // 7
|
||||
}
|
||||
else -> {
|
||||
foo { test(1) }
|
||||
}
|
||||
}
|
||||
|
||||
val c = when {
|
||||
foo { test(1) } > 2 -> 1
|
||||
2 > foo { test(1) } -> 2
|
||||
val c = when { // 11
|
||||
foo { test(1) } > 2 -> 1 // 9
|
||||
2 > foo { test(1) } -> 2 // 10
|
||||
else -> foo { test(1) }
|
||||
}
|
||||
|
||||
// When with expression
|
||||
val a1 = when(prop) {
|
||||
val a1 = when(1) { // 12 14
|
||||
2 -> foo { test(1) }
|
||||
1 -> foo { test(1) }
|
||||
1 -> foo { test(1) } // 13
|
||||
else -> foo { test(1) }
|
||||
}
|
||||
|
||||
val b1 = when(prop) {
|
||||
val b1 = when(1) { // 15 17
|
||||
2 -> {
|
||||
foo { test(1) }
|
||||
}
|
||||
1 -> {
|
||||
foo { test(1) }
|
||||
foo { test(1) } // 16
|
||||
}
|
||||
else -> {
|
||||
foo { test(1) }
|
||||
@@ -48,21 +48,21 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
|
||||
// Break after first
|
||||
val c1 = when(prop) {
|
||||
foo { test(1) } -> 1
|
||||
val c1 = when(1) { // 18 20
|
||||
foo { test(1) } -> 1 // 19
|
||||
foo { test(2) } -> 2
|
||||
else -> foo { test(1) }
|
||||
}
|
||||
|
||||
val a2 = when {
|
||||
2 > 1 -> foo { test(1) }
|
||||
val a2 = when { // 22
|
||||
2 > 1 -> foo { test(1) } // 21
|
||||
1 > 2 -> foo { test(1) }
|
||||
else -> foo { test(1) }
|
||||
}
|
||||
|
||||
val b2 = when {
|
||||
2 > 1 -> {
|
||||
foo { test(1) }
|
||||
val b2 = when { // 25
|
||||
2 > 1 -> { // 23
|
||||
foo { test(1) } // 24
|
||||
}
|
||||
1 > 2 -> {
|
||||
foo { test(1) }
|
||||
@@ -72,12 +72,12 @@ fun main(args: Array<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
val c2 = when {
|
||||
2 > foo { test(1) } -> 2
|
||||
val c2 = when { // 27
|
||||
2 > foo { test(1) } -> 2 // 26
|
||||
foo { test(1) } > 2 -> 1
|
||||
else -> foo { test(1) }
|
||||
}
|
||||
}
|
||||
} // 28
|
||||
|
||||
inline fun foo(f: () -> Int): Int {
|
||||
val a = 1
|
||||
@@ -86,4 +86,4 @@ inline fun foo(f: () -> Int): Int {
|
||||
|
||||
fun test(i: Int) = i
|
||||
|
||||
// STEP_OVER: 41
|
||||
// STEP_OVER: 30
|
||||
+15
-26
@@ -2,40 +2,29 @@ package stepOverWhileWithInline
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
//Breakpoint!
|
||||
var prop = 0
|
||||
var prop = 0 // 1
|
||||
// inline on last line of while
|
||||
while(prop < 1) {
|
||||
prop++
|
||||
foo { test(1) }
|
||||
while(prop < 1) { // 2 5
|
||||
prop++ // 3
|
||||
foo { test(1) } // 4
|
||||
}
|
||||
|
||||
// inline call inside while
|
||||
while(prop < 2) {
|
||||
foo { test(1) }
|
||||
prop++
|
||||
while(prop < 2) { // 6 9
|
||||
foo { test(1) } // 7
|
||||
prop++ // 8
|
||||
}
|
||||
|
||||
do {
|
||||
prop++
|
||||
foo { test(1) }
|
||||
} while(prop < 3)
|
||||
prop++ // 10
|
||||
foo { test(1) } // 11
|
||||
} while(prop < 3) // 12
|
||||
|
||||
do {
|
||||
foo { test(1) }
|
||||
prop++
|
||||
} while(prop < 4)
|
||||
|
||||
var i = 1
|
||||
// inline in while condition (true)
|
||||
while(foo { test(i++) } == 1) {
|
||||
prop++
|
||||
}
|
||||
|
||||
// inline in while condition (false)
|
||||
while(foo { test(2) } == 1) {
|
||||
prop++
|
||||
}
|
||||
}
|
||||
foo { test(1) } // 13
|
||||
prop++ // 14
|
||||
} while(prop < 4) // 15
|
||||
} // 16
|
||||
|
||||
inline fun foo(f: () -> Int): Int {
|
||||
val a = 1
|
||||
@@ -44,4 +33,4 @@ inline fun foo(f: () -> Int): Int {
|
||||
|
||||
fun test(i: Int) = i
|
||||
|
||||
// STEP_OVER: 41
|
||||
// STEP_OVER: 16
|
||||
@@ -433,6 +433,18 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineInIfFalse.kt")
|
||||
public void testInlineInIfFalse() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/inlineInIfFalse.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inlineInIfTrue.kt")
|
||||
public void testInlineInIfTrue() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/inlineInIfTrue.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("noParameterLambdaArgumentCallInInline.kt")
|
||||
public void testNoParameterLambdaArgumentCallInInline() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/noParameterLambdaArgumentCallInInline.kt");
|
||||
@@ -445,12 +457,84 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("soInlineAnonymousFunctionArgument.kt")
|
||||
public void testSoInlineAnonymousFunctionArgument() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineAnonymousFunctionArgument.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("soInlineCallInLastStatementInInline.kt")
|
||||
public void testSoInlineCallInLastStatementInInline() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineCallInLastStatementInInline.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("soInlineCallInLastStatementInInlineInInline.kt")
|
||||
public void testSoInlineCallInLastStatementInInlineInInline() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineCallInLastStatementInInlineInInline.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn.kt")
|
||||
public void testSoInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineFunCallInLastStatementOfInlineWithArgumentFromCalleeAndOwn.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("soInlineFunWithLastStatementMultilineArgumentCall.kt")
|
||||
public void testSoInlineFunWithLastStatementMultilineArgumentCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineFunWithLastStatementMultilineArgumentCall.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("soInlineFunWithLastStatementOneLineArgumentCall.kt")
|
||||
public void testSoInlineFunWithLastStatementOneLineArgumentCall() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineFunWithLastStatementOneLineArgumentCall.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("soInlineIfConditionLambdaFalse.kt")
|
||||
public void testSoInlineIfConditionLambdaFalse() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineIfConditionLambdaFalse.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("soInlineIfConditionLambdaTrue.kt")
|
||||
public void testSoInlineIfConditionLambdaTrue() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineIfConditionLambdaTrue.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("soInlineWhileCondition.kt")
|
||||
public void testSoInlineWhileCondition() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soInlineWhileCondition.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("soReifiedInlineIfConditionFalse.kt")
|
||||
public void testSoReifiedInlineIfConditionFalse() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soReifiedInlineIfConditionFalse.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("soSimpleInlineIfCondition.kt")
|
||||
public void testSoSimpleInlineIfCondition() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soSimpleInlineIfCondition.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stepOverCatchClause.kt")
|
||||
public void testStepOverCatchClause() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stepOverCatchClause.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stepOverDeclarationInInlineFun.kt")
|
||||
public void testStepOverDeclarationInInlineFun() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stepOverDeclarationInInlineFun.kt");
|
||||
doStepOverTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("stepOverFalseConditionInLastIfInWhile.kt")
|
||||
public void testStepOverFalseConditionInLastIfInWhile() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stepOverFalseConditionInLastIfInWhile.kt");
|
||||
|
||||
Reference in New Issue
Block a user