Visual Studio 2022 Support!

Hello! We have very good news today. We just released Visual Assist 2021.5 and it has our official support for the Visual Studio 2022 release.

This blog could be as short as that sentence, but I’d like to write a bit more about our support and how we got here. Meanwhile I recommend if you’re using VS2022 you download and install 2021.5 now!

Background

Historically it’s been very important to us to release support for new versions of Visual Studio very quickly, and if you’ve read our blog posts this year about VS2022, you’ll have read me say that before. While many customers stay on older versions for some time, we have a lot of people who upgrade immediately, so we’ve always put a lot of emphasis on being able to ship a version of Visual Assist supporting new versions of Visual Studio quickly. While I’ve been product manager here for almost three years, this is the first new major version of Visual Studio during that time, and I and the whole team were keen to continue that speedy-support tradition.

We started work supporting VS2022 early, and we’ve shared our progress over this past nine months about the work we’ve been doing to support VS2022, with beta support for Previews 3, skipping 4 due to a breaking bug, and 5, 6, and 7/RC. We released Visual Assist 2021.4 shortly before Visual Studio 2022 was released, and many of you are using it with VS2022 already.

Visual Studio 2022 was a large change from previous versions. Not only did it change to 64-bit, but there are many new APIs as well, and these APIs change the interaction model from synchronous to asynchronous interaction. This is a pattern Visual Studio has been following for several years (and we encourage it—it really helps the IDE) but as you may know migrating from any sync to async model is rarely trivial. Usually, the majority of the work for each new Visual Studio release is around adapting to API changes, and that was the case here too. In fact, the most major bug we saw using Visual Assist (abbreviated VAX) 2021.4 with VS2022 and which was one of the issues we fixed for today’s official support, an issue where the code suggestions window sometimes did not show in the right place, was related to the move to one specific async API.

Timeline

  • We released Visual Assist 2021.4 on October 29.
  • Visual Studio 2022 was released on November 8, nine days later.
  • VAX 2021.4 overall worked pretty well with the final VS2022 build
    • But both we and some customers found a few more issues, and we’ve spent the past two weeks since VS’s release resolving them
  • VAX 2021.5 with official support for Visual Studio 2022 was released on Nov 22!

Official Support for VS2022

Yesterday afternoon US time we posted Visual Assist 2021.5 on our website. We have a rolling release mechanism and in about a week you should see in-IDE notifications about the new release, followed a couple of weeks later with the new version being available in the Visual Studio Marketplace. However you can directly download and install it now.

We’ve been working on VS2022 for something like nine months now and we’re really happy to have Visual Assist publicly available with Visual Studio 2022 support. We hope it is useful to you!

A note of thanks: VS2022 was a large change from previous versions, and Microsoft has been very open and helpful. We’re very grateful to them for their communications with us, the beta program, and their assistance while we’ve added support. Thank you!

I want to note as well that though as PM I get to write these posts, I really do very little, and all the credit for this release and VS2022 support goes to our amazing team. Thank you!

Visual Assist 2021.4 is released! (And notes on Visual Studio 2022)

We are pleased to have just released Visual Assist 2021.4. VAX uses a rolling release mechanism, so it will be a couple of weeks until VAX notifies you in-product and a couple more before it’s available on the Visual Studio store, but you can download Visual Assist 2021.4 today from our website.

VAX 2021.4 is a quality-focused release. Our last release, 2021.3, was mostly focused on supporting the upcoming Visual Studio 2022 Previews. That early work on support for VS2022 means that when the official release of VS2022 is out, we’ll be able to ship official support very fast. (More on this below.)

However, not everyone upgrades to a new Visual Studio release immediately — in fact many people have very good reasons for staying on older versions for quite some time! — and we want to focus on providing what all our customers across many versions need. (We still support VS 2005!) That’s the focus for this version. This release, as a quality release, focuses on fixing bugs and adding changes for everyone.

Our release notes contain full info, but some notable changes include support for the new External Include Directories property in Visual Studio, and updating the Code Inspection engine to LLVM/Clang version 12.0.1. There are a plethora of bug fixes as well. All up we feel this release is a solid update for you no matter which version of Visual Studio, and for all ways that you use Visual Assist.

Visual Studio 2022

Swiftly supporting new versions of Visual Studio is very important to us, because we understand it’s important to many of you, and we hope you’ve enjoyed seeing VAX working in many of the Visual Studio 2022 Previews. We expect VS2022 to be released very soon. In fact, as we were preparing this release, Previews 5, 6 and 7 came out, the pace increasing so fast that our installer only mentions support for Preview 6, but we do in fact support Preview 7 as well. At the same time we’ve seen significant stability improvements with each newer preview.

We don’t want to delay our release schedule to wait until VS2022 is shipped, especially because this release is focused on what customers using other versions need, which is why we’re releasing now. But since VS2022 will be released so soon, and since we are very ready for that to happen, you can expect a swift mini-update from us adding official support.

In other words:

  • VAX 2021.4 supports Visual Studio 2022 Previews 5 and 6 (with issues leading to hangs), and 7/RC3 (fully)
  • We’re eagerly waiting for VS2022 to be released, and we’ll add official support for it very quickly when it’s out
Visual Assist 2021.4 running in Visual Studio 2022 Preview 7 (Release Candidate 3)
Visual Assist 2021.4 running in Visual Studio 2022 Preview 7 (Release Candidate 3)

We recommend you install Visual Assist 2021.4 now, and we look forward to shipping official support for Visual Studio 2022 very soon.

Visual Studio 2022 preview version 4 support

Just a quick note to let you know that we are aware of a blocking issue while using the latest version of VA in Preview 4. We offered initial beta support for 3.x, however we do not recommend installing Visual Assist on the latest preview as the hangs will render the IDE unusable. We’re working on it and hope to have an update out soon.

Even though each release offers new challenges and setbacks we’re excited for the move to 64bit and the future of Visual Assist when VS 2022 is fully baked. Thanks for your patience!

Unreal Engine ‘Quality Of Life’ in Visual Assist 2021.2

Unreal Engine ‘Quality Of Life’ in Visual Assist 2021.2

The first two releases of Visual Assist this year contain some great Unreal Engine quality-of-life improvements you may want to take advantage of.

While we’ve always announced features in our changelog and release blogs, we’re starting to blog in greater detail about some of what we change — our December blog about reducing memory usage started this — and this time we’ll dig a bit more into two changes improving using Unreal Engine with Visual Assist.

This applies only to versions 2021.1 and 2021.2, the first two versions this year. If you’re reading from the future, there’s likely much more for UE than is described here!

There are two notable items in these versions:

  • Improving parse times for Unreal Engine projects
  • Removing unwanted generated headers and symbols

These mean that your Unreal Engine projects should be fully usable with Visual Assist faster when you open them, and that Visual Assist only shows and uses methods and other symbols that you’re really interested in.

Parse Times

When a solution is opened in Visual Studio, Visual Assist (VAX) parses that solution. This generates the databases of symbols and other data which VAX uses to be able to implement features like GoTo Related, extra syntax highlighting, parameter info, and so forth.

Parsing can take time. Although VAX is not based around a C++ compiler (one of its strengths), parsing is analogous to compiling a project, and while you can use VAX right away, some features require that data before they will work. Unreal Engine solutions can be very large. Therefore, we spend a lot of thought on how to speed up parse time to make the time between opening a solution and having VAX fully functional be as short as possible.

Avoiding Unnecessary Parsing

This following is going to sound ridiculously simple, and it is. What’s the best way to spend less time doing something? Not to do it.

We do focus on optimisations; the parse engine is heavily multi-threaded; the database uses considerably less memory than it used to; and other techniques. But ultimately, the best way to reduce parse time is to do less parsing.

Unreal Engine projects include plugins. These are additional libraries that add features to your game or project (in-editor or at runtime.) The UE editor lets you enable and disable these, so it’s common to have several installed but only use a subset of them. Yet, the presence of plugins is a key item that makes parsing a UE project lengthier. We added an option to turn off parsing them.

In 2021.1 we added an option to disable indexing these plugins. When off, the default, UE plugins were not parsed.

However, we realised this was based on a flawed understanding: that if plugins are third-party (as plugins often are) then you may not need them to be parsed into VAX’s memory: after all, we thought, you’re unlikely to do a ‘find references’ on an internal method of a third-party library. Omitting them from being parsed would not affect day to day use of Visual Assist. But we got feedback that it was more common than we thought for plugins to be first-party: that is, for UE developers to move parts of their game or project’s functionality into a plugin. That means that it was necessary to parse some plugins, and so a simple on/off parse all-or-none toggle was not useful.

In 2021.2 we expanded the setting so that Visual Assist can parse plugins that are genuinely used by your project, only. Today the ‘Index Unreal Engine plugins’ setting has three options for parsing plugins:

  • None: don’t parse anything in the Plugins folder. This reduces parse time the most
  • Referenced: parse only plugins references by the project, and referenced by default. Depending on how many plugins you have installed that are not used, this still reduces parse time. It is the recommended setting
  • All: parse all plugins; there is no reduction in parse time.
Visual Assist Options dialog, showing the settings to index all, referenced, or no Unreal Engine plugins

Real-World Performance Improvements

The amount of time saved by not parsing unused plugins depends on the complexity of your Unreal Engine solution and the specific machine on which Visual Studio runs, but some real-world measurements are as follows:

Time (minutes and seconds) to fully index an Unreal Engine project, when indexing UE plugins. The percentage annotations are the fraction the Referenced Plugins or No Plugins times are of the time indexing the same project with all plugins.

The absolute values may vary but we expect the relative percentage to be broadly applicable.

Notes

If you open a file from a plugin folder which was not parsed (either not referenced, or the above setting was set to None), then you will see a notification message that the file was not parsed and Visual Assist won’t provide your expected functionality for that file. This is shown only once, and won’t be shown again until Visual Studio restarts.

Avoiding Parsing UE-Generated Files

Saving a very useful change for last — there are many places Visual Assist shows you the symbols and files it’s aware of. The two main windows are Open File In Solution which lists all headers (and other files), and Find Symbol will list every symbol in the database. Unreal Engine, however, generates header files, and these include generated symbols, neither of which are useful in practice when coding on your UE project in Visual Studio.

Voila, a new setting, which means Visual Assist won’t show *.generated.h files, and the Find Symbol dialog is not polluted with generated symbols either. The setting is called ‘Index generated code’ and is off by default. That is, the default is aimed at clean results within Visual Assist, to not index these generated files and store those generated symbols. You can always turn it back on if you want the old behaviour.

Visual Assist Options dialog showing the checkbox to index generated code. By default it is off, which means the results shown within Unreal Engine will be cleaner

Unreal Engine with Visual Assist 2021.1 and 2021.2

The above covers only the first two releases this year, and we have more planned. However, the parsing speed improvements (including our followup for more granular parsing of plugins) and removing generated files and symbols by default should the general ‘quality of life’ using Visual Assist with Unreal Engine. As always, feedback is welcome!

Busy Busy Busy!

Are you busy? I know we are. Our development team has been taking a hard look at what’s going on in the development landscape, and I thought we could share a few things that we’ve got going on behind the scenes:

Visual Studio 2022 Public Preview is Here

Visual Studio 2022 is in public beta, with some exciting changes – they’re moving to 64-bit! The team at Microsoft has been super supportive, and we’ve been working on adding full support as we learn more and more about the changes being made. Much of this work is just making sure we’re ready for the release, but there will be some improvements made along the way. Don’t worry. If you’re not ready to move to VS 2022, we’re not dropping support for 2019, or 2017, 2015, or… (we do support a lot of versions, don’t we?) If you are an early adopter, be sure to opt-in for beta downloads. We’ll be releasing a new version with initial support for VS 2022 in the coming weeks!

Unreal Engine 5 Early Access

The team at Epic has been a great partner and supportive of our development efforts, and granted us an early look at some of the things we might encounter with the update. Again, much of the effort is just making sure everything works for UE5 the same way it does for UE4. While initial support is there, we know there will be more to come. We know our game devs are excited about this update and so are we. Again, be sure to sign up for beta to get the latest updates from our end. 

Windows What?

While most (I mean myself) weren’t expecting a big update from Windows, it looks like it is indeed happening. This won’t have as big of an impact on Visual Assist, as we’re more dependent on the IDE than anything else. However, we’re more excited to see what the future holds for Windows and what the downstream effects will be. If you’re in the know, feel free to comment. Either way, we’ll be supporting any moves made as we are able.

All this to say we’re busy and excited about this year in development news. As things get back to somewhat normal in day-to-day life, it looks like we’ll be making up for lost time from 2020 fairly quickly.

Looking for a New Database?

A last note for Visual Studio users: our sister company InterBase has released a new plugin on the VS extension store, adding support for ADO.NET to an already amazing database. We know everyone’s needs around a database are different and think InterBase is a solid mix of lightweight and full-featured with solid encryption all around. Learn more and give it a try here.

How to Set Up VA

Visual Assist is a coding productivity tool for C++ and C# developers. It extends Visual Studio to make the programming experience better by providing tools for understanding code, checking code, and writing code. Some of its benefits include fast navigation, code inspection and modernization, many refactorings, code correction, Unreal Engine 4 support (for which it is famous), and code assistance. In this article, we will walk through the steps needed to set up Visual Assist and show you a very brief overview of how to use it.

1. Installing Visual Assist

First, visit the Whole Tomato Visual Assist website to download the installer. You can use Visual Assist for free for a month as a trial, or alternatively, you can choose to buy a license from the get-go. Keep in mind that once your free trial is over, you will need to buy the license to keep using it.

On the main page, click the red “Try it for free” button, and on the next page, click “Download Free Trial” to download the installer.  

Before downloading the file, you will need to fill in some required information.

Once you have completed this step, your download will begin.

When you are done downloading the installation file, open it to begin the installation process. Visual Assist supports many versions of Visual Studio, and you can install it for any version you have on your computer.

Once the installation is complete, you can immediately start making use of Visual Assist.

When you run Visual Studio, Visual Assist will show you a tip. You can turn this off, but we recommend you keep it on since it shows helpful information about what you can achieve each time you start.

And that’s it! Visual Assist is installed. 

Visual Assist is very powerful but has a very low UI. That’s great for power users who know it well, but if you’re new to using it, it can be harder to discover all the things it can do. Read on for a short intro about using it with a new application. 

Using Visual Assist

The following few steps show you how to create a new application in Visual C++. If you’re familiar with this, you can skip ahead to where we demonstrate Visual Assist.

When starting Visual Studio, you will be directed to the Welcome page, where you will be able to create new projects from the pop-up window. Click on “Create new project” to move to the next step.    

You can create different types of applications using Visual Studio. In this guide, we will create a Windows C++ application for the purpose of illustration. 

Select Windows Desktop Application (note the C++ label) to start building your app. You can select whichever type of application you are interested in building. Once this is complete and you have successfully configured your project, you will finally be able to make use of Visual Assist. Click on “Create” and watch the magic unfold.  

Note that Visual Assist is low UI to prevent it from getting in your way while making use of Visual Studio. Click on “Extensions” in the toolbar and navigate to “VAssistX,” which will present a list of functionalities that you can explore.

You can also access the Quick Action and Refactoring menu by using the following shortcut (Shift+Alt+Q). For a comprehensive list of keyboard shortcuts, click here.

3. Like Visual Assist?

When your trial comes to an end, you will be prompted to use a license. Select “Buy” to purchase a license or “Register” to use an existing one. 

By now you should be able to set up Visual Assist without any problem and start making use of it alongside Visual Studio. To find out more about Visual Assist and some of its functions, and why everyone from developers in major studios right down to students uses it, click here.

Bartłomiej Filipek Reveals Why He’s a Big Fan of Visual Assist

Bartłomiej Filipek Reveals Why He’s a Big Fan of Visual Assist

Bartlomiej Filipek is a software developer from the Polish city of Cracow. Bartek, as he prefers to be called, started coding when he was 14 years old, after reading “C++ in 24h”, and got his first real programming job in 2007. Bartek broad professional experience includes Native Windows Desktop Apps, OpenGL, Gamedev, BioFeedback games, .NET, large-scale app development, flight planning, and graphics driver coding. As a master’s student he also created lectures about OpenGL and gamedev. Since 2014 he has worked as a C++ software developer for Xara.

Bartek took time to tell us about his experience with Visual Assist, and why he’s a big fan.

When did you start using Visual Assist and how long have you been using it?

It’s hard to recall, but it was very early in my professional career. After using Visual Studio (VS 2003 and 2005) for some time, I knew I needed some more productivity enhancements. Visual Studio 2005or 2008 wasn’t best at that. I searched for solutions and found Visual Assist – which was amazing.

What was it like building software before you had Visual Assist?

Visual Studio was great for development, but it lacked some essential improvements like the refactoring helpers. I wasn’t able to efficiently rename my variables or member functions. And most importantly, the speed of Intellisense was relatively poor on large solutions. Sometimes I had to wait a couple of seconds to get the list of methods for my object.

How does Visual Assist help you create your applications?

First of all, I love many refactoring tools that I get with VA. I can quickly and safely rename my variables, functions, and much more. Another important part is code extraction and the ability to move the code back and forth between a header file or the implementation. Additionally, VA is super fast with even larger projects, and I can quickly get a list of member functions, function signatures, and much more. Recently, I have also been exploring VA Code Inspections which helps with code modernization.

What made Visual Assist stand out from other options?I think it’s at least three elements:

I think it has three elements:

  • Performance (as it’s super fast even for large solutions)
  • Lots of refactoring capabilities 
  • Lots of options to understand and move through code faster

What made you happiest about working with Visual Assist?

I like the overall speed of Virtual Assist, I can quickly jump around my code, see definitions, list member functions and even make notes with Hashtags.

What have you been able to achieve through using Virtual Assist to help create your applications?

I think I can write safer code (thanks to code inspections), avoid code smells (like large functions because I can quickly make them smaller with code extraction tools). And overall, it contributes to better quality and readability of my code.

What are some future plans for your applications?

At Xara – my main job – we plan to make some great enhancements to our powerful document online editor. For my other projects, especially blogs and educational content, I hope to experiment with some latest C++ 20 features and practice good modern C++ techniques.


Thank you, Bartek! You can find the link to Bartek’s blog here

https://www.wholetomato.com/downloads
How To Modernize With Visual Assist Part 2

How To Modernize With Visual Assist Part 2

In the previous article, you read about five popular techniques to improve your projects and apply several Modern C++ patterns. Here’s a list of five more things! We’ll go from the override keyword to nullptr, scoped enums, and more. All techniques are super-easy with Visual Assist!

1. Override

Let’s have a look at the following code with a simple class hierarchy:

using BmpData = std::vector<int>;

class BaseBrush {
public:
virtual ~BaseBrush() = default;

virtual bool Generate() = 0;

virtual BmpData ApplyFilter(const std::string&) { return BmpData{}; }
};

class PBrush : public BaseBrush {
public:
PBrush() = default;

bool Generate() { return true; }

BmpData ApplyFilter(const std::string& filterName) {
std::cout << "applying filter: " << filterName;
return BmpData{};
}

private:
BmpData m_data;
};

When you run VA code inspections, you’ll immediately see that it complains about not using the override keyword on those two virtual methods.

image1

In short, the override keyword allows us to explicitly specify that a given member function overrides a function from a base class. It’s a new keyword available since C++11.

As you might already know, you can go to VA Code Inspection Results and apply the fixes automatically. You’ll get the following code:

class PBrush : public BaseBrush {
public:
PBrush() = default;

bool Generate() override;

BmpData ApplyFilter(const std::string& filterName) override;
private:
BmpData m_data;
};

What are the benefits of using override?

The most significant advantage is that we can now easily catch mismatches between the virtual base function and its override. When you have even a slight difference in the declaration, then the virtual polymorphism will might not work. 

Another critical point is code expressiveness. With override, it’s effortless to read what the function is supposed to do.

And another one is being more modern as this keyword is also available in other languages like C#, Visual Basic, Java, and Delphi.

2. nullptr

When I work with legacy code, my Visual Assist Code Inspection Result is often filled with lots of the following items:

image3

This often happens with code like:

if (pInput == NULL) {
    LOG(Error, "input is null!")
    return;
}

or

pObject->Generate("image.bmp", NULL, NULL, 32);

Why does Visual Assist complain about the code? It’s because NULL is just a define and means only 0, so it doesn’t mean a null pointer, but it means 0. This is also a problem when you have code like:

int func(int param);
int func(float* data);
if you call:
func(NULL);

You could expect that the function with the pointer should be called, but it’s not. That’s why it’s often a guideline in C or early C++ that suggests not making function overrides with pointers and integral types.

The solution? Just use nullptr from C++11.

nullptr is not 0, but it has a distinct type nullptr_t.

Now when you write:

func(nullptr);

you can expect the proper function invocation. The version with func(float* data) will be invoked.

Not to mention that nullptr is a separate keyword in C++, so it stands out from the regular code. Sometimes NULL is displayed in a different color, but sometimes it is not.

Visual Assist makes it super easy to apply the fix, and it’s a very safe change.

3. Convert enum to scoped enum

Another pattern that is enhanced with Modern C++ is a way you can define enums.

It was popular to write the following code:

enum ActionType {
    atNone,
    atProcess,
    atRemove,
    atAdd
};

ActionType action = atNone;
Since C++11 it's better to you can define this type in the following way:
enum class ActionType {
    None,
    Process,
    Remove,
    Add
};

ActionType action = ActionType::None;

What are the benefits of such transformations?

  • They don’t pollute the global namespace. As you may have noticed, it was often necessary to add various prefixes so the names wouldn’t clash. That’s why you see atNone. But in the scoped enum version, we can write None.
  • You get strong typing, and the compiler will warn when you want to convert into some integral value accidentally.
  • You can forward scope enums and thus save some file dependencies.

What’s best about Visual Assist is that it has a separate tool to convert unscoped enums to enum classes, all with proper renames and changes in all places where this particular type was used. Right-click on the type and select “Convert Unscoped Enum to Scoped Enum.”. This opens a preview window where you can see and select which references will be replaced.

image2

Read more in Convert Unscoped Enum to Scoped Enum in the VA documentation.

4. Use more auto

One of the key characteristics of Modern C++ is shorter and more expressive code. You saw one example where we converted from for loops with long names for iterators into a nice and compact range-based for loops.

What’s more, we can also apply shorter syntax to regular variables thanks to automatic type deduction. In C++11, we have a “reused” keyword auto for that.

Have a look:

std::vector<int> vec { 1, 2, 3, 4, 5, 6, 7, 8};
std::vector<int>::const_iterator cit = vec.cbegin();

We can now replace it with:

std::vector<int> vec { 1, 2, 3, 4, 5, 6, 7, 8};
auto cit = vec.cbegin();

Previously, template-type deduction worked only for functions, but now it’s enabled for variables. It’s similar to the following code:

template <typename T> func(T cit) {
    // use cit...
}
std::vector<int> vec { 1, 2, 3, 4, 5, 6, 7, 8};
func(vec.cbegin()); // template deduction here!

Following are some other examples:

auto counter = 0;   // deduced int
auto factor = 42.5; // deduces double
auto start = myVector.begin(); // deduces iterator type
auto& ref = counter; // reference to int
auto ptr = &factor;  // a pointer to double
auto myPtr = std::make_unique<int>(42);
auto lam = [](int x) { return x*x; };

Have a look at the last line above. Without auto, it wouldn’t be possible to name a type of a lambda expression as it’s only known to the compiler and generated uniquely.

What do you get by using auto?

  • Much shorter code, especially for types with long names
  • Auto variables must always be initialized, so you cannot write unsafe code in that regard
  • Helps with refactoring when you want to change types
  • Helps with avoiding unwanted conversions

As for other features, you’re also covered by Visual Assist, which can automatically apply auto. In many places, you’ll see the following suggestions:

image5

This often happens in places like

SomeLongClassName* pDowncasted = static_cast<SomeLongClassName*>(pBtrToBase); 
// no need to write SomeLongClassName twice:
auto pDonwcasted = static_cast<SomeLongClassName*>(pBtrToBase);

or

unsigned int val = static_cast<unsigned int>(some_computation / factor);
// just use:
auto val = static_cast<unsigned int>(some_computation / factor);

As you can see, thanks to auto, we get shorter code and, in most cases, more comfortable to read. If you think that auto hides a type name for you, you can hover on it, and the Visual Studio will show you that name. Additionally, things like “go to definition” from Visual Assist work regularly.

5. Deprecated functionality

With C++11, a lot of functionality was marked as deprecated and was removed in C++17. Visual Assist helps with conversion to new types and functions.

For example, it’s now considered unsafe to use random_shuffle as it internally relied on simple rand(), which is very limited as a random function generator.

std::vector<int> vec { 1, 2, 3, 4, 5, 6, 7, 8 };
std::random_shuffle(vec.begin(), vec.end());

Visual Assist can replace the above code with the following:

std::shuffle(vec.begin(), vec.end(), std::mt19937(std::random_device()()));

Additionally, you’ll get suggestions to improve old C-style headers and convert them into C++ style:

image4

Some other handy fixes

We have covered a few inspections, but there’s much more! Here are some exciting items that you might want to see:

The whole list is available here: List of Code Inspections

Summary

Thanks for reading our small series on Clang Tidy, Code Inspections, and Visual Assist. We covered a lot of items, and I hope you learned something new. The techniques I presented in most cases are very easy to use, especially thanks to VA support, and you can gradually refactor your code into Modern C++.

https://www.wholetomato.com/downloads

How to Modernize C++ Code with Visual Assist in Five Easy Steps

How to Modernize C++ Code with Visual Assist in Five Easy Steps

You probably know that over time our projects seem to get old and legacy. Code written now might look suspicious five years later. With the standardization of C++11 in 2011, developers coined the term Modern C++. In this article (and the next one) we’ll take a look at some techniques you might apply to get nicer code and be closer to the best feature that recent versions of C++ offer. 

Let’s start! 

1. Rename and Aim for Meaningful Names You might be surprised by the first point on our list. 

Is rename added to C++11 as a feature? 

No, it’s definitely not just an element of C++. In fact, having good names is not a feature of any programming language, as it depends on your style. The compiler can take any names, including single letters and even almost any Unicode character. Thanks to better IDE support and powerful text editors, we can now avoid shortcuts and rely on full and meaningful names. 

And what’s most important is that we can leverage extra refactoring tools, like those from Visual Assist, to fix code with the legacy style. 

Let’s have a look at the following class: 

class PBrush { 
public: 
	PBrush(); 
	~PBrush(); 

	bool Gen(HDC r) { } 
	bool IsAval() const { return aval; } 

private: 
	bool aval; 
	
	HGLOBAL m_hGlobal; 
	LPBITMAPINFO lpBitmap; 
	LPBYTE lpBits; 
	HDC ReferenceDC; 
	
	RGBQUAD m_pal[256]; 
}; 

Read the above code and think about potential naming issues. Is the code clear and descriptive? What would you change? 

Or take a look at the following function, which uses this PBrush objects: 

std::vector<PBrush*> FilterAvalBrushes(const std::vector<PBrush*>& brs) { std::vector<PBrush*> o;
	ULONG totalBCount = 0; 
	size_t totalBitmaps = 0; 
	
	for (size_t i = 0; i < brs.size(); ++i) { 
		if (brs[i]->IsAval()) { 
			o.push_back(brs[i]); 
			++totalBitmaps; 
			totalBCount += brs[i]->GetByteCount(); 
		} 
	} 
	
	// make sure they have some bits ready: 
	for (size_t i = 0; i < o.size(); ++i) { 
		if (!o[i]->Bits()) 
			Log("ERROR, empty bitmap!"); 
	} 
	
	Log("Byte count %d, total bitmaps %d", totalBCount, totalBitmaps); return o; 
}

How could we improve the code? 

You might be tempted to say that it’s better to leave old code and not touch it since other systems might depend on it. However, adding or changing to better names and keeping it useful to other systems is very simple. In most cases, you can find and replace old names or use Rename from Visual Assist. 

Visual Assist has a powerful feature for renaming objects and making sure the code compiles after this transformation. It was also one of the earliest VA features and enabled using this refactoring capability years before Visual Studio added it. 

You can invoke the rename tool in many situations. 

The simplest way is to hit a key shortcut when your cursor is inside a particular name ( Shift + Alt + R by default). For example, let’s say that I’d like to rename bool aval, so I move my cursor there and invoke the dialog, and then I can see the following window: 

Another option is to write a new name, and then VA will show a handy context menu where you can invoke the rename or see the preview window before making the changes. 

What other things can you do with rename? 

Improve consistency of names. For example, your style guide might suggest adding m_ before each nonstatic data member for classes. So you might quickly improve it and add this prefix for classes that don’t share this style. In our example, some names start with m_ while others don’t. 

It’s not only variables and functions but also things like enumerations and namespaces. 

But most importantly, what name would be better for aval? Do you prefer m_isAvailable ? or Available ? I’ll leave it as an exercise. 

2. Extract Smaller Functions 

Here’s another example to fix: 

// number of data components 
switch ( format ) 
{ 
case GL_RGB: 
case GL_BGR_EXT: components = 3; break; 
case GL_RGBA: 
case GL_BGRA_EXT: components = 4; break; 
case GL_LUMINANCE: components = 1; break; 
default: components = 1; 
} 

GLuint t; 
glGenTextures(1, &t); 

// load data 
HBITMAP hBmp = (HBITMAP)LoadImage(NULL, fname, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); 
if (hBmp == NULL) 
	return 0; 
	
// rest of code... long code

The above code is just a part of some longer function that loads, opens a file, loads bytes, and creates an OpenGL texture object with the loaded data. One thing that we might immediately do is to make this function smaller. More compact functions are easier to read and allow for more code reuse.  We can see that it has several smaller subtasks, so it would be better to extract them into separate parts. For example, we can implement FormatToComponents

And when you select this context menu, you’ll get the following dialog: 

After some adjustments (for example, we don’t need to take components as input argument), we can prepare the following code: 

int FormatToComponents(GLenum format) { 
	switch (format) { 
	case GL_RGB: 
	case GL_BGR_EXT: return 3; 
	case GL_RGBA: 
	case GL_BGRA_EXT: return 4; 
	case GL_LUMINANCE: return 1; 
	} 
	return 1; 
} 

And then call it from our initial function: 

GLuint LoadTextureFromBmp(const char *fname, GLenum format, GLuint filter) { const int components 
	= FormatToComponents(format);  

This not only gave us shorter, cleaner code, but also we can now mark our variable as const, which even improves the quality. Additionally, this function might be reused in some other places of the system. 

Here are the general rules for the extraction by VA: 

Symbols available globally, or within the class of the original and new methods, are not passed via a parameter list. 

Symbols used only in the right side of expressions (i.e., not modified) are passed by value. Symbols used in the left side of expressions (i.e., assigned) are passed by reference. Symbols referenced with dot notation within the extracted code (e.g., classes and structs) are always passed by reference. 

When a newly created method assigns a value to only one symbol, that symbol is passed by value and the assignment is done in the original method via return value. 

Symbols local to extracted code become local to the new method; they are not passed.

 3. Improve Function Interfaces 

Let’s now challenge ourselves with this one: 

bool Init2d(HDC hdcContext, FontMode fm, HFONT hFont, GLuint iWidth, GLuint iHeigth, GLuint iTexture, bool forceBold, bool forceItalic, size_t numGlyphs); 

It’s a member function in GLFont that is responsible for creating a texture font from a Window font. We can later use this created object to draw text in an OpenGL application. 

Isn’t it worrying that this function takes nine input arguments? 

And here’s an even more suspicious-looking call site: 

glFont.Init2d(const_cast<CGLApp *>(glApp)->GetHdc(), fmBitmap, hFont, iWidth, iHeight, 0, false, false, 256);

Some books suggest that if you have more than 5… or 7, then it’s some worrying code smell.  Such long lists of function arguments are hard to read, and caller sites might easily put them in a wrong order. Another issue is that there are a few boolean parameters, and it’s hard to see what they mean from the caller perspective. 

You can use Change Signature to modify all parts of a signature, including: 

  • Method name 
  • Return type 
  • Visibility 
  • Parameter names 
  • Parameter types 
  • Parameter order 
  • Number of parameters 
  • Qualifiers 

The plan for our function is to introduce a structure that would hold all parameters. We can do it by simply copying the parameter list and putting it into a structure above the function declaration: 

struct FontCreationParams { 
	GLuint iWidth; 
	GLuint iHeigth; 
	GLuint iTexture { 0 }; 
	bool forceBold { false}; 
	bool forceItalic { false}; 
	size_t numGlyphs { 256 }; 
}; 

As you can see, I even assigned some default values. 

And then we can change the signature in two steps: 

1. Add new argument to the function: const FontCreationParams& param with a default value of TODO. 

2. And then, again remove those extra arguments. 

Then you might compile code and fix call sites. 

The final code might look as follows: 

FontCreationParams params; 
params.iWidth = iWidth; 
params.iHeigth = iHeight; 
glFont.Init2d(const_cast<CGLApp *>(glApp)->GetHdc(), fmBitmap, hFont, params);

With this approach, if you need some more parameters (or you need to alter them), it’s just a matter of modifying the structure, and the function declaration will be the same. 

While you can do such a change manually, Visual Assist makes it much more comfortable and takes care of most of the cases at the call site. So this significantly simplifies and automates the process when you have many function calls. 

So far, we discussed basic principles for code modernization, but how about automation? Can we use extra tools that would tell us what to change in our code? 

Let’s see the fourth point. 

4. Enable Code Inspections 

Since a few years ago, Visual Assist has come with code Inspections that automatically check your code and pinpoint any issues. 

Code Inspection analyzes C/C++ for specific code quality issues as you edit. The feature, based on LLVM/Clang, warns you of issues in your code and if possible, suggests and applies quick fixes. 

You can enable them via Settings or as shown below: 

You can read the full description of Inspections in the excellent documentation website Introduction to Code Inspection and also see our previous article where we dive a bit deeper A Brief Introduction to Clang-Tidy and Its Role in Visual Assist – Tomato Soup. 

Currently,  we have almost 30 code inspections, and the number grows with each revision: List of Code Inspections. 

They range from checking .empty() vs size() , using emplace_back(), nullptr usages, and many more. They can help not only with code modernization but even with finding some performance issues in code. It’s like a small code analysis run on the code. 

Let’s  take a look at one related to for loops. 

5. Make For-Loops More Compact 

One of the coolest elements of C++11 style comes from using simpler for loops. This is especially important for code that uses containers from the Standard Library. 

For example, before C++11, you had to write: 

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

Now, this can be simplified with this simple syntax: 

std::vector<int> vec { 1, 2, 3, 4, 5, 6 }; 
for (const auto& elem : vec) 
	std::cout << elem << '\n';

Why not automate this transformation? 

VA identifies places where you can use this modern syntax and then rewrites loops for you. 

Consider this example: 

std::vector<PBrush*> FilterAvalBrushes(const std::vector<PBrush*>& brushes) { // ... 
	for (size_t i = 0; i < brushes.size(); ++i) { 
		if (brushes[i]->IsAval()) { 
			out.push_back(brushes[i]); 
			++totalBitmaps; 
		} 
	} 
} 

When code inspections are enabled, we can see the following suggestions:

What’s nice about Visual Assist is that it’s very smart and tries to deduce the correct loop syntax. 

For example, when our vector holds pointers, then the converted loop is as follows: 

std::vector<PBrush*> FilterAvalBrushes(const std::vector<PBrush*>& brushes) { // ... 
	for (auto brushe : brushes) { 
		if (brushe->IsAval()) { 
			out.push_back(brushe); 
			++totalBitmaps; 
			totalBCount += brushe->GetByteCount(); 
		} 
	} 
} 

But when we change the type into const std::vector<PBrush> (so it holds not pointer but “full” objects), then the loop is as follows: 

for (const auto & brushe : brushes) { 
	if (brushe.IsAval()) { 
		out.push_back(brushe); 
		++totalBitmaps; 
		totalBCount += brushe.GetByteCount(); 
	} 
}

The system is smart and avoids situations where you’d copy objects during loop iteration, as it’s more efficient to use references. 

That’s just a taste of what you can automatically do with Visual Assist and its code inspections! 

Summary 

In this article, you’ve seen five suggestions on how to check and improve your code. We started with something fundamental but often skipped: naming. Then we made functions smaller and with better interfaces. And at the end, we enabled code inspections so that Visual Assist can automatically identify more things to repair. 

In the last item, we looked at loop transformation, which is available from C++11. Thanks to Visual Assist, we can automate this task and quickly modernize our code to the newer standard 

After such refactoring, we aim to have safer, more readable code. What’s more, with more expressive code, we can help the compiler to identify potential errors. This is just a start, and stay tuned for the next article where you’ll see other code modernization techniques: override keyword, nullptr, enum class, auto type deduction, and deprecated headers.

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: