After last week’s transition from C++ to C99, I decided to dedicate this week to code cleanup.
Re-enabling all warnings
My compiler of choice is Clang and I like to build with the
-Weverything and disabled warnings to a minimum, but whenever I do a cleanup pass (or when I upgrade my compiler toolchain) I re-enable all warnings in order to reassess the state of the codebase.
I also try to keep the code GCC-compatible, but I usually only use it during cleanup/benchmarking sessions, as I find it to be slower than Clang for day-to-day usage. Plus I feel the warnings are still not up to par, compared with Clang’s excellent error reporting.
Merciless removal, courtesy of git
I tend to aggressively delete unused code paths during cleanup passes. I lean heavily on carefully crafted
git commits in order to make it easy on myself in case I ever need to recover deleted code.
For each coherent block of code I delete, I make a commit with only that change and a commit message stuffed with relevant keywords that I can later
grep on in case of need.
I also try not to touch API boundaries as much as possible, in order to avoid introducing bugs, but if I find unused functions, or branches I’m quick to the delete key.
During cleanup passes I also like to add GCC-style
__attribute__ decorations, as I found quite a few of them can help catch bugs.
__attribute__((warn_unused_result)), for example, is one of my favorite function attributes, as it causes a warning to be emitted if a caller of the function does not use its return value.
__attribute__((pure)) is another attribute I use quite often, more for documentation purposes than for compiler optimization.
A sprinkle of unit tests
The test suite for Rival Fortress is pretty poor, if I have to be honest, so I try to invest some of the alloted cleanup time to adding some unit tests for algorithmically complex and functions that look like they have poor coverage.
I guesstimate code coverage for a function with the simple terminal onliner:
grep FUNCTIONAME | wc -l. This gives me the all the callsites for the function, so I can quickly skim through, and get a feel for the use cases.
One of these days I’ll have to look into code coverage mapping.