[clang-tools-extra] [clang-tidy] Extend `modernize-type-traits` to fold remove_cv_t<remove_reference_t<...>> into remove_cv_ref_t (PR #204789)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 19 02:46:07 PDT 2026
https://github.com/serge-sans-paille updated https://github.com/llvm/llvm-project/pull/204789
>From fa0465b09df494651c5efc88cd46d82e7f3e03cc Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Fri, 19 Jun 2026 11:29:35 +0200
Subject: [PATCH 1/2] [clang-tidy] Extend `modernize-type-traits` to fold
remove_cv_t<remove_reference_t<...>> into remove_cv_ref_t
---
.../clang-tidy/modernize/TypeTraitsCheck.cpp | 29 +++++++++++++++++++
clang-tools-extra/docs/ReleaseNotes.rst | 4 +++
.../checks/modernize/type-traits.rst | 3 ++
.../modernize/type-traits-remove-cvref.cpp | 27 +++++++++++++++++
4 files changed, 63 insertions(+)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits-remove-cvref.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
index 0d03006750d07..7c43219375cdb 100644
--- a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
@@ -196,6 +196,20 @@ void TypeTraitsCheck::registerMatchers(MatchFinder *Finder) {
this);
}
Finder->addMatcher(typeLoc(isType()).bind(Bind), this);
+
+ // Only register matchers for std::remove_cvref_t simplification in c++20
+ // mode.
+ if (getLangOpts().CPlusPlus20) {
+ Finder->addMatcher(templateSpecializationTypeLoc(
+ loc(qualType(hasDeclaration(
+ namedDecl(hasName("::std::remove_cv_t"))))),
+ hasTemplateArgumentLoc(
+ 0, hasTypeLoc(templateSpecializationTypeLoc(loc(
+ qualType(hasDeclaration(namedDecl(hasName(
+ "::std::remove_reference_t")))))))))
+ .bind("remove_cvref"),
+ this);
+ }
}
static bool isNamedDeclInStdTraitsSet(const NamedDecl *ND,
@@ -308,6 +322,21 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) {
DNTL->getElaboratedKeywordLoc());
return;
}
+
+ if (const auto *TSTL = Result.Nodes.getNodeAs<TemplateSpecializationTypeLoc>(
+ "remove_cvref")) {
+ auto Diag = diag(TSTL->getBeginLoc(), "use c++20 type alias");
+ TemplateSpecializationTypeLoc OuterTL =
+ TSTL->getArgLoc(0)
+ .getTypeSourceInfo()
+ ->getTypeLoc()
+ .castAs<TemplateSpecializationTypeLoc>();
+ Diag << FixItHint::CreateReplacement(
+ SourceRange(TSTL->getBeginLoc(), OuterTL.getLAngleLoc()),
+ "std::remove_cvref_t<")
+ << FixItHint::CreateRemoval(OuterTL.getRAngleLoc());
+ return;
+ }
}
void TypeTraitsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 64dad5fc29905..92443f2b6e6b7 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -616,6 +616,10 @@ Changes in existing checks
<clang-tidy/checks/modernize/return-braced-init-list>` check to apply fix-it
when type qualifiers and/or reference modifiers are used with parameters.
+- Improved :doc:`modernize-type-traits
+ <clang-tidy/checks/modernize/type-traits>` check to suggest usage of
+ ``std::remove_cvref_t`` when applicable.
+
- Improved :doc:`modernize-use-default-member-init
<clang-tidy/checks/modernize/use-default-member-init>` check by fixing a
false positive when a constructor initializer refers to a declaration that
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/type-traits.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/type-traits.rst
index fbe2b856c6b85..f5ff8bdf5524e 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/type-traits.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/type-traits.rst
@@ -25,6 +25,9 @@ Would be converted into:
std::add_const_t<T>
std::make_signed_t<unsigned>
+Also suggests converting ``std::remove_cv_t<std::remove_reference_t<...>`` into
+``std::remove_cvref_t<...>`` when targeting C++20 or above.
+
Options
-------
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits-remove-cvref.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits-remove-cvref.cpp
new file mode 100644
index 0000000000000..38d3d235d5d4b
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/type-traits-remove-cvref.cpp
@@ -0,0 +1,27 @@
+// RUN: %check_clang_tidy -std=c++20-or-later %s modernize-type-traits %t
+
+namespace std {
+template <class> struct remove_cv {
+ using type = int;
+};
+template <class T>
+using remove_cv_t = typename remove_cv<T>::type; // NOLINT
+
+template <class> struct remove_reference {
+ using type = int;
+};
+template <class T>
+using remove_reference_t = typename remove_reference<T>::type; // NOLINT
+}
+
+using foo = std::remove_cv_t<std::remove_reference_t<int>>;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use c++20 type alias
+// CHECK-FIXES: using foo = std::remove_cvref_t<int>;
+
+std::remove_cv_t<std::remove_reference_t<int>> var;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use c++20 type alias
+// CHECK-FIXES: std::remove_cvref_t<int> var;
+
+template<class=std::remove_cv_t<std::remove_reference_t<int>>> struct Foo {};
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use c++20 type alias
+// CHECK-FIXES: template<class=std::remove_cvref_t<int>> struct Foo {};
>From 4a90a8c4183bacb5c11ac8d2b4d9f31f7bf8d766 Mon Sep 17 00:00:00 2001
From: serge-sans-paille <sguelton at mozilla.com>
Date: Fri, 19 Jun 2026 11:45:32 +0200
Subject: [PATCH 2/2] fixup! [clang-tidy] Extend `modernize-type-traits` to
fold remove_cv_t<remove_reference_t<...>> into remove_cv_ref_t
---
clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
index 7c43219375cdb..6264a49479902 100644
--- a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp
@@ -326,7 +326,7 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) {
if (const auto *TSTL = Result.Nodes.getNodeAs<TemplateSpecializationTypeLoc>(
"remove_cvref")) {
auto Diag = diag(TSTL->getBeginLoc(), "use c++20 type alias");
- TemplateSpecializationTypeLoc OuterTL =
+ auto OuterTL =
TSTL->getArgLoc(0)
.getTypeSourceInfo()
->getTypeLoc()
More information about the cfe-commits
mailing list