diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt index ed277c3d913..6a3e7850517 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/CodeFragmentAnalyzer.kt @@ -24,7 +24,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.codeFragmentUtil.suppressDiagnosticsInDebugMode 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.bindingContextUtil.getDataFlowInfoAfter import org.jetbrains.kotlin.resolve.calls.components.InferenceSession @@ -94,7 +94,7 @@ class CodeFragmentAnalyzer( 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 dataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY var scope: LexicalScope? = null @@ -127,7 +127,10 @@ class CodeFragmentAnalyzer( val functionDescriptor = bindingContextForFunction[BindingContext.FUNCTION, context] if (functionDescriptor != null) { bindingContext = bindingContextForFunction + + @Suppress("NON_TAIL_RECURSIVE_CALL") val outerScope = getContextInfo(context.getParentOfType(true), resolutionFactory).scope + val localRedeclarationChecker = LocalRedeclarationChecker.DO_NOTHING scope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, localRedeclarationChecker) } @@ -144,7 +147,7 @@ class CodeFragmentAnalyzer( } if (scope == null) { - val parentDeclaration = context?.getParentOfTypes2() + val parentDeclaration = context?.getParentOfTypes3() if (parentDeclaration != null) { return getContextInfo(parentDeclaration, resolutionFactory) } diff --git a/idea/jvm-debugger/jvm-debugger-util/src/org/jetbrains/kotlin/idea/debugger/CodeFragmentContextUtils.kt b/idea/jvm-debugger/jvm-debugger-util/src/org/jetbrains/kotlin/idea/debugger/CodeFragmentContextUtils.kt index 5d1084f45fc..e9fa08a99dd 100644 --- a/idea/jvm-debugger/jvm-debugger-util/src/org/jetbrains/kotlin/idea/debugger/CodeFragmentContextUtils.kt +++ b/idea/jvm-debugger/jvm-debugger-util/src/org/jetbrains/kotlin/idea/debugger/CodeFragmentContextUtils.kt @@ -8,10 +8,10 @@ package org.jetbrains.kotlin.idea.debugger import com.intellij.psi.* import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.asJava.classes.KtLightClass -import org.jetbrains.kotlin.idea.core.util.CodeInsightUtils -import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.idea.debugger.KotlinEditorTextProvider.Companion.isAcceptedAsCodeFragmentContext import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.psiUtil.parents fun getContextElement(elementAt: PsiElement?): PsiElement? { if (elementAt == null) return null @@ -36,15 +36,21 @@ fun getContextElement(elementAt: PsiElement?): PsiElement? { 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) - ?.takeIfAcceptedAsCodeFragmentContext() - ?.let { return CodeInsightUtils.getTopmostElementAtOffset(it, lineStartOffset, KtExpression::class.java) } + if (targetExpression != null) { + if (isAcceptedAsCodeFragmentContext(targetExpression)) { + return targetExpression + } - KotlinEditorTextProvider.findExpressionInner(elementAt, true) - ?.takeIfAcceptedAsCodeFragmentContext() - ?.let { return it } + KotlinEditorTextProvider.findExpressionInner(elementAt, true) + ?.takeIf { isAcceptedAsCodeFragmentContext(it) } + ?.let { return it } + + targetExpression.parents + .firstOrNull { isAcceptedAsCodeFragmentContext(it) } + ?.let { return it } + } return containingFile } \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/valueParameterName.kt b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/valueParameterName.kt new file mode 100644 index 00000000000..a1810ffd3e8 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/valueParameterName.kt @@ -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; \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/valueParameterName.out b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/valueParameterName.out new file mode 100644 index 00000000000..a06fef7a49e --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/valueParameterName.out @@ -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 diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java index fe545f7d2cf..335a58e76d7 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -406,6 +406,11 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat 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") public void testVars() throws Exception { runTest("idea/testData/debugger/tinyApp/src/evaluate/singleBreakpoint/vars.kt");