--- 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."