This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG100ffbf991e7: [include-cleaner] Report all specializations if the primary template is… (authored by hokein).
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D152345/new/ https://reviews.llvm.org/D152345 Files: clang-tools-extra/include-cleaner/lib/WalkAST.cpp clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp Index: clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp =================================================================== --- clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -252,6 +252,36 @@ "auto x = [] { ^foo<int>(); };"), ElementsAre(Decl::FunctionTemplate)); } +TEST(WalkAST, TemplateSpecializationsFromUsingDecl) { + // Class templates + testWalk(R"cpp( +namespace ns { +template<class T> class $ambiguous^Z {}; // primary template +template<class T> class $ambiguous^Z<T*> {}; // partial specialization +template<> class $ambiguous^Z<int> {}; // full specialization +} + )cpp", + "using ns::^Z;"); + + // Var templates + testWalk(R"cpp( +namespace ns { +template<class T> T $ambiguous^foo; // primary template +template<class T> T $ambiguous^foo<T*>; // partial specialization +template<> int* $ambiguous^foo<int>; // full specialization +} + )cpp", + "using ns::^foo;"); + // Function templates, no partial template specializations. + testWalk(R"cpp( +namespace ns { +template<class T> void $ambiguous^function(T); // primary template +template<> void $ambiguous^function(int); // full specialization +} + )cpp", + "using ns::^function;"); +} + TEST(WalkAST, Alias) { testWalk(R"cpp( Index: clang-tools-extra/include-cleaner/lib/WalkAST.cpp =================================================================== --- clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -24,6 +24,7 @@ #include "clang/Basic/Specifiers.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLFunctionalExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" namespace clang::include_cleaner { @@ -169,12 +170,39 @@ return true; } + // Report all (partial) specializations of a class/var template decl. + template <typename TemplateDeclType, typename ParitialDeclType> + void reportSpecializations(SourceLocation Loc, NamedDecl *ND) { + const auto *TD = llvm::dyn_cast<TemplateDeclType>(ND); + if (!TD) + return; + + for (auto *Spec : TD->specializations()) + report(Loc, Spec, RefType::Ambiguous); + llvm::SmallVector<ParitialDeclType *> PartialSpecializations; + TD->getPartialSpecializations(PartialSpecializations); + for (auto *PartialSpec : PartialSpecializations) + report(Loc, PartialSpec, RefType::Ambiguous); + } bool VisitUsingDecl(UsingDecl *UD) { for (const auto *Shadow : UD->shadows()) { auto *TD = Shadow->getTargetDecl(); auto IsUsed = TD->isUsed() || TD->isReferenced(); report(UD->getLocation(), TD, IsUsed ? RefType::Explicit : RefType::Ambiguous); + + // All (partial) template specializations are visible via a using-decl, + // However a using-decl only refers to the primary template (per C++ name + // lookup). Thus, we need to manually report all specializations. + reportSpecializations<ClassTemplateDecl, + ClassTemplatePartialSpecializationDecl>( + UD->getLocation(), TD); + reportSpecializations<VarTemplateDecl, + VarTemplatePartialSpecializationDecl>( + UD->getLocation(), TD); + if (const auto *FTD = llvm::dyn_cast<FunctionTemplateDecl>(TD)) + for (auto *Spec : FTD->specializations()) + report(UD->getLocation(), Spec, RefType::Ambiguous); } return true; }
Index: clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp =================================================================== --- clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -252,6 +252,36 @@ "auto x = [] { ^foo<int>(); };"), ElementsAre(Decl::FunctionTemplate)); } +TEST(WalkAST, TemplateSpecializationsFromUsingDecl) { + // Class templates + testWalk(R"cpp( +namespace ns { +template<class T> class $ambiguous^Z {}; // primary template +template<class T> class $ambiguous^Z<T*> {}; // partial specialization +template<> class $ambiguous^Z<int> {}; // full specialization +} + )cpp", + "using ns::^Z;"); + + // Var templates + testWalk(R"cpp( +namespace ns { +template<class T> T $ambiguous^foo; // primary template +template<class T> T $ambiguous^foo<T*>; // partial specialization +template<> int* $ambiguous^foo<int>; // full specialization +} + )cpp", + "using ns::^foo;"); + // Function templates, no partial template specializations. + testWalk(R"cpp( +namespace ns { +template<class T> void $ambiguous^function(T); // primary template +template<> void $ambiguous^function(int); // full specialization +} + )cpp", + "using ns::^function;"); +} + TEST(WalkAST, Alias) { testWalk(R"cpp( Index: clang-tools-extra/include-cleaner/lib/WalkAST.cpp =================================================================== --- clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -24,6 +24,7 @@ #include "clang/Basic/Specifiers.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLFunctionalExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" namespace clang::include_cleaner { @@ -169,12 +170,39 @@ return true; } + // Report all (partial) specializations of a class/var template decl. + template <typename TemplateDeclType, typename ParitialDeclType> + void reportSpecializations(SourceLocation Loc, NamedDecl *ND) { + const auto *TD = llvm::dyn_cast<TemplateDeclType>(ND); + if (!TD) + return; + + for (auto *Spec : TD->specializations()) + report(Loc, Spec, RefType::Ambiguous); + llvm::SmallVector<ParitialDeclType *> PartialSpecializations; + TD->getPartialSpecializations(PartialSpecializations); + for (auto *PartialSpec : PartialSpecializations) + report(Loc, PartialSpec, RefType::Ambiguous); + } bool VisitUsingDecl(UsingDecl *UD) { for (const auto *Shadow : UD->shadows()) { auto *TD = Shadow->getTargetDecl(); auto IsUsed = TD->isUsed() || TD->isReferenced(); report(UD->getLocation(), TD, IsUsed ? RefType::Explicit : RefType::Ambiguous); + + // All (partial) template specializations are visible via a using-decl, + // However a using-decl only refers to the primary template (per C++ name + // lookup). Thus, we need to manually report all specializations. + reportSpecializations<ClassTemplateDecl, + ClassTemplatePartialSpecializationDecl>( + UD->getLocation(), TD); + reportSpecializations<VarTemplateDecl, + VarTemplatePartialSpecializationDecl>( + UD->getLocation(), TD); + if (const auto *FTD = llvm::dyn_cast<FunctionTemplateDecl>(TD)) + for (auto *Spec : FTD->specializations()) + report(UD->getLocation(), Spec, RefType::Ambiguous); } return true; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits