[clang-tools-extra] 27eb381 - [clang-tidy] Add detection of decltype(nullptr) => std::nullptr_t to modernize-use-nullptr (#224591)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Sep 20 10:38:34 PDT 2026
Author: serge-sans-paille
Date: 2026-09-20T17:38:28Z
New Revision: 27eb38144a2bc40e989cdefb8265b6eb7aedb21b
URL: https://github.com/llvm/llvm-project/commit/27eb38144a2bc40e989cdefb8265b6eb7aedb21b
DIFF: https://github.com/llvm/llvm-project/commit/27eb38144a2bc40e989cdefb8265b6eb7aedb21b.diff
LOG: [clang-tidy] Add detection of decltype(nullptr) => std::nullptr_t to modernize-use-nullptr (#224591)
Hidden behind an option switch, but on by default.
Added:
clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-t.cpp
Modified:
clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
clang-tools-extra/docs/ReleaseNotes.md
clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst
clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
index 4f561a1f10204..01bb98cfbcfd4 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp
@@ -28,6 +28,12 @@ AST_MATCHER(Type, sugaredNullptrType) {
return false;
}
+AST_MATCHER(DecltypeType, decltypeTypeNullptrLiteral) {
+ if (const Expr *E = Node.getUnderlyingExpr())
+ return isa<CXXNullPtrLiteralExpr>(E->IgnoreParens());
+ return false;
+}
+
} // namespace
static constexpr char CastSequence[] = "sequence";
@@ -81,6 +87,11 @@ void UseNullptrCheck::registerMatchers(MatchFinder *Finder) {
// Skip defaulted comparison operators.
unless(hasAncestor(functionDecl(isDefaulted())))),
this);
+
+ if (UseNullptrT)
+ Finder->addMatcher(typeLoc(loc(decltypeType(decltypeTypeNullptrLiteral())))
+ .bind("matchDecltypeNullptr"),
+ this);
}
static bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc,
@@ -495,17 +506,40 @@ UseNullptrCheck::UseNullptrCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
NullMacrosStr(Options.get("NullMacros", "NULL")),
IgnoredTypes(utils::options::parseStringList(Options.get(
- "IgnoredTypes", "_CmpUnspecifiedParam;^std::__cmp_cat::__unspec"))) {
+ "IgnoredTypes", "_CmpUnspecifiedParam;^std::__cmp_cat::__unspec"))),
+ UseNullptrT(Options.get("UseNullptrT", true)),
+ IncludeInserter(Options.getLocalOrGlobal("IncludeStyle",
+ utils::IncludeSorter::IS_LLVM),
+ areDiagsSelfContained()) {
NullMacrosStr.split(NullMacros, ",");
}
+void UseNullptrCheck::registerPPCallbacks(const SourceManager &SM,
+ Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP) {
+ IncludeInserter.registerPreprocessor(PP);
+}
+
void UseNullptrCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "NullMacros", NullMacrosStr);
Options.store(Opts, "IgnoredTypes",
utils::options::serializeStringList(IgnoredTypes));
+ Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle());
+ Options.store(Opts, "UseNullptrT", UseNullptrT);
}
void UseNullptrCheck::check(const MatchFinder::MatchResult &Result) {
+ if (const auto *MatchedTypeLoc =
+ Result.Nodes.getNodeAs<TypeLoc>("matchDecltypeNullptr")) {
+ diag(MatchedTypeLoc->getBeginLoc(), "use std::nullptr_t instead")
+ << IncludeInserter.createIncludeInsertion(
+ Result.SourceManager->getFileID(MatchedTypeLoc->getBeginLoc()),
+ "<cstddef>")
+ << FixItHint::CreateReplacement(MatchedTypeLoc->getSourceRange(),
+ "std::nullptr_t");
+ return;
+ }
+
const auto *NullCast = Result.Nodes.getNodeAs<CastExpr>(CastSequence);
assert(NullCast && "Bad Callback. No node provided");
diff --git a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
index 1caa07afe352a..7f3eb6e4dd18b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USENULLPTRCHECK_H
#include "../ClangTidyCheck.h"
+#include "../utils/IncludeInserter.h"
namespace clang::tidy::modernize {
@@ -19,6 +20,8 @@ class UseNullptrCheck : public ClangTidyCheck {
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus11 || LangOpts.C23;
}
+ void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP,
+ Preprocessor *ModuleExpanderPP) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
@@ -27,6 +30,8 @@ class UseNullptrCheck : public ClangTidyCheck {
const StringRef NullMacrosStr;
SmallVector<StringRef, 1> NullMacros;
std::vector<StringRef> IgnoredTypes;
+ const bool UseNullptrT;
+ utils::IncludeInserter IncludeInserter;
};
} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 0447458c147ad..d0906f9ee6be8 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -236,6 +236,10 @@ infrastructure are described first, followed by tool-specific sections.
<clang-tidy/checks/modernize/use-noexcept>` when analyzing malformed template
code with an unparsed exception specification.
+- Extend {doc}`modernize-use-nullptr
+ <clang-tidy/checks/modernize/use-nullptr>` to turn `decltype(nullptr)` into
+ `std::nullptr_t` from `<cstdef>`.
+
- Improved {doc}`performance-inefficient-algorithm
<clang-tidy/checks/performance/inefficient-algorithm>` check to no longer
produce a fix with the container or the searched-for value missing, such as
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst
index 25e17fee0a3d6..ce43e1e4eb5dc 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-nullptr.rst
@@ -6,6 +6,9 @@ modernize-use-nullptr
The check converts the usage of null pointer constants (e.g. ``NULL``, ``0``)
to use the new C++11 and C23 ``nullptr`` keyword.
+It also replaces references to ``decltype(nullptr)`` with ``std::nullptr_t``
+from ``<cstdef>``.
+
Example
-------
@@ -21,11 +24,15 @@ Example
return 0;
}
+ void expect_null(decltype(nullptr));
+
transforms to:
.. code-block:: c++
+ #include <cstddef>
+
void assignment() {
char *a = nullptr;
char *b = nullptr;
@@ -36,6 +43,9 @@ transforms to:
return nullptr;
}
+ void expect_null(std::nullptr_t);
+
+
Options
-------
@@ -51,6 +61,16 @@ Options
``NULL``. By default this check will only replace the ``NULL`` macro and will
skip any similar user-defined macros.
+.. option:: UseNullptrT
+
+ Boolean controlling whether we should replace ``decltype(nullptr)`` with the
+ type ``std::nullptr_t`` from ``<cstddef>``. Defaults to ``true``.
+
+.. option:: IncludeStyle
+
+ A string specifying which include-style is used, `llvm` or `google`. Default
+ is `llvm`.
+
Example
^^^^^^^
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-t.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-t.cpp
new file mode 100644
index 0000000000000..ccee775f4b55a
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-t.cpp
@@ -0,0 +1,20 @@
+// RUN: %check_clang_tidy %s modernize-use-nullptr %t -- -- -fno-delayed-template-parsing
+
+// CHECK-FIXES: #include <cstddef>
+
+void foo(decltype(nullptr));
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use std::nullptr_t instead
+// CHECK-FIXES: void foo(std::nullptr_t);
+void foo(const decltype(nullptr));
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use std::nullptr_t instead
+// CHECK-FIXES: void foo(const std::nullptr_t);
+void foo(decltype((nullptr))*);
+// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use std::nullptr_t instead
+// CHECK-FIXES: void foo(std::nullptr_t*);
+decltype(nullptr) a;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use std::nullptr_t instead
+// CHECK-FIXES: std::nullptr_t a;
+template<class T=decltype(nullptr)>
+struct bar {};
+// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: use std::nullptr_t instead
+// CHECK-FIXES: template<class T=std::nullptr_t>
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr.cpp
index 0092a5cc9a47b..309cb1823ff6d 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr.cpp
@@ -1,5 +1,5 @@
// RUN: %check_clang_tidy %s modernize-use-nullptr %t -- \
-// RUN: -config="{CheckOptions: {modernize-use-nullptr.NullMacros: 'MY_NULL,NULL'}}"
+// RUN: -config="{CheckOptions: {modernize-use-nullptr.NullMacros: 'MY_NULL,NULL', modernize-use-nullptr.UseNullptrT: false}}"
#include <cstddef>
More information about the cfe-commits
mailing list