[clang-tools-extra] [clang-tidy] Move isStdInitializerList to utils::type_traits and add unit tests (PR #205449)
Grigory Pastukhov via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 24 09:14:29 PDT 2026
https://github.com/grigorypas updated https://github.com/llvm/llvm-project/pull/205449
>From 10cd335568bd5c75d72f85da14c1fdf4f5da1f50 Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <gpastukhov at meta.com>
Date: Tue, 23 Jun 2026 16:12:06 -0700
Subject: [PATCH 1/2] [clang-tidy] Move isStdInitializerList to
utils::type_traits and add unit tests
---
.../misc/ExplicitConstructorCheck.cpp | 24 +-------
.../clang-tidy/utils/TypeTraits.cpp | 22 +++++++
.../clang-tidy/utils/TypeTraits.h | 3 +
.../unittests/clang-tidy/CMakeLists.txt | 1 +
.../unittests/clang-tidy/TypeTraitsTest.cpp | 60 +++++++++++++++++++
5 files changed, 88 insertions(+), 22 deletions(-)
create mode 100644 clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp
diff --git a/clang-tools-extra/clang-tidy/misc/ExplicitConstructorCheck.cpp b/clang-tools-extra/clang-tidy/misc/ExplicitConstructorCheck.cpp
index 8c6f8ef978991..23261fe5af61b 100644
--- a/clang-tools-extra/clang-tidy/misc/ExplicitConstructorCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/ExplicitConstructorCheck.cpp
@@ -8,6 +8,7 @@
#include "ExplicitConstructorCheck.h"
#include "../utils/LexerUtils.h"
+#include "../utils/TypeTraits.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
@@ -31,27 +32,6 @@ void ExplicitConstructorCheck::registerMatchers(MatchFinder *Finder) {
this);
}
-static bool declIsStdInitializerList(const NamedDecl *D) {
- // First use the fast getName() method to avoid unnecessary calls to the
- // slow getQualifiedNameAsString().
- return D->getName() == "initializer_list" &&
- D->getQualifiedNameAsString() == "std::initializer_list";
-}
-
-static bool isStdInitializerList(QualType Type) {
- Type = Type.getCanonicalType();
- if (const auto *TS = Type->getAs<TemplateSpecializationType>()) {
- if (const TemplateDecl *TD = TS->getTemplateName().getAsTemplateDecl())
- return declIsStdInitializerList(TD);
- }
- if (const auto *RT = Type->getAs<RecordType>()) {
- if (const auto *Specialization =
- dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()))
- return declIsStdInitializerList(Specialization->getSpecializedTemplate());
- }
- return false;
-}
-
void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
constexpr char NoExpressionWarningMessage[] =
"%0 must be marked explicit to avoid unintentional implicit conversions";
@@ -79,7 +59,7 @@ void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) {
const ExplicitSpecifier ExplicitSpec = Ctor->getExplicitSpecifier();
- const bool TakesInitializerList = isStdInitializerList(
+ const bool TakesInitializerList = utils::type_traits::isStdInitializerList(
Ctor->getParamDecl(0)->getType().getNonReferenceType());
if (ExplicitSpec.isExplicit() &&
(Ctor->isCopyOrMoveConstructor() || TakesInitializerList)) {
diff --git a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp
index c15d90b19d359..06d489129cd43 100644
--- a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp
+++ b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp
@@ -9,6 +9,7 @@
#include "TypeTraits.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include <optional>
namespace clang::tidy::utils::type_traits {
@@ -146,4 +147,25 @@ bool hasNonTrivialMoveAssignment(QualType Type) {
Record->hasNonTrivialMoveAssignment();
}
+static bool declIsStdInitializerList(const NamedDecl *D) {
+ // First use the fast getName() method to avoid unnecessary calls to the
+ // slow getQualifiedNameAsString().
+ return D->getName() == "initializer_list" &&
+ D->getQualifiedNameAsString() == "std::initializer_list";
+}
+
+bool isStdInitializerList(QualType Type) {
+ Type = Type.getCanonicalType();
+ if (const auto *TS = Type->getAs<TemplateSpecializationType>()) {
+ if (const TemplateDecl *TD = TS->getTemplateName().getAsTemplateDecl())
+ return declIsStdInitializerList(TD);
+ }
+ if (const auto *RT = Type->getAs<RecordType>()) {
+ if (const auto *Specialization =
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()))
+ return declIsStdInitializerList(Specialization->getSpecializedTemplate());
+ }
+ return false;
+}
+
} // namespace clang::tidy::utils::type_traits
diff --git a/clang-tools-extra/clang-tidy/utils/TypeTraits.h b/clang-tools-extra/clang-tidy/utils/TypeTraits.h
index 98a4a99bf8d4d..03711461b51ac 100644
--- a/clang-tools-extra/clang-tidy/utils/TypeTraits.h
+++ b/clang-tools-extra/clang-tidy/utils/TypeTraits.h
@@ -34,6 +34,9 @@ bool hasNonTrivialMoveConstructor(QualType Type);
/// Return true if `Type` has a non-trivial move assignment operator.
bool hasNonTrivialMoveAssignment(QualType Type);
+/// Returns `true` if `Type` is a `std::initializer_list<...>` specialization.
+bool isStdInitializerList(QualType Type);
+
} // namespace clang::tidy::utils::type_traits
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_TYPETRAITS_H
diff --git a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
index 26ceb977d27a6..00498813d1e52 100644
--- a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
+++ b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
@@ -35,6 +35,7 @@ add_extra_unittest(ClangTidyTests
UsingInserterTest.cpp
ReadabilityModuleTest.cpp
TransformerClangTidyCheckTest.cpp
+ TypeTraitsTest.cpp
)
clang_target_link_libraries(ClangTidyTests
diff --git a/clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp b/clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp
new file mode 100644
index 0000000000000..3c4f4b5726251
--- /dev/null
+++ b/clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp
@@ -0,0 +1,60 @@
+//===--- TypeTraitsTest.cpp - clang-tidy ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../clang-tidy/utils/TypeTraits.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang::tidy::test {
+namespace {
+
+using namespace ast_matchers;
+
+// Returns whether the type of the declaration named `DeclName` in `Code` is a
+// std::initializer_list specialization.
+bool declTypeIsStdInitializerList(StringRef Code, StringRef DeclName) {
+ std::unique_ptr<ASTUnit> AST =
+ tooling::buildASTFromCodeWithArgs(Code, {"-std=c++17"});
+ EXPECT_NE(AST, nullptr);
+ auto Matches =
+ match(valueDecl(hasName(DeclName)).bind("d"), AST->getASTContext());
+ EXPECT_EQ(Matches.size(), 1u);
+ const auto *D = Matches[0].getNodeAs<ValueDecl>("d");
+ return utils::type_traits::isStdInitializerList(D->getType());
+}
+
+constexpr char InitializerListDecl[] =
+ "namespace std { template <typename T> class initializer_list {}; }\n";
+
+TEST(IsStdInitializerListTest, MatchesSpecialization) {
+ EXPECT_TRUE(declTypeIsStdInitializerList(
+ std::string(InitializerListDecl) + "std::initializer_list<int> v;", "v"));
+}
+
+TEST(IsStdInitializerListTest, MatchesDependentSpecialization) {
+ EXPECT_TRUE(declTypeIsStdInitializerList(
+ std::string(InitializerListDecl) +
+ "template <typename T> void f(std::initializer_list<T> p);",
+ "p"));
+}
+
+TEST(IsStdInitializerListTest, RejectsBuiltin) {
+ EXPECT_FALSE(declTypeIsStdInitializerList("int v;", "v"));
+}
+
+TEST(IsStdInitializerListTest, RejectsNonStdInitializerList) {
+ EXPECT_FALSE(declTypeIsStdInitializerList(
+ "template <typename T> class initializer_list {}; "
+ "initializer_list<int> v;",
+ "v"));
+}
+
+} // namespace
+} // namespace clang::tidy::test
>From a7db3cd6adae7f16e680b5c3f9983e649555680e Mon Sep 17 00:00:00 2001
From: Grigory Pastukhov <grigoriypas at gmail.com>
Date: Wed, 24 Jun 2026 09:14:19 -0700
Subject: [PATCH 2/2] Update
clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp
Co-authored-by: Zeyi Xu <zeyi2 at nekoarch.cc>
---
clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp b/clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp
index 3c4f4b5726251..13261c3aa9e52 100644
--- a/clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp
+++ b/clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp
@@ -1,4 +1,4 @@
-//===--- TypeTraitsTest.cpp - clang-tidy ----------------------------------===//
+//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
More information about the cfe-commits
mailing list