Reviving Old Ideas: My clang-tidy Contributions to LLVM

⚡ LLVM 🔧 C++ / Clang 👤 Helmut Januschka

Invest in tooling once, reap the benefits forever

Status: Ongoing | First Merged PR: #116033


The Origin Story

Years ago, while working on Chromium, Peter Kasting introduced me to clang-tidy. During code reviews he'd point out patterns that could be automated - things he'd seen hundreds of times, anti-patterns that kept appearing, modernization opportunities too tedious to do by hand.

I started keeping my own scratchpad, jotting down his suggestions and ideas. That document sat there for years - until I recently picked it back up.

Why clang-tidy Matters for Large Codebases

When you're working on a codebase with millions of lines of C++ - like Chromium - modernization isn't optional, it's survival. New C++ standards bring better performance, safer patterns, and clearer intent. But manually updating millions of lines? Impossible.

That's where clang-tidy comes in. Write a check once, run it across the entire codebase, get automated fixes. A single check can identify thousands of modernization opportunities and fix them automatically.

Chromium actively uses clang-tidy for ongoing modernization. The base::StringPiece to std::string_view migration, the adoption of std::optional, the move to starts_with/ends_with - all of these are driven by clang-tidy checks that find patterns and transform them at scale.

My First Contribution: substr to starts_with

My first merged PR enhanced an existing check to detect a common anti-pattern:

// Before: Creates a temporary string, then compares
if (str.substr(0, 5) == "hello") { ... }

// After: Direct comparison, no allocation
if (str.starts_with("hello")) { ... }

The starts_with method was added in C++20. It's clearer, faster (no temporary string), and expresses intent better.

The PR (#116033) extended modernize-use-starts-ends-with to catch substr patterns. The review process was educational - the LLVM community suggested integrating it into the existing check rather than creating a new one.

Key patterns now detected:

The Scratchpad Comes Alive

After that first merge, I went back to my old scratchpad. Many of Peter's ideas that seemed far-fetched years ago are now practical with C++20 and C++23 features available. I started working through them one by one.

Currently open PRs:

Modernization checks:

Readability checks:

Enhancements:

The Chromium Connection

The loop closes here: a small contribution to clang-tidy becomes a massive lever for Chromium cleanups. One check can identify thousands of instances across the codebase, generate automated fixes, and make follow-up CLs trivial.

Quick search across Chromium for the actual patterns these checks catch:

Pattern Check Instances
.substr(0, n) == modernize-use-starts-ends-with ~730
.find(x) == 0 modernize-use-starts-ends-with ~1,100
.compare(0, n) modernize-use-starts-ends-with ~50
.subspan(0, n) readability-use-span-first-last ~10

That's nearly 2,000 starts_with/ends_with candidates alone - each one a clearer, faster replacement. And that's just one family of checks.

Links


Sometimes the best ideas need time to mature. That scratchpad waited years - but Peter's suggestions are now becoming real tools that help developers write better C++.

Thanks to: