Fix steping for inline functions with reified parameters
This commit is contained in:
+29
-14
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.psi.*
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
|
||||||
@@ -58,8 +59,10 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
|
|||||||
|
|
||||||
val file = sourcePosition.file as? JetFile ?: return null
|
val file = sourcePosition.file as? JetFile ?: return null
|
||||||
|
|
||||||
val inlinedArguments = getInlinedArgumentsIfAny(sourcePosition)
|
val inlineFunctionCalls = getInlineFunctionCallsIfAny(sourcePosition)
|
||||||
if (inlinedArguments.isEmpty()) return null
|
if (inlineFunctionCalls.isEmpty()) return null
|
||||||
|
|
||||||
|
val inlinedArguments = getInlinedArgumentsIfAny(inlineFunctionCalls)
|
||||||
|
|
||||||
if (inlinedArguments.any { it.shouldNotUseStepOver(sourcePosition.elementAt) }) {
|
if (inlinedArguments.any { it.shouldNotUseStepOver(sourcePosition.elementAt) }) {
|
||||||
return null
|
return null
|
||||||
@@ -305,7 +308,16 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInlinedArgumentsIfAny(sourcePosition: SourcePosition): List<JetFunction> {
|
private fun getInlinedArgumentsIfAny(inlineFunctionCalls: List<JetCallExpression>): List<JetFunction> {
|
||||||
|
return inlineFunctionCalls.flatMap {
|
||||||
|
it.valueArguments
|
||||||
|
.map { it.getArgumentExpression() }
|
||||||
|
.filterIsInstance<JetFunctionLiteralExpression>()
|
||||||
|
.map { it.functionLiteral }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getInlineFunctionCallsIfAny(sourcePosition: SourcePosition): List<JetCallExpression> {
|
||||||
val file = sourcePosition.file as? JetFile ?: return emptyList()
|
val file = sourcePosition.file as? JetFile ?: return emptyList()
|
||||||
val lineNumber = sourcePosition.line
|
val lineNumber = sourcePosition.line
|
||||||
var elementAt = sourcePosition.elementAt
|
var elementAt = sourcePosition.elementAt
|
||||||
@@ -327,20 +339,23 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
|
|||||||
val start = topMostElement.startOffset
|
val start = topMostElement.startOffset
|
||||||
val end = topMostElement.endOffset
|
val end = topMostElement.endOffset
|
||||||
|
|
||||||
val allInlinedArguments = CodeInsightUtils.
|
fun isInlineCall(expr: JetExpression): Boolean {
|
||||||
findElementsOfClassInRange(file, start, end, JetFunctionLiteral::class.java, JetNamedFunction::class.java)
|
val context = expr.analyze(BodyResolveMode.PARTIAL)
|
||||||
.filter { JetPsiUtil.getParentCallIfPresent(it as JetExpression) != null }
|
val resolvedCall = expr.getResolvedCall(context) ?: return false
|
||||||
.filterIsInstance<JetFunction>()
|
return InlineUtil.isInline(resolvedCall.resultingDescriptor)
|
||||||
.filter {
|
}
|
||||||
val context = it.analyze(BodyResolveMode.PARTIAL)
|
|
||||||
InlineUtil.isInlinedArgument(it, context, false)
|
val allInlineFunctionCalls = CodeInsightUtils.
|
||||||
}
|
findElementsOfClassInRange(file, start, end, JetExpression::class.java)
|
||||||
|
.map { JetPsiUtil.getParentCallIfPresent(it as JetExpression) }
|
||||||
|
.filterIsInstance<JetCallExpression>()
|
||||||
|
.filter { isInlineCall(it) }
|
||||||
|
.toSet()
|
||||||
|
|
||||||
// It is necessary to check range because of multiline assign
|
// It is necessary to check range because of multiline assign
|
||||||
var linesRange = lineNumber..lineNumber
|
var linesRange = lineNumber..lineNumber
|
||||||
return allInlinedArguments.filter {
|
return allInlineFunctionCalls.filter {
|
||||||
val parentCall = JetPsiUtil.getParentCallIfPresent(it)!!
|
val shouldInclude = it.getLineNumber() in linesRange
|
||||||
val shouldInclude = parentCall.getLineNumber() in linesRange
|
|
||||||
if (shouldInclude) {
|
if (shouldInclude) {
|
||||||
linesRange = Math.min(linesRange.start, it.getLineNumber())..Math.max(linesRange.end, it.getLineNumber(false))
|
linesRange = Math.min(linesRange.start, it.getLineNumber())..Math.max(linesRange.end, it.getLineNumber(false))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
LineBreakpoint created at stepOverReifiedParam.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! stepOverReifiedParam.StepOverReifiedParamPackage
|
||||||
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
stepOverReifiedParam.kt:5
|
||||||
|
stepOverReifiedParam.kt:6
|
||||||
|
stepOverReifiedParam.kt:7
|
||||||
|
stepOverReifiedParam.kt:8
|
||||||
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package stepOverReifiedParam
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
//Breakpoint!
|
||||||
|
val a = 1
|
||||||
|
foo(a)
|
||||||
|
val b = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> foo(t: T): T {
|
||||||
|
val a = t
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP_OVER: 3
|
||||||
@@ -367,6 +367,12 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
|||||||
doStepOverTest(fileName);
|
doStepOverTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("stepOverReifiedParam.kt")
|
||||||
|
public void testStepOverReifiedParam() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stepOverReifiedParam.kt");
|
||||||
|
doStepOverTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("stepOverSimpleFun.kt")
|
@TestMetadata("stepOverSimpleFun.kt")
|
||||||
public void testStepOverSimpleFun() throws Exception {
|
public void testStepOverSimpleFun() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stepOverSimpleFun.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stepOverSimpleFun.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user