Skip to main content

Raymii.org Raymii.org Logo

Quis custodiet ipsos custodes?
Home | About | All pages | Cluster Status | RSS Feed | Gopher

Run one specific clang-tidy check on your entire codebase

Published: 05-04-2021 | Author: Remy van Elst | Text only version of this article


❗ This post is over one year old. It may no longer be up to date. Opinions may have changed.

Table of Contents


Recently I did a major refactor on a piece of code that involved thousands of lines of code which were in one way or another related to string handling. All of the code handled char* (C style character pointer arrays) and the concept of const or ownership was literally unknown in that part of the codebase. The refactored code uses std::string's, but due to the legacy nature, a large number of methods returned nullptr's instead of empty strings (like ""). I understand why this was done, but finding all those instances and the fact it only gives a runtime error was a bit of a bummer.

I'm developing a desktop monitoring app, Leaf Node Monitoring, open source, but paid. For Windows, Linux & Android, go check it out.

Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.

You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $100 credit for 60 days.

Luckily clang-tidy is here to save the day. In my IDE, CLion, it gives a warning when you return a nullptr. It however does that only in the file you're currently editing, and since we're talking millions of files, I wasn't going to open them by hand. You can run clang-tidy easily on one file, and it's not hard to run it on an entire codebase as well, using the script run-clang-tidy.py, provided in their packages.

This snippet shows you how to run one specific clang-tidy check, in my case, bugprone-string-constructor, on a (cmake and C++) codebase.

Here's the clang-tidy message in CLion:

screenshot

Example code with undefined behaviour

This is an example piece of code demonstrating the behavior:

#include <string>
#include <iostream>

class Example {
public:
    std::string getName() { return nullptr; }
};

int main() {
    Example ex;
    std::cout << "Example: " << ex.getName() << std::endl;
    return 0;
}

If you try to run the above code example, you'll get a runtime error:

terminate called after throwing an instance of 'std::logic_error'
    what():  basic_string::_M_construct null not valid

Opinions on nullptr and std::string differ depending on who you ask, but as of now it's not possible to construct a std::string with a nullptr.

Run clang-tidy on you entire codebase

Make sure you have clang-tidy installed:

apt install clang-tidy

Navigate into your project folder:

cd my/cpp/project

If you haven't already, create a build folder (mkdir build; cd build) and run cmake with an extra flag to create the compilation database for clang-tidy:

cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug 

In the build folder, run run-clang-tidy. It might be a different command (run-clang-tidy.py or run-clang-tidy-VERSIONNUMBER) depending on your distro's packaging preference.

run-clang-tidy -extra-arg=-Wno-unknown-warning-option -checks='-*,bugprone-string-constructor' 2>&1 | tee -a clang-tidy-result

This will take a while, when the command is finished, you can look at the results, or in the file clang-tidy-result. In my case it gave specific filenames and line numbers where it found the undefined behavior.

The -extra-arg was required due to some other compiler extension flag for our code, you can probably omit that.

The -checks='-*' disables all checks, the next ,bugprone-string-constructor enables only the specific string check I want to run. You can add more specific checks, separate them by a comma. An example with just 2 checks enabled:

-checks='-*,bugprone-string-constructor,bugprone-string-integer-assignment'

An up to date list of clang-tidy checks can be found on the LLVM website.

Tags: c++ , clang , clang-tidy , cpp , development , legacy , refactoring , snippets