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;
|
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
|
@Nullable
|
||||||
public static <T> T getTopmostElementAtOffset(@NotNull PsiElement element, int offset, @NotNull Class<T> klass) {
|
public static <T> T getTopmostElementAtOffset(@NotNull PsiElement element, int offset, @NotNull Class<T> klass) {
|
||||||
T lastElementOfType = null;
|
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.getLineEndOffset
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
|
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
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.load.java.JvmAbi
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
|
||||||
import org.jetbrains.kotlin.psi.KtFunction
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -218,3 +217,21 @@ fun findElementAtLine(file: KtFile, line: Int): PsiElement? {
|
|||||||
|
|
||||||
return topMostElement
|
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 file = sourcePosition.file as? KtFile ?: return emptyList()
|
||||||
val lineNumber = sourcePosition.line
|
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 start = lineElement.startOffset
|
||||||
val end = lineElement.endOffset
|
val end = lineElement.endOffset
|
||||||
|
|||||||
-1
@@ -3,7 +3,6 @@ Run Java
|
|||||||
Connected to the target VM
|
Connected to the target VM
|
||||||
soInlineCallInLastStatementInInlineFunctionArgument.kt:7
|
soInlineCallInLastStatementInInlineFunctionArgument.kt:7
|
||||||
soInlineCallInLastStatementInInlineFunctionArgument.kt:8
|
soInlineCallInLastStatementInInlineFunctionArgument.kt:8
|
||||||
soInlineCallInLastStatementInInlineFunctionArgument.kt:14
|
|
||||||
soInlineCallInLastStatementInInlineFunctionArgument.kt:9
|
soInlineCallInLastStatementInInlineFunctionArgument.kt:9
|
||||||
Disconnected from the target VM
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ fun main(args: Array<String>) {
|
|||||||
bar {
|
bar {
|
||||||
nop()
|
nop()
|
||||||
//Breakpoint!
|
//Breakpoint!
|
||||||
foo() // <-- Should not stop here twice
|
foo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-1
@@ -3,7 +3,6 @@ Run Java
|
|||||||
Connected to the target VM
|
Connected to the target VM
|
||||||
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:7
|
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:7
|
||||||
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:8
|
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:8
|
||||||
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:14
|
|
||||||
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:9
|
soInlineCallInLastStatementInInlineFunctionArgumentDex.kt:9
|
||||||
Disconnected from the target VM
|
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);
|
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")
|
@TestMetadata("soNonSuspendableSuspendCall.kt")
|
||||||
public void testSoNonSuspendableSuspendCall() throws Exception {
|
public void testSoNonSuspendableSuspendCall() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soNonSuspendableSuspendCall.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/soNonSuspendableSuspendCall.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user