Node.js debug: breakpoint in the first line does not work (WEB-16779)

This commit is contained in:
Konstantin Ulitin
2017-12-20 10:50:58 +03:00
parent f2b7eea017
commit bf84ddb886
3 changed files with 55 additions and 22 deletions
@@ -15,7 +15,6 @@
*/
package org.jetbrains.debugger
import com.intellij.openapi.util.Ref
import com.intellij.util.Url
import org.jetbrains.concurrency.Promise
import java.util.*
@@ -32,14 +31,19 @@ interface BreakpointManager {
val regExpBreakpointSupported: Boolean
get() = false
@Deprecated("use another overload")
fun setBreakpoint(target: BreakpointTarget,
line: Int,
condition: String? = null): Breakpoint {
throw UnsupportedOperationException()
}
fun setBreakpoint(target: BreakpointTarget,
line: Int,
column: Int = Breakpoint.EMPTY_VALUE,
url: Url? = null,
condition: String? = null,
ignoreCount: Int = Breakpoint.EMPTY_VALUE,
enabled: Boolean = true,
promiseRef: Ref<Promise<out Breakpoint>>? = null): Breakpoint
ignoreCount: Int = Breakpoint.EMPTY_VALUE): SetBreakpointResult
fun remove(breakpoint: Breakpoint): Promise<*>
@@ -75,6 +79,10 @@ interface BreakpointManager {
* with a null value and not null callback simply returns current value.
*/
fun enableBreakpoints(enabled: Boolean): Promise<*>
interface SetBreakpointResult
data class BreakpointExist(val existingBreakpoint: Breakpoint) : SetBreakpointResult
data class BreakpointCreated(val breakpoint: Breakpoint, val isResolved: Promise<out Breakpoint>) : SetBreakpointResult
}
interface BreakpointListener : EventListener {
@@ -16,14 +16,16 @@
package org.jetbrains.debugger
import com.intellij.concurrency.ConcurrentCollectionFactory
import com.intellij.openapi.util.Ref
import com.intellij.openapi.util.text.StringUtil
import com.intellij.util.EventDispatcher
import com.intellij.util.SmartList
import com.intellij.util.Url
import com.intellij.util.containers.ContainerUtil
import gnu.trove.TObjectHashingStrategy
import org.jetbrains.concurrency.*
import org.jetbrains.concurrency.Promise
import org.jetbrains.concurrency.all
import org.jetbrains.concurrency.nullPromise
import org.jetbrains.concurrency.rejectedPromise
import java.util.concurrent.ConcurrentMap
abstract class BreakpointManagerBase<T : BreakpointBase<*>> : BreakpointManager {
@@ -40,7 +42,12 @@ abstract class BreakpointManagerBase<T : BreakpointBase<*>> : BreakpointManager
return result
}
override fun equals(b1: T, b2: T) = b1.target.javaClass == b2.target.javaClass && b1.target == b2.target && b1.line == b2.line && b1.column == b2.column && StringUtil.equals(b1.condition, b2.condition)
override fun equals(b1: T, b2: T) =
b1.target.javaClass == b2.target.javaClass &&
b1.target == b2.target &&
b1.line == b2.line &&
b1.column == b2.column &&
StringUtil.equals(b1.condition, b2.condition)
})
protected val dispatcher: EventDispatcher<BreakpointListener> = EventDispatcher.create(BreakpointListener::class.java)
@@ -49,24 +56,22 @@ abstract class BreakpointManagerBase<T : BreakpointBase<*>> : BreakpointManager
protected abstract fun doSetBreakpoint(target: BreakpointTarget, url: Url?, breakpoint: T): Promise<out Breakpoint>
override fun setBreakpoint(target: BreakpointTarget, line: Int, column: Int, url: Url?, condition: String?, ignoreCount: Int, enabled: Boolean, promiseRef: Ref<Promise<out Breakpoint>>?): Breakpoint {
val breakpoint = createBreakpoint(target, line, column, condition, ignoreCount, enabled)
override fun setBreakpoint(target: BreakpointTarget,
line: Int,
column: Int,
url: Url?,
condition: String?,
ignoreCount: Int): BreakpointManager.SetBreakpointResult {
val breakpoint = createBreakpoint(target, line, column, condition, ignoreCount, true)
val existingBreakpoint = breakpointDuplicationByTarget.putIfAbsent(breakpoint, breakpoint)
if (existingBreakpoint != null) {
promiseRef?.set(resolvedPromise(breakpoint))
return existingBreakpoint
return BreakpointManager.BreakpointExist(existingBreakpoint)
}
breakpoints.add(breakpoint)
if (enabled) {
val promise = doSetBreakpoint(target, url, breakpoint)
.rejected { dispatcher.multicaster.errorOccurred(breakpoint, it.message ?: it.toString()) }
promiseRef?.set(promise)
}
else {
promiseRef?.set(resolvedPromise(breakpoint))
}
return breakpoint
val promise = doSetBreakpoint(target, url, breakpoint)
.rejected { dispatcher.multicaster.errorOccurred(breakpoint, it.message ?: it.toString()) }
return BreakpointManager.BreakpointCreated(breakpoint, promise)
}
override final fun remove(breakpoint: Breakpoint): Promise<*> {
@@ -110,11 +115,13 @@ abstract class BreakpointManagerBase<T : BreakpointBase<*>> : BreakpointManager
override fun enableBreakpoints(enabled: Boolean): Promise<*> = rejectedPromise<Any?>("Unsupported")
}
// used in goland
@Suppress("unused")
class DummyBreakpointManager : BreakpointManager {
override val breakpoints: Iterable<Breakpoint>
get() = emptyList()
override fun setBreakpoint(target: BreakpointTarget, line: Int, column: Int, url: Url?, condition: String?, ignoreCount: Int, enabled: Boolean, promiseRef: Ref<Promise<out Breakpoint>>?): Breakpoint {
override fun setBreakpoint(target: BreakpointTarget, line: Int, column: Int, url: Url?, condition: String?, ignoreCount: Int): BreakpointManager.SetBreakpointResult {
throw UnsupportedOperationException()
}
@@ -41,6 +41,8 @@ abstract class LineBreakpointManager(internal val debugProcess: DebugProcessImpl
open fun isAnyFirstLineBreakpoint(breakpoint: Breakpoint) = false
open protected fun unregisterAnyFirstLineBreakpoint(breakpoint: Breakpoint) {}
private val breakpointResolvedListenerAdded = ContainerUtil.createConcurrentWeakMap<Vm, Unit>()
fun setBreakpoint(vm: Vm, breakpoint: XLineBreakpoint<*>) {
@@ -190,7 +192,23 @@ abstract class LineBreakpointManager(internal val debugProcess: DebugProcessImpl
promiseRef?.set(resolvedPromise(it))
return it
}
return breakpointManager.setBreakpoint(target, location.line, location.column, location.url, breakpoint?.conditionExpression?.expression, promiseRef = promiseRef)
val setBreakpointResult = breakpointManager.setBreakpoint(target, location.line, location.column, location.url,
breakpoint?.conditionExpression?.expression)
return when (setBreakpointResult) {
is BreakpointManager.BreakpointExist -> {
unregisterAnyFirstLineBreakpoint(setBreakpointResult.existingBreakpoint)
promiseRef?.set(resolvedPromise(setBreakpointResult.existingBreakpoint))
setBreakpointResult.existingBreakpoint
}
is BreakpointManager.BreakpointCreated -> {
promiseRef?.set(setBreakpointResult.isResolved)
setBreakpointResult.breakpoint
}
else -> {
throw AssertionError(setBreakpointResult.javaClass)
}
}
}
protected abstract fun createTarget(breakpoint: XLineBreakpoint<*>?, breakpointManager: BreakpointManager, location: Location, isTemporary: Boolean): BreakpointTarget