hokein created this revision. hokein added a reviewer: kadircet. Herald added a project: All. hokein requested review of this revision. Herald added a project: clang-tools-extra.
This will fix unused-include false positive. // primary.h namespace ns { template<class T1, class T2> class Z {}; // primary template } // partial.h namespace ns { template<class T> class Z<T, T*> {}; // partial specialization } // main.cpp using ns::Z; // refs to the primary void k() { Z<int, int*> z; // use the partial specialization } Repository: rG LLVM Github Monorepo 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,60 @@ "auto x = [] { ^foo<int>(); };"), ElementsAre(Decl::FunctionTemplate)); } +TEST(WalkAST, TemplateSpecializationsFromUsingDecl) { + // Class templates + testWalk(R"cpp( +namespace ns { +template<class T1, class T2> class $ambiguous^Z {}; // primary template +template<class T> class $ambiguous^Z<T, T*> {}; // partial specialization +template<class T> class $ambiguous^Z<T, T&> {}; // partial specialization +} + )cpp", + "using ns::^Z;"); + testWalk(R"cpp( +namespace ns { +template<class T1> class $ambiguous^Z {}; // primary template +template<> class $ambiguous^Z<int> {}; // full 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<> +int* $ambiguous^foo<int>; // full specialization +} + )cpp", + "using ns::^foo;"); + testWalk(R"cpp( +namespace ns { +template<class T, class U> +T $ambiguous^bar; // primary + +template<class T> +T* $ambiguous^bar<T, int>; // partial specialization +} + )cpp", + "using ns::^bar;"); + + // Function templates, no partial template specializations. + testWalk(R"cpp( +namespace ns { +template<class T> +void $ambiguous^function(T); // primary + +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 @@ -20,6 +20,7 @@ #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "llvm/ADT/STLExtras.h" @@ -169,12 +170,38 @@ return true; } + // Report all (partial) specializations of a class/var template decl. + template <typename TemplateDeclType, typename ParitialDeclType> + void reportSpecializations(SourceLocation Loc, NamedDecl *ND) { + if (const auto *TD = dyn_cast<TemplateDeclType>(ND)) { + for (auto *Spec : TD->specializations()) + report(Loc, Spec, RefType::Ambiguous); + 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 = 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