SmartStepInto in top level functions. Add test for debugger

#KT-4737 Fixed
This commit is contained in:
Natalia Ukhorskaya
2014-03-28 11:48:39 +04:00
parent 4aa3dff2a2
commit 32a6205d81
39 changed files with 800 additions and 19 deletions
@@ -0,0 +1,6 @@
<root>
<item
name='com.intellij.debugger.ExecutionWithDebuggerToolsTestCase void onBreakpoint(com.intellij.debugger.engine.SuspendContextRunnable) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -0,0 +1,16 @@
<root>
<item
name='com.intellij.debugger.engine.MethodFilter boolean locationMatches(com.intellij.debugger.engine.DebugProcessImpl, com.sun.jdi.Location) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item
name='com.intellij.debugger.engine.MethodFilter boolean locationMatches(com.intellij.debugger.engine.DebugProcessImpl, com.sun.jdi.Location) 1'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.intellij.debugger.engine.SuspendContextImpl'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='com.intellij.debugger.engine.SuspendContextRunnable void run(com.intellij.debugger.engine.SuspendContextImpl) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -0,0 +1,5 @@
<root>
<item name='com.intellij.debugger.impl.OutputChecker'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -0,0 +1,5 @@
<root>
<item name='com.intellij.execution.ExecutionTestCase java.lang.String getTestAppPath()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
+5
View File
@@ -0,0 +1,5 @@
<root>
<item name='com.sun.jdi.Location com.sun.jdi.Method method()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -48,7 +48,7 @@ public class MockLibraryUtil {
File contentDir = JetTestUtils.tmpDir("lib-content");
File classesDir = new File(contentDir, "classes");
compile(sourcesPath, classesDir);
compileKotlin(sourcesPath, classesDir);
List<File> javaFiles = FileUtil.findFilesByMask(Pattern.compile(".*\\.java"), new File(sourcesPath));
if (!javaFiles.isEmpty()) {
@@ -88,7 +88,7 @@ public class MockLibraryUtil {
}
// Runs compiler in custom class loader to avoid effects caused by replacing Application with another one created in compiler.
private static void compile(String sourcesPath, File outDir) {
public static void compileKotlin(@NotNull String sourcesPath, @NotNull File outDir) {
try {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
Class<?> compilerClass = getCompilerClass();
@@ -102,6 +102,7 @@ import org.jetbrains.jet.plugin.imports.AbstractOptimizeImportsTest
import org.jetbrains.jet.plugin.debugger.AbstractSmartStepIntoTest
import org.jetbrains.jet.plugin.stubs.AbstractStubBuilderTest
import org.jetbrains.jet.plugin.codeInsight.AbstractJetInspectionTest
import org.jetbrains.jet.plugin.debugger.AbstractKotlinSteppingTest
fun main(args: Array<String>) {
System.setProperty("java.awt.headless", "true")
@@ -540,6 +541,11 @@ fun main(args: Array<String>) {
model("debugger/smartStepInto")
}
testClass(javaClass<AbstractKotlinSteppingTest>()) {
model("debugger/tinyApp/src/stepInto", testMethod = "doStepIntoTest", testClassName = "StepInto")
model("debugger/tinyApp/src/stepInto", testMethod = "doSmartStepIntoTest", testClassName = "SmartStepInto")
}
testClass(javaClass<AbstractStubBuilderTest>()) {
model("stubs", extension = "kt")
}
@@ -33,6 +33,13 @@ import com.intellij.psi.PsiElement
import com.intellij.util.text.CharArrayUtil
import org.jetbrains.jet.lang.psi.*
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor
import com.intellij.debugger.engine.MethodFilter
import com.intellij.debugger.engine.BasicStepMethodFilter
import com.intellij.debugger.engine.DebugProcessImpl
import com.sun.jdi.Location
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiFile
import com.intellij.openapi.editor.Editor
public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
@@ -122,19 +129,19 @@ public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
}
override fun visitSimpleNameExpression(expression: JetSimpleNameExpression) {
val resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression)
val resolvedCall = bindingContext[BindingContext.RESOLVED_CALL, expression]
if (resolvedCall != null) {
val propertyDescriptor = resolvedCall.getResultingDescriptor()
if (propertyDescriptor is PropertyDescriptor) {
val getterDescriptor = propertyDescriptor.getGetter()
if (getterDescriptor != null && !getterDescriptor.isDefault()) {
val delegatedResolvedCall = bindingContext.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor)
val delegatedResolvedCall = bindingContext[BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, getterDescriptor]
if (delegatedResolvedCall == null) {
val getter = BindingContextUtils.callableDescriptorToDeclaration(bindingContext, getterDescriptor)
if (getter is JetPropertyAccessor && (getter.getBodyExpression() != null || getter.getEqualsToken() != null)) {
val psiMethod = LightClassUtil.getLightClassAccessorMethod(getter)
if (psiMethod != null) {
result.add(MethodSmartStepTarget(psiMethod, null, expression, false, lines))
result.add(KotlinMethodSmartStepTarget(getter, psiMethod, null, expression, false, lines))
}
}
}
@@ -145,7 +152,7 @@ public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
if (function is JetNamedFunction) {
val psiMethod = LightClassUtil.getLightClassMethod(function)
if (psiMethod != null) {
result.add(MethodSmartStepTarget(psiMethod, "${propertyDescriptor.getName()}.", expression, false, lines))
result.add(KotlinMethodSmartStepTarget(function, psiMethod, "${propertyDescriptor.getName()}.", expression, false, lines))
}
}
}
@@ -157,7 +164,7 @@ public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
}
private fun recordFunction(expression: JetExpression) {
val resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression)
val resolvedCall = bindingContext[BindingContext.RESOLVED_CALL, expression]
if (resolvedCall == null) return
val descriptor = resolvedCall.getResultingDescriptor()
@@ -166,7 +173,7 @@ public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
if (function is JetNamedFunction) {
val psiMethod = LightClassUtil.getLightClassMethod(function)
if (psiMethod != null) {
result.add(MethodSmartStepTarget(psiMethod, null, expression, false, lines))
result.add(KotlinMethodSmartStepTarget(function, psiMethod, null, expression, false, lines))
}
}
}
@@ -176,6 +183,32 @@ public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
return result
}
override fun createMethodFilter(stepTarget: SmartStepTarget?): MethodFilter? {
if (stepTarget is KotlinMethodSmartStepTarget) {
return KotlinBasicStepMethodFilter(stepTarget)
}
return super.createMethodFilter(stepTarget)
}
class KotlinBasicStepMethodFilter(val stepTarget: KotlinMethodSmartStepTarget): BasicStepMethodFilter(stepTarget.getMethod(), stepTarget.getCallingExpressionLines()) {
override fun locationMatches(process: DebugProcessImpl, location: Location): Boolean {
if (super.locationMatches(process, location)) return true
val containingFile = stepTarget.resolvedElement.getContainingFile()
if (containingFile !is JetFile) return false
val positionManager = process.getPositionManager()
if (positionManager == null) return false
val classes = positionManager.getAllClasses(MockSourcePosition(_file = containingFile, _elementAt = stepTarget.resolvedElement))
val method = location.method()
return stepTarget.getMethod().getName() == method.name() &&
myTargetMethodSignature?.getName(process) == method.signature() &&
classes.contains(location.declaringType())
}
}
private fun getTopmostElementAtOffset(element: PsiElement, offset: Int): PsiElement? {
var resultElement: PsiElement? = element
while (resultElement?.getParent()?.getTextRange() != null &&
@@ -185,4 +218,12 @@ public class KotlinSmartStepIntoHandler : JvmSmartStepIntoHandler() {
return resultElement
}
class KotlinMethodSmartStepTarget(val resolvedElement: JetElement,
psiMethod: PsiMethod,
label: String?,
highlightElement: PsiElement,
needBreakpointRequest: Boolean,
lines: Range<Int>
): MethodSmartStepTarget(psiMethod, label, highlightElement, needBreakpointRequest, lines)
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.debugger
import com.intellij.psi.PsiElement
import com.intellij.debugger.SourcePosition
import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiFile
class MockSourcePosition(
val _file: PsiFile? = null,
val _elementAt: PsiElement? = null,
val _line: Int? = null,
val _offset: Int? = null,
val _editor: Editor? = null
): SourcePosition() {
override fun getFile() = _file ?: throw UnsupportedOperationException("Parameter file isn't set for MockSourcePosition")
override fun getElementAt() = _elementAt ?: throw UnsupportedOperationException("Parameter elementAt isn't set for MockSourcePosition")
override fun getLine() = _line ?: throw UnsupportedOperationException("Parameter line isn't set for MockSourcePosition")
override fun getOffset() = _offset ?: throw UnsupportedOperationException("Parameter offset isn't set for MockSourcePosition")
override fun openEditor(requestFocus: Boolean) = _editor ?: throw UnsupportedOperationException("Parameter editor isn't set for MockSourcePosition")
override fun navigate(requestFocus: Boolean) = throw UnsupportedOperationException("navigate() isn't supported for MockSourcePosition")
override fun canNavigate() = throw UnsupportedOperationException("canNavigate() isn't supported for MockSourcePosition")
override fun canNavigateToSource() = throw UnsupportedOperationException("canNavigateToSource() isn't supported for MockSourcePosition")
}
@@ -0,0 +1,8 @@
LineBreakpoint created at classObjectFunFromClass.kt:6
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! classObjectFunFromClass.ClassObjectFunFromClassPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
classObjectFunFromClass.kt:5
classObjectFunFromClass.kt:10
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,8 @@
LineBreakpoint created at classObjectFunFromTopLevel.kt:13
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! classObjectFunFromTopLevel.ClassObjectFunFromTopLevelPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
classObjectFunFromTopLevel.kt:12
classObjectFunFromTopLevel.kt:5
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,8 @@
LineBreakpoint created at extFun.kt:12
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! extFun.ExtFunPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
extFun.kt:11
extFun.kt:5
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,8 @@
LineBreakpoint created at memberFunFromClass.kt:6
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! memberFunFromClass.MemberFunFromClassPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
memberFunFromClass.kt:5
memberFunFromClass.kt:9
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,8 @@
LineBreakpoint created at memberFunFromTopLevel.kt:11
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! memberFunFromTopLevel.MemberFunFromTopLevelPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
memberFunFromTopLevel.kt:10
memberFunFromTopLevel.kt:4
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,8 @@
LineBreakpoint created at memberGetterFromClass.kt:6
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! memberGetterFromClass.MemberGetterFromClassPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
memberGetterFromClass.kt:5
memberGetterFromClass.kt:10
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,8 @@
LineBreakpoint created at memberGetterFromTopLevel.kt:13
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! memberGetterFromTopLevel.MemberGetterFromTopLevelPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
memberGetterFromTopLevel.kt:12
memberGetterFromTopLevel.kt:5
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,8 @@
LineBreakpoint created at objectFun.kt:11
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! objectFun.ObjectFunPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
objectFun.kt:10
objectFun.kt:4
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,8 @@
LineBreakpoint created at topLevelFunFromClass.kt:6
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! topLevelFunFromClass.TopLevelFunFromClassPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
topLevelFunFromClass.kt:5
topLevelFunFromClass.kt:10
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,8 @@
LineBreakpoint created at topLevelFunFromTopLevel.kt:9
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! topLevelFunFromTopLevel.TopLevelFunFromTopLevelPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
topLevelFunFromTopLevel.kt:8
topLevelFunFromTopLevel.kt:3
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,8 @@
LineBreakpoint created at topLevelGetterFromClass.kt:6
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! topLevelGetterFromClass.TopLevelGetterFromClassPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
topLevelGetterFromClass.kt:5
topLevelGetterFromClass.kt:11
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,8 @@
LineBreakpoint created at topLevelGetterFromTopLevel.kt:11
!JDK_HOME!\bin\java -agentlib:jdwp=transport=dt_socket,address=!HOST_NAME!:!HOST_PORT!,suspend=y,server=n -Dfile.encoding=!FILE_ENCODING! -classpath !APP_PATH!\classes;!KOTLIN_RUNTIME!;!RT_JAR! topLevelGetterFromTopLevel.TopLevelGetterFromTopLevelPackage
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
topLevelGetterFromTopLevel.kt:10
topLevelGetterFromTopLevel.kt:4
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -0,0 +1,18 @@
package classObjectFunFromClass
class A {
fun bar() {
//Breakpoint!
foo()
}
class object {
fun foo() {
val a = 1
}
}
}
fun main(args: Array<String>) {
A().bar()
}
@@ -0,0 +1,14 @@
package classObjectFunFromTopLevel
class A {
class object {
fun bar() {
val a = 1
}
}
}
fun main(args: Array<String>) {
//Breakpoint!
A.bar()
}
@@ -0,0 +1,13 @@
package extFun
class A
fun A.bar() {
val a = 1
}
fun main(args: Array<String>) {
val a = A()
//Breakpoint!
a.bar()
}
@@ -0,0 +1,16 @@
package memberFunFromClass
class A {
fun bar() {
//Breakpoint!
foo()
}
fun foo() {
val a = 1
}
}
fun main(args: Array<String>) {
A().bar()
}
@@ -0,0 +1,12 @@
package memberFunFromTopLevel
class A {
fun bar() {
val a = 1
}
}
fun main(args: Array<String>) {
//Breakpoint!
A().bar()
}
@@ -0,0 +1,18 @@
package memberGetterFromClass
class A {
fun bar() {
//Breakpoint!
foo
}
val foo: Int
get() {
val a = 1
return 1
}
}
fun main(args: Array<String>) {
A().bar()
}
@@ -0,0 +1,14 @@
package memberGetterFromTopLevel
class A {
val bar: Int
get() {
val a = 1
return 1
}
}
fun main(args: Array<String>) {
//Breakpoint!
A().bar
}
@@ -0,0 +1,12 @@
package objectFun
object A {
fun bar() {
val a = 1
}
}
fun main(args: Array<String>) {
//Breakpoint!
A.bar()
}
@@ -0,0 +1,17 @@
package topLevelFunFromClass
class A {
fun bar() {
//Breakpoint!
foo()
}
}
fun foo() {
val a = 1
}
fun main(args: Array<String>) {
A().bar()
}
@@ -0,0 +1,10 @@
package topLevelFunFromTopLevel
fun bar() {
val a = 1
}
fun main(args: Array<String>) {
//Breakpoint!
bar()
}
@@ -0,0 +1,19 @@
package topLevelGetterFromClass
class A {
fun bar() {
//Breakpoint!
foo
}
}
val foo: Int
get() {
val a = 1
return 1
}
fun main(args: Array<String>) {
A().bar()
}
@@ -0,0 +1,12 @@
package topLevelGetterFromTopLevel
val bar: Int
get() {
val a = 1
return 1
}
fun main(args: Array<String>) {
//Breakpoint!
bar
}
@@ -0,0 +1,115 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.debugger
import com.intellij.debugger.engine.SuspendContextImpl
import com.intellij.debugger.engine.MethodFilter
import com.intellij.debugger.engine.StackFrameContext
import com.intellij.debugger.engine.DebugProcessImpl
import org.jetbrains.jet.plugin.debugger.KotlinSmartStepIntoHandler.KotlinMethodSmartStepTarget
import org.jetbrains.jet.plugin.debugger.KotlinSmartStepIntoHandler.KotlinBasicStepMethodFilter
import com.intellij.debugger.jdi.StackFrameProxyImpl
import com.intellij.debugger.SourcePosition
import com.intellij.psi.PsiElement
import com.intellij.debugger.DebuggerManagerEx
import com.intellij.debugger.ui.breakpoints.LineBreakpoint
import com.intellij.psi.PsiFile
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils
import org.jetbrains.jet.lang.resolve.name.FqName
import java.io.File
abstract class AbstractKotlinSteppingTest : KotlinDebuggerTestCase() {
protected fun doStepIntoTest(path: String) {
createDebugProcess(path)
onBreakpoint { stepInto() }
finish()
}
protected fun doSmartStepIntoTest(path: String) {
createDebugProcess(path)
onBreakpoint { smartStepInto() }
finish()
}
// Workaround for KT-4617 - Start
override fun resume(context: SuspendContextImpl?) = super.resume(context)
override fun printContext(context: StackFrameContext?) = super.printContext(context)
override fun printFrameProxy(frameProxy: StackFrameProxyImpl?) = super.printFrameProxy(frameProxy)
override fun getDebugProcess() = super.getDebugProcess()
// Workaround for KT-4617 - End
private val dp: DebugProcessImpl
get() = getDebugProcess() ?: throw AssertionError("createLocalProcess() should be called before getDebugProcess()")
private fun onBreakpoint(doOnBreakpoint: SuspendContextImpl.() -> Unit) {
super.onBreakpoint {
it.printContext()
it.doOnBreakpoint()
}
}
private fun SuspendContextImpl.smartStepInto() {
this.smartStepInto(false)
}
private fun SuspendContextImpl.stepInto() {
this.stepInto(false, null)
}
private fun SuspendContextImpl.stepInto(ignoreFilters: Boolean, smartStepFilter: MethodFilter?) {
dp.getManagerThread()!!.schedule(dp.createStepIntoCommand(this, ignoreFilters, smartStepFilter))
}
private fun SuspendContextImpl.smartStepInto(ignoreFilters: Boolean) {
createSmartStepIntoFilters().forEach {
dp.getManagerThread()!!.schedule(dp.createStepIntoCommand(this, ignoreFilters, it))
}
}
private fun SuspendContextImpl.printContext() {
printContext(this)
}
private fun createDebugProcess(pathToFile: String) {
val file = File(pathToFile)
val packageName = file.name.replace(".kt", "")
createLocalProcess(PackageClassUtils.getPackageClassFqName(FqName(packageName)).asString())
}
private fun finish() {
onBreakpoint {
resume(this)
}
}
private fun createSmartStepIntoFilters(): List<KotlinBasicStepMethodFilter> {
val breakpointManager = DebuggerManagerEx.getInstanceEx(getProject())?.getBreakpointManager()
val breakpoint = breakpointManager?.getBreakpoints()?.first { it is LineBreakpoint }
val line = (breakpoint as LineBreakpoint).getLineIndex()
val containingFile = breakpoint.getPsiFile()
if (containingFile == null) throw AssertionError("Couldn't find file for breakpoint at the line $line")
val position = MockSourcePosition(_file = containingFile, _line = line)
val stepTargets = KotlinSmartStepIntoHandler().findSmartStepTargets(position)
return stepTargets.filter { it is KotlinMethodSmartStepTarget }.map { KotlinBasicStepMethodFilter(it as KotlinMethodSmartStepTarget) }
}
}
@@ -38,17 +38,7 @@ abstract class AbstractSmartStepIntoTest : LightCodeInsightFixtureTestCase() {
val offset = fixture.getCaretOffset()
val line = fixture.getDocument(fixture.getFile())!!.getLineNumber(offset)
val position = object: SourcePosition() {
override fun getFile() = fixture.getFile()!!
override fun getElementAt(): PsiElement? = throw UnsupportedOperationException()
override fun getLine() = line
override fun getOffset() = offset
override fun openEditor(requestFocus: Boolean) = fixture.getEditor()
override fun navigate(requestFocus: Boolean) {
}
override fun canNavigate() = false
override fun canNavigateToSource() = false
}
val position = MockSourcePosition(_file = fixture.getFile(), _line = line, _offset = offset, _editor = fixture.getEditor())
val actual = KotlinSmartStepIntoHandler().findSmartStepTargets(position).map { renderTarget(it) }
@@ -0,0 +1,104 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.debugger;
import com.intellij.debugger.DebuggerTestCase;
import com.intellij.debugger.impl.OutputChecker;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.MockLibraryUtil;
import org.jetbrains.jet.asJava.KotlinLightClassForPackage;
import org.jetbrains.jet.codegen.forTestCompile.ForTestCompileRuntime;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
import java.io.File;
public abstract class KotlinDebuggerTestCase extends DebuggerTestCase {
protected static final String TINY_APP = PluginTestCaseBase.getTestDataPathBase() + "/debugger/tinyApp";
private File outputDir;
@Override
protected OutputChecker initOutputChecker() {
return new KotlinOutputChecker(TINY_APP);
}
@NotNull
@Override
protected String getTestAppPath() {
return TINY_APP;
}
@Override
public void tearDown() throws Exception {
super.tearDown();
if (outputDir != null && outputDir.exists()) {
FileUtil.delete(outputDir);
}
}
@Override
protected void ensureCompiledAppExists() throws Exception {
String modulePath = getTestAppPath();
outputDir = new File(modulePath + File.separator + "classes");
MockLibraryUtil.compileKotlin(modulePath + File.separator + "src", outputDir);
}
private static class KotlinOutputChecker extends OutputChecker {
public KotlinOutputChecker(@NotNull String appPath) {
super(appPath);
}
@Override
protected String replaceAdditionalInOutput(String str) {
return super.replaceAdditionalInOutput(str.replace(ForTestCompileRuntime.runtimeJarForTests().getPath(), "!KOTLIN_RUNTIME!"));
}
}
@Override
protected String getAppClassesPath() {
return super.getAppClassesPath() + File.pathSeparator + ForTestCompileRuntime.runtimeJarForTests().getPath();
}
@Override
protected void createBreakpoints(final String className) {
PsiClass psiClass = ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
@Override
public PsiClass compute() {
return JavaPsiFacade.getInstance(myProject).findClass(className, GlobalSearchScope.allScope(myProject));
}
});
if (psiClass instanceof KotlinLightClassForPackage) {
PsiElement element = psiClass.getNavigationElement();
if (element instanceof JetFile) {
createBreakpoints((JetFile) element);
return;
}
}
createBreakpoints(psiClass.getContainingFile());
}
}
@@ -0,0 +1,177 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.plugin.debugger;
import junit.framework.Assert;
import junit.framework.Test;
import junit.framework.TestSuite;
import java.io.File;
import java.util.regex.Pattern;
import org.jetbrains.jet.JetTestUtils;
import org.jetbrains.jet.test.InnerTestClasses;
import org.jetbrains.jet.test.TestMetadata;
import org.jetbrains.jet.plugin.debugger.AbstractKotlinSteppingTest;
/** This class is generated by {@link org.jetbrains.jet.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@InnerTestClasses({KotlinSteppingTestGenerated.StepInto.class, KotlinSteppingTestGenerated.SmartStepInto.class})
public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
@TestMetadata("idea/testData/debugger/tinyApp/src/stepInto")
public static class StepInto extends AbstractKotlinSteppingTest {
public void testAllFilesPresentInStepInto() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/debugger/tinyApp/src/stepInto"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("classObjectFunFromClass.kt")
public void testClassObjectFunFromClass() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/classObjectFunFromClass.kt");
}
@TestMetadata("classObjectFunFromTopLevel.kt")
public void testClassObjectFunFromTopLevel() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/classObjectFunFromTopLevel.kt");
}
@TestMetadata("extFun.kt")
public void testExtFun() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/extFun.kt");
}
@TestMetadata("memberFunFromClass.kt")
public void testMemberFunFromClass() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/memberFunFromClass.kt");
}
@TestMetadata("memberFunFromTopLevel.kt")
public void testMemberFunFromTopLevel() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/memberFunFromTopLevel.kt");
}
@TestMetadata("memberGetterFromClass.kt")
public void testMemberGetterFromClass() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromClass.kt");
}
@TestMetadata("memberGetterFromTopLevel.kt")
public void testMemberGetterFromTopLevel() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromTopLevel.kt");
}
@TestMetadata("objectFun.kt")
public void testObjectFun() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/objectFun.kt");
}
@TestMetadata("topLevelFunFromClass.kt")
public void testTopLevelFunFromClass() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/topLevelFunFromClass.kt");
}
@TestMetadata("topLevelFunFromTopLevel.kt")
public void testTopLevelFunFromTopLevel() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/topLevelFunFromTopLevel.kt");
}
@TestMetadata("topLevelGetterFromClass.kt")
public void testTopLevelGetterFromClass() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/topLevelGetterFromClass.kt");
}
@TestMetadata("topLevelGetterFromTopLevel.kt")
public void testTopLevelGetterFromTopLevel() throws Exception {
doStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/topLevelGetterFromTopLevel.kt");
}
}
@TestMetadata("idea/testData/debugger/tinyApp/src/stepInto")
public static class SmartStepInto extends AbstractKotlinSteppingTest {
public void testAllFilesPresentInSmartStepInto() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/debugger/tinyApp/src/stepInto"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("classObjectFunFromClass.kt")
public void testClassObjectFunFromClass() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/classObjectFunFromClass.kt");
}
@TestMetadata("classObjectFunFromTopLevel.kt")
public void testClassObjectFunFromTopLevel() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/classObjectFunFromTopLevel.kt");
}
@TestMetadata("extFun.kt")
public void testExtFun() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/extFun.kt");
}
@TestMetadata("memberFunFromClass.kt")
public void testMemberFunFromClass() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/memberFunFromClass.kt");
}
@TestMetadata("memberFunFromTopLevel.kt")
public void testMemberFunFromTopLevel() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/memberFunFromTopLevel.kt");
}
@TestMetadata("memberGetterFromClass.kt")
public void testMemberGetterFromClass() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromClass.kt");
}
@TestMetadata("memberGetterFromTopLevel.kt")
public void testMemberGetterFromTopLevel() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/memberGetterFromTopLevel.kt");
}
@TestMetadata("objectFun.kt")
public void testObjectFun() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/objectFun.kt");
}
@TestMetadata("topLevelFunFromClass.kt")
public void testTopLevelFunFromClass() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/topLevelFunFromClass.kt");
}
@TestMetadata("topLevelFunFromTopLevel.kt")
public void testTopLevelFunFromTopLevel() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/topLevelFunFromTopLevel.kt");
}
@TestMetadata("topLevelGetterFromClass.kt")
public void testTopLevelGetterFromClass() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/topLevelGetterFromClass.kt");
}
@TestMetadata("topLevelGetterFromTopLevel.kt")
public void testTopLevelGetterFromTopLevel() throws Exception {
doSmartStepIntoTest("idea/testData/debugger/tinyApp/src/stepInto/topLevelGetterFromTopLevel.kt");
}
}
public static Test suite() {
TestSuite suite = new TestSuite("KotlinSteppingTestGenerated");
suite.addTestSuite(StepInto.class);
suite.addTestSuite(SmartStepInto.class);
return suite;
}
}