diff options
Diffstat (limited to 'docs/RAVFrontendAction.html')
-rw-r--r-- | docs/RAVFrontendAction.html | 224 |
1 files changed, 0 insertions, 224 deletions
diff --git a/docs/RAVFrontendAction.html b/docs/RAVFrontendAction.html deleted file mode 100644 index b30cd57..0000000 --- a/docs/RAVFrontendAction.html +++ /dev/null @@ -1,224 +0,0 @@ -<!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> - |