Debugger: Fix evaluation on value parameter name position (KT-30976)
This commit is contained in:
+6
-3
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
|||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
|
import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypes2
|
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypes3
|
||||||
import org.jetbrains.kotlin.resolve.*
|
import org.jetbrains.kotlin.resolve.*
|
||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
|
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
|
||||||
@@ -94,7 +94,7 @@ class CodeFragmentAnalyzer(
|
|||||||
return info.copy(scope = enrichScopeWithImports(info.scope, codeFragment))
|
return info.copy(scope = enrichScopeWithImports(info.scope, codeFragment))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getContextInfo(context: PsiElement?, resolutionFactory: (KtElement) -> BindingContext): ContextInfo {
|
private tailrec fun getContextInfo(context: PsiElement?, resolutionFactory: (KtElement) -> BindingContext): ContextInfo {
|
||||||
var bindingContext: BindingContext = BindingContext.EMPTY
|
var bindingContext: BindingContext = BindingContext.EMPTY
|
||||||
var dataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY
|
var dataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY
|
||||||
var scope: LexicalScope? = null
|
var scope: LexicalScope? = null
|
||||||
@@ -127,7 +127,10 @@ class CodeFragmentAnalyzer(
|
|||||||
val functionDescriptor = bindingContextForFunction[BindingContext.FUNCTION, context]
|
val functionDescriptor = bindingContextForFunction[BindingContext.FUNCTION, context]
|
||||||
if (functionDescriptor != null) {
|
if (functionDescriptor != null) {
|
||||||
bindingContext = bindingContextForFunction
|
bindingContext = bindingContextForFunction
|
||||||
|
|
||||||
|
@Suppress("NON_TAIL_RECURSIVE_CALL")
|
||||||
val outerScope = getContextInfo(context.getParentOfType<KtDeclaration>(true), resolutionFactory).scope
|
val outerScope = getContextInfo(context.getParentOfType<KtDeclaration>(true), resolutionFactory).scope
|
||||||
|
|
||||||
val localRedeclarationChecker = LocalRedeclarationChecker.DO_NOTHING
|
val localRedeclarationChecker = LocalRedeclarationChecker.DO_NOTHING
|
||||||
scope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, localRedeclarationChecker)
|
scope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, localRedeclarationChecker)
|
||||||
}
|
}
|
||||||
@@ -144,7 +147,7 @@ class CodeFragmentAnalyzer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (scope == null) {
|
if (scope == null) {
|
||||||
val parentDeclaration = context?.getParentOfTypes2<KtDeclaration, KtFile>()
|
val parentDeclaration = context?.getParentOfTypes3<KtDeclaration, KtFile, KtExpression>()
|
||||||
if (parentDeclaration != null) {
|
if (parentDeclaration != null) {
|
||||||
return getContextInfo(parentDeclaration, resolutionFactory)
|
return getContextInfo(parentDeclaration, resolutionFactory)
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-9
@@ -8,10 +8,10 @@ package org.jetbrains.kotlin.idea.debugger
|
|||||||
import com.intellij.psi.*
|
import com.intellij.psi.*
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
import org.jetbrains.kotlin.asJava.classes.KtLightClass
|
||||||
import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils
|
import org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider.Companion.isAcceptedAsCodeFragmentContext
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
|
|
||||||
fun getContextElement(elementAt: PsiElement?): PsiElement? {
|
fun getContextElement(elementAt: PsiElement?): PsiElement? {
|
||||||
if (elementAt == null) return null
|
if (elementAt == null) return null
|
||||||
@@ -36,15 +36,21 @@ fun getContextElement(elementAt: PsiElement?): PsiElement? {
|
|||||||
elementAt.textOffset
|
elementAt.textOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KtElement.takeIfAcceptedAsCodeFragmentContext() = takeIf { KotlinEditorTextProvider.isAcceptedAsCodeFragmentContext(it) }
|
val targetExpression = PsiTreeUtil.findElementOfClassAtOffset(containingFile, lineStartOffset, KtExpression::class.java, false)
|
||||||
|
|
||||||
PsiTreeUtil.findElementOfClassAtOffset(containingFile, lineStartOffset, KtExpression::class.java, false)
|
if (targetExpression != null) {
|
||||||
?.takeIfAcceptedAsCodeFragmentContext()
|
if (isAcceptedAsCodeFragmentContext(targetExpression)) {
|
||||||
?.let { return CodeInsightUtils.getTopmostElementAtOffset(it, lineStartOffset, KtExpression::class.java) }
|
return targetExpression
|
||||||
|
}
|
||||||
|
|
||||||
KotlinEditorTextProvider.findExpressionInner(elementAt, true)
|
KotlinEditorTextProvider.findExpressionInner(elementAt, true)
|
||||||
?.takeIfAcceptedAsCodeFragmentContext()
|
?.takeIf { isAcceptedAsCodeFragmentContext(it) }
|
||||||
?.let { return it }
|
?.let { return it }
|
||||||
|
|
||||||
|
targetExpression.parents
|
||||||
|
.firstOrNull { isAcceptedAsCodeFragmentContext(it) }
|
||||||
|
?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
return containingFile
|
return containingFile
|
||||||
}
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package valueParameterName
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
"foo".foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.foo() {
|
||||||
|
val a = Foo(
|
||||||
|
a = this
|
||||||
|
)
|
||||||
|
val b = Foo(
|
||||||
|
//Breakpoint!
|
||||||
|
a = this
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Foo(val a: String)
|
||||||
|
|
||||||
|
// EXPRESSION: this
|
||||||
|
// RESULT: "foo": Ljava/lang/String;
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
LineBreakpoint created at valueParameterName.kt:13
|
||||||
|
Run Java
|
||||||
|
Connected to the target VM
|
||||||
|
valueParameterName.kt:13
|
||||||
|
Compile bytecode for this
|
||||||
|
Disconnected from the target VM
|
||||||
|
|
||||||
|
Process finished with exit code 0
|
||||||
Generated
+5
@@ -406,6 +406,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat
|
|||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/unsafeCall.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/unsafeCall.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("valueParameterName.kt")
|
||||||
|
public void testValueParameterName() throws Exception {
|
||||||
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/valueParameterName.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("vars.kt")
|
@TestMetadata("vars.kt")
|
||||||
public void testVars() throws Exception {
|
public void testVars() throws Exception {
|
||||||
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/vars.kt");
|
runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/vars.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user