Here’s Your Game Changer: Debug Visualizer in CodeRush for Visual Studio
One of the goals of team CodeRush is to release something revolutionary, something with the power to change the way developers work, at least once a year. CodeRush 11.2 was the first tool on any platform to offer duplicate code consolidation. This year CodeRush 12.2 comes out of the gate with another powerful game changer: the Debug Visualizer.
The Debug Visualizer attempts to eliminate a number of productivity barriers inherent with today’s debugging experience. You may have noticed:
- The debugging experience can be slow
- Your hands reaching for the mouse to add a watch or inspect a value
- Your eyes moving back and forth between code and watched values
Sometimes when stepping through code you encounter unexpected results. Unexpected results are frequently interesting because they can reveal details about the code that were previously unknown, and they are a smell indicating a logic error or bad data. Unfortunately the time from the moment you see the unexpected result to the moment you understand why is frequently measured in minutes, not seconds. Drilling down into a complex expression or reviewing historical data leading to a potential issue involves way too many mouse clicks and keyboard shortcuts, and may even require a restart in an attempt to catch the problem where it happens. Unraveling complexity is often tedious and may require intense focus.
The Debug Visualizer is here to dramatically reduce the time between unexpected data and complete understanding.
Here’s how it works.
Historic Visual Record
As you step into a method the Debug Visualizer immediately gets to work, revealing values for any arguments passed into the method.
Figure 1: The Debug Visualizer acting like a Locals window, but without the messy window.
Those local values you see just below the arguments persist as you step through this method, serving as a sort of historical document on the original values on entry or assignment, which may be useful if those later change inside the method.
See Changes Right Where They Occur
When values change as you step through the code, you’ll see those changes immediately. For example, in the screenshot below we can see the value of surfaceAreaOfCylinder is 0.0.
Figure 2. An assignment statement before execution.
Stepping over this line of code updates the local variable’s value, shown in red on the left:
Figure 3. Now we can easily see which line of code changed a variable.
Showing Function Results
One debugging task that takes far too many steps and too much time is determining the value of a function that returns a calculation. There seems to be no easy way to get to this important information quickly.
Fortunately the Debug Visualizer makes this pain a thing of the past. Now when you step up to a return statement, you can see the value returned before you leave the function:
Figure 4: Easily see calculated values that functions return.
Revealing the Future
In addition to documenting the past, the Debug Visualizer can also reveal the future. Step through the code and you’ll see the values for expressions on the active line before they are executed. For example, in the code below, the Math.Sqrt() call has not been executed yet, however the future result, 42.0, can be seen right below the expression:
Figure 5: The future revealed, and the answer is… 42?
If there is an unexpected value on the current line, many times it’s useful to know this before the line executes. It’s much easier to step into a method call or property getter before the line executes than after:
Stepping into a Method Call or Property Getter:
Before the Line Executes | After the Line Executes |
![]() |
|
![]() | |
![]() | |
![]() |
The future previews are here to save all those extra steps and waiting.
Values of expressions involving potential side-effects that may impact program behavior are not predicted; you’ll see a Refresh button instead. Click the button or press Ctrl+R to see the values.
Expression Explorer
So, what happens when you encounter an unexpected value while debugging? For this section, we’ll use a simple code example, however you might want to imagine this working on an expression with greater complexity.
Figure 6: An unexpected value.
With the caret anywhere on the active statement, press Alt+Down to bring up the Expression Explorer.
Figure 7: Drilling into the expression.
The Expression Explorer lets you drill into individual expression parts and see their corresponding values. In the screenshot above we can see the result of the call to Math.Sqrt() is 4.58 (we were expecting 5), and that the value of the expression passed into the Sqrt call is 21.0 (expecting 25).
Once the Expression Explorer is up, you can move around and drill into expression parts with the arrow keys. For example, pressing the Down arrow (using the example code above) reveals the children of the active expression:
Figure 8. Drilling further... aSide * aSide == 9.0
The Node Map to the right shows a hierarchical representation of the expression. You can click and drag this window to reposition it if necessary.
Figure 9. The Node Map reveals the active node (emphasized with high-contrast), parent nodes in purple, other nodes in blue, and hidden child nodes in gray.
Notice the high-contrast active node on the left contains two hidden children (in gray). Sometimes you just want to take a peek at the child node values without actually changing the active expression. We can toggle child expression visibility by pressing the spacebar. Doing so in our example code produces the following:
Figure 10. Spacebar toggles child expression visibility.
In the screenshot above, we can see the 9.0 comes from 3.0 * 3.0.
We can collapse all child expressions with the spacebar as well. Pressing spacebar again produces this:
Figure 11. Collapsing the child expressions with the spacebar.
The “9.0” value shown above for the “aSide * aSide” expression is expected, and the child expression values look good. Our problem must be elsewhere. Let’s move right.
Figure 12. Continuing to explore…
Expressions and their corresponding values are always left-aligned.
Figure 13. Values are displayed below a horizontal line that matches the length of the corresponding expression.
Let’s move down into the child expressions with the Down arrow.
And to the right with the Right arrow:
And now we can see our problem. This reference to “aSide” should have been a reference to “bSide”. Now we just need to fix the code. You can close the Expression Explorer by pressing Escape, or by clicking anywhere else in the editor. When the Expression Explorer closes, the code looks like this:
Figure 16. The Expression Explorer has closed, and we can still see the last values explored.
With Edit and Continue enabled we can fix the code. As soon as we make any change to the code the Debug Visualizer clears the historical data in the method we’re modifying.
Figure 17. After editing.
Of course, after editing, you can show the Expression Explorer again by pressing Alt+Down.
Figure 18. Results are now as expected.
Here’s the Expression Explorer in action:
And here’s the Expression Explorer scaling up to a more complex expression:
Figure 19. The Expression Explorer scales to handle complex code.
Why is this Expression False (or True)?
Sometimes when stepping through code with Boolean expressions an unexpected result appears. For example, you expected the expression to be true, but it is false. Or maybe you expected it to be false, but it is true. When this happens, the Expression Explorer can help you quickly understand why. For example, in this method we want to rent/hire a car. However the Debug Visualizer tells us this won’t happen:
Figure 20. The Debug Visualizer optionally adorns Boolean expressions with “” (true) or “
” (false) icons.
So the question is “why is this expression false?” To find out, press Alt+Down to bring up the Expression Explorer:
Figure 21. Conclusive Boolean expressions are highlighted (in green) in the code and the Node Map (as squares)
Now we can immediately see the problem. It’s here, highlighted in green:
Figure 22. Conclusive Boolean expressions determine the value of their parent expressions
A parent Boolean expression might contain one or more conclusive Boolean child expressions. In this example there is only one. Let’s navigate into it to get more detail. Press the Right arrow to move right and select the conclusive Boolean expression:
Figure 23. The conclusive Boolean expression, shown as a square in the Node Map, is selected.
And now press the Down arrow (or spacebar) to see the children of this expression:
Figure 24. And now we see why we can’t rent/hire the car.
Highlighting conclusive expressions is useful for understanding why Boolean expressions are true or false.
Evaluating Expressions with Side Effects
Sometimes an expression might contain a method call or property getter access with potential side-effects. If CodeRush is unable to verify that the call is free of side-effects, the Debug Visualizer will display a Refresh button. As long as the line of code is active you can click this button (or Press Ctrl+R) to call into the method and get the result.
Figure 25. Calls with potential side-effects (e.g., the call to “Exists()”) are highlighted.
Note that even though an expression preview may be marked with a Refresh button, it may still be possible to drill down into its children to see their values without refreshing. For example, in the screenshot above, the Exists call prevents evaluation of the parent expression, however you can still see an evaluation of the “drive + path” expression.
The Debug Visualizer is Here Now
So there’s your game-changer for 2012, kids. Faster expression evaluation, historical record of changes, future reveal, function return preview, expression drill down, conclusive Boolean highlighting and important data always right where you need it – right in the source code. It works in C# and Visual Basic and is available right now in CodeRush 12.2 for Visual Studio. JavaScript support is expected in the next minor update. Give it a try and let us know what you think.
...
UPDATE
A file lock issue experienced by some developers has been fixed since the 12.2 release. You can get the update here.