summaryrefslogtreecommitdiff
path: root/docs/RAVFrontendAction.rst
diff options
context:
space:
mode:
authorSean Silva <silvas@purdue.edu>2012-12-13 01:10:46 +0000
committerSean Silva <silvas@purdue.edu>2012-12-13 01:10:46 +0000
commit93ca0217a2aa3047c10518e991ab8578e90829e7 (patch)
tree5ec29392cfd8361d38f2ccaaa810c2f81e3fc268 /docs/RAVFrontendAction.rst
parent1812652c24c5a7847654cef9b0875414000af27f (diff)
downloadclang-93ca0217a2aa3047c10518e991ab8578e90829e7.tar.gz
clang-93ca0217a2aa3047c10518e991ab8578e90829e7.tar.bz2
clang-93ca0217a2aa3047c10518e991ab8578e90829e7.tar.xz
docs: More reST conversion.
Sorry for the large commit, but it is much faster to convert in batches. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@170067 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'docs/RAVFrontendAction.rst')
-rw-r--r--docs/RAVFrontendAction.rst216
1 files changed, 216 insertions, 0 deletions
diff --git a/docs/RAVFrontendAction.rst b/docs/RAVFrontendAction.rst
new file mode 100644
index 0000000000..2f60ce9e82
--- /dev/null
+++ b/docs/RAVFrontendAction.rst
@@ -0,0 +1,216 @@
+==========================================================
+How to write RecursiveASTVisitor based ASTFrontendActions.
+==========================================================
+
+Introduction
+============
+
+In this tutorial you will learn how to create a FrontendAction that uses
+a RecursiveASTVisitor to find CXXRecordDecl AST nodes with a specified
+name.
+
+Creating a FrontendAction
+=========================
+
+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.
+
+::
+
+ class FindNamedClassAction : public clang::ASTFrontendAction {
+ public:
+ virtual clang::ASTConsumer *CreateASTConsumer(
+ clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
+ return new FindNamedClassConsumer;
+ }
+ };
+
+Creating an ASTConsumer
+=======================
+
+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.
+
+::
+
+ 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;
+ };
+
+Using the RecursiveASTVisitor
+=============================
+
+Now that everything is hooked up, the next step is to implement a
+RecursiveASTVisitor to extract the relevant information from the AST.
+
+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.
+
+Let's start by writing a RecursiveASTVisitor that visits all
+CXXRecordDecl's.
+
+::
+
+ 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;
+ }
+ };
+
+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:
+
+::
+
+ bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
+ if (Declaration->getQualifiedNameAsString() == "n::m::C")
+ Declaration->dump();
+ return true;
+ }
+
+Accessing the SourceManager and ASTContext
+==========================================
+
+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.
+
+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:
+
+::
+
+ virtual clang::ASTConsumer *CreateASTConsumer(
+ clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
+ return new FindNamedClassConsumer(&Compiler.getASTContext());
+ }
+
+Now that the ASTContext is available in the RecursiveASTVisitor, we can
+do more interesting things with AST nodes, like looking up their source
+locations:
+
+::
+
+ 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;
+ }
+
+Putting it all together
+=======================
+
+Now we can combine all of the above into a small example program:
+
+::
+
+ #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]);
+ }
+ }
+
+We store this into a file called FindClassDecls.cpp and create the
+following CMakeLists.txt to link it:
+
+::
+
+ set(LLVM_USED_LIBS clangTooling)
+
+ add_clang_executable(find-class-decls FindClassDecls.cpp)
+
+When running this tool over a small code snippet it will output all
+declarations of a class n::m::C it found:
+
+::
+
+ $ ./bin/find-class-decls "namespace n { namespace m { class C {}; } }"
+ Found declaration at 1:29
+