Check correspondent call on end token for better step over (KT-18949)

#KT-18949 Fixed
This commit is contained in:
Nikolay Krasko
2017-07-12 19:09:48 +03:00
parent d282f14eac
commit f664ffb06b
19 changed files with 252 additions and 7 deletions
@@ -339,6 +339,27 @@ public class CodeInsightUtils {
return element;
}
@NotNull
public static PsiElement getTopParentWithEndOffset(@NotNull PsiElement element, @NotNull Class<?> stopAt) {
int endOffset = element.getTextOffset() + element.getTextLength();
do {
PsiElement parent = element.getParent();
if (parent == null || (parent.getTextOffset() + parent.getTextLength()) != endOffset) {
break;
}
element = parent;
if (stopAt.isInstance(element)) {
break;
}
}
while(true);
return element;
}
@Nullable
public static <T> T getTopmostElementAtOffset(@NotNull PsiElement element, int offset, @NotNull Class<T> klass) {
T lastElementOfType = null;
@@ -32,10 +32,9 @@ import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
import org.jetbrains.kotlin.idea.refactoring.getLineEndOffset
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import java.util.*
@@ -218,3 +217,21 @@ fun findElementAtLine(file: KtFile, line: Int): PsiElement? {
return topMostElement
}
fun findCallByEndToken(element: PsiElement): KtCallExpression? {
if (element is KtElement) return null
return when (element.node.elementType) {
KtTokens.RPAR -> (element.parent as? KtValueArgumentList)?.parent as? KtCallExpression
KtTokens.RBRACE -> {
val braceParent = CodeInsightUtils.getTopParentWithEndOffset(element, KtCallExpression::class.java)
when (braceParent) {
is KtCallExpression -> braceParent
is KtLambdaArgument -> braceParent.parent as? KtCallExpression
is KtValueArgument -> (braceParent.parent as? KtValueArgumentList)?.parent as? KtCallExpression
else -> null
}
}
else -> null
}
}
@@ -235,7 +235,18 @@ private fun findCallsOnPosition(sourcePosition: SourcePosition, filter: (KtCallE
val file = sourcePosition.file as? KtFile ?: return emptyList()
val lineNumber = sourcePosition.line
val lineElement = findElementAtLine(file, lineNumber) as? KtElement ?: return emptyList()
val lineElement = findElementAtLine(file, lineNumber)
if (lineElement !is KtElement) {
if (lineElement != null) {
val call = findCallByEndToken(lineElement)
if (call != null && filter(call)) {
return listOf(call)
}
}
return emptyList()
}
val start = lineElement.startOffset
val end = lineElement.endOffset
@@ -3,7 +3,6 @@ Run Java
Connected to the target VM
soInlineCallInLastStatementInInlineFunctionArgument.kt:7
soInlineCallInLastStatementInInlineFunctionArgument.kt:8
soInlineCallInLastStatementInInlineFunctionArgument.kt:14
soInlineCallInLastStatementInInlineFunctionArgument.kt:9
Disconnected from the target VM
@@ -4,7 +4,7 @@ fun main(args: Array<String>) {
bar {
nop()
//Breakpoint!
foo() // <-- Should not stop here twice
foo()
}
}
@@ -3,7 +3,6 @@ Run Java
Connected to the target VM
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:7
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:8
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:14
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:9
Disconnected from the target VM
@@ -0,0 +1,17 @@
package soLastStatementInInlineFunctionArgumenBeforeOtherArgument
fun main(args: Array<String>) {
bar({
//Breakpoint!
nop()
}, 12)
}
inline fun bar(f: () -> Unit, a: Any) {
nop()
f()
} // <-- Ideally this line should not be visited
fun nop() {}
// STEP_OVER: 2
@@ -0,0 +1,9 @@
LineBreakpoint created at soLastStatementInInlineFunctionArgumenBeforeOtherArgument.kt:6
Run Java
Connected to the target VM
soLastStatementInInlineFunctionArgumenBeforeOtherArgument.kt:6
soLastStatementInInlineFunctionArgumenBeforeOtherArgument.kt:7
soLastStatementInInlineFunctionArgumenBeforeOtherArgument.kt:13
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,17 @@
package soLastStatementInInlineFunctionArgumentAsAnonymous
fun main(args: Array<String>) {
bar(fun() {
//Breakpoint!
nop()
})
}
inline fun bar(f: () -> Unit) {
nop()
f()
}
fun nop() {}
// STEP_OVER: 2
@@ -0,0 +1,9 @@
LineBreakpoint created at soLastStatementInInlineFunctionArgumentAsAnonymous.kt:6
Run Java
Connected to the target VM
soLastStatementInInlineFunctionArgumentAsAnonymous.kt:6
soLastStatementInInlineFunctionArgumentAsAnonymous.kt:7
soLastStatementInInlineFunctionArgumentAsAnonymous.kt:8
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,18 @@
package soLastStatementInInlineFunctionArgumentAsAnonymousParNextLine
fun main(args: Array<String>) {
bar(fun() {
//Breakpoint!
nop()
}
)
}
inline fun bar(f: () -> Unit) {
nop()
f()
}
fun nop() {}
// STEP_OVER: 2
@@ -0,0 +1,9 @@
LineBreakpoint created at soLastStatementInInlineFunctionArgumentAsAnonymousParNextLine.kt:6
Run Java
Connected to the target VM
soLastStatementInInlineFunctionArgumentAsAnonymousParNextLine.kt:6
soLastStatementInInlineFunctionArgumentAsAnonymousParNextLine.kt:7
soLastStatementInInlineFunctionArgumentAsAnonymousParNextLine.kt:9
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,17 @@
package soLastStatementInInlineFunctionArgumentInGetOperator
fun main(args: Array<String>) {
12[{
//Breakpoint!
nop()
}]
}
inline operator fun Int.get(f: () -> Unit) {
nop()
f()
} // <-- Ideally this line should not be visited
fun nop() {}
// STEP_OVER: 2
@@ -0,0 +1,9 @@
LineBreakpoint created at soLastStatementInInlineFunctionArgumentInGetOperator.kt:6
Run Java
Connected to the target VM
soLastStatementInInlineFunctionArgumentInGetOperator.kt:6
soLastStatementInInlineFunctionArgumentInGetOperator.kt:7
soLastStatementInInlineFunctionArgumentInGetOperator.kt:13
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,22 @@
package soLastStatementInInlineFunctionArgumentInNonInlineCall
fun main(args: Array<String>) {
nonInline { bar {
//Breakpoint!
nop()
} }
}
fun nonInline(f: () -> Unit) {
f()
}
inline fun bar(f: () -> Unit) {
nop()
f()
} // <-- Ideally this line should not be visited
fun nop() {}
// STEP_OVER: 2
@@ -0,0 +1,9 @@
LineBreakpoint created at soLastStatementInInlineFunctionArgumentInNonInlineCall.kt:6
Run Java
Connected to the target VM
soLastStatementInInlineFunctionArgumentInNonInlineCall.kt:6
soLastStatementInInlineFunctionArgumentInNonInlineCall.kt:7
soLastStatementInInlineFunctionArgumentInNonInlineCall.kt:17
Disconnected from the target VM
Process finished with exit code 0
@@ -0,0 +1,17 @@
package soLastStatementInInlineFunctionArgumentInPars
fun main(args: Array<String>) {
bar({
//Breakpoint!
nop()
})
}
inline fun bar(f: () -> Unit) {
nop()
f()
}
fun nop() {}
// STEP_OVER: 2
@@ -0,0 +1,9 @@
LineBreakpoint created at soLastStatementInInlineFunctionArgumentInPars.kt:6
Run Java
Connected to the target VM
soLastStatementInInlineFunctionArgumentInPars.kt:6
soLastStatementInInlineFunctionArgumentInPars.kt:7
soLastStatementInInlineFunctionArgumentInPars.kt:8
Disconnected from the target VM
Process finished with exit code 0
@@ -620,6 +620,42 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
doStepOverTest(fileName);
}
@TestMetadata("soLastStatementInInlineFunctionArgumenBeforeOtherArgument.kt")
public void testSoLastStatementInInlineFunctionArgumenBeforeOtherArgument() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soLastStatementInInlineFunctionArgumenBeforeOtherArgument.kt");
doStepOverTest(fileName);
}
@TestMetadata("soLastStatementInInlineFunctionArgumentAsAnonymous.kt")
public void testSoLastStatementInInlineFunctionArgumentAsAnonymous() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soLastStatementInInlineFunctionArgumentAsAnonymous.kt");
doStepOverTest(fileName);
}
@TestMetadata("soLastStatementInInlineFunctionArgumentAsAnonymousParNextLine.kt")
public void testSoLastStatementInInlineFunctionArgumentAsAnonymousParNextLine() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soLastStatementInInlineFunctionArgumentAsAnonymousParNextLine.kt");
doStepOverTest(fileName);
}
@TestMetadata("soLastStatementInInlineFunctionArgumentInGetOperator.kt")
public void testSoLastStatementInInlineFunctionArgumentInGetOperator() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soLastStatementInInlineFunctionArgumentInGetOperator.kt");
doStepOverTest(fileName);
}
@TestMetadata("soLastStatementInInlineFunctionArgumentInNonInlineCall.kt")
public void testSoLastStatementInInlineFunctionArgumentInNonInlineCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soLastStatementInInlineFunctionArgumentInNonInlineCall.kt");
doStepOverTest(fileName);
}
@TestMetadata("soLastStatementInInlineFunctionArgumentInPars.kt")
public void testSoLastStatementInInlineFunctionArgumentInPars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soLastStatementInInlineFunctionArgumentInPars.kt");
doStepOverTest(fileName);
}
@TestMetadata("soNonSuspendableSuspendCall.kt")
public void testSoNonSuspendableSuspendCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soNonSuspendableSuspendCall.kt");