Many C++ projects have a set of coding standards regarding what functions to use, and CMake is no exception. Clang-tidy is a program which enforces some universally relevant standards to C++ projects. CMake runs clang-tidy on its code as part of its CI process, but clang-tidy alone does not have a way to enforce standards that are specific to CMake’s code base.
Luckily, clang-tidy has supported loadable plugins for several versions, and LLVM and clang have very comprehensive documentation for their internal APIs. Clang-tidy can also automatically apply its suggested fix to the source file in some cases. This means that a developer who is familiar with the internals of clang-tidy can write a plugin to enforce their own code standards on their own projects, complete with automatic correction.
In partnership with the Department of Computer Science at the University at Albany, Kitware has overseen the development of a clang-tidy plugin that will be used to enforce CMake’s code standards. This will allow CMake maintainers to review code more easily, and has also provided a learning opportunity for graduating seniors in the computer science department who are completing their capstone project.
Our new clang-tidy plugin enforces six CMake-specific coding guidelines:
- Calls to
sizeof()on a string literal should be replaced with calls to
- Instances of
std::fstreamshould be replaced with
- Functions with a
boolparameter should replace it with an
- Headers that have include guards (
#endif) should use
std::ostringstreamshould not be used. Instead, strings should be built using
- Strings should not be concatenated together with
+=. Instead, they should be concatenated using
The plugin that we’ve developed is already active in CMake’s CI system, actively enforcing checks 1, 2, and 4 (checks 3, 5, and 6 are currently disabled due to a large number of outstanding violations.) The code for the plugin can be found here. The CI system builds the plugin against the clang-tidy headers and then calls clang-tidy with the
--load argument pointed to the newly-built
.so plugin file.
In addition, we have added a new feature to CMake to allow clang-tidy to export all of its suggested fixes to a directory, which can then be applied to the source code after the build is complete. This will allow mass refactoring to enable new clang-tidy checks, and can also be used by the CI system to automatically generate a patch file containing its suggested fixes.
This project has proved to be a useful tool for C++ code review in CI systems. In addition to improving the quality of the CMake code base, we hope that the knowledge gained from this project will allow us to develop clang-tidy plugins for customers who want to enforce their own standards on their own code.
As an example of what the plugin can do, consider the following code snippet:
fout << "Hello world!\n";
CMake’s code standards dictate that
cmsys::ofstream, CMake’s internal
ofstream implementation which handles internationalization of filenames on Windows, be used instead of
std::ofstream. The clang-tidy plugin detects this incorrect usage of
std::ofstream, issues a warning to the user, and automatically corrects it:
fout << "Hello world!\n";
Future work will include adding more checks to CMake’s clang-tidy plugin, upstreaming the
#pragma once check back to the LLVM project, and adding a new feature to clang-tidy to add a
NOLINT line to the source code in the case that it is not able to apply an automatic fix. This new feature will allow checks that have a large number of outstanding violations to be turned on without failing, giving the existing violations a grace period to be fixed while preventing any new ones from being added to the code base.
Kitware would like to recognize Joseph Blaauboer, Mikhail Glebov, and Sean Orner for their hard work on this project, and congratulate them on their graduation from the University at Albany (UAlbany). We would also like to acknowledge Pradeep Atrey, Ph.D., professor at UAlbany, for overseeing this computer science capstone project.