| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" | 
 |           "http://www.w3.org/TR/html4/strict.dtd"> | 
 | <html> | 
 | <head> | 
 | <title>How to write RecursiveASTVisitor based ASTFrontendActions.</title> | 
 | <link type="text/css" rel="stylesheet" href="../menu.css"> | 
 | <link type="text/css" rel="stylesheet" href="../content.css"> | 
 | </head> | 
 | <body> | 
 |  | 
 | <!--#include virtual="../menu.html.incl"--> | 
 |  | 
 | <div id="content"> | 
 |  | 
 | <h1>How to write RecursiveASTVisitor based ASTFrontendActions.</h1> | 
 |  | 
 | <!-- ======================================================================= --> | 
 | <h2 id="intro">Introduction</h2> | 
 | <!-- ======================================================================= --> | 
 |  | 
 | In this tutorial you will learn how to create a FrontendAction that uses | 
 | a RecursiveASTVisitor to find CXXRecordDecl AST nodes with a specified name. | 
 |  | 
 | <!-- ======================================================================= --> | 
 | <h2 id="action">Creating a FrontendAction</h2> | 
 | <!-- ======================================================================= --> | 
 |  | 
 | <p>When writing a clang based tool like a Clang Plugin or a standalone tool | 
 | based on LibTooling, the common entry point is the FrontendAction. | 
 | FrontendAction is an interface that allows execution of user specific actions | 
 | as part of the compilation. To run tools over the AST clang provides the | 
 | convenience interface ASTFrontendAction, which takes care of executing the | 
 | action. The only part left is to implement the CreateASTConsumer method that | 
 | returns an ASTConsumer per translation unit.</p> | 
 | <pre> | 
 |   class FindNamedClassAction : public clang::ASTFrontendAction { | 
 |   public: | 
 |     virtual clang::ASTConsumer *CreateASTConsumer( | 
 |       clang::CompilerInstance &Compiler, llvm::StringRef InFile) { | 
 |       return new FindNamedClassConsumer; | 
 |     } | 
 |   }; | 
 | </pre> | 
 |  | 
 | <!-- ======================================================================= --> | 
 | <h2 id="consumer">Creating an ASTConsumer</h2> | 
 | <!-- ======================================================================= --> | 
 |  | 
 | <p>ASTConsumer is an interface used to write generic actions on an AST, | 
 | regardless of how the AST was produced. ASTConsumer provides many different | 
 | entry points, but for our use case the only one needed is HandleTranslationUnit, | 
 | which is called with the ASTContext for the translation unit.</p> | 
 | <pre> | 
 |   class FindNamedClassConsumer : public clang::ASTConsumer { | 
 |   public: | 
 |     virtual void HandleTranslationUnit(clang::ASTContext &Context) { | 
 |       // Traversing the translation unit decl via a RecursiveASTVisitor | 
 |       // will visit all nodes in the AST. | 
 |       Visitor.TraverseDecl(Context.getTranslationUnitDecl()); | 
 |     } | 
 |   private: | 
 |     // A RecursiveASTVisitor implementation. | 
 |     FindNamedClassVisitor Visitor; | 
 |   }; | 
 | </pre> | 
 |  | 
 | <!-- ======================================================================= --> | 
 | <h2 id="rav">Using the RecursiveASTVisitor</h2> | 
 | <!-- ======================================================================= --> | 
 |  | 
 | <p>Now that everything is hooked up, the next step is to implement a | 
 | RecursiveASTVisitor to extract the relevant information from the AST.</p> | 
 | <p>The RecursiveASTVisitor provides hooks of the form | 
 | bool VisitNodeType(NodeType *) for most AST nodes; the exception are TypeLoc | 
 | nodes, which are passed by-value. We only need to implement the methods for the | 
 | relevant node types. | 
 | </p> | 
 | <p>Let's start by writing a RecursiveASTVisitor that visits all CXXRecordDecl's. | 
 | <pre> | 
 |   class FindNamedClassVisitor | 
 |     : public RecursiveASTVisitor<FindNamedClassVisitor> { | 
 |   public: | 
 |     bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) { | 
 |       // For debugging, dumping the AST nodes will show which nodes are already | 
 |       // being visited. | 
 |       Declaration->dump(); | 
 |  | 
 |       // The return value indicates whether we want the visitation to proceed. | 
 |       // Return false to stop the traversal of the AST. | 
 |       return true; | 
 |     } | 
 |   }; | 
 | </pre> | 
 | </p> | 
 | <p>In the methods of our RecursiveASTVisitor we can now use the full power of | 
 | the Clang AST to drill through to the parts that are interesting for us. For | 
 | example, to find all class declaration with a certain name, we can check for a | 
 | specific qualified name: | 
 | <pre> | 
 |   bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) { | 
 |     if (Declaration->getQualifiedNameAsString() == "n::m::C") | 
 |       Declaration->dump(); | 
 |     return true; | 
 |   } | 
 | </pre> | 
 | </p> | 
 |  | 
 | <!-- ======================================================================= --> | 
 | <h2 id="context">Accessing the SourceManager and ASTContext</h2> | 
 | <!-- ======================================================================= --> | 
 |  | 
 | <p>Some of the information about the AST, like source locations and global | 
 | identifier information, are not stored in the AST nodes themselves, but in | 
 | the ASTContext and its associated source manager. To retrieve them we need to | 
 | hand the ASTContext into our RecursiveASTVisitor implementation.</p> | 
 | <p>The ASTContext is available from the CompilerInstance during the call | 
 | to CreateASTConsumer. We can thus extract it there and hand it into our | 
 | freshly created FindNamedClassConsumer:</p> | 
 | <pre> | 
 |   virtual clang::ASTConsumer *CreateASTConsumer( | 
 |     clang::CompilerInstance &Compiler, llvm::StringRef InFile) { | 
 |     return new FindNamedClassConsumer(<b>&Compiler.getASTContext()</b>); | 
 |   } | 
 | </pre> | 
 |  | 
 | <p>Now that the ASTContext is available in the RecursiveASTVisitor, we can do | 
 | more interesting things with AST nodes, like looking up their source | 
 | locations:</p> | 
 | <pre> | 
 |   bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) { | 
 |     if (Declaration->getQualifiedNameAsString() == "n::m::C") { | 
 |       // getFullLoc uses the ASTContext's SourceManager to resolve the source | 
 |       // location and break it up into its line and column parts. | 
 |       FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getLocStart()); | 
 |       if (FullLocation.isValid()) | 
 |         llvm::outs() << "Found declaration at " | 
 |                      << FullLocation.getSpellingLineNumber() << ":" | 
 |                      << FullLocation.getSpellingColumnNumber() << "\n"; | 
 |     } | 
 |     return true; | 
 |   } | 
 | </pre> | 
 |  | 
 | <!-- ======================================================================= --> | 
 | <h2 id="full">Putting it all together</h2> | 
 | <!-- ======================================================================= --> | 
 |  | 
 | <p>Now we can combine all of the above into a small example program:</p> | 
 | <pre> | 
 |   #include "clang/AST/ASTConsumer.h" | 
 |   #include "clang/AST/RecursiveASTVisitor.h" | 
 |   #include "clang/Frontend/CompilerInstance.h" | 
 |   #include "clang/Frontend/FrontendAction.h" | 
 |   #include "clang/Tooling/Tooling.h" | 
 |  | 
 |   using namespace clang; | 
 |  | 
 |   class FindNamedClassVisitor | 
 |     : public RecursiveASTVisitor<FindNamedClassVisitor> { | 
 |   public: | 
 |     explicit FindNamedClassVisitor(ASTContext *Context) | 
 |       : Context(Context) {} | 
 |  | 
 |     bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) { | 
 |       if (Declaration->getQualifiedNameAsString() == "n::m::C") { | 
 |         FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getLocStart()); | 
 |         if (FullLocation.isValid()) | 
 |           llvm::outs() << "Found declaration at " | 
 |                        << FullLocation.getSpellingLineNumber() << ":" | 
 |                        << FullLocation.getSpellingColumnNumber() << "\n"; | 
 |       } | 
 |       return true; | 
 |     } | 
 |  | 
 |   private: | 
 |     ASTContext *Context; | 
 |   }; | 
 |  | 
 |   class FindNamedClassConsumer : public clang::ASTConsumer { | 
 |   public: | 
 |     explicit FindNamedClassConsumer(ASTContext *Context) | 
 |       : Visitor(Context) {} | 
 |  | 
 |     virtual void HandleTranslationUnit(clang::ASTContext &Context) { | 
 |       Visitor.TraverseDecl(Context.getTranslationUnitDecl()); | 
 |     } | 
 |   private: | 
 |     FindNamedClassVisitor Visitor; | 
 |   }; | 
 |  | 
 |   class FindNamedClassAction : public clang::ASTFrontendAction { | 
 |   public: | 
 |     virtual clang::ASTConsumer *CreateASTConsumer( | 
 |       clang::CompilerInstance &Compiler, llvm::StringRef InFile) { | 
 |       return new FindNamedClassConsumer(&Compiler.getASTContext()); | 
 |     } | 
 |   }; | 
 |  | 
 |   int main(int argc, char **argv) { | 
 |     if (argc > 1) { | 
 |       clang::tooling::runToolOnCode(new FindNamedClassAction, argv[1]); | 
 |     } | 
 |   } | 
 | </pre> | 
 |  | 
 | <p>We store this into a file called FindClassDecls.cpp and create the following | 
 | CMakeLists.txt to link it:</p> | 
 | <pre> | 
 | set(LLVM_USED_LIBS clangTooling) | 
 |  | 
 | add_clang_executable(find-class-decls FindClassDecls.cpp) | 
 | </pre> | 
 |  | 
 | <p>When running this tool over a small code snippet it will output all | 
 | declarations of a class n::m::C it found:</p> | 
 | <pre> | 
 |   $ ./bin/find-class-decls "namespace n { namespace m { class C {}; } }" | 
 |   Found declaration at 1:29 | 
 | </pre> | 
 |  | 
 | </div> | 
 | </body> | 
 | </html> | 
 |  |