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

Benoit Belley Benoit.Belley at autodesk.com
Thu Aug 26 13:18:05 PDT 2010


Hi Tom,

Thanks for the comments. I have attached the patch with the corrected code layout.

BTW, I am also confused about whether data members and member functions should start with an upper or lower case letter. Clang source code does not seem to be consistent in that regard. In fact, even the class RecursiveASTVisitor is not (getDerived() vs TraverseDecl()).

Benoit


===================================================================
--- include/clang/AST/RecursiveASTVisitor.h (revision 111934)
+++ include/clang/AST/RecursiveASTVisitor.h (working copy)
@@ -123,12 +123,32 @@
 /// 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 +380,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 +1119,61 @@
 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>


-------------- next part --------------
A non-text attachment was scrubbed...
Name: RecursiveASTVisitor-TemplSpec.patch
Type: application/octet-stream
Size: 6671 bytes
Desc: RecursiveASTVisitor-TemplSpec.patch
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100826/fec4c9ad/attachment.obj>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100826/fec4c9ad/attachment.htm>
-------------- 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/fec4c9ad/attachment.gif>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100826/fec4c9ad/attachment-0001.htm>


More information about the cfe-commits mailing list