DebugView.st
changeset 19020 7c16c8db82dd
parent 18863 8ca8ff8081a1
child 19030 892df81100b6
--- a/DebugView.st	Fri Aug 23 22:07:16 2019 +0200
+++ b/DebugView.st	Fri Aug 23 23:40:01 2019 +0200
@@ -37,13 +37,14 @@
 		classToDefineIn gotoApplicationActionMethodButton
 		isStoppedInApplicationAction isStoppedAtStatementBreakpoint
 		verboseBacktraceHolder foundRaisingMethod gotoRaisingMethodButton
-		stepInButton infoLabelHolder isStoppedAtError'
+		stepInButton infoLabelHolder isStoppedAtError isStoppedAtAssert'
 	classVariableNames:'CachedDebugger CachedExclusive OpenDebuggers MoreDebuggingDetail
 		DebuggingDebugger DebuggingDebugger2 DebuggingContextWalk
 		DefaultDebuggerBackgroundColor InitialNChainShown IgnoredHalts
 		ShowThreadID LastIgnoreHaltNTimes LastIgnoreHaltDuration
 		LastExtent LastOrigin RememberedCallChain DebuggingDebugger3
-		NumberOfDebuggers DebuggerOnMainDisplayOnly IgnoredErrors'
+		NumberOfDebuggers DebuggerOnMainDisplayOnly IgnoredErrors
+		IgnoredAsserts'
 	poolDictionaries:''
 	category:'Interface-Debugger'
 !
@@ -303,12 +304,31 @@
     ^ IgnoredHalts notEmptyOrNil
 !
 
+ignoreAssertIn:haltingMethod at:lineNrOfHalt
+        forCount:countOrNil orTimeDuration:dTOrNil orUntilShiftKey:untilShiftKey
+        orReceiverClass:receiverClassOrNil orProcess:processOrNil
+        orIfCalledFromMethod:ifCalledForMethodOrNil
+
+    "remember to ignore an assert in some method for some number of invocations
+     or until some time has elapsed. 
+     With a count of -1, it is ignored forever (i.e. until reenabled via the settings).
+     With nil count and time arguments, such an ignored assert is reactivated"
+
+    self
+        ignoreHaltOrBreakpoint:#assert
+        method:haltingMethod line:lineNrOfHalt
+        parameter:nil
+        forCount:countOrNil orTimeDuration:dTOrNil orUntilShiftKey:untilShiftKey
+        orReceiverClass:receiverClassOrNil orProcess:processOrNil
+        orIfCalledFromMethod:ifCalledForMethodOrNil
+!
+
 ignoreBreakpointWithParameter:parameterOrNil
         forCount:countOrNil orTimeDuration:dTOrNil orUntilShiftKey:untilShiftKey
         orReceiverClass:receiverClassOrNil orProcess:processOrNil
 
-    "remember to ignore a breakpoint with a parameter (i.e. breakpoint:#cg) for some number of invocations
-     or until some time has elapsed.
+    "remember to ignore a breakpoint with a parameter (i.e. breakpoint:#cg) 
+     for some number of invocations or until some time has elapsed.
      With nil count and time arguments, such an ignored breakpoint is reactivated"
 
     self
@@ -325,7 +345,7 @@
         orReceiverClass:receiverClassOrNil orProcess:processOrNil
         orIfCalledFromMethod:ifCalledFromMethodOrNil
 
-    "remember to ignore an error, either forEver, for some number of invocations
+    "remember to ignore an error, either forEver, for some number of invocations,
      or until some time has elapsed.
      With nil count and time arguments, such an ignored error is reactivated"
 
@@ -393,7 +413,7 @@
         forCount:countOrNil orTimeDuration:dTOrNil orUntilShiftKey:untilShiftKey
         orReceiverClass:receiverClassOrNil orProcess:processOrNil
 
-    "remember to ignore a halt in some method for some number of invocations
+    "remember to ignore a halt in some method for some number of invocations,
      or until some time has elapsed.
      With nil count and time arguments, such an ignored halt is reactivated"
 
@@ -413,8 +433,7 @@
 
     "remember to ignore a halt in some method for some number of invocations
      or until some time has elapsed. 
-     With a count of -1, it is ignored forever (i.e. until reenabled via the
-     settings).
+     With a count of -1, it is ignored forever (i.e. until reenabled via the settings).
      With nil count and time arguments, such an ignored halt is reactivated"
 
     self
@@ -430,8 +449,8 @@
         forCount:countOrNil orTimeDuration:dTOrNil orUntilShiftKey:untilShiftKey
         orReceiverClass:receiverClassOrNil orProcess:processOrNil
 
-    "remember to ignore a breakpoint with a parameter (i.e. breakpoint:#cg) for some number of invocations
-     or until some time has elapsed.
+    "remember to ignore a breakpoint with a parameter (i.e. breakpoint:#cg) 
+     for some number of invocations or until some time has elapsed.
      With nil count and time arguments, such an ignored breakpoint is reactivated"
 
     ^ self
@@ -446,8 +465,8 @@
         orReceiverClass:receiverClassOrNil orProcess:processOrNil
         orIfCalledFromMethod:ifCalledFromMethodOrNil
 
-    "remember to ignore a breakpoint with a parameter (i.e. breakpoint:#cg) for some number of invocations
-     or until some time has elapsed.
+    "remember to ignore a breakpoint with a parameter (i.e. breakpoint:#cg) 
+     for some number of invocations or until some time has elapsed.
      With nil count and time arguments, such an ignored breakpoint is reactivated"
 
     |oldEntry ign|
@@ -519,6 +538,32 @@
     "Modified: / 05-06-2018 / 18:34:17 / Claus Gittinger"
 !
 
+isAssertToBeIgnoredIn:haltingMethod atLineNr:lineNrInHaltingMethod context:aContext modifyEntryCount:modifyCount
+    "should an assert be ignored ?"
+
+    IgnoredAsserts isNil ifTrue:[^ false].
+
+    "/ Transcript showCR:'halt/break in ',haltingMethod printString,' at ',lineNrInHaltingMethod printString.
+    IgnoredAsserts do:[:ign |
+        (ign isAssertIgnoredInMethod:haltingMethod line:lineNrInHaltingMethod context:aContext) ifTrue:[
+            Transcript showCR:'Debugger [info]: assert ignored: %1' with:ign.
+
+            modifyCount ifTrue:[ ign decrementIgnoreCount ].
+            ign isHaltIgnored ifFalse:[
+                Transcript showCR:'Debugger [info]: no longer ignored (rest count=0)'.
+                IgnoredHalts remove:ign ifAbsent:[].
+            ].
+            ^ true.
+        ].
+    ].
+
+    IgnoredAsserts := (IgnoredAsserts reject:[:ign | ign isActive not]) asNilIfEmpty.
+
+    ^ false.
+
+    "Modified (comment): / 06-03-2012 / 12:51:43 / cg"
+!
+
 isBreakpointToBeIgnoredForParameter:parameter context:aContext modifyEntryCount:modifyCount
     "/ should a breakpoint be ignored ?
 
@@ -1051,6 +1096,7 @@
           )
          (MenuItem
             label: 'Ignore this Halt/BreakPoint'
+            enabled: isStoppedAtHaltOrBreakPointOrSelectedContextIsWrappedAndHasPreviousIgnoreTime
             submenu: 
            (Menu
               (
@@ -1151,6 +1197,7 @@
               nil
             )
           )
+
          (MenuItem
             label: 'Ignore all Halts/BreakPoints'
             submenu: 
@@ -1182,6 +1229,63 @@
             label: '-'
           )
          (MenuItem
+            label: 'Ignore this Assertion'
+            enabled: isStoppedAtAssert
+            submenu: 
+           (Menu
+              (
+               (MenuItem
+                  enabled: isStoppedAtAssert
+                  label: 'Forever (Until Ignoring is Stopped)'
+                  itemValue: ignoreAssertionForever
+                )
+               (MenuItem
+                  enabled: isStoppedAtAssert
+                  label: 'For Some Time...'
+                  itemValue: openIgnoreAssertionUntilTimeElapsedDialog
+                )
+               (MenuItem
+                  label: 'For Another Timeduration'
+                  itemValue: ignoreAssertionUntilAnotherTimeDurationElapsed
+                  isVisible: isStoppedAtAssertAndHasPreviousIgnoreTime
+                )
+               (MenuItem
+                  enabled: isStoppedAtAssert
+                  label: 'For the Next N Times...'
+                  itemValue: openIgnoreAssertionNTimesDialog
+                )
+               (MenuItem
+                  enabled: isStoppedAtAssert
+                  label: 'Until Shift-Key is Pressed'
+                  itemValue: ignoreAssertionUntilShiftKeyIsPressed
+                )
+               (MenuItem
+                  label: '-'
+                )
+               (MenuItem
+                  enabled: isStoppedAtAssert
+                  label: 'In Current Process'
+                  itemValue: ignoreAssertionForCurrentProcess
+                )
+               (MenuItem
+                  enabled: isStoppedAtAssert
+                  label: 'For this Receiver Class'
+                  itemValue: ignoreAssertionForThisReceiverClass
+                )
+               (MenuItem
+                  enabled: isStoppedAtAssert
+                  label: 'If Called From'
+                  submenuChannel: menuForIgnoreAssertionIfCalledFromAnyOf
+                )
+               )
+              nil
+              nil
+            )
+          )
+         (MenuItem
+            label: '-'
+          )
+         (MenuItem
             label: 'Ignore this Error and Abort'
             submenu: 
            (Menu
@@ -2130,6 +2234,16 @@
 
 !DebugView class methodsFor:'private'!
 
+assertSelectors
+    "these can be ignored via the menu"
+    
+    ^ #( 
+        #'assert:' #'assert:description:' #'assert:message:' #'assertNotNil'   
+    ).
+
+    "Created: / 27-02-2019 / 13:38:12 / Claus Gittinger"
+!
+
 errorSelectors
     "these can be ignored via the menu"
     
@@ -7036,6 +7150,54 @@
     self allowBreakPointsInDebugger:true
 !
 
+ignoreAllAssertsForCurrentProcess
+    self
+        addIgnoredAssertForCount:nil orTimeDuration:nil orUntilShiftKey:false
+        orThisReceiverClass:false orCurrentProcess:true
+        orIfCalledFromMethod:nil
+        forAll:true.
+
+    "Created: / 27-01-2012 / 11:32:14 / cg"
+!
+
+ignoreAllAssertsForThisReceiverClass
+    self
+        addIgnoredAssertForCount:nil orTimeDuration:nil orUntilShiftKey:false
+        orThisReceiverClass:true orCurrentProcess:false
+        orIfCalledFromMethod:nil
+        forAll:true.
+
+    "Created: / 27-01-2012 / 11:32:14 / cg"
+!
+
+ignoreAllAssertsForever
+    self
+        addIgnoredAssertForCount:-1 orTimeDuration:nil orUntilShiftKey:false
+        orThisReceiverClass:false orCurrentProcess:false
+        orIfCalledFromMethod:nil
+        forAll:true.
+
+    "Created: / 08-05-2011 / 10:19:56 / cg"
+!
+
+ignoreAllAssertsIfCalledFromMethod:aMethod
+    self
+        addIgnoredAssertForCount:nil orTimeDuration:nil orUntilShiftKey:false
+        orThisReceiverClass:false orCurrentProcess:false
+        orIfCalledFromMethod:aMethod
+        forAll:true.
+!
+
+ignoreAllAssertsUntilShiftKeyIsPressed
+    self
+        addIgnoredAssertForCount:nil orTimeDuration:nil orUntilShiftKey:true
+        orThisReceiverClass:false orCurrentProcess:false
+        orIfCalledFromMethod:nil
+        forAll:true.
+
+    "Created: / 27-01-2012 / 11:32:14 / cg"
+!
+
 ignoreAllHaltsForCurrentProcess
     self
         addIgnoredHaltForCount:nil orTimeDuration:nil orUntilShiftKey:false
@@ -7084,6 +7246,64 @@
     "Created: / 27-01-2012 / 11:32:14 / cg"
 !
 
+ignoreAssertForCurrentProcess
+    self
+        addIgnoredAssertForCount:nil orTimeDuration:nil orUntilShiftKey:false
+        orThisReceiverClass:false orCurrentProcess:true
+        orIfCalledFromMethod:nil
+        forAll:false.
+
+    "Created: / 27-01-2012 / 11:32:14 / cg"
+!
+
+ignoreAssertForThisReceiverClass
+    self
+        addIgnoredAssertForCount:nil orTimeDuration:nil orUntilShiftKey:false
+        orThisReceiverClass:true orCurrentProcess:false
+        orIfCalledFromMethod:nil
+        forAll:false.
+
+    "Created: / 27-01-2012 / 11:32:14 / cg"
+!
+
+ignoreAssertForever
+    self
+        addIgnoredAssertForCount:-1 orTimeDuration:nil orUntilShiftKey:false
+        orThisReceiverClass:false orCurrentProcess:false
+        orIfCalledFromMethod:nil
+        forAll:false.
+
+    "Modified: / 27-01-2012 / 11:31:37 / cg"
+!
+
+ignoreAssertIfCalledFromMethod:aMethod
+    self
+        addIgnoredAssertForCount:nil orTimeDuration:nil orUntilShiftKey:false
+        orThisReceiverClass:false orCurrentProcess:false
+        orIfCalledFromMethod:aMethod
+        forAll:false.
+!
+
+ignoreAssertUntilAnotherTimeDurationElapsed
+    self
+        addIgnoredAssertForCount:nil orTimeDuration:LastIgnoreHaltDuration orUntilShiftKey:false
+        orThisReceiverClass:false orCurrentProcess:false
+        orIfCalledFromMethod:nil
+        forAll:false.
+
+    "Created: / 09-11-2018 / 20:40:17 / Claus Gittinger"
+!
+
+ignoreAssertUntilShiftKeyIsPressed
+    self
+        addIgnoredAssertForCount:nil orTimeDuration:nil orUntilShiftKey:true
+        orThisReceiverClass:false orCurrentProcess:false
+        orIfCalledFromMethod:nil
+        forAll:false.
+
+    "Created: / 27-01-2012 / 11:36:54 / cg"
+!
+
 ignoreBreakpointsWithThisParameterForever
     Object disableBreakPoint:breakPointParameter.
     "/ self addIgnoredHaltForCount:-1 orTimeDuration:nil orUntilShiftKey:false forAll:false.
@@ -7625,6 +7845,380 @@
     ^ codeView selectedInterval
 !
 
+setContext:aContext releaseInspectors:releaseInspectors
+    "show calling chain from aContext in the walk-back listview.
+     Most complications here arise from filtering less-interesting contexts
+     if not in verbose-context mode or when hiding implementation contexts.
+     There is a lot of heuristic magic here, to make the debugger as useful
+     as possible for the user (but not particularly for the debugger-developer).
+     On the fly, as we move along the contexts, update the isStoppedAtXXX booleans."
+
+    |con sel text method caller caller2 called called2 m count c cc sndr
+     suspendContext calledBySuspendContext nm h calledContext show2
+     alreadyInApplicationCode verboseBacktrace
+     errorSelectors haltSelectors assertSelectors|
+
+"/    (contextArray size > 0 and:[aContext == (contextArray at:1)]) ifTrue:[
+"/        "no change"
+"/        ^ false
+"/    ].
+
+    errorSelectors := self class errorSelectors.
+    haltSelectors := self class haltSelectors.
+    assertSelectors := self class assertSelectors.
+
+    isStoppedAtHaltOrBreakPoint := isStoppedAtBreakPointWithParameter := false.
+    foundRaisingMethod := false.
+    isStoppedInModalDialog := isStoppedInApplicationAction := alreadyInApplicationCode := false.
+    isStoppedAtStatementBreakpoint := isStoppedAtError := isStoppedAtAssert := false.
+    firstContext := aContext.
+    verboseBacktrace := self verboseBacktraceHolder value.
+
+    m := contextView middleButtonMenu.
+    m notNil ifTrue:[
+        m disable:#showMore.
+    ].
+    canShowMore := false.
+
+    aContext isNil ifTrue:[
+        text := Array with:'** no context **'.
+        contextArray := nil.
+    ] ifFalse:[
+        text := OrderedCollection new:nChainShown.
+        contextArray := OrderedCollection new:nChainShown.
+
+        con := aContext.
+        calledContext := nil.
+
+        DebuggingContextWalk == true ifTrue:[
+            '======================================' print. con printCR.
+        ].
+        alreadyInApplicationCode :=
+                con receiver isProtoObject not     "/ careful to not force futures/lazy values
+                and:[con receiver class includesBehavior:ApplicationModel].     "do not use #isKindOf: - ProtoObject compat"
+
+        verboseBacktrace ~~ true ifTrue:[
+            "/ with dense backtrace, hide the ProcessorScheduler
+            "/ contexts at the top; look for a Process>>suspend*
+            "/ context within the first 10 contexts
+
+            suspendContext := nil.
+            c := con.
+            1 to:10 do:[:i |
+                |selector|
+
+                c notNil ifTrue:[
+                    selector := c selector.
+                    selector notNil ifTrue:[
+                        (selector isSymbol and:[(selector startsWith:'suspend') and:[c receiver isMemberOf:Process]]) ifTrue:[
+                            suspendContext := c.
+                            calledBySuspendContext := cc.
+                        ].
+                    ].
+                    cc := c.
+                    c := c sender.
+                ]
+            ].
+            suspendContext notNil ifTrue:[
+                con := suspendContext.
+                calledContext := calledBySuspendContext.
+                suspendContext := nil
+            ].
+        ].
+        "/ Transcript show:'1 '; showCR:con.
+        con notNil ifTrue:[
+            "/ hide the halt implementation
+            sel := con selector.
+            (haltSelectors includes:sel) ifTrue:[
+                (method := con method) notNil ifTrue:[
+                    method mclass == Object ifTrue:[
+                        (sel isSymbol and:[ sel startsWith:'breakPoint:']) ifTrue:[
+                            isStoppedAtBreakPointWithParameter := true.
+                            breakPointParameter := con argAt:1.
+                        ].
+                        isStoppedAtHaltOrBreakPoint := true.
+                        verboseBacktrace ~~ true ifTrue:[
+                            calledContext := con.
+                            con := con sender.
+                        ]
+                    ] ifFalse:[
+                        method mclass == Breakpoint ifTrue:[
+                            isStoppedAtHaltOrBreakPoint := true.
+                            isStoppedAtStatementBreakpoint := true.
+                            verboseBacktrace ~~ true ifTrue:[
+                                calledContext := con.
+                                con := con sender.
+                            ].
+                            "/ Transcript show:'2 '; showCR:con.
+                        ].
+                    ].
+                ].
+            ].
+            (errorSelectors includes:sel) ifTrue:[
+                isStoppedAtError := true.
+            ].
+            (assertSelectors includes:sel) ifTrue:[
+                isStoppedAtAssert := true.
+            ].
+        ].
+
+        (verboseBacktrace not or:[ hideSupportCode]) ifTrue:[
+            [
+                con notNil
+                and:[ con isBlockContext not
+                and:[ con method notNil
+                and:[ (con method shouldBeSkippedInDebuggersWalkBack)
+                and:[ (haltSelectors includes: con selector) not]]]]
+            ] whileTrue:[
+                (errorSelectors includes:con selector) ifTrue:[
+                    isStoppedAtError := true.
+                ].
+                (assertSelectors includes:con selector) ifTrue:[
+                    isStoppedAtAssert := true.
+                ].
+                "/ Transcript show:'xx '; showCR:con.
+                calledContext := con.
+                con := con sender
+            ].
+        ].
+
+        "
+         get them all, by walking along the caller chain.
+         depending on the settings, skip some intermediate contexts
+         (such as collection enumeration implementations), which are usually not
+         of interest when debugging an application.
+         On the fly, gather some additional information
+         such as: are we at a halt/breakpoint, are we in a modal dialog opened,
+         are we coming from an application model's action etc.
+        "
+        count := 0.
+        [con notNil and:[count <= nChainShown]] whileTrue:[
+            "/ remember any halt/breakpoint or openModal on the fly
+            DebuggingContextWalk == true ifTrue:[ '---' print. con printCR ].
+
+            sel := con selector.
+            (errorSelectors includes:sel) ifTrue:[
+                isStoppedAtError := true.
+            ].
+            (assertSelectors includes:sel) ifTrue:[
+                isStoppedAtAssert := true.
+            ].
+            (haltSelectors includes:sel) ifTrue:[
+                (method := con method) notNil ifTrue:[
+                    method mclass == Object ifTrue:[
+                        (sel isSymbol and:[sel startsWith:'breakPoint:']) ifTrue:[
+                            isStoppedAtBreakPointWithParameter := true.
+                            breakPointParameter := con argAt:1.
+                        ].
+                        isStoppedAtHaltOrBreakPoint := true.
+                    ] ifFalse:[
+                        method mclass == Breakpoint ifTrue:[
+                            isStoppedAtHaltOrBreakPoint := true.
+                        ].
+                    ]
+                ]
+            ] ifFalse:[
+                ((sel == #openModal) or:[sel == #openModal:]) ifTrue:[
+                    isStoppedInModalDialog := true.
+                ] ifFalse:[
+                    ((sel == #doRaise) and:[(con receiver isException)]) ifTrue:[
+                        foundRaisingMethod := true.
+                    ] ifFalse:[
+                        alreadyInApplicationCode ifFalse:[
+                            (con receiver isProtoObject not  "/ careful to not force futures/lazy values
+                             and:[con receiver isKindOf:ApplicationModel]) ifTrue:[
+                                isStoppedInApplicationAction := true.
+                            ]
+                        ]
+                    ]
+                ].
+            ].
+
+            "/ '---' infoPrintCR.            
+            "/ con infoPrintCR.            
+
+            [
+                |show1|
+
+                show1 := self showingContext1:con calling:calledContext.
+                DebuggingDebugger3 == true ifTrue:[
+                    'showingContext1: (' print. con print. ') --> ' print. show1 printCR.
+                ].
+                show1
+            ] whileFalse:[
+                "/ 'skip1: ' infoPrint. con infoPrintCR.            
+                calledContext := con.
+                con := con sender.
+            ].
+
+            show2 := self showingContext2:con nesting:count.
+            DebuggingDebugger3 == true ifTrue:[
+                'showingContext2: (' print. con print. ') --> ' print. show2 printCR.
+            ].
+
+            show2 ifTrue:[
+                contextArray add:con.
+
+                (MoreDebuggingDetail == true) ifTrue:[
+                    nm := (((ObjectMemory addressOf:con) printStringRadix:16) , ' ' , con printString).
+                ] ifFalse:[
+                    nm := self contextListEntryFor:con.
+                ].
+                text add:nm.
+                count := count + 1.
+            ] ifFalse:[
+                "/ 'skip2: ' infoPrint. con infoPrintCR.            
+            ].
+
+            "/ with hidden support code, skip over internals of exceptions
+            false "hideSupportCode == true" ifTrue:[
+                "/ Transcript showCR:'x'.
+                (con isBlockContext
+                and:[ (h := con home) notNil
+                and:[ (self is:h inCallingChainOf:con) ]]) ifTrue:[
+                    |blocksReceiver|
+
+                    blocksReceiver := con receiver.
+                    c := con sender.
+                    [
+                        c notNil
+                        and:[
+                            sndr := c sender.
+                            (sndr ~= h)
+                            and:[
+                                blocksReceiver isCollection         "/ skip collection implementations
+                                or:[ ( #( #'handle:do:'         "/ skip exception implementations
+                                          #'handleDo:'
+                                          #'answer:do:'
+                                          #'ensure:' ) includes: c selector )
+                                or:[ #'perform:*'               "/ skip perform implementations
+                                         match: c selector ]]
+                            ]
+                        ]
+                    ] whileTrue:[
+                        "/ 'skip3: ' infoPrint. c infoPrintCR.
+                        c := sndr
+                    ].
+                    c notNil ifTrue:[
+                        con := c "sender".
+                    ].
+                ].
+            ].
+
+            "/
+            "/ kludge: if it's a wrapped method, then hide the wrap-call
+            "/
+            method := con method.
+            method notNil ifTrue:[
+                called := con.
+                caller := con sender.
+                (caller notNil and:[caller receiver == method]) ifTrue:[
+                    called2 := caller.
+                    caller2 := caller sender.
+                    caller2 notNil ifTrue:[
+                        (caller2 method isWrapped
+                        and:[ caller2 method originalMethod == method ]) ifTrue:[
+                            calledContext := called2.
+                            con := caller2
+                        ].
+                    ].
+
+                ].
+                caller := caller2 := nil
+            ].
+
+            "/ with dense backtrace, skip the doIt method's context
+            "/ (its dummy anyway) and fake that context's name
+
+            verboseBacktrace ~~ true ifTrue:[
+                (con isBlockContext
+                 and:[(h := con home) == con sender
+                 and:[h notNil
+                 and:[(self setOfHiddenCallingSelectors includes:h selector)
+                 and:[h method who isNil]]]]) ifTrue:[
+                    calledContext := con.
+                    con := con sender.
+                    text removeLast.
+
+                    text add:(self contextListEntryFor:con methodHome).
+                ].
+                h := nil.  "/ never keep refs to contexts unless you really need them ...
+            ].
+
+            "/ hook for subclasses
+            (self stopShowingMoreContextsAfter:con) ifTrue:[
+                con := nil
+            ] ifFalse:[
+                "/ with dense backtrace, don't show contexts below the doIt
+                ( verboseBacktrace ~~ true
+                and:[ (self setOfHiddenCallingSelectors includes:con selector) ]
+                ) ifTrue:[
+                    con := nil.
+                ] ifFalse:[
+                    calledContext := con.
+                    con := con sender
+                ].
+            ].
+        ].
+
+        "
+         did we reach the end ?
+        "
+        (con isNil or:[con sender isNil]) ifTrue:[
+
+            "/ the very last one is the startup context
+            "/ (in main) - it has nil as receiver and nil as selector
+
+            (contextArray notEmpty
+            and:[contextArray last selector isNil]) ifTrue:[
+                contextArray removeLast.
+                text removeLast
+            ].
+
+            verboseBacktrace ~~ true ifTrue:[
+                "/ in dense mode, remove process startup contexts (if any)
+
+                (contextArray size > 0
+                and:[(con := contextArray last) methodClass == Process]) ifTrue:[
+                    con selector == #start ifTrue:[
+                        contextArray removeLast.
+                        text removeLast.
+
+                        [contextArray size > 0
+                         and:[contextArray last methodHome == con]] whileTrue:[
+                            contextArray removeLast.
+                            text removeLast.
+                        ]
+                    ]
+                ]
+            ]
+        ] ifFalse:[
+            m notNil ifTrue:[
+                m enable:#showMore.
+            ].
+            canShowMore := true.
+            text add:(resources string:'*** more walkback follows - click here to see them ***')
+        ].
+    ].
+
+    contextView setList:text.
+
+    releaseInspectors ifTrue:[
+        receiverInspector release.
+        contextInspector release.
+    ].
+
+    m notNil ifTrue:[
+        m disableAll:#(addBreakpoint removeBreakpoint browseImplementors browseSenders browseReceiversClass).
+    ].
+    self updateMenuItems.
+    ^ true
+
+    "Created: / 14-12-1995 / 19:10:31 / cg"
+    "Modified: / 30-11-2017 / 12:16:08 / cg"
+    "Modified: / 27-02-2019 / 22:38:55 / Claus Gittinger"
+!
+
 showError:message
     codeView contents:(resources string:message).
     shown ifTrue:[
@@ -8078,25 +8672,29 @@
     ^ exitAction == #abort
 !
 
+isStoppedAtAssert
+    ^ isStoppedAtAssert ? false 
+!
+
 isStoppedAtBreakPointWithParameter
-    ^ isStoppedAtBreakPointWithParameter
+    ^ isStoppedAtBreakPointWithParameter ? false 
 
     "Created: / 06-03-2012 / 12:16:56 / cg"
 !
 
 isStoppedAtError
-    ^ isStoppedAtError "/ ^ self isStoppedAtHaltOrBreakPoint not
+    ^ isStoppedAtError ? false  "/ ^ self isStoppedAtHaltOrBreakPoint not
 
     "Created: / 27-02-2019 / 12:36:35 / Claus Gittinger"
     "Modified: / 27-02-2019 / 22:18:04 / Claus Gittinger"
 !
 
 isStoppedAtHaltOrBreakPoint
-    ^ isStoppedAtHaltOrBreakPoint
+    ^ isStoppedAtHaltOrBreakPoint ? false 
 !
 
 isStoppedAtHaltOrBreakPointOrSelectedContextIsWrapped
-    ^ isStoppedAtHaltOrBreakPoint or:[self selectedContextIsWrapped]
+    ^ (isStoppedAtHaltOrBreakPoint ? false) or:[self selectedContextIsWrapped]
 !
 
 isStoppedAtHaltOrBreakPointOrSelectedContextIsWrappedAndHasPreviousIgnoreTime
@@ -8128,6 +8726,46 @@
 
 !DebugView methodsFor:'private-breakpoints'!
 
+addIgnoredAssertForCount:countOrNil
+        orTimeDuration:dTOrNil orUntilShiftKey:untilShiftKey
+        orThisReceiverClass:forThisReceiverClass orCurrentProcess:forCurrentProcess
+        orIfCalledFromMethod:ifCalledForMethodOrNil
+        forAll:aBoolean
+
+    |assertingContext assertingMethod lineNrOfHalt receiverClassOrNil processOrNil|
+
+    aBoolean ifTrue:[
+        assertingMethod := #all
+    ] ifFalse:[
+        assertingContext := self findHaltingContext.
+        assertingContext isNil ifTrue:[
+            Transcript showCR:'no asserting context found'.
+            ^ self
+        ].
+
+        assertingMethod := assertingContext method.
+        lineNrOfHalt := assertingContext lineNumber.
+        (lineNrOfHalt isNil or:[lineNrOfHalt <= 0]) ifTrue:[
+            Transcript showCR:'no assert lineNr found'.
+            ^ self
+        ].
+        forThisReceiverClass ifTrue:[
+            receiverClassOrNil := assertingContext receiver class
+        ].
+        forCurrentProcess ifTrue:[
+            processOrNil := Processor activeProcess
+        ].
+    ].
+
+    self class
+        ignoreHaltIn:assertingMethod at:lineNrOfHalt
+        forCount:countOrNil orTimeDuration:dTOrNil orUntilShiftKey:untilShiftKey
+        orReceiverClass:receiverClassOrNil orProcess:processOrNil
+        orIfCalledFromMethod:ifCalledForMethodOrNil
+
+    "Created: / 27-01-2012 / 11:31:12 / cg"
+!
+
 addIgnoredErrorForCount:countOrNil
         orTimeDuration:dTOrNil orUntilShiftKey:untilShiftKey
         orThisReceiverClass:forThisReceiverClass orCurrentProcess:forCurrentProcess
@@ -8223,6 +8861,13 @@
     ^ m notNil and:[m isEnabled:#removeBreakpoint]
 !
 
+findAssertingContext
+    ^ self
+        findContextWithAnySelector:(self class assertSelectors) 
+        orMClass:nil 
+        orWrapped:false
+!
+
 findContextWithAnySelector:selectors orMClass:mClass orWrapped:orWrappedBoolean
     |con|
 
@@ -8536,370 +9181,6 @@
     "Modified: 27.6.1996 / 17:21:59 / cg"
 !
 
-setContext:aContext releaseInspectors:releaseInspectors
-    "show calling chain from aContext in the walk-back listview.
-     Most complications here arise from filtering less-interesting contexts
-     if not in verbose-context mode or when hiding implementation contexts.
-     There is a lot of heuristic magic here, to make the debugger as useful
-     as possible for the user (but not particularly for the debugger-developer).
-     On the fly, as we move along the contexts, update the isStoppedAtXXX booleans."
-
-    |con sel text method caller caller2 called called2 m count c cc sndr
-     suspendContext calledBySuspendContext nm h calledContext show2
-     alreadyInApplicationCode verboseBacktrace
-     errorSelectors haltSelectors|
-
-"/    (contextArray size > 0 and:[aContext == (contextArray at:1)]) ifTrue:[
-"/        "no change"
-"/        ^ false
-"/    ].
-
-    errorSelectors := self class errorSelectors.
-    haltSelectors := self class haltSelectors.
-    
-    isStoppedAtHaltOrBreakPoint := isStoppedAtBreakPointWithParameter := false.
-    foundRaisingMethod := false.
-    isStoppedInModalDialog := isStoppedInApplicationAction := alreadyInApplicationCode := false.
-    isStoppedAtStatementBreakpoint := isStoppedAtError := false.
-    firstContext := aContext.
-    verboseBacktrace := self verboseBacktraceHolder value.
-
-    m := contextView middleButtonMenu.
-    m notNil ifTrue:[
-        m disable:#showMore.
-    ].
-    canShowMore := false.
-
-    aContext isNil ifTrue:[
-        text := Array with:'** no context **'.
-        contextArray := nil.
-    ] ifFalse:[
-        text := OrderedCollection new:nChainShown.
-        contextArray := OrderedCollection new:nChainShown.
-
-        con := aContext.
-        calledContext := nil.
-
-        DebuggingContextWalk == true ifTrue:[
-            '======================================' print. con printCR.
-        ].
-        alreadyInApplicationCode :=
-                con receiver isProtoObject not     "/ careful to not force futures/lazy values
-                and:[con receiver class includesBehavior:ApplicationModel].     "do not use #isKindOf: - ProtoObject compat"
-
-        verboseBacktrace ~~ true ifTrue:[
-            "/ with dense backtrace, hide the ProcessorScheduler
-            "/ contexts at the top; look for a Process>>suspend*
-            "/ context within the first 10 contexts
-
-            suspendContext := nil.
-            c := con.
-            1 to:10 do:[:i |
-                |selector|
-
-                c notNil ifTrue:[
-                    selector := c selector.
-                    selector notNil ifTrue:[
-                        (selector isSymbol and:[(selector startsWith:'suspend') and:[c receiver isMemberOf:Process]]) ifTrue:[
-                            suspendContext := c.
-                            calledBySuspendContext := cc.
-                        ].
-                    ].
-                    cc := c.
-                    c := c sender.
-                ]
-            ].
-            suspendContext notNil ifTrue:[
-                con := suspendContext.
-                calledContext := calledBySuspendContext.
-                suspendContext := nil
-            ].
-        ].
-        "/ Transcript show:'1 '; showCR:con.
-        con notNil ifTrue:[
-            "/ hide the halt implementation
-            sel := con selector.
-            (haltSelectors includes:sel) ifTrue:[
-                (method := con method) notNil ifTrue:[
-                    method mclass == Object ifTrue:[
-                        (sel isSymbol and:[ sel startsWith:'breakPoint:']) ifTrue:[
-                            isStoppedAtBreakPointWithParameter := true.
-                            breakPointParameter := con argAt:1.
-                        ].
-                        isStoppedAtHaltOrBreakPoint := true.
-                        verboseBacktrace ~~ true ifTrue:[
-                            calledContext := con.
-                            con := con sender.
-                        ]
-                    ] ifFalse:[
-                        method mclass == Breakpoint ifTrue:[
-                            isStoppedAtHaltOrBreakPoint := true.
-                            isStoppedAtStatementBreakpoint := true.
-                            verboseBacktrace ~~ true ifTrue:[
-                                calledContext := con.
-                                con := con sender.
-                            ].
-                            "/ Transcript show:'2 '; showCR:con.
-                        ].
-                    ].
-                ].
-            ].
-            (errorSelectors includes:sel) ifTrue:[
-                isStoppedAtError := true.
-            ].
-        ].
-
-        (verboseBacktrace not or:[ hideSupportCode]) ifTrue:[
-            [
-                con notNil
-                and:[ con isBlockContext not
-                and:[ con method notNil
-                and:[ (con method shouldBeSkippedInDebuggersWalkBack)
-                and:[ (haltSelectors includes: con selector) not]]]]
-            ] whileTrue:[
-                (errorSelectors includes:con selector) ifTrue:[
-                    isStoppedAtError := true.
-                ].
-                "/ Transcript show:'xx '; showCR:con.
-                calledContext := con.
-                con := con sender
-            ].
-        ].
-
-        "
-         get them all, by walking along the caller chain.
-         depending on the settings, skip some intermediate contexts
-         (such as collection enumeration implementations), which are usually not
-         of interest when debugging an application.
-         On the fly, gather some additional information
-         such as: are we at a halt/breakpoint, are we in a modal dialog opened,
-         are we coming from an application model's action etc.
-        "
-        count := 0.
-        [con notNil and:[count <= nChainShown]] whileTrue:[
-            "/ remember any halt/breakpoint or openModal on the fly
-            DebuggingContextWalk == true ifTrue:[ '---' print. con printCR ].
-
-            sel := con selector.
-            (errorSelectors includes:sel) ifTrue:[
-                isStoppedAtError := true.
-            ].
-            (haltSelectors includes:sel) ifTrue:[
-                (method := con method) notNil ifTrue:[
-                    method mclass == Object ifTrue:[
-                        (sel isSymbol and:[sel startsWith:'breakPoint:']) ifTrue:[
-                            isStoppedAtBreakPointWithParameter := true.
-                            breakPointParameter := con argAt:1.
-                        ].
-                        isStoppedAtHaltOrBreakPoint := true.
-                    ] ifFalse:[
-                        method mclass == Breakpoint ifTrue:[
-                            isStoppedAtHaltOrBreakPoint := true.
-                        ].
-                    ]
-                ]
-            ] ifFalse:[
-                ((sel == #openModal) or:[sel == #openModal:]) ifTrue:[
-                    isStoppedInModalDialog := true.
-                ] ifFalse:[
-                    ((sel == #doRaise) and:[(con receiver isException)]) ifTrue:[
-                        foundRaisingMethod := true.
-                    ] ifFalse:[
-                        alreadyInApplicationCode ifFalse:[
-                            (con receiver isProtoObject not  "/ careful to not force futures/lazy values
-                             and:[con receiver isKindOf:ApplicationModel]) ifTrue:[
-                                isStoppedInApplicationAction := true.
-                            ]
-                        ]
-                    ]
-                ].
-            ].
-
-            "/ '---' infoPrintCR.            
-            "/ con infoPrintCR.            
-
-            [
-                |show1|
-
-                show1 := self showingContext1:con calling:calledContext.
-                DebuggingDebugger3 == true ifTrue:[
-                    'showingContext1: (' print. con print. ') --> ' print. show1 printCR.
-                ].
-                show1
-            ] whileFalse:[
-                "/ 'skip1: ' infoPrint. con infoPrintCR.            
-                calledContext := con.
-                con := con sender.
-            ].
-
-            show2 := self showingContext2:con nesting:count.
-            DebuggingDebugger3 == true ifTrue:[
-                'showingContext2: (' print. con print. ') --> ' print. show2 printCR.
-            ].
-
-            show2 ifTrue:[
-                contextArray add:con.
-
-                (MoreDebuggingDetail == true) ifTrue:[
-                    nm := (((ObjectMemory addressOf:con) printStringRadix:16) , ' ' , con printString).
-                ] ifFalse:[
-                    nm := self contextListEntryFor:con.
-                ].
-                text add:nm.
-                count := count + 1.
-            ] ifFalse:[
-                "/ 'skip2: ' infoPrint. con infoPrintCR.            
-            ].
-
-            "/ with hidden support code, skip over internals of exceptions
-            false "hideSupportCode == true" ifTrue:[
-                "/ Transcript showCR:'x'.
-                (con isBlockContext
-                and:[ (h := con home) notNil
-                and:[ (self is:h inCallingChainOf:con) ]]) ifTrue:[
-                    |blocksReceiver|
-
-                    blocksReceiver := con receiver.
-                    c := con sender.
-                    [
-                        c notNil
-                        and:[
-                            sndr := c sender.
-                            (sndr ~= h)
-                            and:[
-                                blocksReceiver isCollection         "/ skip collection implementations
-                                or:[ ( #( #'handle:do:'         "/ skip exception implementations
-                                          #'handleDo:'
-                                          #'answer:do:'
-                                          #'ensure:' ) includes: c selector )
-                                or:[ #'perform:*'               "/ skip perform implementations
-                                         match: c selector ]]
-                            ]
-                        ]
-                    ] whileTrue:[
-                        "/ 'skip3: ' infoPrint. c infoPrintCR.
-                        c := sndr
-                    ].
-                    c notNil ifTrue:[
-                        con := c "sender".
-                    ].
-                ].
-            ].
-
-            "/
-            "/ kludge: if it's a wrapped method, then hide the wrap-call
-            "/
-            method := con method.
-            method notNil ifTrue:[
-                called := con.
-                caller := con sender.
-                (caller notNil and:[caller receiver == method]) ifTrue:[
-                    called2 := caller.
-                    caller2 := caller sender.
-                    caller2 notNil ifTrue:[
-                        (caller2 method isWrapped
-                        and:[ caller2 method originalMethod == method ]) ifTrue:[
-                            calledContext := called2.
-                            con := caller2
-                        ].
-                    ].
-
-                ].
-                caller := caller2 := nil
-            ].
-
-            "/ with dense backtrace, skip the doIt method's context
-            "/ (its dummy anyway) and fake that context's name
-
-            verboseBacktrace ~~ true ifTrue:[
-                (con isBlockContext
-                 and:[(h := con home) == con sender
-                 and:[h notNil
-                 and:[(self setOfHiddenCallingSelectors includes:h selector)
-                 and:[h method who isNil]]]]) ifTrue:[
-                    calledContext := con.
-                    con := con sender.
-                    text removeLast.
-
-                    text add:(self contextListEntryFor:con methodHome).
-                ].
-                h := nil.  "/ never keep refs to contexts unless you really need them ...
-            ].
-
-            "/ hook for subclasses
-            (self stopShowingMoreContextsAfter:con) ifTrue:[
-                con := nil
-            ] ifFalse:[
-                "/ with dense backtrace, don't show contexts below the doIt
-                ( verboseBacktrace ~~ true
-                and:[ (self setOfHiddenCallingSelectors includes:con selector) ]
-                ) ifTrue:[
-                    con := nil.
-                ] ifFalse:[
-                    calledContext := con.
-                    con := con sender
-                ].
-            ].
-        ].
-
-        "
-         did we reach the end ?
-        "
-        (con isNil or:[con sender isNil]) ifTrue:[
-
-            "/ the very last one is the startup context
-            "/ (in main) - it has nil as receiver and nil as selector
-
-            (contextArray notEmpty
-            and:[contextArray last selector isNil]) ifTrue:[
-                contextArray removeLast.
-                text removeLast
-            ].
-
-            verboseBacktrace ~~ true ifTrue:[
-                "/ in dense mode, remove process startup contexts (if any)
-
-                (contextArray size > 0
-                and:[(con := contextArray last) methodClass == Process]) ifTrue:[
-                    con selector == #start ifTrue:[
-                        contextArray removeLast.
-                        text removeLast.
-
-                        [contextArray size > 0
-                         and:[contextArray last methodHome == con]] whileTrue:[
-                            contextArray removeLast.
-                            text removeLast.
-                        ]
-                    ]
-                ]
-            ]
-        ] ifFalse:[
-            m notNil ifTrue:[
-                m enable:#showMore.
-            ].
-            canShowMore := true.
-            text add:(resources string:'*** more walkback follows - click here to see them ***')
-        ].
-    ].
-
-    contextView setList:text.
-
-    releaseInspectors ifTrue:[
-        receiverInspector release.
-        contextInspector release.
-    ].
-
-    m notNil ifTrue:[
-        m disableAll:#(addBreakpoint removeBreakpoint browseImplementors browseSenders browseReceiversClass).
-    ].
-    self updateMenuItems.
-    ^ true
-
-    "Created: / 14-12-1995 / 19:10:31 / cg"
-    "Modified: / 30-11-2017 / 12:16:08 / cg"
-    "Modified: / 27-02-2019 / 22:38:55 / Claus Gittinger"
-!
-
 setContextSkippingInterruptContexts:aContext
     "show calling chain from aContext in the walk-back listview.
      Ignore any non-interesting interrupt-context."