[cfe-commits] [Patch][Review request] RecursiveASTVisitor can now traverse template specializations

Benoit Belley Benoit.Belley at autodesk.com
Thu Aug 26 12:24:46 PDT 2010


Hi Everyone,

I have modified the RecursiveASTVisitor so that it can now optionally visit every template specialization (class and fucntion templates, implicit and explicit instantiations). 

By default this visitor will not recurse in template specializations since the instatiated class isn’t written in the source code anywhere. This behavior can now be changed by calling setVisitingTemplateSpecializations(true) before starting the traversal.

Please feel free to comment on the coding style also. I am new to Clang.

Thanks,
Benoit

Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h	(revision 111934)
+++ include/clang/AST/RecursiveASTVisitor.h	(working copy)
@@ -123,12 +123,35 @@
 /// users may override Traverse* and WalkUpFrom* to implement custom
 /// traversal strategies.  Returning false from one of these overridden
 /// functions will abort the entire traversal.
+///
+/// By default this visitor will not recurse in template
+/// specializations ("set<int> x;") since the instatiated class isn't
+/// written in the source code anywhere. This behavior can be changed
+/// by calling setVisitingTemplateSpecializations(true) before
+/// starting the traversal.
 template<typename Derived>
 class RecursiveASTVisitor {
 public:
+  RecursiveASTVisitor() : visitingTemplateSpecializations(false) {}
+  
+
   /// \brief Return a reference to the derived class.
   Derived &getDerived() { return *static_cast<Derived*>(this); }
 
+  /// \brief Control whether this visitor should recurse into
+  /// template specializations.
+  void setVisitingTemplateSpecializations(bool flag)
+  {
+    visitingTemplateSpecializations = flag;
+  }
+  
+  /// \brief Return whether this visitor should recurse into
+  /// template specializations.
+  bool isVisitingTemplateSpecializations() const
+  {
+    return visitingTemplateSpecializations;
+  }
+  
   /// \brief Recursively visit a statement or expression, by
   /// dispatching to Traverse*() based on the argument's dynamic type.
   ///
@@ -360,6 +383,10 @@
   bool TraverseDeclContextHelper(DeclContext *DC);
   bool TraverseFunctionHelper(FunctionDecl *D);
   bool TraverseVarHelper(VarDecl *D);
+
+  // This flag indicates that the RecursiveASTVisitor should visit
+  // template specializations.
+  bool visitingTemplateSpecializations;
 };
 
 #define DISPATCH(NAME, CLASS, VAR) \
@@ -1095,16 +1122,58 @@
 DEF_TRAVERSE_DECL(ClassTemplateDecl, {
     TRY_TO(TraverseDecl(D->getTemplatedDecl()));
     TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
-    // We should not traverse the specializations/partial
-    // specializations.  Those will show up in other contexts.
-    // getInstantiatedFromMemberTemplate() is just a link from a
-    // template instantiation back to the template from which it was
-    // instantiated, and thus should not be traversed either.
+    // By default, we do not traverse the specializations/partial
+    // specializations. Implicitely instantiated templates do not
+    // apprear in the user code and explicitely instantiated templates
+    // show up in other contexts.
+    //
+    // Note that getInstantiatedFromMemberTemplate() is just a link
+    // from a template instantiation back to the template from which
+    // it was instantiated, and thus should not be traversed.
+    //
+    // FIXME: When visiting implicitely instantiated templates, the
+    // specialization of an explicit instantiation will be visited
+    // twice, once at the template function declaration and another
+    // time at the template instantiation site. Is this an issue ? If
+    // so, when should be visited.
+    if ( isVisitingTemplateSpecializations() ) {
+      {
+        ClassTemplateDecl::spec_iterator end = D->spec_end();
+        for (ClassTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
+          TRY_TO(TraverseClassTemplateSpecializationDecl(*it));
+        }
+      }
+
+      {
+        ClassTemplateDecl::partial_spec_iterator end = D->partial_spec_end();
+        for (ClassTemplateDecl::partial_spec_iterator it = D->partial_spec_begin(); it != end; ++it) {
+          TRY_TO(TraverseClassTemplatePartialSpecializationDecl(*it));
+        }
+      }
+    }
   })
 
 DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
     TRY_TO(TraverseDecl(D->getTemplatedDecl()));
     TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+
+    // By default, we do not traverse the function
+    // specializations. Implicitely instantiated templates do not
+    // apprear in the user code and explicitely instantiated templates
+    // show up in other contexts.
+    //
+    // FIXME: When visiting implicitely instantiated templates, the
+    // specialization of an explicit instantiation will be visited
+    // twice, once at the template function declaration and another
+    // time at the template instantiation site. Is this an issue ? If
+    // so, when should be visited.
+    if ( isVisitingTemplateSpecializations() ) {
+      FunctionTemplateDecl::spec_iterator end = D->spec_end();
+      for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) {
+        TRY_TO(TraverseFunctionDecl(*it));
+      }
+    }
+
   })
 
 DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
@@ -1192,18 +1261,22 @@
   })
 
 DEF_TRAVERSE_DECL(ClassTemplateSpecializationDecl, {
-    // For implicit instantiations ("set<int> x;"), we don't want to
-    // recurse at all, since the instatiated class isn't written in
-    // the source code anywhere.  (Note the instatiated *type* --
-    // set<int> -- is written, and will still get a callback of
-    // TemplateSpecializationType).  For explicit instantiations
-    // ("template set<int>;"), we do need a callback, since this
-    // is the only callback that's made for this instantiation.
-    // We use getTypeAsWritten() to distinguish.
-    // FIXME: see how we want to handle template specializations.
-    if (TypeSourceInfo *TSI = D->getTypeAsWritten())
-      TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
-    return true;
+    if ( isVisitingTemplateSpecializations() ) {
+      TRY_TO(TraverseCXXRecordHelper(D));
+    }
+    else {
+      // For implicit instantiations ("set<int> x;"), we don't want to
+      // recurse at all, since the instatiated class isn't written in
+      // the source code anywhere.  (Note the instatiated *type* --
+      // set<int> -- is written, and will still get a callback of
+      // TemplateSpecializationType).  For explicit instantiations
+      // ("template set<int>;"), we do need a callback, since this
+      // is the only callback that's made for this instantiation.
+      // We use getTypeAsWritten() to distinguish.
+      // FIXME: see how we want to handle template specializations.
+      if (TypeSourceInfo *TSI = D->getTypeAsWritten())
+        TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
+    }
   })
 
 template <typename Derived>

Thanks
Benoit 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: RecursiveASTVisitor-TemplSpec.patch
Type: application/octet-stream
Size: 6647 bytes
Desc: RecursiveASTVisitor-TemplSpec.patch
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100826/6b058869/attachment.obj>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: ATT00001..txt
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100826/6b058869/attachment.txt>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image002.gif
Type: image/gif
Size: 651 bytes
Desc: image002.gif
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100826/6b058869/attachment.gif>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: ATT00002..txt
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100826/6b058869/attachment-0001.txt>


More information about the cfe-commits mailing list