kadircet created this revision. kadircet added a reviewer: hokein. Herald added a project: All. kadircet requested review of this revision. Herald added a project: clang-tools-extra. Herald added a subscriber: cfe-commits.
Fixes https://github.com/llvm/llvm-project/issues/61652 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D146732 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 @@ -114,6 +114,25 @@ // One explicit call from the TypeLoc in constructor spelling, another // implicit reference through the constructor call. testWalk("struct $explicit^$implicit^S { static int x; };", "auto y = ^S();"); + testWalk("template<typename> struct $explicit^Foo {};", "^Foo<int> x;"); + testWalk(R"cpp( + template<typename> struct Foo {}; + template<> struct $explicit^Foo<int> {};)cpp", + "^Foo<int> x;"); + testWalk(R"cpp( + template<typename> struct Foo {}; + template<typename T> struct $explicit^Foo<T*> { void x(); };)cpp", + "^Foo<int *> x;"); + testWalk(R"cpp( + template<typename> struct Foo {}; + template struct $explicit^Foo<int>;)cpp", + "^Foo<int> x;"); + // FIXME: This is broken due to + // https://github.com/llvm/llvm-project/issues/42259. + testWalk(R"cpp( + template<typename T> struct $explicit^Foo { Foo(T); }; + template<> struct Foo<int> { void get(); Foo(int); };)cpp", + "^Foo x(3);"); } TEST(WalkAST, Alias) { @@ -124,6 +143,25 @@ "int y = ^x;"); testWalk("using $explicit^foo = int;", "^foo x;"); testWalk("struct S {}; using $explicit^foo = S;", "^foo x;"); + testWalk(R"cpp( + template<typename> struct Foo {}; + template<> struct Foo<int> {}; + namespace ns { using ::$explicit^Foo; })cpp", + "ns::^Foo<int> x;"); + testWalk(R"cpp( + template<typename> struct Foo {}; + namespace ns { using ::Foo; } + template<> struct ns::$explicit^Foo<int> {};)cpp", + "^Foo<int> x;"); + // AST doesn't have enough information to figure out whether specialization + // happened through an exported type or not. So err towards attributing use to + // the using-decl, specializations on the exported type should be rare and + // they're not permitted on type-aliases. + testWalk(R"cpp( + template<typename> struct Foo {}; + namespace ns { using ::$explicit^Foo; } + template<> struct ns::Foo<int> {};)cpp", + "ns::^Foo<int> x;"); } TEST(WalkAST, Using) { @@ -183,10 +221,6 @@ template <template <typename> typename> struct X {}; X<^S> x;)cpp"); testWalk("template<typename T> struct $explicit^S { S(T); };", "^S s(42);"); - // Should we mark the specialization instead? - testWalk( - "template<typename> struct $explicit^S {}; template <> struct S<int> {};", - "^S<int> s;"); } TEST(WalkAST, MemberExprs) { 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 @@ -7,16 +7,19 @@ //===----------------------------------------------------------------------===// #include "AnalysisInternal.h" +#include "clang-include-cleaner/Types.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/Support/Casting.h" namespace clang::include_cleaner { @@ -62,6 +65,23 @@ return resolveTemplateName(TST->getTemplateName()); return Base->getAsRecordDecl(); } + // Templated as TemplateSpecializationType and + // DeducedTemplateSpecializationType doesn't share a common base. + template <typename T> + // Picks the most specific specialization for a + // (Deduced)TemplateSpecializationType, while prioritizing using-decls. + NamedDecl *getMostRelevantTemplatePattern(const T *TST) { + // This is the underlying decl used by TemplateSpecializationType, can be + // null when type is dependent. + auto *RD = TST->getAsTagDecl(); + auto *ND = resolveTemplateName(TST->getTemplateName()); + // In case of exported template names always prefer the using-decl. This + // implies we'll point at the using-decl even when there's an explicit + // specializaiton using the exported name, but that's rare. + if (llvm::isa<UsingShadowDecl, TypeAliasTemplateDecl>(ND) || !RD) + return ND; + return RD; + } public: ASTWalker(DeclCallback Callback) : Callback(Callback) {} @@ -161,17 +181,15 @@ } bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) { - // FIXME: Handle explicit specializations. report(TL.getTemplateNameLoc(), - resolveTemplateName(TL.getTypePtr()->getTemplateName())); + getMostRelevantTemplatePattern(TL.getTypePtr())); return true; } bool VisitDeducedTemplateSpecializationTypeLoc( DeducedTemplateSpecializationTypeLoc TL) { - // FIXME: Handle specializations. report(TL.getTemplateNameLoc(), - resolveTemplateName(TL.getTypePtr()->getTemplateName())); + getMostRelevantTemplatePattern(TL.getTypePtr())); return true; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits