Pure C++

Live Source Browsing in Visual C++

Boris Jabes and Ameya Limaye

Contents

What is Source Browsing?
How Does Live Source Browsing Work?
Limitations of Live Source Browsing
Browsing Enhancements
Wrap-Up

If you're wondering where Stan Lippman is, we're happy to report that he has graciously granted us the use of his column this month to talk about some of the recent work the Visual C++ team has been doing to improve developer productivity. Unlike most of Stan's columns, this one will not focus on C++ itself, but will discuss the tool we use to develop programs—Visual Studio® 2005.

While Visual Studio 2005 supports many languages, we're going to discuss the C++ features. From the simplest syntax highlighting, all the way to powerful integrated debugging, IDEs like Visual Studio 2005 can be a major source of productivity. Visual C++® has supported source browsing as a feature for many years now, but we have given the 2005 version a major overhaul and have renamed it live source browsing to more accurately describe its features.

What is Source Browsing?

As developers, we spend most of our time in front of the machine writing code, but there are a number of peripheral activities we perform daily. These include reviewing, compiling, and debugging code. Sometimes we need to understand a foreign code base such as an API, and at other times we need to navigate through a large one. Source browsing is the feature that enables this.

Source browsing goes beyond showing the code; it focuses on examining the relationships between code elements, such as what member functions are in a class and which classes derive from another. Browsing abstracts the physical structure of the code; in other words, it exposes this information for a whole project (for those unfamiliar with Visual C++, projects represent a set of files, which are ultimately built into an executable or library).

During the build process in previous versions of Visual Studio, the IDE was able to create a browse information file called Browser Source Cache (BSC) that contains the data necessary to enable browsing features. This process involves the generation of an additional file during the compilation of each source file, adding an additional overhead of 10-15 percent to the build time. This additional compilation step leads to another significant deficiency in BSC-based browsing: in order to reflect any code modifications, we must rebuild the browse information file. Thus, the code needs to be in a fully compilable state before we can generate a BSC file for it.

When making significant modifications to code or starting a new project from scratch, the program as a whole cannot be compiled. In these situations, BSC-based browsing is not possible. In Visual C++ 2005, we have created a new architecture in order to solve these problems, ensuring that the browsing features are always accessible and reflect the current state of the code (even unsaved changes). This is the "live" part of live source browsing.

How Does Live Source Browsing Work?

Live source browsing is built on top of the Visual C++ IntelliSense® engine. The IntelliSense engine maintains a store that contains the data required for the editor to provide intelligent auto-completion and tooltips. We call this store the No Compile Browse (NCB) file. To populate it, we created an auxiliary parser, which specializes in parsing fuzzy C++ code. This parser makes accommodations for improper or incomplete statements (such as missing brackets), unlike a full-fledged compiler. As users work in the editor, the IDE monitors files for changes. When changes occur, the parser reparses the affected files in the background and updates the NCB file if necessary. Another difference when using NCB-based browsing is the treatment of C++ preprocessor macros. In the BSC model, the compilation process evaluates the preprocessor macros and their definitions become unrelated to their use. On the other hand, the NCB file keeps the macros in its store just like it keeps other symbols. Consider this simple piece of code:

#define FUNC func void func() { } void main() { FUNC(); }

Here, BSC browsing identifies FUNC() as a call to the function func(); however, it does not track macros and cannot relate the reference to the macro FUNC to its definition. On the other hand, NCB browsing is unable to determine that the reference to the macro FUNC is also a call to the function func(); it will simply relate the call to the macro FUNC. Figure 1 illustrates this example using three callers graphs (given a function or method, a hierarchy of functions that call it or that it calls is generated). In Figure 1, the callers graphs from top to bottom are NCB-based browsing for the function func, BSC-based browsing for the function func, and NCB-based browsing for the macro FUNC (note that BSC browsing cannot be done for FUNC).

Figure 1 Callers Graphs

Figure 1** Callers Graphs **

Limitations of Live Source Browsing

There are a few limitations in this new architecture. They are the result of the workings of our fuzzy parser and the way we store data in the NCB file. The most significant limitation is the one mentioned earlier, namely that when a macro expands to a function call, our engine cannot equate the underlying function call with its definition. Another type of call that goes undetected is a call through a function pointer or through a delegate (including events). Finally, implicit calls such as constructors or operators also go undetected. We are committed to removing all these limitations, with time being our only constraint. Note, however, that some of these limitations exist in BSC browsing, too.

Browsing Enhancements

Visual C++ 2005 provides myriad features to aid developers with browsing-related tasks, some brand new. What follows is a look at the most important features and enhancements.

Figure 2 Inheritance Tree

Figure 2** Inheritance Tree **

Class View Class View has been a staple of Visual C++ for many years. It's a window (accessible with Ctrl+Shift+C) that displays all elements, such as classes and methods, for a project. Double-clicking on an element causes the editor to jump to its definition in code. As we mentioned before, browsing code means examining relationships; to achieve this effect, Class View organizes types and namespaces into a tree structure with child nodes. For example, a class node might be a child of a namespace node.

We display members in a second pane whose contents depend on the currently selected element in the upper pane. Of course, all these details sound very familiar if you have used the IDE, but we have made some noteworthy additions in 2005. The first and foremost is the inheritance graph (see Figure 2). When looking at a type, you can now expand its node to see all classes that derive (subclass) from this type as well as all classes that this type derives from. The second enhancement is the addition of a filtering box at the top of the class view window (see Figure 3). When the user types into this box, Class View automatically filters the full list of symbols by pattern matching the string entered.

Figure 3 Filtering Class View

Figure 3** Filtering Class View **

Call Browser The Call Browser is a very powerful feature brand new to Visual Studio 2005. As we mentioned earlier, given a function or method, Class Browser generates a hierarchy of functions called by or calling the given function, which are named Callers Graph and Call Graph, respectively. These graphs can be expanded such that if method A calls B, and B calls C, the callers are properly reflected in the graph (see Figure 4). Although this sounds simple, exposing these relationships is tremendously powerful when trying to decipher the logical flow of code without running it. For example, often you have pinpointed the location of a bug but you're lacking a call stack. The call browser allows you to visualize all possible paths to this function, as well as the paths out of it. For each level of the tree, the graph also lists each site in the code where the calls are made. In Visual C++ 2005, you can generate these graphs by right-clicking on a function anywhere in code (or in Class View) and selecting the graph you want under the Call Browser menu.

Figure 4 Superfunc Callers Graph

Figure 4** Superfunc Callers Graph **

Object Browser The Object Browser (Ctrl+Alt+J) is an expanded version of the Class View window. Instead of limiting itself to a small space, it comes up like an editor document and uses the full space available. It has three panes: the tree of classes, the member fields and methods, and a short description of whatever element is selected. This information is gleaned from the declaration of the type as well as the comments that accompany it. In the case of managed code, the information is retrieved from the metadata that is compiled into the binary. Unlike the class view, the purpose of the object browser is not to jump around the code but more to explore an API or a framework. To further facilitate this, you can look at elements outside of your project in the object browser. You can add external libraries (managed, COM, or native) and peer into their exposed functionality.

Find Symbols and Find All References Sometimes you just want to find a symbol that you know is used somewhere in your code base. However, performing a classic text search causes all sorts of irrelevant strings to be returned, most notably information in comments. In order to handle this scenario more efficiently, we have a command called Find Symbol (accessible with Alt+F12) that searches through the list of symbols stored in the browsing database. The results are presented in a new window (aptly named Find Symbol Results) so that finding and navigating to specific instances of the symbols is fast and efficient. However, what if you have a hypothetical class, CFoo, defined with the same name in a number of different files and namespaces? In these cases, Find Symbol will not be able to differentiate between them. After all, you cannot tell them apart unless you specify this in a search string. In order to handle these types of situations, we have a command called Find All References (accessible with a right-click on a symbol) that performs a search that is more tightly scoped than the previous one. Indeed, it will only return instances of the exact symbol you select in the editor or class view.

Useful Shortcuts Live source browsing enables a number of very simple yet powerful shortcuts in the IDE. The two notable shortcuts, which are not new, are Go To Definition (F12) and Go To Declaration (Ctrl+Alt+F12), which are self-explanatory. These commands are also available in the editor context menu if you prefer using the mouse in these situations. Veterans of the IDE might be familiar with an unfortunate consequence of these shortcuts that jump the editor to other parts of your project: it's hard to get back to your previous position. We are happy to announce that the following commands have been added to Visual Studio 2005: Navigate Backward (Ctrl+-), Navigate Forward (Ctrl+Shift+-), and Pop Browse Context (Ctrl+Num*). The first two act more like the Internet Explorer Back and Forward shortcuts while the third moves backwards through the browsing history.

Wrap-Up

Live source browsing is a major improvement over the previous browsing model. By no longer requiring you to recompile your code, browsing can become part of the coding routine. The advantage is not limited to saving time by not recompiling. Browsing can now be used as a coding tool, not merely for examining large code bases. While we feel we have made major advancements in browsing with Visual Studio 2005, we will continue to improve these features in future releases until they cover all nuances and aspects of the complex C++ language. To learn more about the architecture of our IntelliSense engine, which encompasses aspects of browsing, see IntelliSense Support in Visual C++.

Send your questions and comments to  purecpp@microsoft.com.

Boris Jabes is a program manager on the Visual C++ IDE team responsible for a number of features in the IDE. He holds degrees in Math from the University of Waterloo and Information Networking from Carnegie Mellon.

Ameya Limaye has been a developer on the Visual C++ Compiler team for four years and on the Visual C++ IDE team for the past two years, working mainly on the IntelliSense, Browsing and Editor feature areas. He holds a Masters Degree in Computer Science from Purdue University.