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" });

    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" );

	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" );

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


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!


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:

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.


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 {
    Param(const std::string& str, int val) : mStr(str), mVal(val) { }

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

    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:


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:


and add this line to default.natstepfilter:

    <Name>std\:\:.* </Name>

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


Fly over the IDE Gaps

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.


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
    GLuint mId;
    std::vector<Shader *> mShaders; // refactor: 
                                    // convert to 
                                    // smart pointers!
    // todo: implement other special member functions!

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
    GLuint mId;
    std::vector<Shader *> mShaders; // #refactor
                                    // convert to 
                                    // smart pointers 
    // #refactor #ruleOfZero implement 
    // other special member functions!

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:


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