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