Fix look up for breakpoint in crossinline lambdas in android (KT-15282)
#KT-15282 Fixed
This commit is contained in:
Generated
+1
@@ -2,6 +2,7 @@
|
|||||||
<dictionary name="Nikolay.Krasko">
|
<dictionary name="Nikolay.Krasko">
|
||||||
<words>
|
<words>
|
||||||
<w>accessors</w>
|
<w>accessors</w>
|
||||||
|
<w>crossinline</w>
|
||||||
<w>fqname</w>
|
<w>fqname</w>
|
||||||
<w>goto</w>
|
<w>goto</w>
|
||||||
<w>gradle</w>
|
<w>gradle</w>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import com.intellij.util.containers.ContainerUtil
|
|||||||
import com.sun.jdi.Location
|
import com.sun.jdi.Location
|
||||||
import com.sun.jdi.ReferenceType
|
import com.sun.jdi.ReferenceType
|
||||||
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
|
import org.jetbrains.kotlin.idea.debugger.evaluate.KotlinDebuggerCaches
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getLineCount
|
import org.jetbrains.kotlin.idea.refactoring.getLineCount
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
|
import org.jetbrains.kotlin.idea.refactoring.getLineStartOffset
|
||||||
@@ -42,11 +43,13 @@ import org.jetbrains.kotlin.name.ClassId
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.tail
|
import org.jetbrains.kotlin.name.tail
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.KtFunction
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.check
|
import org.jetbrains.kotlin.utils.addToStdlib.check
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
import org.jetbrains.kotlin.utils.getOrPutNullable
|
import org.jetbrains.kotlin.utils.getOrPutNullable
|
||||||
import org.jetbrains.org.objectweb.asm.*
|
import org.jetbrains.org.objectweb.asm.*
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -254,9 +257,17 @@ internal fun getLocationsOfInlinedLine(type: ReferenceType, position: SourcePosi
|
|||||||
|
|
||||||
val lineStartOffset = file.getLineStartOffset(line) ?: return listOf()
|
val lineStartOffset = file.getLineStartOffset(line) ?: return listOf()
|
||||||
val element = file.findElementAt(lineStartOffset) ?: return listOf()
|
val element = file.findElementAt(lineStartOffset) ?: return listOf()
|
||||||
|
val ktElement = element.parents.firstIsInstanceOrNull<KtElement>() ?: return listOf()
|
||||||
|
|
||||||
val isInInline = runReadAction { element.parents.any { it is KtFunction && it.hasModifier(KtTokens.INLINE_KEYWORD) } }
|
val isInInline = runReadAction { element.parents.any { it is KtFunction && it.hasModifier(KtTokens.INLINE_KEYWORD) } }
|
||||||
if (!isInInline) return listOf()
|
|
||||||
|
if (!isInInline) {
|
||||||
|
// Lambdas passed to crossinline arguments are inlined when they are used in non-inlined lambdas
|
||||||
|
val isInCrossinlineArgument = isInCrossinlineArgument(ktElement)
|
||||||
|
if (!isInCrossinlineArgument) {
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val lines = inlinedLinesNumbers(line + 1, position.file.name, FqName(type.name()), type.sourceName(), project, sourceSearchScope)
|
val lines = inlinedLinesNumbers(line + 1, position.file.name, FqName(type.name()), type.sourceName(), project, sourceSearchScope)
|
||||||
val inlineLocations = lines.flatMap { type.locationsOfLine(it) }
|
val inlineLocations = lines.flatMap { type.locationsOfLine(it) }
|
||||||
@@ -264,6 +275,25 @@ internal fun getLocationsOfInlinedLine(type: ReferenceType, position: SourcePosi
|
|||||||
return inlineLocations
|
return inlineLocations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isInCrossinlineArgument(ktElement: KtElement): Boolean {
|
||||||
|
val argumentFunctions = runReadAction {
|
||||||
|
ktElement.parents.filter {
|
||||||
|
when (it) {
|
||||||
|
is KtFunctionLiteral -> it.parent is KtLambdaExpression && (it.parent.parent is KtValueArgument || it.parent.parent is KtLambdaArgument)
|
||||||
|
is KtFunction -> it.parent is KtValueArgument
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}.filterIsInstance<KtFunction>()
|
||||||
|
}
|
||||||
|
|
||||||
|
val bindingContext = ktElement.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
return argumentFunctions.any {
|
||||||
|
val argumentDescriptor = InlineUtil.getInlineArgumentDescriptor(it, bindingContext)
|
||||||
|
argumentDescriptor?.isCrossinline ?: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun inlinedLinesNumbers(
|
private fun inlinedLinesNumbers(
|
||||||
inlineLineNumber: Int, inlineFileName: String,
|
inlineLineNumber: Int, inlineFileName: String,
|
||||||
destinationTypeFqName: FqName, destinationFileName: String,
|
destinationTypeFqName: FqName, destinationFileName: String,
|
||||||
@@ -281,7 +311,7 @@ private fun inlinedLinesNumbers(
|
|||||||
|
|
||||||
val smap = smapData.kotlinStrata ?: return listOf()
|
val smap = smapData.kotlinStrata ?: return listOf()
|
||||||
|
|
||||||
val mappingsToInlinedFile = smap.fileMappings.filter() { it.name == inlineFileName }
|
val mappingsToInlinedFile = smap.fileMappings.filter { it.name == inlineFileName }
|
||||||
val mappingIntervals = mappingsToInlinedFile.flatMap { it.lineMappings }
|
val mappingIntervals = mappingsToInlinedFile.flatMap { it.lineMappings }
|
||||||
|
|
||||||
val mappedLines = mappingIntervals.asSequence().
|
val mappedLines = mappingIntervals.asSequence().
|
||||||
|
|||||||
+1
-1
@@ -188,7 +188,7 @@ private fun getInlineFunctionsIfAny(file: KtFile, offset: Int): List<KtNamedFunc
|
|||||||
private fun getInlineArgumentsIfAny(inlineFunctionCalls: List<KtCallExpression>): List<KtFunction> {
|
private fun getInlineArgumentsIfAny(inlineFunctionCalls: List<KtCallExpression>): List<KtFunction> {
|
||||||
return inlineFunctionCalls.flatMap {
|
return inlineFunctionCalls.flatMap {
|
||||||
it.valueArguments
|
it.valueArguments
|
||||||
.map { getArgumentExpression(it) }
|
.map(::getArgumentExpression)
|
||||||
.filterIsInstance<KtFunction>()
|
.filterIsInstance<KtFunction>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
LineBreakpoint created at stopInLambdaInInlinedCallWithCrossInline.kt:8
|
||||||
|
!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! stopInLambdaInInlinedCallWithCrossInline.StopInLambdaInInlinedCallWithCrossInlineKt
|
||||||
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
stopInLambdaInInlinedCallWithCrossInline.kt:8
|
||||||
|
stopInLambdaInInlinedCallWithCrossInline.kt:18
|
||||||
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
LineBreakpoint created at stopInLambdaInInlinedCallWithCrossInlineDex.kt:8
|
||||||
|
!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! stopInLambdaInInlinedCallWithCrossInlineDex.StopInLambdaInInlinedCallWithCrossInlineDexKt
|
||||||
|
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
stopInLambdaInInlinedCallWithCrossInlineDex.kt:8
|
||||||
|
stopInLambdaInInlinedCallWithCrossInlineDex.kt:19
|
||||||
|
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package stopInAnonymousFunctionInInlinedCallWithCrossInline
|
||||||
|
|
||||||
|
// KT-15282
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
foo(fun () {
|
||||||
|
//Breakpoint!
|
||||||
|
12
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(f: () -> Unit) {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun foo(crossinline func: () -> Int) {
|
||||||
|
bar {
|
||||||
|
func()
|
||||||
|
}
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package stopInAnonymousFunctionInInlinedCallWithCrossInlineDex
|
||||||
|
|
||||||
|
// KT-15282
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
foo(fun () {
|
||||||
|
//Breakpoint!
|
||||||
|
12
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(f: () -> Unit) {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun foo(crossinline func: () -> Int) {
|
||||||
|
bar {
|
||||||
|
func()
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package stopInLambdaInInlinedCallWithCrossInline
|
||||||
|
|
||||||
|
// KT-15282
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
foo {
|
||||||
|
//Breakpoint!
|
||||||
|
12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(f: () -> Unit) {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun foo(crossinline func: () -> Int) {
|
||||||
|
bar {
|
||||||
|
func()
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package stopInLambdaInInlinedCallWithCrossInlineDex
|
||||||
|
|
||||||
|
// KT-15282
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
foo {
|
||||||
|
//Breakpoint!
|
||||||
|
12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(f: () -> Unit) {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun foo(crossinline func: () -> Int) {
|
||||||
|
bar {
|
||||||
|
func()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -704,6 +704,18 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
|||||||
doStepOverTest(fileName);
|
doStepOverTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("stopInAnonymousFunctionInInlinedCallWithCrossInline.kt")
|
||||||
|
public void testStopInAnonymousFunctionInInlinedCallWithCrossInline() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInAnonymousFunctionInInlinedCallWithCrossInline.kt");
|
||||||
|
doStepOverTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("stopInAnonymousFunctionInInlinedCallWithCrossInlineDex.kt")
|
||||||
|
public void testStopInAnonymousFunctionInInlinedCallWithCrossInlineDex() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInAnonymousFunctionInInlinedCallWithCrossInlineDex.kt");
|
||||||
|
doStepOverTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("stopInInlineCallLocalFunLambda.kt")
|
@TestMetadata("stopInInlineCallLocalFunLambda.kt")
|
||||||
public void testStopInInlineCallLocalFunLambda() throws Exception {
|
public void testStopInInlineCallLocalFunLambda() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInInlineCallLocalFunLambda.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInInlineCallLocalFunLambda.kt");
|
||||||
@@ -746,6 +758,18 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
|||||||
doStepOverTest(fileName);
|
doStepOverTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("stopInLambdaInInlinedCallWithCrossInline.kt")
|
||||||
|
public void testStopInLambdaInInlinedCallWithCrossInline() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInLambdaInInlinedCallWithCrossInline.kt");
|
||||||
|
doStepOverTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("stopInLambdaInInlinedCallWithCrossInlineDex.kt")
|
||||||
|
public void testStopInLambdaInInlinedCallWithCrossInlineDex() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInLambdaInInlinedCallWithCrossInlineDex.kt");
|
||||||
|
doStepOverTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("stopInLambdaInlineCallLambda.kt")
|
@TestMetadata("stopInLambdaInlineCallLambda.kt")
|
||||||
public void testStopInLambdaInlineCallLambda() throws Exception {
|
public void testStopInLambdaInlineCallLambda() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInLambdaInlineCallLambda.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepping/stepOver/stopInLambdaInlineCallLambda.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user