kadircet updated this revision to Diff 508025.
kadircet marked an inline comment as done.
kadircet added a comment.

- use isa_and_present
- indentation for tests


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D146732/new/

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,24 @@
       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_and_present<UsingShadowDecl, TypeAliasTemplateDecl>(ND))
+      return ND;
+    // Fallback to primary template for dependent instantiations.
+    return RD ? RD : ND;
+  }
 
 public:
   ASTWalker(DeclCallback Callback) : Callback(Callback) {}
@@ -161,17 +182,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

Reply via email to