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> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
