Clang tools – the introduction

Imagine the following scenario. Alice needs to review a change submitted by Bob, a new developer in the

Imagine the following scenario. Alice needs to review a change submitted by Bob, a new developer in the project. And it goes likes this:

Review 1: The formatting is inconsistent with the rest of the code. She explains the rules to Bob.
Review 2: It’s better, but it’s still not right. She needs to point out all the remaining violations.
Review 3: Now she notices that Bob does things the old, stinky way. It needs to be improved.
Review 4: Why is he using “1” when he means “true”?
Review 5: Uh, stupid bug. There is a stray semicolon after if condition – the intended if body is always executed. Review 6: Sigh. Bob added some trailing spaces while fixing the last bug.
Review 7: At this point Alice feels pressured to get it over with, so she just accepts the change, without ever getting beyond the details.

What a waste of time! We can hope that Bob will be more careful next time. Yet, in almost every project, similar trivial problems will arise over and over again. Even the senior developers are not immune to distractions and misconfigured editors. So, wouldn’t it be awesome if all of that work could be performed automatically, in seconds, so that the programmers can focus on the stuff that really matters? Well, we have good news. It’s possible, just not everyone has noticed yet.

Linters and automatic formatters are really old concepts, but they weren’t fully embraced by the community until quite recently. Modern languages often emphasize the automation. The Go language appears to be the leader in this aspect. For example one of the favorite features of the Go programmers is the official style defined by gofmt. However, regardless of the technology, the projects can benefit greatly from trying to use computers instead of people to perform the most repetitive and tedious tasks.

The tools are particularly effective when other best practices are in place: code review, automated testing, continuous integration. One proven setup is to run the checks before the tests on build server. The benefits are clear:

  • No need to remember to run all the tools every time. In case something is wrong, the developer will be gently reminded.
  • Quicker feedback. Linters tend to be much faster than tests (this is especially important for dynamic languages, in which case the linter is your first line of defense against typos).
  • No time is wasted on reviewing broken changes.
  • Zero formatting style violations on the official branch.
  • Certainty that some common kinds of bugs don’t exist in the official codebase.

Let’s get to the specifics. Consider C++. It’s undoubtedly one of the most complicated languages out there and it provides plenty of ways to shoot yourself in the foot. So the tools are desperately needed, but it’s quite tricky to build them. Fortunately we have the Clang ecosystem – the heavy lifting is already done and mostly shared with the compiler.

clang-format

Among all the clang tools, the code formatter is probably the easiest to configure. Just create a file called .clang-format in your project directory with the following contents:

 

Instead of LLVM, you can choose a different base style. And of course you can customize the project style further using over 70 individual style options. If you want to see them all you can dump the built-in style like that:

You still won’t be able to express every rule imaginable, but the point of automatic formatting is the consistency. It doesn’t matter that much if you implement exactly your favorite style.

With the configuration ready, you can run clang-format this way (the configuration file needs to be in one of the parent directories of your_file.cpp):

Even though it’s so easy to use, clang-format is actually quite sophisticated. One particularly useful advanced feature is having include groups, defined with regular expressions. The groups will appear in each file in the specified order and within each group the headers will be ordered alphabetically.

 

clang-tidy

Now, let’s discuss our favorite, the linter tool. It’s a collection of independent checks, each looking for one specific issue in the code.

So what can it do? Here are some examples of checks and what the problems they find:

  • cppcoreguidelines-no-malloc – using malloc and free
  • misc-virtual-near-miss – typos when overriding virtual functions
  • misc-suspicious-semicolon – stray semicolons that change the meaning of the program
  • google-runtime-int – using short, long and long long (instead of int16 etc.)
  • modernize-use-nullptr – 0 or NULL instead of nullptr
  • modernize-use-bool-literals – using 0 and 1 instead of false and true.
  • modernize-loop-convert – old-style loops when a range-based loop can be used

In total there are more than 200 checks available (including those provided by the static analyzer).

http://clang.llvm.org/extra/clang-tidy/checks/list.html

Clang tidy also has a unique feature that no other C++ linter has – fixits. It not only flags suspicious code, but it also can transform the code in most cases. This proves extremely useful if you want to modernize a legacy codebase. Manually fixing a thousands lines of code on 100K+ LOC easily takes days, but with clang-tidy it can be done with one command (you still need to review the result, though).

So for example by using modernize-loop-convert:

Can be transformed to:

Note that it is smart enough to figure out the name of the object based on container name if it looks like a plural noun.

Running clang tidy is a little bit more tricky than in case of clang-format – it’s necessary to provide the compilation flags (at least the relevant ones).

You can run it like this:
clang-tidy file.cpp — <flags passed to the compiler>

for example:

Or you can build a compilation database, a simple json file with a compilation command for each file:

and then simply:

To fix the problems (with or without a compilation database) you need to specify -fix option, e.g.:

A more detailed explanation is available here: http://clang.llvm.org/extra/clang-tidy/#using-clang-tidy

Code Checker

Code checker is a GUI tool that uses clang static analyzer and clang-tidy. A potential killer feature is marking false positives, so the tool will not display it next time. It’s especially useful for visualizing path-dependent bugs.

https://github.com/Ericsson/codechecker

Summary

Using automatic tools to enforce coding style and to look for bugs will save you a lot of time and even more importantly they will allow you to focus on the big picture. Of course, if you’re using C++ we strongly recommend clang-format and clang-tidy. We needed to wait for a long time for reasonable tools in a language that complex, but the Clang ecosystem finally gets things right by using modern compiler infrastructure as the base for the tools.

Leave a Comment