RecursiveASTVisitor: Actually walking the AST

Hi,

I have a rather basic conceptual question for the clang experts out there. I am starting out and the examples and tutorials that exist have been very helpful to let me get to the point where I can find all the details about all class/struct/union declarations (with VisitCXXRecordDecl()), and also I am able to enumerate all the fields inside of such items by using VisitFieldDecl().

My question is related to the apparent difficulty of directly navigating the AST as opposed to using callbacks on the RecursiveASTVisitor. I reckon that this difficulty might be the motivation behind the design of RecursiveASTVisitor itself, but nevertheless it is restrictive.

For example: When looking at the output of ast-dump for some code, I can see that there are CXXRecordDecls shown as children of TemplateDecls. Supposing I want to enumerate just the TemplateDecls, it is straightforward to implement RecursiveASTVisitor::VisitTemplateDecl(), but I have been having a very difficult time retrieving any pointer to TemplateDecl from within VisitCXXRecordDecl. Indeed CXXRecordDecl::getParent() yields a DeclContext*, yet TemplateDecl’s aren’t even DeclContexts, AFAICT. The deep AST class hierarchy is making this difficult.

So the next best attempt I can make is to use the SourceManager’s tools to help me narrow down if these separate TemplateDecls and CXXRecordDecls that I find are referring to the same source code locations. This is done manually by comparing actual source location values: If a TemplateDecl and CXXRecordDecl share a location, then I can join together the information that I find (e.g. whether the class/struct is empty and the text list of the template parameters).

This is moderately straightforward, but much less so than directly using AST traversal to achieve such a correlation.

So hopefully someone can shed some light for me on why this is how it is, and what might perhaps be a better way to establish information about the decl’s that are found in the code. In particular, why is it that I can easily and reliably query the CXXRecordDecl to see if it is a template specialization, and similarly easy to query any given FieldDecl for its (CXX)RecordDecl context, but not at all easy to see if a particular CXXRecordDecl happens to be a template declaration.

Thanks.

Hi,

I have a rather basic conceptual question for the clang experts out there. I am starting out and the examples and tutorials that exist have been very helpful to let me get to the point where I can find all the details about all class/struct/union declarations (with VisitCXXRecordDecl()), and also I am able to enumerate all the fields inside of such items by using VisitFieldDecl().

My question is related to the apparent difficulty of directly navigating the AST as opposed to using callbacks on the RecursiveASTVisitor. I reckon that this difficulty might be the motivation behind the design of RecursiveASTVisitor itself, but nevertheless it is restrictive.

For example: When looking at the output of ast-dump for some code, I can see that there are CXXRecordDecls shown as children of TemplateDecls. Supposing I want to enumerate just the TemplateDecls, it is straightforward to implement RecursiveASTVisitor::VisitTemplateDecl(), but I have been having a very difficult time retrieving any pointer to TemplateDecl from within VisitCXXRecordDecl. Indeed CXXRecordDecl::getParent() yields a DeclContext*, yet TemplateDecl’s aren’t even DeclContexts, AFAICT. The deep AST class hierarchy is making this difficult.

So the next best attempt I can make is to use the SourceManager’s tools to help me narrow down if these separate TemplateDecls and CXXRecordDecls that I find are referring to the same source code locations. This is done manually by comparing actual source location values: If a TemplateDecl and CXXRecordDecl share a location, then I can join together the information that I find (e.g. whether the class/struct is empty and the text list of the template parameters).

This is moderately straightforward, but much less so than directly using AST traversal to achieve such a correlation.

So hopefully someone can shed some light for me on why this is how it is, and what might perhaps be a better way to establish information about the decl’s that are found in the code. In particular, why is it that I can easily and reliably query the CXXRecordDecl to see if it is a template specialization, and similarly easy to query any given FieldDecl for its (CXX)RecordDecl context, but not at all easy to see if a particular CXXRecordDecl happens to be a template declaration.

I wasn’t there when this was implemented, but I’d say it’s the way it is because of engineering trade-offs. Putting a single common interface just for traversal in only helps in a small subset of cases. On the other hand, the RAV is of course a pretty complex beast :slight_smile:

We have tried to build something for tool writers that makes it easier to find stuff in the AST, which is called the AST matchers:
http://clang.llvm.org/docs/LibASTMatchers.html

To your specific problem: if I understand you correctly, you want the ClassTemplateDecl, which nicely points to the CXXRecordDecl that describes the template.

Cheers,
/Manuel

Hi Manuel,

Yes, I had deduced that I could get a firehose of everything I could possibly want by using VisitDecl. It was already clear to me the ways (admittedly error-prone and slighty laborious) to filter out the decls I wanted out of all decls. It basically just requires me to look through the API some more and narrow things down.

Thanks for showing me LibASTMatchers. This is the perfect tool for the job.