[clang-tools-extra] fcc105f - [clang-tidy] Move isStdInitializerList to utils::type_traits and add unit tests (#205449)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 25 09:06:27 PDT 2026
Author: Grigory Pastukhov
Date: 2026-06-25T09:06:22-07:00
New Revision: fcc105f40c8ee7cd604c3dafb3750e8ee1db65b6
URL: https://github.com/llvm/llvm-project/commit/fcc105f40c8ee7cd604c3dafb3750e8ee1db65b6
DIFF: https://github.com/llvm/llvm-project/commit/fcc105f40c8ee7cd604c3dafb3750e8ee1db65b6.diff
LOG: [clang-tidy] Move isStdInitializerList to utils::type_traits and add unit tests (#205449)
Moves isStdInitializerList from misc/ExplicitConstructorCheck into
utils::type_traits so it can be shared, and adds unit tests for it. NFC.
Added:
clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp
Modified:
clang-tools-extra/clang-tidy/misc/ExplicitConstructorCheck.cpp
clang-tools-extra/clang-tidy/utils/TypeTraits.cpp
clang-tools-extra/clang-tidy/utils/TypeTraits.h
clang-tools-extra/unittests/clang-tidy/CMakeLists.txt
Removed:
################################################################################
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..136a7b2ed26a8 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,22 @@ bool hasNonTrivialMoveAssignment(QualType Type) {
Record->hasNonTrivialMoveAssignment();
}
+static bool declIsStdInitializerList(const NamedDecl *D) {
+ return D->isInStdNamespace() && D->getName() == "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_if_present<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..13261c3aa9e52
--- /dev/null
+++ b/clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
More information about the cfe-commits
mailing list