Fix steping for inline functions with reified parameters

This commit is contained in:
Natalia Ukhorskaya
2015-09-21 15:00:33 +03:00
parent 33b5e6b255
commit c872f301ff
4 changed files with 60 additions and 14 deletions
@@ -38,6 +38,7 @@ 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.startOffset
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
@@ -58,8 +59,10 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
val file = sourcePosition.file as? JetFile ?: return null
val inlinedArguments = getInlinedArgumentsIfAny(sourcePosition)
if (inlinedArguments.isEmpty()) return null
val inlineFunctionCalls = getInlineFunctionCallsIfAny(sourcePosition)
if (inlineFunctionCalls.isEmpty()) return null
val inlinedArguments = getInlinedArgumentsIfAny(inlineFunctionCalls)
if (inlinedArguments.any { it.shouldNotUseStepOver(sourcePosition.elementAt) }) {
return null
@@ -305,7 +308,16 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
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 lineNumber = sourcePosition.line
var elementAt = sourcePosition.elementAt
@@ -327,20 +339,23 @@ public class KotlinSteppingCommandProvider: JvmSteppingCommandProvider() {
val start = topMostElement.startOffset
val end = topMostElement.endOffset
val allInlinedArguments = CodeInsightUtils.
findElementsOfClassInRange(file, start, end, JetFunctionLiteral::class.java, JetNamedFunction::class.java)
.filter { JetPsiUtil.getParentCallIfPresent(it as JetExpression) != null }
.filterIsInstance<JetFunction>()
.filter {
val context = it.analyze(BodyResolveMode.PARTIAL)
InlineUtil.isInlinedArgument(it, context, false)
}
fun isInlineCall(expr: JetExpression): Boolean {
val context = expr.analyze(BodyResolveMode.PARTIAL)
val resolvedCall = expr.getResolvedCall(context) ?: return false
return InlineUtil.isInline(resolvedCall.resultingDescriptor)
}
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
var linesRange = lineNumber..lineNumber
return allInlinedArguments.filter {
val parentCall = JetPsiUtil.getParentCallIfPresent(it)!!
val shouldInclude = parentCall.getLineNumber() in linesRange
return allInlineFunctionCalls.filter {
val shouldInclude = it.getLineNumber() in linesRange
if (shouldInclude) {
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);
}
@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")
public void testStepOverSimpleFun() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stepOverSimpleFun.kt");