Windfisch created this revision.
Windfisch added a project: clang-c.
Herald added a subscriber: cfe-commits.

Changes `clang_visitChildren()`'s behaviour to also **visit** all explicit and 
implicit **class template instantiations** upon visiting a `ClassTemplateDecl`. 
In analogy to clang++'s `-dump-ast` option, they are treated as children of the 
`ClassTemplateDecl` node.

This is done by

- adding the `CXCursor_ClassTemplateSpecialization` cursor kind,
- adding a `EnforceVisitBody` flag to 
`CursorVisitor::VisitClassTemplateSpecializationDecl`, which overrides the 
existing early exits in that method,
- and recursively descending into `theTemplateDecl->specializations()`.

This patch also adds a query function `clang_getTemplateSpecializationKind` and 
the associated enum type `CXTemplateSpecializationKind` to retrieve the 
specialisation kind. That way, users can distinguish between implicit 
instantiations (which they probably want to visit as child of the 
ClassTemplateDecl) and explicit instantiation (which they may want choose to 
ignore, because their node will reappear at the very location where the 
explicit instantiation takes place).


Repository:
  rC Clang

https://reviews.llvm.org/D43763

Files:
  include/clang-c/Index.h
  lib/Sema/SemaCodeComplete.cpp
  tools/libclang/CIndex.cpp
  tools/libclang/CIndexCXX.cpp
  tools/libclang/CursorVisitor.h
  tools/libclang/libclang.exports

Index: tools/libclang/libclang.exports
===================================================================
--- tools/libclang/libclang.exports
+++ tools/libclang/libclang.exports
@@ -259,6 +259,7 @@
 clang_getSpellingLocation
 clang_getTUResourceUsageName
 clang_getTemplateCursorKind
+clang_getTemplateSpecializationKind
 clang_getTokenExtent
 clang_getTokenKind
 clang_getTokenLocation
Index: tools/libclang/CIndexCXX.cpp
===================================================================
--- tools/libclang/CIndexCXX.cpp
+++ tools/libclang/CIndexCXX.cpp
@@ -80,6 +80,25 @@
   return CXCursor_NoDeclFound;
 }
 
+enum CXTemplateSpecializationKind clang_getTemplateSpecializationKind(CXCursor C) {
+  using namespace clang::cxcursor;
+  
+  if (C.kind == CXCursor_ClassTemplateSpecialization)
+  {
+    switch (static_cast<const ClassTemplateSpecializationDecl *>(getCursorDecl(C))->getSpecializationKind())
+    {
+      #define TRANSL(val) case val: return CX##val;
+      TRANSL(TSK_Undeclared)
+      TRANSL(TSK_ImplicitInstantiation)
+      TRANSL(TSK_ExplicitSpecialization)
+      TRANSL(TSK_ExplicitInstantiationDeclaration)
+      TRANSL(TSK_ExplicitInstantiationDefinition)
+      #undef TRANSL
+    }
+  }
+  return CXTSK_Undeclared;
+}
+
 CXCursor clang_getSpecializedCursorTemplate(CXCursor C) {
   if (!clang_isDeclaration(C.kind))
     return clang_getNullCursor();
Index: tools/libclang/CursorVisitor.h
===================================================================
--- tools/libclang/CursorVisitor.h
+++ tools/libclang/CursorVisitor.h
@@ -205,7 +205,7 @@
   bool VisitTranslationUnitDecl(TranslationUnitDecl *D);
   bool VisitTypedefDecl(TypedefDecl *D);
   bool VisitTagDecl(TagDecl *D);
-  bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D);
+  bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D, bool EnforceVisitBody = false);
   bool VisitClassTemplatePartialSpecializationDecl(
                                      ClassTemplatePartialSpecializationDecl *D);
   bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -498,7 +498,13 @@
     if (!D)
       return false;
 
-    return VisitAttributes(D) || Visit(D);
+    if (VisitAttributes(D))
+      return true;
+
+    if (Cursor.kind == CXCursor_ClassTemplateSpecialization)
+      return VisitClassTemplateSpecializationDecl(static_cast<ClassTemplateSpecializationDecl*>(D), /*EnforceVisitBody*/ true);
+    else
+      return Visit(D);
   }
 
   if (clang_isStatement(Cursor.kind)) {
@@ -701,22 +707,23 @@
 }
 
 bool CursorVisitor::VisitClassTemplateSpecializationDecl(
-                                          ClassTemplateSpecializationDecl *D) {
-  bool ShouldVisitBody = false;
-  switch (D->getSpecializationKind()) {
-  case TSK_Undeclared:
-  case TSK_ImplicitInstantiation:
-    // Nothing to visit
-    return false;
-      
-  case TSK_ExplicitInstantiationDeclaration:
-  case TSK_ExplicitInstantiationDefinition:
-    break;
-      
-  case TSK_ExplicitSpecialization:
-    ShouldVisitBody = true;
-    break;
-  }
+                                          ClassTemplateSpecializationDecl *D, bool EnforceVisitBody) {
+  bool ShouldVisitBody = EnforceVisitBody;
+  if (!EnforceVisitBody)
+    switch (D->getSpecializationKind()) {
+    case TSK_Undeclared:
+    case TSK_ImplicitInstantiation:
+      // Nothing to visit
+      return false;
+        
+    case TSK_ExplicitInstantiationDeclaration:
+    case TSK_ExplicitInstantiationDefinition:
+      break;
+        
+    case TSK_ExplicitSpecialization:
+      ShouldVisitBody = true;
+      break;
+    }
   
   // Visit the template arguments used in the specialization.
   if (TypeSourceInfo *SpecType = D->getTypeAsWritten()) {
@@ -939,7 +946,18 @@
     return true;
   
   auto* CD = D->getTemplatedDecl();
-  return VisitAttributes(CD) || VisitCXXRecordDecl(CD);
+  if (VisitAttributes(CD))
+    return true;
+  if (VisitCXXRecordDecl(CD))
+    return true;
+
+  for (auto *Child : D->specializations())
+    if (Visit(MakeCXCursor(Child, TU)))
+      return true; // FIXME do this for function and var templates too.
+      // inspired by tools/clang/lib/AST/ASTDumper.cpp, ASTDumper::VisitTemplateDecl
+      // which is called from VisitClassTemplateDecl etc.
+  
+  return false;
 }
 
 bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
Index: lib/Sema/SemaCodeComplete.cpp
===================================================================
--- lib/Sema/SemaCodeComplete.cpp
+++ lib/Sema/SemaCodeComplete.cpp
@@ -3222,6 +3222,8 @@
     case Decl::AccessSpec:         return CXCursor_CXXAccessSpecifier;
     case Decl::ClassTemplatePartialSpecialization:
       return CXCursor_ClassTemplatePartialSpecialization;
+    case Decl::ClassTemplateSpecialization:
+      return CXCursor_ClassTemplateSpecialization;
     case Decl::UsingDirective:     return CXCursor_UsingDirective;
     case Decl::StaticAssert:       return CXCursor_StaticAssert;
     case Decl::Friend:             return CXCursor_FriendDecl;
Index: include/clang-c/Index.h
===================================================================
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -2578,6 +2578,31 @@
   CXCursor_OverloadCandidate             = 700
 };
 
+/**
+ * \brief Describes the kind of template specialization a cursor refers to.
+ */
+enum CXTemplateSpecializationKind {
+  
+    /// This template specialization was formed from a template-id but
+    /// has not yet been declared, defined, or instantiated.
+    CXTSK_Undeclared = 0,
+    /// This template specialization was implicitly instantiated from a
+    /// template. (C++ [temp.inst]).
+    CXTSK_ImplicitInstantiation,
+    /// This template specialization was declared or defined by an
+    /// explicit specialization (C++ [temp.expl.spec]) or partial
+    /// specialization (C++ [temp.class.spec]).
+    CXTSK_ExplicitSpecialization,
+    /// This template specialization was instantiated from a template
+    /// due to an explicit instantiation declaration request
+    /// (C++11 [temp.explicit]).
+    CXTSK_ExplicitInstantiationDeclaration,
+    /// This template specialization was instantiated from a template
+    /// due to an explicit instantiation definition request
+    /// (C++ [temp.explicit]).
+    CXTSK_ExplicitInstantiationDefinition
+};
+
 /**
  * \brief A cursor representing some element in the abstract syntax tree for
  * a translation unit.
@@ -4599,6 +4624,24 @@
  * \c CXCursor_NoDeclFound.
  */
 CINDEX_LINKAGE enum CXCursorKind clang_getTemplateCursorKind(CXCursor C);
+
+/**
+ * \brief Given a cursor that represents a template, determine the kind
+ * of specialization (e.g. implicit or explicit instantiation)
+ *
+ * This routine can be used to eliminate duplicate explicit template
+ * instantiations that occur both as a child of the template, and at
+ * the place where they got explicitly instantiated. By ignoring explicit
+ * instantiations which parent is / isn't the template itself, no
+ * duplicates will occur.
+ *
+ * \param C The cursor to query. This cursor should represent a template
+ * declaration.
+ *
+ * \returns The template specialization kind. If \p C is not a template, returns
+ * \c CXTSK_Undeclared.
+ */
+CINDEX_LINKAGE enum CXTemplateSpecializationKind clang_getTemplateSpecializationKind(CXCursor C);
   
 /**
  * \brief Given a cursor that may represent a specialization or instantiation
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to