From 9bcc9e4b1d8309db8dd9c4b1cd3e178f2af178b1 Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Wed, 25 Nov 2015 17:10:36 +0300 Subject: [PATCH] Smart step into for constructors --- .../stepping/KotlinBasicStepMethodFilter.kt | 18 +++----- .../stepping/KotlinSmartStepIntoHandler.kt | 20 ++++++--- .../debugger/smartStepInto/constructor.kt | 44 +++++++++++++++++++ .../debugger/smartStepInto/renderer.kt | 1 + .../debugger/SmartStepIntoTestGenerated.java | 6 +++ 5 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 idea/testData/debugger/smartStepInto/constructor.kt diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinBasicStepMethodFilter.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinBasicStepMethodFilter.kt index 5eaedff0185..6ad5036720e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinBasicStepMethodFilter.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinBasicStepMethodFilter.kt @@ -21,26 +21,22 @@ import com.intellij.debugger.engine.DebugProcessImpl import com.intellij.debugger.engine.NamedMethodFilter import com.intellij.util.Range import com.sun.jdi.Location -import com.sun.jdi.Method -import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.load.java.JvmAbi -import org.jetbrains.kotlin.psi.KtConstructor -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.psi.KtProperty -import org.jetbrains.kotlin.psi.KtPropertyAccessor +import org.jetbrains.kotlin.psi.* public class KotlinBasicStepMethodFilter( - val resolvedFunction: KtElement, + val resolvedElement: KtElement, val myCallingExpressionLines: Range ) : NamedMethodFilter { private val myTargetMethodName: String init { - myTargetMethodName = when (resolvedFunction) { + myTargetMethodName = when (resolvedElement) { + is KtAnonymousInitializer -> "" is KtConstructor<*> -> "" - is KtPropertyAccessor -> JvmAbi.getterName((resolvedFunction.getParent() as KtProperty).getName()!!) - else -> resolvedFunction.getName()!! + is KtPropertyAccessor -> JvmAbi.getterName((resolvedElement.getParent() as KtProperty).getName()!!) + else -> resolvedElement.getName()!! } } @@ -52,7 +48,7 @@ public class KotlinBasicStepMethodFilter( val method = location.method() if (myTargetMethodName != method.name()) return false - val sourcePosition = runReadAction { SourcePosition.createFromElement(resolvedFunction) } ?: return false + val sourcePosition = runReadAction { SourcePosition.createFromElement(resolvedElement) } ?: return false val positionManager = process.getPositionManager() ?: return false val classes = positionManager.getAllClasses(sourcePosition) diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt index 3ef1fd1d64a..6f3ae9e1e90 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/stepping/KotlinSmartStepIntoHandler.kt @@ -27,6 +27,7 @@ import com.intellij.util.Range import com.intellij.util.containers.OrderedSet import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully @@ -64,7 +65,6 @@ public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() { // TODO support class initializers, local functions, delegated properties with specified type, setter for properties element.accept(object: KtTreeVisitorVoid() { - override fun visitFunctionLiteralExpression(expression: KtFunctionLiteralExpression) { recordFunctionLiteral(expression.functionLiteral) } @@ -175,14 +175,20 @@ public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() { val resolvedCall = expression.getResolvedCall(bindingContext) ?: return val descriptor = resolvedCall.getResultingDescriptor() - if (descriptor is CallableMemberDescriptor && !isIntrinsic(descriptor)) { - val function = DescriptorToSourceUtilsIde.getAnyDeclaration(file.getProject(), descriptor) - if (function is KtNamedFunction || function is KtSecondaryConstructor) { + if (descriptor is FunctionDescriptor && !isIntrinsic(descriptor)) { + val resolvedElement = DescriptorToSourceUtilsIde.getAnyDeclaration(file.getProject(), descriptor) + if (resolvedElement is KtNamedFunction || resolvedElement is KtConstructor<*>) { val label = KotlinMethodSmartStepTarget.calcLabel(descriptor) - result.add(KotlinMethodSmartStepTarget(function as KtFunction, label, expression, lines)) + result.add(KotlinMethodSmartStepTarget(resolvedElement as KtFunction, label, expression, lines)) } - else if (function is PsiMethod) { - result.add(MethodSmartStepTarget(function, null, expression, false, lines)) + else if (resolvedElement is PsiMethod) { + result.add(MethodSmartStepTarget(resolvedElement, null, expression, false, lines)) + } + else if (resolvedElement is KtClass) { + resolvedElement.getAnonymousInitializers().firstOrNull()?.let { + val label = KotlinMethodSmartStepTarget.calcLabel(descriptor) + result.add(KotlinMethodSmartStepTarget(it, label, expression, lines)) + } } } } diff --git a/idea/testData/debugger/smartStepInto/constructor.kt b/idea/testData/debugger/smartStepInto/constructor.kt new file mode 100644 index 00000000000..55c6ae92cb9 --- /dev/null +++ b/idea/testData/debugger/smartStepInto/constructor.kt @@ -0,0 +1,44 @@ +fun foo() { + println("${A()} ${B()} ${C(1)} ${D()} ${E(1)} ${F()} ${G()} ${J()} ${K(1)} ${L()}") +} + +class A +class B() +class C(val a: Int) +class D { + constructor() +} +class E { + constructor(i: Int) +} +class F { + constructor() { + + } +} +class G { + constructor(i: Int) { + + } +} +class J { + init { + + } +} +class K(val a: Int) { + init { + + } +} +class L { + constructor() { + + } + + init { + + } +} + +// EXISTS: println(Any?), constructor B(), constructor C(Int), constructor D(), constructor E(Int), constructor F(), constructor G(Int), constructor J(), constructor K(Int), constructor L() \ No newline at end of file diff --git a/idea/testData/debugger/smartStepInto/renderer.kt b/idea/testData/debugger/smartStepInto/renderer.kt index e85683bbbd1..5a86c2b65f5 100644 --- a/idea/testData/debugger/smartStepInto/renderer.kt +++ b/idea/testData/debugger/smartStepInto/renderer.kt @@ -25,4 +25,5 @@ val propFoo: Int // EXISTS: fooWithParam: f.invoke() // EXISTS: test() // EXISTS: constructor FooClass() +// EXISTS: constructor FooClass(Int) // EXISTS: constructor FooClass(Int\, Int) \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/SmartStepIntoTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/SmartStepIntoTestGenerated.java index 2cc9da56eec..3f0ce477476 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/SmartStepIntoTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/SmartStepIntoTestGenerated.java @@ -53,6 +53,12 @@ public class SmartStepIntoTestGenerated extends AbstractSmartStepIntoTest { doTest(fileName); } + @TestMetadata("constructor.kt") + public void testConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/smartStepInto/constructor.kt"); + doTest(fileName); + } + @TestMetadata("conventionMethod.kt") public void testConventionMethod() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/debugger/smartStepInto/conventionMethod.kt");