[clang-tools-extra] 03101e1 - [include-cleaner] Attribute references to explicit specializations

Kadir Cetinkaya via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 24 03:43:16 PDT 2023


Author: Kadir Cetinkaya
Date: 2023-03-24T11:39:21+01:00
New Revision: 03101e141bf745f036be604e2a5a7c085eb02f5e

URL: https://github.com/llvm/llvm-project/commit/03101e141bf745f036be604e2a5a7c085eb02f5e
DIFF: https://github.com/llvm/llvm-project/commit/03101e141bf745f036be604e2a5a7c085eb02f5e.diff

LOG: [include-cleaner] Attribute references to explicit specializations

Fixes https://github.com/llvm/llvm-project/issues/61652

Differential Revision: https://reviews.llvm.org/D146732

Added: 
    

Modified: 
    clang-tools-extra/include-cleaner/lib/WalkAST.cpp
    clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
index 0ca84145721a6..e70a24367d6a9 100644
--- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
+++ b/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 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
       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 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
   }
 
   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;
   }
 

diff  --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
index 68b6b217a2e01..8fcc2b5886ae4 100644
--- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -114,6 +114,25 @@ TEST(WalkAST, TagType) {
   // 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 @@ TEST(WalkAST, Alias) {
            "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 @@ TEST(WalkAST, TemplateNames) {
       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) {


        


More information about the cfe-commits mailing list