Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 281057

Summary: “smart” comments for breakpoints and watchpoints
Product: [Eclipse Project] JDT Reporter: Bogdan Butnaru <bogdanb>
Component: DebugAssignee: JDT-Debug-Inbox <jdt-debug-inbox>
Status: RESOLVED WONTFIX QA Contact:
Severity: enhancement    
Priority: P3 CC: Michael_Rennie
Version: 3.4.2Keywords: helpwanted
Target Milestone: ---   
Hardware: All   
OS: All   
Whiteboard:

Description Bogdan Butnaru CLA 2009-06-22 06:21:01 EDT
Idea: introduce a “microformat” for comments specific to debugging. This is better explained with an example:

/* Example; this comment would be ignored by the new feature. */
void example(){
	for(int i=0; i<1000;){
		// BREAK A: if(i%100==0)
		// SHOW i
		// WATCH i;
		do{
			i = something(i);
			// BREAK with A
		}while(someTest(i));
	}
}
/* End example; this comment would also be ignored. */

What it all means:
	* “// BREAK A: if(i%100==0)” — means  “allow a breakpoint here; name it A; set its condition to « i%100==0 »”. 
			The user can then add a breakpoint at this point (e.g., by double-clicking on the thin bar at the left of the window). The actual break position is the first allowable break-point following the end of the comment. (In this case, it's the line with the “i = something(i)” statement. It could also be a function declaration, breaking whenever it's called.) 
			The name can be any identifier between the “BREAK” label and the colon. (The colon is not needed without a name.)
			A condition takes the form "if(expression)" after the “BREAK” label or the colon if there's a name. Any variables used in the expression(s) are those at the _actual_ break point (see above). For function breakpoints, they include the parameters, too.
		There might be other settings (e.g., a counter).
	* “// SHOW i” — displays the value of i the last time execution passed through here.
			“Here” actually means the same thing it means for breakpoints: the first allowable break-point after the end of the comment; in this case, it's the same as for the for above.
			While debugging, the comment is shown as “// SHOW [expression] = [value of expression]”, i.e. what would be displayed by a normal watch-point on that expression if the user added a normal breakpoint there. The value should be highlighted in a different color. If it contains newlines, they're replaced with a visible characters (e.g., "CR" in a different color). If it's too long, it's truncated, with "..." added. A mouse hover displays the complete value.
			The value shown is for the last time execution passed through that comment i.e., the value the expression had just before the last time the first statement after the comment was executed. It doesn't change if the values used by the expression change, except when execution passes again “through” the comment. If the point has not yet been passed, it displays “<not available>” or something similar. However, once passed it keeps displaying the last value, even if the user steps somewhere where expression is no longer valid (e.g., out of scope). If there are several stack frames that that passed through that point, the highest value below where the user is looking is displayed.
			This works even if there is no actual user breakpoint there (by adding a “hidden” breakpoint).
	“// WATCH i” — behaves exactly like SHOW, but updates the display when the execution advances (including when the users steps or hits “resume” and another breakpoint is reached).
			Unlike usual watch-points, the expression is always evaluated in the context of its comment (which means, as usual, the first statement after the comment), in the topmost stack frame that passed through it. 
			So, for instance, when the “BREAK A” breakpoint is hit, it would display “i = 0” (or “i = 0 [0x0]” if the user has that option enabled). If the user steps _into_ “something(i)”, it will keep showing that until the user returns from it; however, if “something()” calls the function “example()” again, the value is updated until the end. Also, if there are several frames on the stack of this function, the highest below the one the user is looking at is displayed.
	“BREAK with A” — means break here (i.e., at the first statement afterwards) only if the break-point named “A” was hit the last time execution passed through it.
			Note that the description as given above _doesn't_ follow stack frames; this is to allow a breakpoint passed by one thread to trigger a breakpoint in another thread. It might be nice to add different keywords (like “with” and “unless”) for breakpoint dependencies inside a stack frame, but that might be more complicated because of the need to check reach-ability and the like.
			In the example above, it will break on “someTest(i)” whenever i was a multiple of 100 at the start of the for loop. Note that this happens even if “i” changes throughout the do{}while loop; also, if “i” was 3 at the start of the for, the breakpoint is not enabled even if “i” becomes 100 in the do{}while loop. (Unless “something()” or another thread calls “example” again.)
			This could also allow “BREAK except A”, which means break only if A did not break on its last passing. (Useful for exception cases, etc.)

Normally “BREAK” labels have breakpoints automatically enabled for them when the user starts debugging. A “~BREAK” label generates a disabled breakpoint. Users can use double-click on the icon bar to the left of the source window as usual; a double-click enables or disables the breakpoint on that line. (Note that this doesn't interfere much with the usual usage, since a line containing only a comment cannot have a usual breakpoint on it.) This double-click might also add/remove the negation (tilde) to the label without triggering a re-compile. (The same trick can be used to disable SHOW and WATCH labels, but that's not really necessary.)

Note that a very simple version of all this, with only BREAK (with expressions) and WATCH as are usually done in Eclipse, could be added without any modification to the debug engine (they're only syntactic sugar). They would be very helpful because they're integrated with the code, and they'd be much easier to manage than a disconnected list somewhere else on the screen. Normally breakpoints with conditions are hard (read: takes a long time) to move around and edit; and in a complex project, it's easy to add more watch expressions that you can manage (you start deleting them, and then later you need to add them again). This would much simplify things, and should be tried first.

The other details might need a bit more work: a SHOW without a breakpoint near it would need to add a “hidden” breakpoint that updates its value and then resumes; the other behaviors specified would need some analysis of the stack, and could get complicated in the multithreaded case.
Comment 1 Bogdan Butnaru CLA 2009-06-22 06:22:21 EDT
I forgot to mention a note: if a “smart” comment is on the same line with a statement that allows a breakpoint, it's placed there rather than on the following statement.
Comment 2 Michael Rennie CLA 2011-06-07 14:35:04 EDT
There are no plans to implement this, although contributions would be considered.

Marking as wontfix