Check correspondent call on end token for better step over (KT-18949)
#KT-18949 Fixed
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -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
|
||||
|
||||
-1
@@ -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
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ fun main(args: Array<String>) {
|
||||
bar {
|
||||
nop()
|
||||
//Breakpoint!
|
||||
foo() // <-- Should not stop here twice
|
||||
foo()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-1
@@ -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
|
||||
|
||||
|
||||
+17
@@ -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
|
||||
+9
@@ -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
|
||||
+17
@@ -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
|
||||
+9
@@ -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
|
||||
+18
@@ -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
|
||||
+9
@@ -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
|
||||
+17
@@ -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
|
||||
+9
@@ -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
|
||||
+22
@@ -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
|
||||
+9
@@ -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
|
||||
+17
@@ -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
|
||||
+9
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user