[cfe-commits] r155627 - in /cfe/trunk: docs/RAVFrontendAction.html examples/PrintFunctionNames/PrintFunctionNames.cpp

Manuel Klimek klimek at google.com
Thu Apr 26 01:35:39 PDT 2012


Author: klimek
Date: Thu Apr 26 03:35:39 2012
New Revision: 155627

URL: http://llvm.org/viewvc/llvm-project?rev=155627&view=rev
Log:
Adds a small tutorial on how to write RAV based ASTFrontendActions.


Added:
    cfe/trunk/docs/RAVFrontendAction.html   (with props)
Modified:
    cfe/trunk/examples/PrintFunctionNames/PrintFunctionNames.cpp

Added: cfe/trunk/docs/RAVFrontendAction.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/RAVFrontendAction.html?rev=155627&view=auto
==============================================================================
--- cfe/trunk/docs/RAVFrontendAction.html (added)
+++ cfe/trunk/docs/RAVFrontendAction.html Thu Apr 26 03:35:39 2012
@@ -0,0 +1,221 @@
+<!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>
+<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>
+

Propchange: cfe/trunk/docs/RAVFrontendAction.html
------------------------------------------------------------------------------
    svn:eol-style = LF

Propchange: cfe/trunk/docs/RAVFrontendAction.html
------------------------------------------------------------------------------
    svn:mime-type = text/html

Modified: cfe/trunk/examples/PrintFunctionNames/PrintFunctionNames.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/PrintFunctionNames.cpp?rev=155627&r1=155626&r2=155627&view=diff
==============================================================================
--- cfe/trunk/examples/PrintFunctionNames/PrintFunctionNames.cpp (original)
+++ cfe/trunk/examples/PrintFunctionNames/PrintFunctionNames.cpp Thu Apr 26 03:35:39 2012
@@ -17,6 +17,7 @@
 #include "clang/AST/AST.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "llvm/Support/raw_ostream.h"
+#include "clang/Frontend/FrontendActions.h"
 using namespace clang;
 
 namespace {
@@ -67,5 +68,5 @@
 
 }
 
-static FrontendPluginRegistry::Add<PrintFunctionNamesAction>
+static FrontendPluginRegistry::Add<SyntaxOnlyAction>
 X("print-fns", "print function names");





More information about the cfe-commits mailing list