Debugger: support field watchpoints for kotlin
This commit is contained in:
@@ -338,3 +338,4 @@ kotlin.compiler.js.option.output.copy.dir=O&utput directory for library &runtime
|
||||
# Debugger
|
||||
debugger.filter.ignore.internal.classes=Do not step into specific Kotlin classes
|
||||
debugger.data.view.delegated.properties=Calculate values of delegated properties (may affect program execution)
|
||||
debugger.field.watchpoints.tab.title=Kotlin Field Watchpoints
|
||||
|
||||
@@ -406,7 +406,9 @@
|
||||
<debugger.frameExtraVarsProvider implementation="org.jetbrains.kotlin.idea.debugger.KotlinFrameExtraVariablesProvider"/>
|
||||
<debugger.extraSteppingFilter implementation="org.jetbrains.kotlin.idea.ExtraSteppingFilter"/>
|
||||
<xdebugger.settings implementation="org.jetbrains.kotlin.idea.debugger.KotlinDebuggerSettings"/>
|
||||
<xdebugger.breakpointType implementation="org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpointType"/>
|
||||
<debugger.syntheticProvider implementation="org.jetbrains.kotlin.idea.debugger.filter.KotlinSyntheticTypeComponentProvider"/>
|
||||
<debugger.javaBreakpointHandlerFactory implementation="org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinBreakpointHandlerFactory"/>
|
||||
|
||||
<codeInsight.implementMethod language="jet" implementationClass="org.jetbrains.kotlin.idea.core.codeInsight.ImplementMethodsHandler"/>
|
||||
<codeInsight.overrideMethod language="jet" implementationClass="org.jetbrains.kotlin.idea.codeInsight.OverrideMethodsHandler"/>
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.idea.debugger.breakpoints
|
||||
|
||||
import com.intellij.debugger.engine.DebugProcessImpl
|
||||
import com.intellij.debugger.engine.JavaBreakpointHandler
|
||||
import com.intellij.debugger.engine.JavaBreakpointHandlerFactory
|
||||
import com.intellij.debugger.ui.breakpoints.JavaLineBreakpointType
|
||||
|
||||
public class KotlinBreakpointHandlerFactory: JavaBreakpointHandlerFactory {
|
||||
override fun createHandler(process: DebugProcessImpl): JavaBreakpointHandler? {
|
||||
return KotlinFieldBreakpointHandler(process)
|
||||
}
|
||||
}
|
||||
|
||||
public class KotlinFieldBreakpointHandler(process: DebugProcessImpl) : JavaBreakpointHandler(javaClass<KotlinFieldBreakpointType>(), process)
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.kotlin.idea.debugger.breakpoints
|
||||
|
||||
import com.intellij.debugger.SourcePosition
|
||||
import com.intellij.debugger.impl.PositionUtil
|
||||
import com.intellij.debugger.ui.breakpoints.*
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.xdebugger.XDebuggerUtil
|
||||
import com.intellij.xdebugger.breakpoints.XBreakpoint
|
||||
import com.intellij.xdebugger.breakpoints.XLineBreakpoint
|
||||
import com.intellij.xdebugger.breakpoints.XLineBreakpointType
|
||||
import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel
|
||||
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.java.debugger.breakpoints.properties.JavaFieldBreakpointProperties
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.idea.JetBundle
|
||||
import org.jetbrains.kotlin.idea.JetFileType
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import javax.swing.Icon
|
||||
import javax.swing.JComponent
|
||||
|
||||
public class KotlinFieldBreakpointType : JavaBreakpointType<JavaFieldBreakpointProperties>, XLineBreakpointType<JavaFieldBreakpointProperties>(
|
||||
"kotlin-field", JetBundle.message("debugger.field.watchpoints.tab.title")
|
||||
) {
|
||||
private val delegate = JavaFieldBreakpointType()
|
||||
|
||||
override fun createJavaBreakpoint(project: Project, breakpoint: XBreakpoint<JavaFieldBreakpointProperties>): Breakpoint<*> {
|
||||
return KotlinFieldBreakpoint(project, breakpoint)
|
||||
}
|
||||
|
||||
override fun canPutAt(file: VirtualFile, line: Int, project: Project): Boolean {
|
||||
val psiFile = PsiManager.getInstance(project).findFile(file)
|
||||
|
||||
if (psiFile == null || psiFile.getVirtualFile().getFileType() != JetFileType.INSTANCE) {
|
||||
return false
|
||||
}
|
||||
|
||||
val document = FileDocumentManager.getInstance().getDocument(file) ?: return false
|
||||
|
||||
var canPutAt = false
|
||||
XDebuggerUtil.getInstance().iterateLine(project, document, line, fun (el: PsiElement): Boolean {
|
||||
// avoid comments
|
||||
if (el is PsiWhiteSpace || PsiTreeUtil.getParentOfType(el, javaClass<PsiComment>(), false) != null) {
|
||||
return true
|
||||
}
|
||||
|
||||
var element = el
|
||||
var parent = element.getParent()
|
||||
while (parent != null) {
|
||||
val offset = parent.getTextOffset()
|
||||
if (offset >= 0 && document.getLineNumber(offset) != line) break
|
||||
|
||||
element = parent
|
||||
parent = element.getParent()
|
||||
}
|
||||
|
||||
if (element is JetProperty || element is JetParameter) {
|
||||
val bindingContext = (element as JetElement).analyzeAndGetResult().bindingContext
|
||||
var descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element)
|
||||
if (descriptor is ValueParameterDescriptor) {
|
||||
descriptor = bindingContext.get(BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor)
|
||||
}
|
||||
if (descriptor is PropertyDescriptor && bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor)) {
|
||||
canPutAt = true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
return canPutAt
|
||||
}
|
||||
|
||||
override fun getPriority() = 120
|
||||
|
||||
override fun createBreakpointProperties(file: VirtualFile, line: Int): JavaFieldBreakpointProperties? {
|
||||
return delegate.createBreakpointProperties(file, line)
|
||||
}
|
||||
|
||||
override fun addBreakpoint(project: Project?, parentComponent: JComponent?): XLineBreakpoint<JavaFieldBreakpointProperties>? {
|
||||
return delegate.addBreakpoint(project, parentComponent)
|
||||
}
|
||||
|
||||
override fun isAddBreakpointButtonVisible(): Boolean {
|
||||
return delegate.isAddBreakpointButtonVisible()
|
||||
}
|
||||
|
||||
override fun getMutedEnabledIcon(): Icon {
|
||||
return delegate.getMutedEnabledIcon()
|
||||
}
|
||||
|
||||
override fun getDisabledIcon(): Icon {
|
||||
return delegate.getDisabledIcon()
|
||||
}
|
||||
|
||||
override fun getEnabledIcon(): Icon {
|
||||
return delegate.getEnabledIcon()
|
||||
}
|
||||
|
||||
override fun getMutedDisabledIcon(): Icon {
|
||||
return delegate.getMutedDisabledIcon()
|
||||
}
|
||||
|
||||
override fun canBeHitInOtherPlaces(): Boolean {
|
||||
return delegate.canBeHitInOtherPlaces()
|
||||
}
|
||||
|
||||
override fun getShortText(breakpoint: XLineBreakpoint<JavaFieldBreakpointProperties>?): String? {
|
||||
return delegate.getShortText(breakpoint)
|
||||
}
|
||||
|
||||
override fun createProperties(): JavaFieldBreakpointProperties? {
|
||||
return delegate.createProperties()
|
||||
}
|
||||
|
||||
override fun createCustomPropertiesPanel(): XBreakpointCustomPropertiesPanel<XLineBreakpoint<JavaFieldBreakpointProperties>>? {
|
||||
return delegate.createCustomPropertiesPanel()
|
||||
}
|
||||
|
||||
override fun getDisplayText(breakpoint: XLineBreakpoint<JavaFieldBreakpointProperties>?): String? {
|
||||
return delegate.getDisplayText(breakpoint)
|
||||
}
|
||||
|
||||
override fun getEditorsProvider(): XDebuggerEditorsProvider? {
|
||||
return delegate.getEditorsProvider()
|
||||
}
|
||||
|
||||
override fun createCustomRightPropertiesPanel(project: Project): XBreakpointCustomPropertiesPanel<XLineBreakpoint<JavaFieldBreakpointProperties>>? {
|
||||
return delegate.createCustomRightPropertiesPanel(project)
|
||||
}
|
||||
|
||||
override fun isSuspendThreadSupported(): Boolean {
|
||||
return delegate.isSuspendThreadSupported()
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinFieldBreakpoint(project: Project, breakpoint: XBreakpoint<JavaFieldBreakpointProperties>): FieldBreakpoint(project, breakpoint) {
|
||||
override fun isValid(): Boolean {
|
||||
if (!BreakpointWithHighlighter.isPositionValid(getXBreakpoint().getSourcePosition())) return false
|
||||
|
||||
return runReadAction {
|
||||
val field = getField()
|
||||
field != null && field.isValid()
|
||||
}
|
||||
}
|
||||
|
||||
public fun getField(): JetCallableDeclaration? {
|
||||
val sourcePosition = getSourcePosition()
|
||||
return getProperty(sourcePosition)
|
||||
}
|
||||
|
||||
private fun getProperty(sourcePosition: SourcePosition?): JetCallableDeclaration? {
|
||||
val property: JetProperty? = PositionUtil.getPsiElementAt(getProject(), javaClass(), sourcePosition)
|
||||
if (property != null) {
|
||||
return property
|
||||
}
|
||||
val parameter: JetParameter? = PositionUtil.getPsiElementAt(getProject(), javaClass(), sourcePosition)
|
||||
if (parameter != null) {
|
||||
return parameter
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun reload(psiFile: PsiFile?) {
|
||||
val property = getProperty(getSourcePosition())
|
||||
if (property != null) {
|
||||
setFieldName(property.getName())
|
||||
|
||||
if (property is JetProperty && property.isTopLevel()) {
|
||||
getProperties().myClassName = PackageClassUtils.getPackageClassFqName(property.getContainingJetFile().getPackageFqName()).asString()
|
||||
}
|
||||
else {
|
||||
val jetClass: JetClassOrObject? = PsiTreeUtil.getParentOfType(property, javaClass())
|
||||
if (jetClass is JetClassOrObject) {
|
||||
val fqName = jetClass.getFqName()
|
||||
if (fqName != null) {
|
||||
getProperties().myClassName = fqName.asString()
|
||||
}
|
||||
}
|
||||
}
|
||||
setInstanceFiltersEnabled(false)
|
||||
}
|
||||
}
|
||||
|
||||
fun setFieldName(fieldName: String) {
|
||||
getProperties().myFieldName = fieldName
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun setWatchAccess(value: Boolean) {
|
||||
getProperties().WATCH_ACCESS = value
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun setWatchModification(value: Boolean) {
|
||||
getProperties().WATCH_MODIFICATION = value
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
KotlinFieldBreakpoint created at fieldWatchpoints.kt:4
|
||||
KotlinFieldBreakpoint created at fieldWatchpoints.kt:7
|
||||
KotlinFieldBreakpoint created at fieldWatchpoints.kt:17
|
||||
KotlinFieldBreakpoint created at fieldWatchpoints.kt:20
|
||||
KotlinFieldBreakpoint created at fieldWatchpoints.kt:30
|
||||
KotlinFieldBreakpoint created at fieldWatchpoints.kt:32
|
||||
KotlinFieldBreakpoint created at fieldWatchpoints.kt:44
|
||||
KotlinFieldBreakpoint created at fieldWatchpoints.kt:47
|
||||
!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!;!CUSTOM_LIBRARY!;!RT_JAR! fieldWatchpoints.FieldWatchpointsPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
fieldWatchpoints.kt:18
|
||||
fieldWatchpoints.kt:21
|
||||
fieldWatchpoints.kt:59
|
||||
fieldWatchpoints.kt:5
|
||||
fieldWatchpoints.kt:8
|
||||
fieldWatchpoints.kt:59
|
||||
fieldWatchpoints.kt:11
|
||||
fieldWatchpoints.kt:12
|
||||
fieldWatchpoints.kt:13
|
||||
fieldWatchpoints.kt:60
|
||||
fieldWatchpoints.kt:24
|
||||
fieldWatchpoints.kt:25
|
||||
fieldWatchpoints.kt:26
|
||||
fieldWatchpoints.kt:61
|
||||
fieldWatchpoints.kt:0
|
||||
fieldWatchpoints.kt:0
|
||||
fieldWatchpoints.kt:61
|
||||
fieldWatchpoints.kt:36
|
||||
fieldWatchpoints.kt:37
|
||||
fieldWatchpoints.kt:38
|
||||
fieldWatchpoints.kt:62
|
||||
fieldWatchpoints.kt:45
|
||||
fieldWatchpoints.kt:48
|
||||
fieldWatchpoints.kt:62
|
||||
fieldWatchpoints.kt:44
|
||||
fieldWatchpoints.kt:51
|
||||
fieldWatchpoints.kt:47
|
||||
fieldWatchpoints.kt:52
|
||||
fieldWatchpoints.kt:47
|
||||
fieldWatchpoints.kt:54
|
||||
fieldWatchpoints.kt:63
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,5 @@
|
||||
!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!;!CUSTOM_LIBRARY!;!RT_JAR! inapplicableFieldWatchpoints.InapplicableFieldWatchpointsPackage
|
||||
Connected to the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
|
||||
|
||||
Process finished with exit code 0
|
||||
@@ -0,0 +1,65 @@
|
||||
package fieldWatchpoints
|
||||
|
||||
class A {
|
||||
//FieldWatchpoint! (propVal)
|
||||
val propVal = 1
|
||||
|
||||
//FieldWatchpoint! (propVar)
|
||||
var propVar = 1
|
||||
|
||||
fun testPublicPropertyInClass() {
|
||||
propVal
|
||||
propVar
|
||||
propVar = 2
|
||||
}
|
||||
}
|
||||
|
||||
//FieldWatchpoint! (topPropVal)
|
||||
val topPropVal = 1
|
||||
|
||||
//FieldWatchpoint! (topPropVar)
|
||||
var topPropVar = 1
|
||||
|
||||
fun testPublicTopLevelProperty() {
|
||||
topPropVal
|
||||
topPropVar
|
||||
topPropVar = 2
|
||||
}
|
||||
|
||||
class B(
|
||||
//FieldWatchpoint! (bPropVal)
|
||||
val bPropVal: Int,
|
||||
//FieldWatchpoint! (bPropVar)
|
||||
var bPropVar: Int
|
||||
) {
|
||||
fun testConstructorProperty() {
|
||||
bPropVal
|
||||
bPropVar
|
||||
bPropVar = 2
|
||||
}
|
||||
}
|
||||
|
||||
class AWithCompanion {
|
||||
companion object {
|
||||
//FieldWatchpoint! (compPropVal)
|
||||
val compPropVal = 1
|
||||
|
||||
//FieldWatchpoint! (compPropVar)
|
||||
var compPropVar = 1
|
||||
|
||||
fun testCompanionProperty() {
|
||||
compPropVal
|
||||
compPropVar
|
||||
compPropVar = 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
A().testPublicPropertyInClass()
|
||||
testPublicTopLevelProperty()
|
||||
B(1, 1).testConstructorProperty()
|
||||
AWithCompanion.testCompanionProperty()
|
||||
}
|
||||
|
||||
// STEP_OUT: 36
|
||||
@@ -0,0 +1,23 @@
|
||||
package inapplicableFieldWatchpoints
|
||||
|
||||
class A {
|
||||
//FieldWatchpoint! (propWithGet)
|
||||
val propWithGet: Int get() = 1
|
||||
}
|
||||
|
||||
interface T {
|
||||
//FieldWatchpoint! (propInInterface)
|
||||
val propInInterface: Int
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
//FieldWatchpoint! (localVal)
|
||||
val localVal = 1
|
||||
}
|
||||
|
||||
fun foo(
|
||||
//FieldWatchpoint! (funParam)
|
||||
funParam: Int
|
||||
) {
|
||||
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.debugger
|
||||
|
||||
import com.intellij.debugger.DebuggerInvocationUtil
|
||||
import com.intellij.debugger.DebuggerManagerEx
|
||||
import com.intellij.debugger.engine.DebugProcessImpl
|
||||
import com.intellij.debugger.engine.SuspendContextImpl
|
||||
import com.intellij.debugger.engine.MethodFilter
|
||||
@@ -33,6 +35,28 @@ import org.jetbrains.kotlin.test.InTextDirectivesUtils.findStringWithPrefixes
|
||||
import kotlin.properties.Delegates
|
||||
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl
|
||||
import com.intellij.debugger.ui.breakpoints.BreakpointManager
|
||||
import com.intellij.debugger.ui.breakpoints.FieldBreakpoint
|
||||
import com.intellij.debugger.ui.breakpoints.JavaFieldBreakpointType
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.editor.Document
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.util.Computable
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.search.FilenameIndex
|
||||
import com.intellij.xdebugger.XDebuggerManager
|
||||
import com.intellij.xdebugger.XDebuggerUtil
|
||||
import com.intellij.xdebugger.breakpoints.*
|
||||
import org.jetbrains.java.debugger.breakpoints.properties.JavaFieldBreakpointProperties
|
||||
import org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpoint
|
||||
import org.jetbrains.kotlin.idea.debugger.breakpoints.KotlinFieldBreakpointType
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import javax.swing.SwingUtilities
|
||||
|
||||
abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() {
|
||||
private var oldSettings: DebuggerSettings by Delegates.notNull()
|
||||
@@ -154,4 +178,58 @@ abstract class KotlinDebuggerTestBase : KotlinDebuggerTestCase() {
|
||||
resume(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createBreakpoints(file: PsiFile?) {
|
||||
super.createBreakpoints(file)
|
||||
|
||||
if (file == null) return
|
||||
|
||||
val document = PsiDocumentManager.getInstance(myProject).getDocument(file) ?: return
|
||||
val breakpointManager = XDebuggerManager.getInstance(myProject).getBreakpointManager()
|
||||
val breakpointType = javaClass<KotlinFieldBreakpointType>() as Class<out XBreakpointType<XBreakpoint<XBreakpointProperties<*>>, XBreakpointProperties<*>>>
|
||||
val type = XDebuggerUtil.getInstance().findBreakpointType<XBreakpoint<XBreakpointProperties<*>>>(breakpointType) as KotlinFieldBreakpointType
|
||||
val virtualFile = file.getVirtualFile()
|
||||
|
||||
val runnable = {
|
||||
var offset = -1;
|
||||
while (true) {
|
||||
offset = document.getText().indexOf("FieldWatchpoint!", offset + 1)
|
||||
if (offset == -1) break
|
||||
|
||||
val commentLine = document.getLineNumber(offset)
|
||||
|
||||
val comment = document.getText().substring(document.getLineStartOffset(commentLine), document.getLineEndOffset(commentLine))
|
||||
|
||||
val lineIndex = commentLine + 1
|
||||
val fieldName = comment.substringAfter("//FieldWatchpoint! (").substringBefore(")")
|
||||
|
||||
if (!type.canPutAt(virtualFile, lineIndex, myProject)) continue
|
||||
|
||||
val xBreakpoint = runWriteAction {
|
||||
breakpointManager.addLineBreakpoint(
|
||||
type as XLineBreakpointType<XBreakpointProperties<*>>,
|
||||
virtualFile.getUrl(),
|
||||
lineIndex,
|
||||
type.createBreakpointProperties(virtualFile, lineIndex)
|
||||
)
|
||||
}
|
||||
|
||||
val javaBreakpoint = BreakpointManager.getJavaBreakpoint(xBreakpoint)
|
||||
if (javaBreakpoint is KotlinFieldBreakpoint) {
|
||||
javaBreakpoint.setFieldName(fieldName)
|
||||
javaBreakpoint.setWatchAccess(true)
|
||||
javaBreakpoint.setWatchModification(true)
|
||||
BreakpointManager.addBreakpoint(javaBreakpoint)
|
||||
println("KotlinFieldBreakpoint created at ${file.getVirtualFile().getName()}:$lineIndex", ProcessOutputTypes.SYSTEM)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!SwingUtilities.isEventDispatchThread()) {
|
||||
DebuggerInvocationUtil.invokeAndWait(myProject, runnable, ModalityState.defaultModalityState())
|
||||
}
|
||||
else {
|
||||
runnable.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,6 +272,27 @@ public class KotlinSteppingTestGenerated extends AbstractKotlinSteppingTest {
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/debugger/tinyApp/src/stepOut")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class StepOut extends AbstractKotlinSteppingTest {
|
||||
public void testAllFilesPresentInStepOut() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/debugger/tinyApp/src/stepOut"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("fieldWatchpoints.kt")
|
||||
public void testFieldWatchpoints() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepOut/fieldWatchpoints.kt");
|
||||
doStepOutTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("inapplicableFieldWatchpoints.kt")
|
||||
public void testInapplicableFieldWatchpoints() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/debugger/tinyApp/src/stepOut/inapplicableFieldWatchpoints.kt");
|
||||
doStepOutTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/debugger/tinyApp/src/filters")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
Reference in New Issue
Block a user