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

Reply via email to