[clang-tools-extra] 9e5deb9 - [clang-tidy] Speed up `modernize-use-nullptr` (#178829)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Feb 1 16:26:46 PST 2026
Author: Victor Chernyakin
Date: 2026-02-01T16:26:41-08:00
New Revision: 9e5deb963abec2808152b55d826333cba8ad5ab0
URL: https://github.com/llvm/llvm-project/commit/9e5deb963abec2808152b55d826333cba8ad5ab0
DIFF: https://github.com/llvm/llvm-project/commit/9e5deb963abec2808152b55d826333cba8ad5ab0.diff
LOG: [clang-tidy] Speed up `modernize-use-nullptr` (#178829)
As noted in [this
comment](https://github.com/llvm/llvm-project/pull/178149#discussion_r2732896149),
it appears that registering one `anyOf(a, b, ...)` matcher is generally
slower than registering `a, b, ...` all individually. Applying that
knowledge to this check gives us an easy 3x speedup:
```txt
---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
Status quo: 0.3281 ( 6.1%) 0.0469 ( 5.2%) 0.3750 ( 6.0%) 0.3491 ( 5.5%) modernize-use-nullptr
With this change: 0.0938 ( 1.8%) 0.0156 ( 1.8%) 0.1094 ( 1.8%) 0.1260 ( 2.1%) modernize-use-nullptr
```
I'm not exactly sure *why* this works, but it seems pretty consistent.
I've seen a similar result trying this with `bugprone-infinite-loop`.
Added:
Modified:
clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
index cc371a1ab55a7..85224b573edeb 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -45,8 +45,7 @@ static constexpr char CastSequence[] = "sequence";
/// would check for the "NULL" macro instead, but that'd be harder to express.
/// In practice, "NULL" is often defined as "__null", and this is a useful
/// condition.
-static StatementMatcher
-makeCastSequenceMatcher(llvm::ArrayRef<StringRef> NameList) {
+void UseNullptrCheck::registerMatchers(MatchFinder *Finder) {
auto ImplicitCastToNull = implicitCastExpr(
anyOf(hasCastKind(CK_NullToPointer), hasCastKind(CK_NullToMemberPointer)),
anyOf(hasSourceExpression(gnuNullExpr()),
@@ -54,32 +53,34 @@ makeCastSequenceMatcher(llvm::ArrayRef<StringRef> NameList) {
qualType(substTemplateTypeParmType())))),
unless(hasSourceExpression(hasType(sugaredNullptrType()))),
unless(hasImplicitDestinationType(
- qualType(matchers::matchesAnyListedTypeName(NameList)))));
+ qualType(matchers::matchesAnyListedTypeName(IgnoredTypes)))));
auto IsOrHasDescendant = [](const auto &InnerMatcher) {
return anyOf(InnerMatcher, hasDescendant(InnerMatcher));
};
- return traverse(
- TK_AsIs,
- anyOf(castExpr(anyOf(ImplicitCastToNull,
- explicitCastExpr(hasDescendant(ImplicitCastToNull))),
- unless(hasAncestor(explicitCastExpr())),
- unless(hasAncestor(cxxRewrittenBinaryOperator())))
- .bind(CastSequence),
- cxxRewrittenBinaryOperator(
- // Match rewritten operators, but verify (in the check method)
- // that if an implicit cast is found, it is not from another
- // nested rewritten operator.
- expr().bind("matchBinopOperands"),
- hasEitherOperand(IsOrHasDescendant(
- implicitCastExpr(
- ImplicitCastToNull,
- hasAncestor(cxxRewrittenBinaryOperator().bind(
- "checkBinopOperands")))
- .bind(CastSequence))),
- // Skip defaulted comparison operators.
- unless(hasAncestor(functionDecl(isDefaulted()))))));
+ Finder->addMatcher(
+ castExpr(anyOf(ImplicitCastToNull,
+ explicitCastExpr(hasDescendant(ImplicitCastToNull))),
+ unless(hasAncestor(explicitCastExpr())),
+ unless(hasAncestor(cxxRewrittenBinaryOperator())))
+ .bind(CastSequence),
+ this);
+
+ Finder->addMatcher(
+ cxxRewrittenBinaryOperator(
+ // Match rewritten operators, but verify (in the check method)
+ // that if an implicit cast is found, it is not from another
+ // nested rewritten operator.
+ expr().bind("matchBinopOperands"),
+ hasEitherOperand(IsOrHasDescendant(
+ implicitCastExpr(ImplicitCastToNull,
+ hasAncestor(cxxRewrittenBinaryOperator().bind(
+ "checkBinopOperands")))
+ .bind(CastSequence))),
+ // Skip defaulted comparison operators.
+ unless(hasAncestor(functionDecl(isDefaulted())))),
+ this);
}
static bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc,
@@ -505,10 +506,6 @@ void UseNullptrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
utils::options::serializeStringList(IgnoredTypes));
}
-void UseNullptrCheck::registerMatchers(MatchFinder *Finder) {
- Finder->addMatcher(makeCastSequenceMatcher(IgnoredTypes), this);
-}
-
void UseNullptrCheck::check(const MatchFinder::MatchResult &Result) {
const auto *NullCast = Result.Nodes.getNodeAs<CastExpr>(CastSequence);
assert(NullCast && "Bad Callback. No node provided");
More information about the cfe-commits
mailing list