A Brief Introduction To Clang-Tidy And Its Role in Visual Assist

As a developer, you probably know that parsing C++ source code is very complicated. This is also the reason why there might be fewer good tools for coding assistance than we have in other “lighter” languages. Fortunately,  parsing C++ source code has become much more straightforward over the past decade, mainly because of the Clang/LLVM infrastructure. Clang not only introduced a new excellent C++ compiler but also many extra tools that allow us to analyse C++ code efficiently.

Today we’ll meet one tool that can make our life much easier! It’s called clang-tidy.

We’ll cover this valuable utility as it’s also an important part for the Visual Assist internal code analysis system.

Let’s Meet clang-tidy

Here’s a concise and a brief description of this handy tool:

clang-tidy is a clang-based C++ “linter” tool. Its purpose is to provide an extensible framework for diagnosing and fixing typical programming errors, like style violations, interface misuse, or bugs that can be deduced via static analysis. clang-tidy is modular and provides a convenient interface for writing new checks.

As you can read above, this tool gives us a way to check our source code and fix common issues.

Let’s now see how you can install and work with this tool on Windows.

Installation on Windows

clang-tidy is attached with the main Clang package for Windows. You can download it from this site:

LLVM Download Page – version 11.0 (Nov 2020)

(Or also see other Releases: Download LLVM releases)

When Clang is installed, you can open your command line (for example, for this article I’m using PowerShell) and type:

clang-tidy --version

I get the following output:

PS D:\code> clang-tidy --version
LLVM (http://llvm.org/):
LLVM version 11.0.0
Optimised build.
Default target: x86_64-pc-windows-msvc
Host CPU: haswell

In general, clang-tidy operates on a single input file. You pass a filename, plus standard compilations flags and then extra flags about selected checks that will be performed.

Let’s run a simple test to see how it works.

Running a Simple Test

See this artificial code:

#include <vector>
#include <memory>
#include <iostream>
#include <string>

int main() {
    int a;

    std::string hello {"hello"};
    std::string world {"world"};
    if (hello + world == "")
        std::cout << "empty!\n";

    std::unique_ptr<std::string> ptr { new std::string { "abc" } };
    ptr.reset(new std::string{ "xyz" });
    ptr.reset(NULL);

    std::vector<int> vec{ 1, 2, 3, 4 };
    for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
        std::cout << *it << '\n';
}

Can you now play a game and list all of the “spurious” smells in the code? What would you improve here?

Let’s now compare your results with suggestions from clang-tidy.

I ran the tool with the following options:

clang-tidy --checks='modernize*, readability*' hello_tidy.cpp -- -std=c++14

On my machine, I get the those results:

As you can see above, I run it against all checks in the “modernise” and “readability” categories. You can find all available checks here: clang-tidy – Clang-Tidy Checks — Extra Clang Tools 12 documentation

You can also list all available checks for your version with the following command:

clang-tidy --list-checks

In summary the tool found the following issues:

  • suggestion to use trailing return type for main()
  • suggestion about using .empty() rather than comparing string with an empty string
  • make_unique
  • nullptr rather than NULL
  • modernising range based for loop
  • braces around single-line if and loop statements

Experimenting with Fixes

But there’s more!

clang-tidy can not only find issues but also fix them! A lot of checks have “auto-fixes”! By providing the -fix command, you can ask the tool to modify the code. For example:

clang-tidy --checks='modernize-* readability-container*' -fix hello_tidy.cpp -- -std=c++14

As you can see, this time I used “readability-container” only as I didn’t want to modify braces around simple if statements.

I got the following output:

clang-tidy nicely lists all the fixes that it managed to apply.

The final source code looks as follows:

#include <memory>   // oops!
#include <vector>
#include <memory>
#include <iostream>
#include <string>

auto main() -> int {
	int a;

    std::string hello {"hello"};
    std::string world {"world"};
    if (hello + world.empty())   // oops!
        std::cout << "empty!\n";

	std::unique_ptr<std::string> ptr { new std::string { "abc" } };
	ptr = std::make_unique<std::string>( "xyz" );
	ptr.reset(nullptr);

	std::vector<int> vec{ 1, 2, 3, 4 };
	for (int & it : vec)
		std::cout << it << '\n';
}

In the above code sample the tool managed to fix several issues, and we can decide if we want to apply all or maybe just select a few of them. For example, I’m not sure about using a trailing return type for all functions. Additionally, the tool couldn’t improve and apply make_unique in the place where we declare and initialise ptr. So hopefully, with each new revision, we’ll get even better results.

But also it’s important to remember that you have to be careful with the fixes.

See lines 1 and 12.

Clang-tidy added extra and duplicated header file “memory” (this was probably needed for make_unique()). This is not critical, but shouldn’t happen. But what’s worse is that at line 12 the code is now wrong.

The line if (hello + world == "") was changed into if (hello + world.empty()). This changes the meaning of the statement!

When applying fixes, be sure to review code and check if this is what you expected.

I hope you now get a general idea of how to use the tool and what its output is.

Running this tool from a command line might not be the best choice. Fortunately, there are many options on how we can plug it inside our build system or IDE.

For example, you can learn how to make use of it with CMake on a KDAB blog or… Clang-Tidy, part 1: Modernise your source code using C++11/C++14 – KDAB

Let’s now have a brief look at the options in Visual Studio.

Clang Tools in Visual Studio

clang-tidy support is available starting with Visual Studio 2019 version 16.4.

clang-tidy is the default analysis tool when using the LLVM/clang-cl toolset, but you can also enable it with MSVC compiler:

And you can configure it with a separate property panel:

And when you run a code analysis you can get results to your Error/Warning list:

Unfortunately, the current version of Visual Studio doesn’t offer a way to apply fixes, so you need to modify the code on your own.

Luckily, with the help of Visual Assist, you can change it. See below.

How Visual Assist Makes Things Much Safer And Easier

Visual Assist offers a service called “Code Inspection”, which is based on a standalone LLVM/Clang embedded into the VA system. You can enable it (even in Visual studio 2008!), and for our simple example you might get the following results (in a separate VA Code Inspection Window):

And what’s best is that for many of them you can apply a fix!

See the following context menu:

This is great! Thanks to the embedded LLVM/Clang subsystem, Visual Assist can perform the analysis and help you with many tasks related to code modernisation and fundamental code analysis!

But what’s best is that Visual Assist cleans up the output from clang-tidy and makes sure the fixes are correct and safe. Here’s the code after I applied all suggestions:

#include <vector>
#include <memory>
#include <iostream>
#include <string>

int main() {
	int a;

	std::string hello{ "hello" };
	std::string world{ "world" };
	if ((hello + world).empty())
		std::cout << "empty!\n";

	std::unique_ptr<std::string> ptr{ new std::string { "abc" } };
	ptr = std::make_unique<std::string>( "xyz" );
	ptr.reset(nullptr);

	std::vector<int> vec{ 1, 2, 3, 4 };
	for (int & it : vec)
		std::cout << it << '\n';
}

Nice!

As you can see there’s no extra include statement. And what’s most important is in line 12. VA added extra brackets, so the whole expression is now correct and safe!

Summary

In this article, we covered clang-tidy – a handy tool for code analysis that can (experimentally) fix your code automatically! The tool is quite verbose and might be hard to configure to work with large projects. In addition, please make sure you review code when applying fixes.

By default, you can download it and launch from a command line, but it’s much better to use it from Visual Studio (limited).

To get the best experience and safety have a look at the embedded clang-tidy inside Visual Assist – in the form of “VA Code Inspections”. This extra feature makes sure the results of code analysis are easy to read and meaningful, and the fixes are correct.

Today we only scratched the surface of this exciting topic. In two upcoming blog posts you’ll see some more use cases where Visual Assist can help you with code refactoring and modernisation (also leveraging embedded clang-tidy). Stay tuned.

For now you can read more in:

Technical Deep Dive: Reducing Memory Consumption in Visual Assist build 2393

Technical Deep Dive: Reducing Memory Consumption in Visual Assist build 2393

November 2020’s release of Visual Assist had some significant memory usage improvements, great for those with large projects. Here’s how we did it.

Written by David Millington (Product Manager), Goran Mitrovic (Senior Software Engineer) and Christopher Gardner (Engineering Lead)

Visual Assist is an extension which lives inside Visual Studio, and Visual Studio is a 32-bit process, meaning that its address space, even on a modern 64-bit version of Windows, is limited to a maximum of 4GB. Today 4GB doesn’t always go very far. A typical game developer, for example, may have a large solution, plus perhaps the Xbox and Playstation SDKs, plus other tools – already using a lot of memory – plus Visual Assist. A lot of Visual Assist is built around analysis of your solution, and that requires storing data about your source code, what we call the symbol database. Sometimes, with all of these things squashed into one process’ memory space together, some users with large and complex projects start running out of memory.

The latest version of Visual Assist (build 2393, 28 Oct 2020) reduces in-process memory consumption significantly. It’s a change we think will help many of you who are reading this, because those with large solutions who run into memory issues should find those memory issues alleviated or disappearing completely; and those with small or medium solutions may find Visual Assist runs a little faster.

Plus, it’s just part of being a good member of the Visual Studio ecosystem: as an extension relied on by thousands of developers, yet sitting in the same shared process as other tools, we should have as little impact as we can.

Chart showing memory usage from a Find References operation in the Unreal Engine source code. The new build of Visual Assist uses 50% the memory of the previous build (152 MB vs 302 MB)
Difference in memory usage running a Find References on the Unreal Engine 4.26 source code. Smaller is better.

The chart above shows that the new build of Visual Assist reduces VA’s memory usage by about 50% – that is, half as much memory is used. You can see more charts below, and we consistently see 30%, 40% and 50% memory savings.

We’d like to share some technical information about the approaches we took to achieve this, and we hope that as C++ or Windows developers you’ll find the work interesting. This is a fairly long blog, and starts off light and gets more technical as it goes on. It covers:

Concepts

Many readers may know this, but to follow this post here’s a quick primer on some concepts. Feel free to skip to the next section if you’re already familiar.

Address space refers to the total amount of memory an application can use. It’s usually limited by the size of a pointer (because a pointer points to memory): a 32-bit pointer can address 232 (about 4 billion) bytes, which is 4GB. So we say that a 32-bit process has a 32-bit address space, or an address space of 4GB. (This is hand-wavy – although true, on 32-bit versions of Windows this 4GB was split between kernel and user mode, and a normal app can only access usermode memory; depending on settings, this actually meant your app could access only 2GB or 3GB of memory before it could not allocate any more. On a 64-bit version of Windows, a 32-bit app has the entire 4GB available. Plus, there are techniques to access more memory than this even on 32-bit systems, which is getting ahead of where this blog post is going.)

This address space is a virtual address space; the application uses virtual memory. This means that the 4GB is not actually a sequential block of memory in RAM. Pieces of it can be stored anywhere, including on disk (swapped out) and loaded in when needed. The operating system looks after mapping the logical address, the address your application uses, to the actual location in RAM. This is important because it means that any address you use has what backs it, where it actually points to, under Window’s control.

A process is how your application is represented by the operating system: it is what has the virtual address space above, and contains one or more threads which are the code that runs. It is isolated from other processes, both in permissions and memory addresses: that is, two processes do not share the same memory address space.

If you’re really familiar with those concepts, we hope you’ll forgive us for such a short introduction. OS architecture including processes, threads, virtual memory etc is a fascinating topic.

Background – Where Visual Assist Uses Memory

Visual Assist parses your solution and creates what we call the ‘symbol database’, which is what’s used for almost every operation – find references, refactoring, our syntax highlighting (which understands where symbols are introduced), generating code, etc. The database is very string-heavy. It stores the names of all your symbols: classes, variables and so forth. While relationships between symbols can be stored with relatively little memory, strings themselves take up a lot of space in memory.

Our first work on memory optimization focused on the relationships, the links between data, and metadata stored for each symbol, and we did indeed reduce the memory they used. But that left a large amount of memory used by strings generated from source code. In addition our string allocation patterns meant strings were not removed from memory when memory became full and there was allocation pressure, but instead at predefined points in code, and that also increased the risk for large projects of getting out of memory errors.

Clearly we needed to solve string memory usage.

We researched and prototyped several different solutions.

String Storage Optimizations

Stepping back in time a little, string memory usage is obviously not a new problem. Over time, Visual Assist has used several techniques to handle string storage. While there are many possible approaches, here’s an overview of three, one of which Visual Assist used and two of which it has never used, presented in case they are new or interesting to you.

String interning addresses when there are many copies of the same string in memory. For example, while Visual Assist has no need to store the word “class”, you can imagine that in C++ code “class” is repeated many times throughout any solution. Instead of storing it many times, store it once, usually looked up by a hash, and each place that refers to the string has a reference to the same single copy. (The model is to give a string to the interning code, and get back a reference to a string.) Visual Assist used to use string interning, but no longer: reference counting was an overhead, and today the amount of memory is not an issue itself, only the amount of memory used inside the Visual Studio process.

While we’re discussing strings, here are two other techniques that are not useful for us but may be useful for you:

  • To compress strings. Visual Assist never used this technique: decompression takes CPU cycles, and strings are used a lot so this would occur often.
  • To make use of common substrings in other strings: when a string contains another string, you can refer to that substring to save memory. A first cut might use substrings or string views. This is not useful for us due to the overhead of searching for substrings, which would be a significant slowdown, and the nature of the strings Visual Assist processes not leading to enough duplication of substrings to make it worthwhile. A more realistic option (in terms of performance, such as insertion) for sharing string data than shared substrings would be to share data via prefix, such as storing strings in tries. However, due to the nature of the strings in C++ codebases, our analysis shows this is not a valuable approach for us.

The approach we took to the recent work was not to focus on further optimising string storage, but to move where the string storage was located completely.

Moving Out Of Process: Entire Parser

Visual Assist is loaded into Visual Studio as a DLL. The obvious approach to reducing memory pressure in a 32-bit process is to move the memory – and whatever uses it – out of process, which is a phrase used to mean splitting your app up into multiple separate processes. Multi-process architectures are fairly common today. Browsers use multiple processes for security. Visual Studio Code hosts extensions in a helper process, or provides code completion through a separate process.

As noted in the primer above, a second process has its own address space, so if we split Visual Assist into two, even if the second was still a 32-bit process it could double the memory available to both in total. (Actually, more than double: the Visual Studio process where Visual Assist lives has memory used by many things; the second process would be 100% Visual Assist only. Also, once out of Visual Studio, we could make that second process 64-bit, ie it could use almost as much memory as it wanted.) Multi-process architectures can’t share memory directly (again hand-wavy, there are ways to read or write another process’s memory, or ways to share memory, but that’s too much for this blog); generally in a multi-process architecture the processes communicate via inter-process communication (IPC), such as sockets or named pipes, which form a channel where data is sent and received.

There were two ways to do this. The first is to move most of the Visual Assist logic out to a second process, with just a thin layer living inside Visual Studio. The second is just to move the memory-intensive areas. While the first is of interest, Visual Assist has very tight integration with Visual Studio – things like drawing in the editor, for example. It’s not trivial to split this and keep good performance. We focused instead on having only the parser or database in the second process.

Prototyping the parser and database in a second process, communicating with IPC back to the Visual Studio process, showed two problems:

  • Very large code changes, since symbols are accessed in many places
  • Performance problems. Serializing or marshalling data had an impact. Every release, we want VA to be at least the same speed, but preferably faster; any solution with a performance impact was not a solution at all

Moving Just Memory

Multi-process is not a required technique, just one approach. The goal is simply to reduce the memory usage in the Visual Studio process and move the memory elsewhere; we don’t have to do that by moving the memory to another process—and this is a key insight. While multiprocess is a fashionable technique today, it’s not the only one for the goal. Windows provides other tools, and the one we landed on is a memory mapped file.

In the primer above, we noted that virtual memory maps an address to another location. Memory-mapped files are a way to map a portion of your address space to something else – despite the name, and that it’s backed by a file, it may not be located on disk. The operating system can actually store that data in memory or a pagefile. That data or file can be any size; the only thing restricted is your view of it: because of the 32-bit size of your address space, if the mapped file is very large you can only see a portion of it at once. That is, a memory mapped file is a technique for making a portion of your address space be a view onto a larger set of data than can fit in your address space, and you can move that view or views so, although doing so piece by piece, ultimately a 32-bit process can read and write more data than fits in a 32-bit address space.

Benchmarking showed memory mapped files were significantly faster than an approach using any form of IPC.

The release notes for this build of Visual Assist referred to moving memory ‘out of process’. Normally that means to a second process. Here, we use the term to refer to accessing memory through a file mapping, that is, accessing memory stored by the OS, and potentially more memory than can fit in the process’ address space. Referring to it as out of process is in some ways a holdover from when the work was planned, because we had initially thought we would need multiple processes. But it’s an accurate term: after all, the memory is not in our process in a normal alloc/free sense; it’s an OS-managed (therefore out of process) resource into which our process has a view.

Note re ‘memory mapped files were significantly faster than … using any form of IPC’: sharing memory mapped files can be a form of IPC as well – you can create the mapped file in one process, open in another, and share data. However, we had no need to move logic to another process – just memory.

Chunk / Block Structure and Allocation / Freeing

We already mentioned that the data we stored in the memory mapped file is strings only. In-process, we have a database with metadata fields; in the mapped view are all strings. As you can imagine any tool that processes source code uses strings heavily; therefore, there are many areas in that mapped memory we want to access at or near-at once.

Our implementation uses many file mappings to read and write many areas at once. To reduce the number, each is a fixed size of 2MB. Every one of these 2MB chunks is a fixed heap, with blocks of a fixed size. These are stored in lists:

  • 2MB chunks that are mapped, and locked as they are being used to read or write data
  • Chunks that are mapped, but unused at the moment (this works like a most recently used cache, and saves the overhead of re-mapping)
  • Chunks that are not mapped
  • Chunks that are empty

Most C++ symbols fit within 256 bytes (note, of course, this is not always the case – something like Boost is famous for causing very long symbol names.) This means most chunks are subdivided into blocks 256 bytes long. To allocate or free is to mark one of these blocks as used or unused, which can be done by setting a single bit. Therefore, per two-megabyte chunk, one kilobyte of memory is enough to represent one bit per block and to allocate or deallocate blocks within a chunk. To find a free block, we can scan 32bits at a time in a single instruction, BitScanForward, which is handily an intrinsic in Visual C++.

This means that Visual Assist’s database now always has a 40MB impact on the Visual Studio memory space—twenty 2MB chunks are always mapped—plus a variable amount of memory often due to intermediate work, such as finding references, which can be seen in the charts below and which even in our most extreme stress test topped out at a couple of hundred megabytes. We think this is very low impact given the whole 4GB memory space, and given Visual Assist’s functionality.

Optimizations

There are a number of optimizations we introduced this release, including improvements for speedily parsing and resolving the type of type deduction / ‘auto’ variables, changes in symbol lookup, optimisations around template handling, and others – some of which we can’t discuss. I’d love to write about these but they verge into territory we keep confidential about how our technology works. We can say that things like deducing types, or template specialisation, are faster.

However we can mention some optimizations that aren’t specific to our approach.

The best fast string access code is code that never accesses strings at all. We hash strings and use that for string comparison (this is not new, but something Visual Assist has done for a long time.) Often it is not necessary to access a string in memory.

Interestingly, we find in very large codebases with many symbols (millions) that hash collisions are a significant problem. This is surprising because hash algorithms usually are good at avoiding collisions, and the reason is that we use an older algorithm, and one with a hash value only 32 bits wide. We plan to change algorithms in future.

We also have a number of other optimizations: for example, a very common operation is to look up the ancestor classes of a class, often resolving symbols on the way, and we have a cache for the results of these lookups. Similarly, we reviewed all database lookups for areas where we can detect ahead of time a lookup does not need to be done.

Our code is heavily multi-threaded, and needs to be performant, avoid deadlocks, and avoid contention. Code is carefully locked for minimal locking, both in time (duration) and scope (to prevent locking a resource that is not required to be locked, ie, fine-grained locking.) This has to be done very carefully to avoid deadlocks and we spent significant time analysing the codebase and architecture.

In contrast we also reduced our use of threads. In the past we would often create a new thread to handle a request, such as to look up symbol information. Creating a thread has a lot of overhead. Now, we much more aggressively re-use threads and often use Visual C++’s parallel invocation and thread pool (the concurrency runtime); the performance of blocking an information request until a thread is available to process it is usually less than creating a thread to process it.

Symbols are protected by custom read-write locks, which is written entirely in userspace to avoid the overhead of kernel locking primitives. This lock is custom written by us, and is based around a semaphore which we find provides good performance.

Results

All these changes were done with careful profiling and measurement at each stage, testing with several C++ projects. These included projects with 2 million symbols, 3 million symbols, and 6 million symbols.

The end result is the following:

  • For very large projects – we’re talking games, operating systems, etc – you will see:
    • 50% less memory usage between low/high peaks doing operations such as Find References (average memory usage difference is less once the operation is complete; this is measured during the work and so during memory access.)
    • Identical performance to earlier versions of Visual Assist
  • For smaller projects:
    • Memory usage is reduced, though for a smaller project the effect is not so noticeable or important. But:
    • Improved performance compared to earlier versions of Visual Assist

In other words, something for everyone: you either get far less memory pressure in Visual Studio, with the same performance, or if memory was not an issue for you then you get even faster Visual Assist results.

Here are the results we see. We’re measuring the memory usage in megabytes after the initial parse of a project, and then after doing work with that project’s data—here, doing a Find References, which is a good test of symbol database work. Memory usage here is ascribed to Visual Assist; the total memory usage in the Visual Studio process is often higher (for example, Visual Studio might use 2GB of memory with a project loaded between itself and every other extension, but we focus here on the memory used by Visual Assist’s database and processing.)

One good test project is Unreal Engine:

Chart showing memory usage in an Unreal Engine project, with 28% less memory used after the initial parse, and 50% less after a Find References
Memory savings for Unreal Engine 4.26 (smaller is better):
Initial parse (180MB, vs 130MB now) and
Find References (302MB vs 152MB now)

Another excellent large C++ codebase is Qt:

Chart showing memory usage for Qt, with 40% less memory used after the initial parse, and also 40% less after a Find References
Memory savings for Qt (smaller is better):
Initial parse (424MB, vs 254MB now) and
Find References (481MB vs 291MB now)

Our feedback has been very positive: we often work with customers with very large codebases and significant memory usage from many sources inside Visual C++, and the lower impact of Visual Assist has made a noticeable difference. That’s our goal: be useful, and be low-impact.

We hope you’ve enjoyed reading this deep dive into the changes we made in Visual Assist build 2393. Our audience is you – developers – and we hope you’ve been interested to get some insight into the internals of a tool you use. While as the product manager I get to have my name on the post, it’s not fair because I did nothing: the credit goes to the engineers who build Visual Assist, especially Goran Mitrovic and Sean Echevarria who were engineers developing this work, and Chris Gardner our team lead, all of whom helped write this blog post.

A build of VA with the changes described in this post is available for download now, including trying it for free if you’d like. If you’re new to VA, read the quick start or browse our feature list: our aim is not to have the longest feature list but instead to provide everything you need, and nothing you don’t. We also do so with minimal UI – VA sits very much in the background. Our aim is to interrupt or distract you as little as possible while being there when you need it. You can see the kind of engineering we put into VA. It’s built by developers for developers.

Visual Assist Build 2393 is Here!

We’re really making an effort to keep blogs more instructional or industry related, but man o’ man is this release worth a few lines. Our team has been working behind the scenes for much of the year on performance improvements. And sure, we could’ve just done a few things here and there over time to make it feel like we were consistently improving (which we are), but with this release we decided we were ready to go all out.

Essentially we parse all of your source code and store that information in a database. Of course the larger your code base, the larger the database. And this can bottleneck you pretty bad in Visual Studio. So we’ve moved a portion of the database out of process decreasing the available memory we consume inside of Visual Studio and increasing the available memory. Yes, this is an over simplification of what we’ve done and doesn’t do justice to our developers, but download the latest, give it a whirl and let us know what you think.

Of course we didn’t stop there. We’ve updated our code inspection tool, LLVM/Clang, to the latest and greatest. We also added Code Inspection for performance-inefficient-algorithm clang checker. And we added more suggestions for UE4 macros. You can check out our full release notes here and be sure to download. Remember, maintenance must be current as of 2020.10.28.

Whether you’ve been using Visual Assist for a while or you’re brand new, you’re going to notice a difference with this build. Happy Coding!

Prevent debugger from stepping into unwanted functions in Visual Studio

When you’re in a debugging session, sometimes the debugger can visit a lot of trivial functions or code from third-party libraries. In Visual Studio and also in Visual Assist, there are ways to filter out call stack events so that you can focus just on the critical code path.

Read on to find out how.

Background

As you may already know, step into, step over, and step out functions are essential while debugging. However, it would be very time consuming to visit all of the functions. Sometimes debugger might lead you to methods that are not important from your perspective.

Let’s see an example:

#include <iostream>
#include <string>

class Param {
public:
    Param(const std::string& str, int val) : mStr(str), mVal(val) { }

    std::string GetStrVal() const {
        return mStr + "..." + std::to_string(mVal);
    }

private:
    std::string mStr;
    int mVal;
};

void CallBackFunction(Param p1, Param p2) {
    std::cout << p1.GetStrVal() << "\n";
    std::cout << p2.GetStrVal() << "\n";
}

int main() {
    CallBackFunction({ "Hello", 1 }, { "World", 2 });
}

In the above example you can find a simple code that creates a named integer parameter into a separate type: Param. When you run the code, it should output the following:

Hello...1
World...2

The problem is that we have an ellipsis ... rather than the colon : that we wanted in the first place. You can run the debugger and see where this output comes from.

Set a breakpoint at the line where CallBackFunction is called and then press F11 to try to step into the function. Since the code is relatively simple, we can just step into every procedure and investigate the program flow. Where will the debugger go at the start? I see something like this (assuming you have “Just My Code” disabled):

(Just My Code is available for C++ since Visual Studio 2017 15.8. See this post for more information: Announcing C++ Just My Code Stepping in Visual Studio | C++ Team Blog.)

In the above example, debugger goes to the next instruction after the breakpoint. In our case, it’s a constructor of std::string!

While sometimes it might be interesting to look into the internals of the Standard Library, it’s probably not the best place to look for the solution to our problem with the string output.

Imagine what happens if you have several parameters. When you want to step into a method, you’ll first need to visit all code related to the creation of the parameters. The whole process might be frustrating, and you would lose a lot of time before going into the target function. Of course, you might just set a breakpoint at the beginning of the destination code; this will skip all of the unwanted behavior. But there is a better option.

What if you could control and filter out unwanted functions?

Filtering in Visual Studio

Before VS 2012 it was relatively tricky to filter out the code. Usually, it involved playing with some registry values. Fortunately, since Visual Studio 2012, this useful feature has been much improved.

All you need to do is edit the default.natstepfilter XML file. It’s usually located in:

// VS 2015
Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Packages\Debugger\Visualizers

// VS 2019:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Packages\Debugger\Visualizers

This is the same for VS 2015, and for VS 2013 and VS 2012.

To add more functions that will be filtered out, you can use regex expressions:

In our example, when we want to skip all the functions from the std:: namespace, we can write the following:

std\:\:.*  

and add this line to default.natstepfilter:

<Function>
    <Name>std\:\:.* </Name>
    <Action>NoStepInto</Action>
</Function>

Please note that the file might be blocked for writing. The file default.natstepfilter is loaded each time a debugger session starts.

You can now set up the most common functions in your project that you don’t want to visit during debugging. Usually, those are trivial functions or from third-party code (std, boost?). Remember not to filter out too much!

In the latest versions of Visual Studio, you can also benefit from “Just My Code”, which won’t enter code that is not “your” module. That means system calls, the Standard Library, ATL, MFC, and others. You can even set your third-party libraries.

While each revision of Visual Studio makes it easier and easier to control the debugging flow, there’s an even faster and more straightforward solution.

See below:

Even more with Visual Assist

In Visual Assist, you have a separate window that allows you to see all debugger events and filter them during the debugging session!

You can show it from Visual Assist -> Debug -> VA Step Filter. You also have to have debugger integration enabled (turned on by default).

For our example, the first time I run a debugger and press F11, it will still step into the constructor of std::string. But the VA Step Filter window will show the following output:

As you can see in the Debug Events section, Visual Assist lists: breakpoints, step into, step out, and step over actions.

I can now click on std::string::basic_string... and then the next time debugger enters the same event, it will skip it and move forward. In our case, it will step into the constructor of our Param class.

By default, VA has several predefined filters for the shared Windows libraries. You can also control the filters on a global level (all projects) or per solution.

What are the main advantages?

  • It’s more visual than text files and XML files you have to edit for native debugger settings.
  • You can easily switch the event while you’re in a debugging session. In our case, I can enable it for the first argument evaluation for CallBackfunction but disable it for the second argument—no need to restart the session.
  • It has more control than “Just My Code” because sometimes you can skip an unwanted function from your application code. For one debugging session, you might want to get to the solution faster by skipping some places.
  • You can control the filter per solution level.

Try it out and see more information on the separate page: VA Step Filter

References

Fly over the IDE Gaps

Going Remote or Crazy?

If you’re like most, you’re reading this from the comfort (hopefully) of your home office. We hope whatever you’re doing, you’re being safe and smart about it. Our staff lucked out as most were already working from home when all this started. So the transition has been fairly easy, with the exception of having more distractions and noise. But, we know the transition for companies and teams can be difficult.

Over the last month we’ve been working on a way to make licensing for remote teams easier. Consider this our official launch of Concurrent Licensing for Standard License users!

Concurrent Licensing will allow companies to purchase a number of concurrent active user licenses and have teams or individuals access a license at any time. Licenses will be “checked out” upon startup and “returned” after closing Visual Assist, freeing up the license to be used by another employee. This is especially helpful when teams jump from one project to another that may or may not require Visual Assist.

We hope concurrent licensing will allow for easier management and greater flexibility for remote employees that may work different office hours or be traveling to hunker down with family.

For more information about making the switch or adding a concurrent pool to your existing licenses, contact your account manager today.

Visual Assist Build 2375

  • NEW Added Code Inspection for modernize-deprecrated-headers clang checker.
    • Some headers from C library were deprecated in C++ and are no longer welcome in C++ codebases. This check replaces C standard library headers with their C++ alternatives and removes redundant ones.
  • NEW Added MakeShared/MakeUnique Smart Suggestions for UE4 smart pointer initialization.
  • NEW Change Signature on UE4 RPC/BlueprintNative methods update the implementations.
  • NEW Reduced memory required in very large solutions.
    • You’re not the only one that’s noticed larger solutions causing memory exhaustion. We’re doing our part to reduce our memory consumption.
  • NEW Code Inspection engine updated to LLVM/Clang version 10.
    • Again, keeping up with the times and updating as we’re able. While this won’t impact you much today, this sets us up for more to come in the future.

Check out the full release notes and be sure to download. Remember, maintenance must be current as of 2020.05.09 

How to add notes and navigation metadata directly in source code in Visual Studio

Comments in code might not only be some text floating around the functions, variables and classes, but they might contain some extra semantic information. With this improvement, you can navigate through projects much faster or even organize your knowledge. In this blog post, I’ll show you two ways on how to add extra metadata to comments in Visual Studio.

Intro

Navigating through a large codebase might be a complicated task. It might be especially an issue when you have big projects (not to mention legacy systems) where logical parts are spread across many different files.

In Visual Studio offers many tools that help with moving between headers, declarations, class hierarchies or all references of a given symbol. But what if you’d like to put a “todo” item? Or some extra note? Such supplementary information can not only help with quick tasks but also might build knowledge about a system.

Here are the things you might want to use to help in Visual Studio

  • Task List
  • Hashtags (as an extra plugin)

Let’s start with the first one.

Task Lists

Visual Studio contains a feature that enables us to add metadata directly in comments; It’s called Task List. Take a look at this piece of code from my legacy project:

class ShaderProgram
{
private:
    GLuint mId;
    std::vector<Shader *> mShaders; // refactor: 
                                    // convert to 
                                    // smart pointers!
public:
    // todo: implement other special member functions!
    ShaderProgram();
    ~ShaderProgram();

As you can see above, I put keywords like refactor: or todo: inside comments.

Visual Studio builds an index of all comments with those special keywords and shows them in a separate window:

Visual Studio task list

This is a handy way of managing simple activities or just taking some small notes for the future. What’s more, the refactor keyword is a custom marker. Visual Studio adds flexibility to set it in the environment settings.

Here’s the link to the documentation Use the Task List – Visual Studio | Microsoft Docs

The task list is a nice improvement! The metadata lives inside comments so that other developers can pick up the same information. Still, you cannot easily transfer custom keywords, and the task window offers only basic support. For example, it doesn’t group things (like grouping all of the to-do lines).

Is there anything better?

Hashtags in Visual Assist

For several years I’ve been a happy user of Visual Assist – which is an excellent tool for enhancing various aspects of Visual Studio (have a look at my previous blog posts here or here). The tool also has a powerful feature called Hashtags. This is a combination of named bookmarks, task list and tags that you might know from social networks.

Take a look at the example from my project with extra notes:

/// creates and can build GLSL programs, #shadersSystem
class ShaderProgram
{
private:
    GLuint mId;
    std::vector<Shader *> mShaders; // #refactor
                                    // convert to 
                                    // smart pointers 
public:
    // #refactor #ruleOfZero implement 
    // other special member functions!
    ShaderProgram();
    ~ShaderProgram();

As you can see, this is just regular source code, but please notice those words proceeded with #. I’m using them to mark places that might be worth refactoring. For example, notes about refactoring:

std::vector<Shader *> mShaders; // #refactor 
                                // convert to smart pointers

Or another example:

/// creates and can build GLSL programs, #shadersSystem

This time I’ve used #shadersSystem which groups elements that are crucial to the handling of OpenGL Shaders in my animation application.

Below you can see all of the tags that are displayed in the VA Hashtags window. Similarly to Visual Studio, Visual Assist scans the source code and presents the indexed data.

Hash Tags Window

In the picture above, you can see lots of different tags that I put throughout the code, for example:

  • #GlutCallbacks – they refer to all callbacks that I passed to the GLUT framework (for my OpenGL Windows Application). With all of the tags grouped under one item, I can quickly move between those functions.
  • #refactoror #modernize – things to improve later.
  • Other “notes” that refer to some subsystems like #uiTweaks, #mainLoop and others.

The screenshot also shows a considerable difference compared to the task window. The hashtags are grouped, you can also filter them, or hide according to the project name, directory or even a filename.

Tags are created “on the fly”, there’s no need to predefine them in some configuration window. You just type # and some extra text (you can configure the minimum length of a tag, it’s 3 by default).

Tags are stored directly in the source code, so other developers can immediately see the same information (assuming they also use Visual Assist). Such functionality can be used to create even some simple task manager when you can assign a task by the name of a developer:

// #bartekToDo: please improve this code! don't use goto!

Here are some more things you can do with them

  • Cross-reference other tags. You can write see:#otherTag and Visual Assist will build an extra list per tag that you can check.
  • When you type # Visual Assist with autocomplete tags, so you can easily refer to existing hashtags
  • When you hover over a hashtag in the hashtags window, you’ll see a tooltip with the source code that’s near the tag; this allows to get a better orientation without actually moving to the code.
  • And many more!

Here’s a great video that summarises the tool:

Summary

In this short blog post, I wanted to describe two tools that you can use to add extra information to comments. Having little todo: comments or additional notes can enhance your daily work and build a handy list of actions for the future, or even build up the knowledge about the system.

Depending on your preferences, you can keep those extra notes permanently in your code or just temporarily and gradually move the knowledge and todo actions into external documentation or task manager.

In my daily work, I prefer VA hashtags over regular bookmarks, as they are easier to use in most cases and shows that extra information and structure. You can read more about VA Hashtags on their documentation page: Visual Assist Hashtags.

Back to you

  • Do you use some extra tools that help you with code navigation?
  • Do you use Visual Studio task window and task comments?
  • Have you tried VA hashtags?

This blog was brought to you by Bartlomiej Filipek, you can check out his C++ blog at bfilipek.com

Visual Assist Build 2366 is Available!

Build 2366 is all about keeping the lights on and letting you code faster and more effectively. While the release includes tons of bug fixes, you’ll find that we’ve added a few new items as well. In keeping with the latest and greatest, we’ve updated to LLVM/Clang 9.0.1. Other notable items include per monitor DPI awareness, Indentation fix for UE4 RIGVM_METHOD() and GENERATED_BODY() macros, and my personal favorite, Open File in Solution is now available during initial solution parse! Check out the full release notes and be sure to download. Remember, maintenance must be current as of 2020.02.20.

Tools for Tuesday

While we hope Visual Assist is your favorite dev tool, we know we can’t (and won’t) do everything for you. As we continue developing solutions, we’ll also showcase tools or tips for other problems you may face in other parts of development. This week, you’ll hear from our friends at Ranorex:

How to continue to test in Visual Studio in a post Coded UI world. 

Producing powerful on-time releases demands high-quality code and thorough testing. This is why developers have been encouraged to continuously inspect their code for errors and to shift their testing left.  Visual studio is far and away the most popular IDE on the planet with an estimated market share of 39%, and there are some great code inspection tools that extend Visual Studio functionality out there, but what about left-shifted test automation? 

For users of Visual Studio, Coded UI facilitated a shift-left approach to development by enabling automated UI-driven functional testing from within the IDE. However, earlier this year Microsoft announced that Coded UI was deprecated. Visual Studio 2019 would be the last version to support Coded UI.

Does this mean that left-shifted developers and technical testers are bereft of a testing framework that operates from within Visual Studio? The answer my friends is “not on your nelly”. The Ranorex testing framework provides an API for C# and VB.Net that completely replaces Coded UI.

Migration from Coded UI to the Ranorex testing framework is as easy as one, two, three. Once you have downloaded and installed Ranorex Studio simply follow the instructions below:

1. Create a new Visual Studio project 

Open Visual Studio, go to File > New Project. Next, you will need to select .Net Framework 4.5.2 or higher, you will be prompted to choose your programing language, you can select either C# or VB.Net. All that is now left to do in this first step is to select Console Application and hit OK.   

New project window

2. Add Ranorex core assemblies as references

To ensure a seamless migration away from Coded UI you will next need to add the Ranorex core assemblies. To do so navigate to the project’s Solution Explorer, right mouse click on the References Folder and select Add Reference… 

Solution explorer

Click browse and then navigate to the Bin folder of your Ranorex installation, (the default location is C:\Program Files (x86)Ranorex Bin). 

Add the following:

  • Ranorex.Bootstrapper
  • Ranorex.Common
  • Ranorex.Core
  • Ranorex.Core.Resolver
  • All Ranorex.Plugin assemblies
https://miro.medium.com/max/846/1*H3t63DTmK-_Gg9AITVokEA.png

Set the Copy Local option to False for all Ranorex assemblies except for Ranorex.Core.Resolver

3. Over to you 

Start writing code and continue with left-shifted testing in Visual Studio. 

Before you go

Not only are you able to continue to test in your preferred IDE you can also benefit from the best object recognition on the market. Ranorex Spy is the tool developers and technical testers love. Use it to analyze your AUT, its element structure, available object properties and attributes, and build the most robust and reliable XPaths for use in Visual Studio.

Be in full control of your XPaths. Increase or decrease dynamism in line with the complexity your tests require. Add variables to your XPaths and customize how you uniquely identify UI elements even when testing mixed technology applications. 

You can also benefit from all the functionality associated with Ranorex. Have a better understanding of failed tests with fully customizable reports. Get built-in object repository access and organize your tests in logical hierarchical structures. 

Conclusion

Left-shifted developers and technical testers who have used Coded UI need not mourn its passing, rather they should see the deprecation as an opportunity to increase the speed and quality of their releases. The Ranorex testing framework offers an API that completely replaces Coded UI, has far superior object recognition, and increased functionality. But don’t take my word for it download you full featured 30-day free trial and find out for yourself. 

Visual Assist build 2358 is available!

New Year, New Build! Welcome to 2020 and 2358. This release was driven largely to fix an issue with our licensing server and some corruption that may have been experienced by Unity users, but why stop there?

  • NEW Added C++ modernization refactoring: Convert Unscoped Enum to Scoped Enum (execute on the enum definition). See the documentation.
  • NEW Goto Related now allows hopping between *_Implementation and *_Validate implementations in UE4.
  • FIX Goto from a method declaration will now list *_Validate as a target in UE4.
  • NEW Added option (on the Goto page of Visual Assist Options dialog) to prefer implementations when executing Goto (Alt+G) (execution on the implementation will continue to go to the declaration as before).

Take a look at the full list of features and bug fixes here. And of course be sure to update!