Skip to content

Commit 68f722b

Browse files
NataliaUkhorskayaNikolay Krasko
authored andcommitted
Debugger: fix evaluate expression when breakpoint is set on function without body inside object
#KT-15855 Fixed
1 parent faac1c3 commit 68f722b

File tree

3 files changed

+23
-19
lines changed

3 files changed

+23
-19
lines changed

idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,9 @@ import com.intellij.psi.PsiElement
2424
import com.intellij.psi.PsiFile
2525
import com.intellij.util.ExceptionUtil
2626
import org.jetbrains.kotlin.idea.actions.internal.KotlinInternalMode
27-
import org.jetbrains.kotlin.idea.caches.resolve.analyze
2827
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
2928
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
3029
import org.jetbrains.kotlin.idea.core.replaced
31-
import org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention
3230
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*
3331
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.AnalysisResult.ErrorMessage
3432
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.AnalysisResult.Status
@@ -42,7 +40,6 @@ import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
4240
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
4341
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
4442
import org.jetbrains.kotlin.renderer.DescriptorRenderer
45-
import org.jetbrains.kotlin.resolve.BindingContext.IMPLICIT_RECEIVER_SMARTCAST
4643
import org.jetbrains.kotlin.resolve.BindingContext.SMARTCAST
4744

4845
fun getFunctionForExtractedFragment(
@@ -290,12 +287,12 @@ private fun findElementBefore(contextElement: PsiElement): PsiElement? {
290287
contextElement is KtProperty && !contextElement.isLocal -> {
291288
val delegateExpressionOrInitializer = contextElement.delegateExpressionOrInitializer
292289
if (delegateExpressionOrInitializer != null) {
293-
wrapInRunFun(delegateExpressionOrInitializer)
290+
wrapInLambdaCall(delegateExpressionOrInitializer)
294291
}
295292
else {
296293
val getter = contextElement.getter!!
297294
if (!getter.hasBlockBody()) {
298-
wrapInRunFun(getter.bodyExpression!!)
295+
wrapInLambdaCall(getter.bodyExpression!!)
299296
}
300297
else {
301298
(getter.bodyExpression as KtBlockExpression).statements.first()
@@ -323,7 +320,7 @@ private fun findElementBefore(contextElement: PsiElement): PsiElement? {
323320
newBlock.rBrace
324321
}
325322
contextElement is KtDeclarationWithBody && !contextElement.hasBlockBody() -> {
326-
wrapInRunFun(contextElement.bodyExpression!!)
323+
wrapInLambdaCall(contextElement.bodyExpression!!)
327324
}
328325
contextElement is KtDeclarationWithBody && contextElement.hasBlockBody() -> {
329326
val block = contextElement.bodyExpression as KtBlockExpression
@@ -336,7 +333,7 @@ private fun findElementBefore(contextElement: PsiElement): PsiElement? {
336333
entryExpression.statements.firstOrNull() ?: entryExpression.lastChild
337334
}
338335
else {
339-
wrapInRunFun(entryExpression!!)
336+
wrapInLambdaCall(entryExpression!!)
340337
}
341338
}
342339
else -> {
@@ -345,18 +342,12 @@ private fun findElementBefore(contextElement: PsiElement): PsiElement? {
345342
}
346343
}
347344

348-
private fun replaceByRunFunction(expression: KtExpression): KtCallExpression {
349-
val callExpression = KtPsiFactory(expression).createExpression("run { \n${expression.text} \n}") as KtCallExpression
350-
val replaced = expression.replaced(callExpression)
351-
val typeArguments = InsertExplicitTypeArgumentsIntention.createTypeArguments(replaced, replaced.analyze())
352-
if (typeArguments?.arguments?.isNotEmpty() ?: false) {
353-
val calleeExpression = replaced.calleeExpression
354-
replaced.addAfter(typeArguments!!, calleeExpression)
355-
}
356-
return replaced
345+
private fun replaceByLambdaCall(expression: KtExpression): KtCallExpression {
346+
val callExpression = KtPsiFactory(expression).createExpression("{ \n${expression.text} \n}()") as KtCallExpression
347+
return expression.replaced(callExpression)
357348
}
358349

359-
private fun wrapInRunFun(expression: KtExpression): PsiElement? {
360-
val replacedBody = replaceByRunFunction(expression)
361-
return replacedBody.lambdaArguments.first().getLambdaExpression().bodyExpression?.firstChild
350+
private fun wrapInLambdaCall(expression: KtExpression): PsiElement? {
351+
val replacedBody = replaceByLambdaCall(expression)
352+
return (replacedBody.calleeExpression as? KtLambdaExpression)?.bodyExpression?.firstChild
362353
}

idea/testData/debugger/tinyApp/outs/withoutBodyFunctions.out

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ LineBreakpoint created at withoutBodyFunctions.kt:21
44
LineBreakpoint created at withoutBodyFunctions.kt:27
55
LineBreakpoint created at withoutBodyFunctions.kt:32
66
LineBreakpoint created at withoutBodyFunctions.kt:37
7+
LineBreakpoint created at withoutBodyFunctions.kt:43
78
!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! withoutBodyFunctions.WithoutBodyFunctionsKt
89
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
910
withoutBodyFunctions.kt:9
@@ -18,6 +19,8 @@ withoutBodyFunctions.kt:32
1819
Compile bytecode for i
1920
withoutBodyFunctions.kt:37
2021
Compile bytecode for i
22+
withoutBodyFunctions.kt:43
23+
Compile bytecode for test2()
2124
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
2225

2326
Process finished with exit code 0

idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/withoutBodyFunctions.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ fun fooOneLine(i: Int): Int { return 1 }
3636
//Breakpoint!
3737
fun fooEmpty(i: Int) {}
3838

39+
object A {
40+
// EXPRESSION: test2()
41+
// RESULT: 2: I
42+
//Breakpoint!
43+
@JvmStatic fun fooWithoutBodyInsideObject() = test2()
44+
fun test2() = 2
45+
}
46+
3947
fun main(args: Array<String>) {
4048
aGet
4149
aGet2
@@ -44,4 +52,6 @@ fun main(args: Array<String>) {
4452
foo(2)
4553
fooOneLine(2)
4654
fooEmpty(2)
55+
56+
A.fooWithoutBodyInsideObject()
4757
}

0 commit comments

Comments
 (0)