From 519c2784ffdbbfee66dbae3198a0ff76778130dc Mon Sep 17 00:00:00 2001 From: Natalia Ukhorskaya Date: Fri, 24 Jul 2015 12:24:50 +0300 Subject: [PATCH] Debugger: allow evaluate expression in constructors --- .../caches/resolve/CodeFragmentAnalyzer.kt | 14 +++++++ .../extractFunctionForDebuggerUtil.kt | 9 +++++ .../codeFragments/primaryConstructor.kt | 12 ++++++ .../primaryConstructor.kt.fragment | 1 + .../codeFragments/secondaryConstructor.kt | 6 +++ .../secondaryConstructor.kt.fragment | 1 + .../secondaryConstructorWithoutBraces.kt | 6 +++ ...ondaryConstructorWithoutBraces.kt.fragment | 1 + .../debugger/tinyApp/outs/constructors.out | 17 +++++++++ .../multipleBreakpoints/constructors.kt | 37 +++++++++++++++++++ ...CodeFragmentHighlightingTestGenerated.java | 18 +++++++++ ...KotlinEvaluateExpressionTestGenerated.java | 6 +++ 12 files changed, 128 insertions(+) create mode 100644 idea/testData/checker/codeFragments/primaryConstructor.kt create mode 100644 idea/testData/checker/codeFragments/primaryConstructor.kt.fragment create mode 100644 idea/testData/checker/codeFragments/secondaryConstructor.kt create mode 100644 idea/testData/checker/codeFragments/secondaryConstructor.kt.fragment create mode 100644 idea/testData/checker/codeFragments/secondaryConstructorWithoutBraces.kt create mode 100644 idea/testData/checker/codeFragments/secondaryConstructorWithoutBraces.kt.fragment create mode 100644 idea/testData/debugger/tinyApp/outs/constructors.out create mode 100644 idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/constructors.kt 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 a55d4d2ac7c..da92ea12a3c 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 @@ -93,6 +93,20 @@ public class CodeFragmentAnalyzer( val dataFlowInfo: DataFlowInfo when (context) { + is JetPrimaryConstructor -> { + val descriptor = resolveSession.getClassDescriptor(context.getContainingClassOrObject(), NoLookupLocation.FROM_IDE) as ClassDescriptorWithResolutionScopes + + scopeForContextElement = descriptor.getScopeForInitializerResolution() + dataFlowInfo = DataFlowInfo.EMPTY + } + is JetSecondaryConstructor -> { + val correctedContext = context.getDelegationCall().calleeExpression!! + + val contextForElement = resolveToElement(correctedContext) + + scopeForContextElement = contextForElement[BindingContext.LEXICAL_SCOPE, correctedContext] + dataFlowInfo = DataFlowInfo.EMPTY + } is JetClassOrObject -> { val descriptor = resolveSession.getClassDescriptor(context, NoLookupLocation.FROM_IDE) as ClassDescriptorWithResolutionScopes diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt index 2a163aa5044..ee6bc1567bd 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/extractFunctionForDebuggerUtil.kt @@ -209,6 +209,10 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment } } } + contextElement is JetPrimaryConstructor -> { + val classOrObject = contextElement.getContainingClassOrObject() + insertNewInitializer(classOrObject.getOrCreateBody()) + } contextElement is JetClassOrObject -> { insertNewInitializer(contextElement.getBody()!!) } @@ -216,6 +220,11 @@ private fun addDebugExpressionBeforeContextElement(codeFragment: JetCodeFragment val block = contextElement.getBodyExpression()!! block.getStatements().firstOrNull() ?: block.getLastChild() } + contextElement is JetDeclarationWithBody && !contextElement.hasBody()-> { + val block = psiFactory.createBlock("") + val newBlock = contextElement.add(block) as JetBlockExpression + newBlock.getRBrace() + } contextElement is JetDeclarationWithBody && !contextElement.hasBlockBody()-> { wrapInRunFun(contextElement.getBodyExpression()!!) } diff --git a/idea/testData/checker/codeFragments/primaryConstructor.kt b/idea/testData/checker/codeFragments/primaryConstructor.kt new file mode 100644 index 00000000000..d2c08540cfb --- /dev/null +++ b/idea/testData/checker/codeFragments/primaryConstructor.kt @@ -0,0 +1,12 @@ +class A( + a: Int +): Base(1) { + val c = 1 + + init { + val d = 1 + val e = 1 + } +} + +open class Base(i: Int) \ No newline at end of file diff --git a/idea/testData/checker/codeFragments/primaryConstructor.kt.fragment b/idea/testData/checker/codeFragments/primaryConstructor.kt.fragment new file mode 100644 index 00000000000..8bd8aac70ae --- /dev/null +++ b/idea/testData/checker/codeFragments/primaryConstructor.kt.fragment @@ -0,0 +1 @@ +a + c + d + e \ No newline at end of file diff --git a/idea/testData/checker/codeFragments/secondaryConstructor.kt b/idea/testData/checker/codeFragments/secondaryConstructor.kt new file mode 100644 index 00000000000..74f6062ba36 --- /dev/null +++ b/idea/testData/checker/codeFragments/secondaryConstructor.kt @@ -0,0 +1,6 @@ +class A(a: Int, val a1: Int) { + + constructor(b: Int): this(b, b) {} + + val c = 1 +} \ No newline at end of file diff --git a/idea/testData/checker/codeFragments/secondaryConstructor.kt.fragment b/idea/testData/checker/codeFragments/secondaryConstructor.kt.fragment new file mode 100644 index 00000000000..5067d33f046 --- /dev/null +++ b/idea/testData/checker/codeFragments/secondaryConstructor.kt.fragment @@ -0,0 +1 @@ +a + b + c + a1 \ No newline at end of file diff --git a/idea/testData/checker/codeFragments/secondaryConstructorWithoutBraces.kt b/idea/testData/checker/codeFragments/secondaryConstructorWithoutBraces.kt new file mode 100644 index 00000000000..5db5246537a --- /dev/null +++ b/idea/testData/checker/codeFragments/secondaryConstructorWithoutBraces.kt @@ -0,0 +1,6 @@ +class A(a: Int, val a1: Int) { + + constructor(b: Int): this(b, b) + + val c = 1 +} \ No newline at end of file diff --git a/idea/testData/checker/codeFragments/secondaryConstructorWithoutBraces.kt.fragment b/idea/testData/checker/codeFragments/secondaryConstructorWithoutBraces.kt.fragment new file mode 100644 index 00000000000..5067d33f046 --- /dev/null +++ b/idea/testData/checker/codeFragments/secondaryConstructorWithoutBraces.kt.fragment @@ -0,0 +1 @@ +a + b + c + a1 \ No newline at end of file diff --git a/idea/testData/debugger/tinyApp/outs/constructors.out b/idea/testData/debugger/tinyApp/outs/constructors.out new file mode 100644 index 00000000000..f2900c80495 --- /dev/null +++ b/idea/testData/debugger/tinyApp/outs/constructors.out @@ -0,0 +1,17 @@ +LineBreakpoint created at constructors.kt:9 +LineBreakpoint created at constructors.kt:13 +LineBreakpoint created at constructors.kt:20 +LineBreakpoint created at constructors.kt:28 +!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! constructors.ConstructorsPackage +Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' +constructors.kt:9 +Compile bytecode for p +constructors.kt:13 +Compile bytecode for p + 1 +constructors.kt:20 +Compile bytecode for p1 + p2 +constructors.kt:28 +Compile bytecode for i1 +Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket' + +Process finished with exit code 0 diff --git a/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/constructors.kt b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/constructors.kt new file mode 100644 index 00000000000..f34f782dcf4 --- /dev/null +++ b/idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/constructors.kt @@ -0,0 +1,37 @@ +package constructors + +class Derived2(): Base(1) { + + // constructor with body + // EXPRESSION: p + // RESULT: 1: I + //Breakpoint! + constructor(p: Int): this() { + // EXPRESSION: p + 1 + // RESULT: 2: I + //Breakpoint! + val a = 1 + } + + // constructor without body + // EXPRESSION: p1 + p2 + // RESULT: 2: I + //Breakpoint! + constructor(p1: Int, p2: Int): this() +} + +// EXPRESSION: i1 +// RESULT: 1: I +class Derived1( + i1: Int + //Breakpoint! +): Base(i1) + +open class Base(i: Int) + +fun main(args: Array) { + Derived2(1) + Derived2(1, 1) + + Derived1(1) +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentHighlightingTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentHighlightingTestGenerated.java index 15da139a3e2..7e51879049d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentHighlightingTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/CodeFragmentHighlightingTestGenerated.java @@ -97,6 +97,12 @@ public class CodeFragmentHighlightingTestGenerated extends AbstractCodeFragmentH doTest(fileName); } + @TestMetadata("primaryConstructor.kt") + public void testPrimaryConstructor() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/checker/codeFragments/primaryConstructor.kt"); + doTest(fileName); + } + @TestMetadata("privateFunArgumentsResolve.kt") public void testPrivateFunArgumentsResolve() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/checker/codeFragments/privateFunArgumentsResolve.kt"); @@ -121,6 +127,18 @@ public class CodeFragmentHighlightingTestGenerated extends AbstractCodeFragmentH doTest(fileName); } + @TestMetadata("secondaryConstructor.kt") + public void testSecondaryConstructor() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/checker/codeFragments/secondaryConstructor.kt"); + doTest(fileName); + } + + @TestMetadata("secondaryConstructorWithoutBraces.kt") + public void testSecondaryConstructorWithoutBraces() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/checker/codeFragments/secondaryConstructorWithoutBraces.kt"); + doTest(fileName); + } + @TestMetadata("simpleNameExpression.kt") public void testSimpleNameExpression() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/checker/codeFragments/simpleNameExpression.kt"); 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 a45b7a497fb..4072e2dae1f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/debugger/evaluate/KotlinEvaluateExpressionTestGenerated.java @@ -652,6 +652,12 @@ public class KotlinEvaluateExpressionTestGenerated extends AbstractKotlinEvaluat doMultipleBreakpointsTest(fileName); } + @TestMetadata("constructors.kt") + public void testConstructors() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/constructors.kt"); + doMultipleBreakpointsTest(fileName); + } + @TestMetadata("exceptions.kt") public void testExceptions() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/evaluate/multipleBreakpoints/exceptions.kt");