Fix step over if there isn't any inlined arguments
This commit is contained in:
+28
-14
@@ -21,6 +21,7 @@ import com.intellij.debugger.engine.DebugProcessImpl
|
|||||||
import com.intellij.debugger.engine.SuspendContextImpl
|
import com.intellij.debugger.engine.SuspendContextImpl
|
||||||
import com.intellij.debugger.engine.events.DebuggerCommandImpl
|
import com.intellij.debugger.engine.events.DebuggerCommandImpl
|
||||||
import com.intellij.debugger.impl.JvmSteppingCommandProvider
|
import com.intellij.debugger.impl.JvmSteppingCommandProvider
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.util.concurrency.Semaphore
|
import com.intellij.util.concurrency.Semaphore
|
||||||
import com.intellij.xdebugger.impl.XSourcePositionImpl
|
import com.intellij.xdebugger.impl.XSourcePositionImpl
|
||||||
import com.sun.jdi.Location
|
import com.sun.jdi.Location
|
||||||
@@ -30,6 +31,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||||
import org.jetbrains.kotlin.idea.core.refactoring.getLineCount
|
import org.jetbrains.kotlin.idea.core.refactoring.getLineCount
|
||||||
|
import org.jetbrains.kotlin.idea.core.refactoring.getLineEndOffset
|
||||||
import org.jetbrains.kotlin.idea.core.refactoring.getLineStartOffset
|
import org.jetbrains.kotlin.idea.core.refactoring.getLineStartOffset
|
||||||
import org.jetbrains.kotlin.idea.util.DebuggerUtils
|
import org.jetbrains.kotlin.idea.util.DebuggerUtils
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -56,7 +58,8 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
|
|||||||
|
|
||||||
val file = sourcePosition.file as? JetFile ?: return null
|
val file = sourcePosition.file as? JetFile ?: return null
|
||||||
|
|
||||||
val inlinedArguments = getInlinedArgumentsIfAny(sourcePosition) ?: return null
|
val inlinedArguments = getInlinedArgumentsIfAny(sourcePosition)
|
||||||
|
if (inlinedArguments.isEmpty()) return null
|
||||||
|
|
||||||
val locations = computedReferenceType.allLineLocations()
|
val locations = computedReferenceType.allLineLocations()
|
||||||
val countOfLinesInFile = file.getLineCount()
|
val countOfLinesInFile = file.getLineCount()
|
||||||
@@ -96,7 +99,7 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
|
|||||||
val nextLineLocations = locations.dropWhile { it.lineNumber() != location.lineNumber() }.filter { it.method() == location.method() }
|
val nextLineLocations = locations.dropWhile { it.lineNumber() != location.lineNumber() }.filter { it.method() == location.method() }
|
||||||
|
|
||||||
val inlineFunction = getInlineFunctionsIfAny(file, lineStartOffset)
|
val inlineFunction = getInlineFunctionsIfAny(file, lineStartOffset)
|
||||||
if (inlineFunction != null) {
|
if (inlineFunction.isNotEmpty()) {
|
||||||
val xPosition = suspendContext.getXPositionForStepOutFromInlineFunction(nextLineLocations, inlineFunction) ?: return null
|
val xPosition = suspendContext.getXPositionForStepOutFromInlineFunction(nextLineLocations, inlineFunction) ?: return null
|
||||||
return suspendContext.debugProcess.createRunToCursorCommand(suspendContext, xPosition, true)
|
return suspendContext.debugProcess.createRunToCursorCommand(suspendContext, xPosition, true)
|
||||||
}
|
}
|
||||||
@@ -152,12 +155,12 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInlineFunctionsIfAny(file: JetFile, offset: Int): List<JetNamedFunction>? {
|
private fun getInlineFunctionsIfAny(file: JetFile, offset: Int): List<JetNamedFunction> {
|
||||||
val elementAt = file.findElementAt(offset) ?: return null
|
val elementAt = file.findElementAt(offset) ?: return emptyList()
|
||||||
val containingFunction = elementAt.getParentOfType<JetNamedFunction>(false) ?: return null
|
val containingFunction = elementAt.getParentOfType<JetNamedFunction>(false) ?: return emptyList()
|
||||||
|
|
||||||
val descriptor = containingFunction.resolveToDescriptor()
|
val descriptor = containingFunction.resolveToDescriptor()
|
||||||
if (!InlineUtil.isInline(descriptor)) return null
|
if (!InlineUtil.isInline(descriptor)) return emptyList()
|
||||||
|
|
||||||
val inlineFunctionsCalls = DebuggerUtils.analyzeElementWithInline(
|
val inlineFunctionsCalls = DebuggerUtils.analyzeElementWithInline(
|
||||||
containingFunction.getResolutionFacade(),
|
containingFunction.getResolutionFacade(),
|
||||||
@@ -211,16 +214,27 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInlinedArgumentsIfAny(sourcePosition: SourcePosition): List<JetFunction>? {
|
private fun getInlinedArgumentsIfAny(sourcePosition: SourcePosition): List<JetFunction> {
|
||||||
val file = sourcePosition.file as? JetFile ?: return null
|
val file = sourcePosition.file as? JetFile ?: return emptyList()
|
||||||
val lineNumber = sourcePosition.line
|
val lineNumber = sourcePosition.line
|
||||||
val elementAt = CodeInsightUtils.getTopmostElementAtOffset(
|
var elementAt = sourcePosition.elementAt
|
||||||
sourcePosition.elementAt,
|
|
||||||
file.getLineStartOffset(lineNumber) ?: sourcePosition.elementAt.startOffset
|
|
||||||
) ?: return null
|
|
||||||
|
|
||||||
val start = elementAt.startOffset
|
var startOffset = file.getLineStartOffset(lineNumber) ?: elementAt.startOffset
|
||||||
val end = elementAt.endOffset
|
var endOffset = file.getLineEndOffset(lineNumber) ?: elementAt.endOffset
|
||||||
|
|
||||||
|
var topMostElement: PsiElement? = null
|
||||||
|
while (topMostElement !is JetElement && startOffset < endOffset) {
|
||||||
|
elementAt = file.findElementAt(startOffset)
|
||||||
|
if (elementAt != null) {
|
||||||
|
topMostElement = CodeInsightUtils.getTopmostElementAtOffset(elementAt, startOffset)
|
||||||
|
}
|
||||||
|
startOffset++
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topMostElement == null) return emptyList()
|
||||||
|
|
||||||
|
val start = topMostElement.startOffset
|
||||||
|
val end = topMostElement.endOffset
|
||||||
|
|
||||||
return CodeInsightUtils.
|
return CodeInsightUtils.
|
||||||
findElementsOfClassInRange(file, start, end, JetFunctionLiteral::class.java, JetNamedFunction::class.java)
|
findElementsOfClassInRange(file, start, end, JetFunctionLiteral::class.java, JetNamedFunction::class.java)
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ public class SelectionAwareScopeHighlighter(val editor: Editor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun PsiFile.getLineStartOffset(line: Int): Int? {
|
fun PsiFile.getLineStartOffset(line: Int): Int? {
|
||||||
val doc = this.let { file -> PsiDocumentManager.getInstance(getProject()).getDocument(file) }
|
val doc = PsiDocumentManager.getInstance(project).getDocument(this)
|
||||||
if (doc != null) {
|
if (doc != null) {
|
||||||
val startOffset = doc.getLineStartOffset(line)
|
val startOffset = doc.getLineStartOffset(line)
|
||||||
val element = findElementAt(startOffset) ?: return startOffset
|
val element = findElementAt(startOffset) ?: return startOffset
|
||||||
@@ -291,6 +291,10 @@ fun PsiFile.getLineStartOffset(line: Int): Int? {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun PsiFile.getLineEndOffset(line: Int): Int? {
|
||||||
|
return PsiDocumentManager.getInstance(project).getDocument(this)?.getLineEndOffset(line)
|
||||||
|
}
|
||||||
|
|
||||||
fun PsiElement.getLineCount(): Int {
|
fun PsiElement.getLineCount(): Int {
|
||||||
val doc = getContainingFile()?.let { file -> PsiDocumentManager.getInstance(getProject()).getDocument(file) }
|
val doc = getContainingFile()?.let { file -> PsiDocumentManager.getInstance(getProject()).getDocument(file) }
|
||||||
if (doc != null) {
|
if (doc != null) {
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
LineBreakpoint created at stepOverSimpleFun.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! stepOverSimpleFun.StepOverSimpleFunPackage
|
||||||
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
stepOverSimpleFun.kt:11
|
||||||
|
stepOverSimpleFun.kt:4
|
||||||
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package stepOverSimpleFun
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
foo(1)
|
||||||
|
val a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(i: Int): Int {
|
||||||
|
if (i > 0) {
|
||||||
|
//Breakpoint!
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not remove: kotlin strata should be available for this test
|
||||||
|
inline fun f(p: () -> Unit) {
|
||||||
|
val b = 1
|
||||||
|
p()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun f2() {
|
||||||
|
f {
|
||||||
|
val b = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -348,6 +348,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
|||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stepOverInlinedLambdaStdlib.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stepOverInlinedLambdaStdlib.kt");
|
||||||
doStepOverTest(fileName);
|
doStepOverTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("stepOverSimpleFun.kt")
|
||||||
|
public void testStepOverSimpleFun() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stepOverSimpleFun.kt");
|
||||||
|
doStepOverTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("idea/testData/debugger/tinyApp/src/stepping/filters")
|
@TestMetadata("idea/testData/debugger/tinyApp/src/stepping/filters")
|
||||||
|
|||||||
Reference in New Issue
Block a user