xref: /minix3/external/bsd/llvm/dist/clang/docs/RAVFrontendAction.rst (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc==========================================================
2f4a2713aSLionel SambucHow to write RecursiveASTVisitor based ASTFrontendActions.
3f4a2713aSLionel Sambuc==========================================================
4f4a2713aSLionel Sambuc
5f4a2713aSLionel SambucIntroduction
6f4a2713aSLionel Sambuc============
7f4a2713aSLionel Sambuc
8f4a2713aSLionel SambucIn this tutorial you will learn how to create a FrontendAction that uses
9f4a2713aSLionel Sambuca RecursiveASTVisitor to find CXXRecordDecl AST nodes with a specified
10f4a2713aSLionel Sambucname.
11f4a2713aSLionel Sambuc
12f4a2713aSLionel SambucCreating a FrontendAction
13f4a2713aSLionel Sambuc=========================
14f4a2713aSLionel Sambuc
15f4a2713aSLionel SambucWhen writing a clang based tool like a Clang Plugin or a standalone tool
16f4a2713aSLionel Sambucbased on LibTooling, the common entry point is the FrontendAction.
17f4a2713aSLionel SambucFrontendAction is an interface that allows execution of user specific
18f4a2713aSLionel Sambucactions as part of the compilation. To run tools over the AST clang
19f4a2713aSLionel Sambucprovides the convenience interface ASTFrontendAction, which takes care
20f4a2713aSLionel Sambucof executing the action. The only part left is to implement the
21f4a2713aSLionel SambucCreateASTConsumer method that returns an ASTConsumer per translation
22f4a2713aSLionel Sambucunit.
23f4a2713aSLionel Sambuc
24f4a2713aSLionel Sambuc::
25f4a2713aSLionel Sambuc
26f4a2713aSLionel Sambuc      class FindNamedClassAction : public clang::ASTFrontendAction {
27f4a2713aSLionel Sambuc      public:
28*0a6a1f1dSLionel Sambuc        virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
29f4a2713aSLionel Sambuc          clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
30*0a6a1f1dSLionel Sambuc          return std::unique_ptr<clang::ASTConsumer>(
31*0a6a1f1dSLionel Sambuc              new FindNamedClassConsumer);
32f4a2713aSLionel Sambuc        }
33f4a2713aSLionel Sambuc      };
34f4a2713aSLionel Sambuc
35f4a2713aSLionel SambucCreating an ASTConsumer
36f4a2713aSLionel Sambuc=======================
37f4a2713aSLionel Sambuc
38f4a2713aSLionel SambucASTConsumer is an interface used to write generic actions on an AST,
39f4a2713aSLionel Sambucregardless of how the AST was produced. ASTConsumer provides many
40f4a2713aSLionel Sambucdifferent entry points, but for our use case the only one needed is
41f4a2713aSLionel SambucHandleTranslationUnit, which is called with the ASTContext for the
42f4a2713aSLionel Sambuctranslation unit.
43f4a2713aSLionel Sambuc
44f4a2713aSLionel Sambuc::
45f4a2713aSLionel Sambuc
46f4a2713aSLionel Sambuc      class FindNamedClassConsumer : public clang::ASTConsumer {
47f4a2713aSLionel Sambuc      public:
48f4a2713aSLionel Sambuc        virtual void HandleTranslationUnit(clang::ASTContext &Context) {
49f4a2713aSLionel Sambuc          // Traversing the translation unit decl via a RecursiveASTVisitor
50f4a2713aSLionel Sambuc          // will visit all nodes in the AST.
51f4a2713aSLionel Sambuc          Visitor.TraverseDecl(Context.getTranslationUnitDecl());
52f4a2713aSLionel Sambuc        }
53f4a2713aSLionel Sambuc      private:
54f4a2713aSLionel Sambuc        // A RecursiveASTVisitor implementation.
55f4a2713aSLionel Sambuc        FindNamedClassVisitor Visitor;
56f4a2713aSLionel Sambuc      };
57f4a2713aSLionel Sambuc
58f4a2713aSLionel SambucUsing the RecursiveASTVisitor
59f4a2713aSLionel Sambuc=============================
60f4a2713aSLionel Sambuc
61f4a2713aSLionel SambucNow that everything is hooked up, the next step is to implement a
62f4a2713aSLionel SambucRecursiveASTVisitor to extract the relevant information from the AST.
63f4a2713aSLionel Sambuc
64f4a2713aSLionel SambucThe RecursiveASTVisitor provides hooks of the form bool
65f4a2713aSLionel SambucVisitNodeType(NodeType \*) for most AST nodes; the exception are TypeLoc
66f4a2713aSLionel Sambucnodes, which are passed by-value. We only need to implement the methods
67f4a2713aSLionel Sambucfor the relevant node types.
68f4a2713aSLionel Sambuc
69f4a2713aSLionel SambucLet's start by writing a RecursiveASTVisitor that visits all
70f4a2713aSLionel SambucCXXRecordDecl's.
71f4a2713aSLionel Sambuc
72f4a2713aSLionel Sambuc::
73f4a2713aSLionel Sambuc
74f4a2713aSLionel Sambuc      class FindNamedClassVisitor
75f4a2713aSLionel Sambuc        : public RecursiveASTVisitor<FindNamedClassVisitor> {
76f4a2713aSLionel Sambuc      public:
77f4a2713aSLionel Sambuc        bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
78f4a2713aSLionel Sambuc          // For debugging, dumping the AST nodes will show which nodes are already
79f4a2713aSLionel Sambuc          // being visited.
80f4a2713aSLionel Sambuc          Declaration->dump();
81f4a2713aSLionel Sambuc
82f4a2713aSLionel Sambuc          // The return value indicates whether we want the visitation to proceed.
83f4a2713aSLionel Sambuc          // Return false to stop the traversal of the AST.
84f4a2713aSLionel Sambuc          return true;
85f4a2713aSLionel Sambuc        }
86f4a2713aSLionel Sambuc      };
87f4a2713aSLionel Sambuc
88f4a2713aSLionel SambucIn the methods of our RecursiveASTVisitor we can now use the full power
89f4a2713aSLionel Sambucof the Clang AST to drill through to the parts that are interesting for
90f4a2713aSLionel Sambucus. For example, to find all class declaration with a certain name, we
91f4a2713aSLionel Sambuccan check for a specific qualified name:
92f4a2713aSLionel Sambuc
93f4a2713aSLionel Sambuc::
94f4a2713aSLionel Sambuc
95f4a2713aSLionel Sambuc      bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
96f4a2713aSLionel Sambuc        if (Declaration->getQualifiedNameAsString() == "n::m::C")
97f4a2713aSLionel Sambuc          Declaration->dump();
98f4a2713aSLionel Sambuc        return true;
99f4a2713aSLionel Sambuc      }
100f4a2713aSLionel Sambuc
101f4a2713aSLionel SambucAccessing the SourceManager and ASTContext
102f4a2713aSLionel Sambuc==========================================
103f4a2713aSLionel Sambuc
104f4a2713aSLionel SambucSome of the information about the AST, like source locations and global
105f4a2713aSLionel Sambucidentifier information, are not stored in the AST nodes themselves, but
106f4a2713aSLionel Sambucin the ASTContext and its associated source manager. To retrieve them we
107f4a2713aSLionel Sambucneed to hand the ASTContext into our RecursiveASTVisitor implementation.
108f4a2713aSLionel Sambuc
109f4a2713aSLionel SambucThe ASTContext is available from the CompilerInstance during the call to
110f4a2713aSLionel SambucCreateASTConsumer. We can thus extract it there and hand it into our
111f4a2713aSLionel Sambucfreshly created FindNamedClassConsumer:
112f4a2713aSLionel Sambuc
113f4a2713aSLionel Sambuc::
114f4a2713aSLionel Sambuc
115*0a6a1f1dSLionel Sambuc      virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
116f4a2713aSLionel Sambuc        clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
117*0a6a1f1dSLionel Sambuc        return std::unique_ptr<clang::ASTConsumer>(
118*0a6a1f1dSLionel Sambuc            new FindNamedClassConsumer(&Compiler.getASTContext()));
119f4a2713aSLionel Sambuc      }
120f4a2713aSLionel Sambuc
121f4a2713aSLionel SambucNow that the ASTContext is available in the RecursiveASTVisitor, we can
122f4a2713aSLionel Sambucdo more interesting things with AST nodes, like looking up their source
123f4a2713aSLionel Sambuclocations:
124f4a2713aSLionel Sambuc
125f4a2713aSLionel Sambuc::
126f4a2713aSLionel Sambuc
127f4a2713aSLionel Sambuc      bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
128f4a2713aSLionel Sambuc        if (Declaration->getQualifiedNameAsString() == "n::m::C") {
129f4a2713aSLionel Sambuc          // getFullLoc uses the ASTContext's SourceManager to resolve the source
130f4a2713aSLionel Sambuc          // location and break it up into its line and column parts.
131f4a2713aSLionel Sambuc          FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getLocStart());
132f4a2713aSLionel Sambuc          if (FullLocation.isValid())
133f4a2713aSLionel Sambuc            llvm::outs() << "Found declaration at "
134f4a2713aSLionel Sambuc                         << FullLocation.getSpellingLineNumber() << ":"
135f4a2713aSLionel Sambuc                         << FullLocation.getSpellingColumnNumber() << "\n";
136f4a2713aSLionel Sambuc        }
137f4a2713aSLionel Sambuc        return true;
138f4a2713aSLionel Sambuc      }
139f4a2713aSLionel Sambuc
140f4a2713aSLionel SambucPutting it all together
141f4a2713aSLionel Sambuc=======================
142f4a2713aSLionel Sambuc
143f4a2713aSLionel SambucNow we can combine all of the above into a small example program:
144f4a2713aSLionel Sambuc
145f4a2713aSLionel Sambuc::
146f4a2713aSLionel Sambuc
147f4a2713aSLionel Sambuc      #include "clang/AST/ASTConsumer.h"
148f4a2713aSLionel Sambuc      #include "clang/AST/RecursiveASTVisitor.h"
149f4a2713aSLionel Sambuc      #include "clang/Frontend/CompilerInstance.h"
150f4a2713aSLionel Sambuc      #include "clang/Frontend/FrontendAction.h"
151f4a2713aSLionel Sambuc      #include "clang/Tooling/Tooling.h"
152f4a2713aSLionel Sambuc
153f4a2713aSLionel Sambuc      using namespace clang;
154f4a2713aSLionel Sambuc
155f4a2713aSLionel Sambuc      class FindNamedClassVisitor
156f4a2713aSLionel Sambuc        : public RecursiveASTVisitor<FindNamedClassVisitor> {
157f4a2713aSLionel Sambuc      public:
158f4a2713aSLionel Sambuc        explicit FindNamedClassVisitor(ASTContext *Context)
159f4a2713aSLionel Sambuc          : Context(Context) {}
160f4a2713aSLionel Sambuc
161f4a2713aSLionel Sambuc        bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
162f4a2713aSLionel Sambuc          if (Declaration->getQualifiedNameAsString() == "n::m::C") {
163f4a2713aSLionel Sambuc            FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getLocStart());
164f4a2713aSLionel Sambuc            if (FullLocation.isValid())
165f4a2713aSLionel Sambuc              llvm::outs() << "Found declaration at "
166f4a2713aSLionel Sambuc                           << FullLocation.getSpellingLineNumber() << ":"
167f4a2713aSLionel Sambuc                           << FullLocation.getSpellingColumnNumber() << "\n";
168f4a2713aSLionel Sambuc          }
169f4a2713aSLionel Sambuc          return true;
170f4a2713aSLionel Sambuc        }
171f4a2713aSLionel Sambuc
172f4a2713aSLionel Sambuc      private:
173f4a2713aSLionel Sambuc        ASTContext *Context;
174f4a2713aSLionel Sambuc      };
175f4a2713aSLionel Sambuc
176f4a2713aSLionel Sambuc      class FindNamedClassConsumer : public clang::ASTConsumer {
177f4a2713aSLionel Sambuc      public:
178f4a2713aSLionel Sambuc        explicit FindNamedClassConsumer(ASTContext *Context)
179f4a2713aSLionel Sambuc          : Visitor(Context) {}
180f4a2713aSLionel Sambuc
181f4a2713aSLionel Sambuc        virtual void HandleTranslationUnit(clang::ASTContext &Context) {
182f4a2713aSLionel Sambuc          Visitor.TraverseDecl(Context.getTranslationUnitDecl());
183f4a2713aSLionel Sambuc        }
184f4a2713aSLionel Sambuc      private:
185f4a2713aSLionel Sambuc        FindNamedClassVisitor Visitor;
186f4a2713aSLionel Sambuc      };
187f4a2713aSLionel Sambuc
188f4a2713aSLionel Sambuc      class FindNamedClassAction : public clang::ASTFrontendAction {
189f4a2713aSLionel Sambuc      public:
190*0a6a1f1dSLionel Sambuc        virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
191f4a2713aSLionel Sambuc          clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
192*0a6a1f1dSLionel Sambuc          return std::unique_ptr<clang::ASTConsumer>(
193*0a6a1f1dSLionel Sambuc              new FindNamedClassConsumer(&Compiler.getASTContext()));
194f4a2713aSLionel Sambuc        }
195f4a2713aSLionel Sambuc      };
196f4a2713aSLionel Sambuc
197f4a2713aSLionel Sambuc      int main(int argc, char **argv) {
198f4a2713aSLionel Sambuc        if (argc > 1) {
199f4a2713aSLionel Sambuc          clang::tooling::runToolOnCode(new FindNamedClassAction, argv[1]);
200f4a2713aSLionel Sambuc        }
201f4a2713aSLionel Sambuc      }
202f4a2713aSLionel Sambuc
203f4a2713aSLionel SambucWe store this into a file called FindClassDecls.cpp and create the
204f4a2713aSLionel Sambucfollowing CMakeLists.txt to link it:
205f4a2713aSLionel Sambuc
206f4a2713aSLionel Sambuc::
207f4a2713aSLionel Sambuc
208f4a2713aSLionel Sambuc    set(LLVM_USED_LIBS clangTooling)
209f4a2713aSLionel Sambuc
210f4a2713aSLionel Sambuc    add_clang_executable(find-class-decls FindClassDecls.cpp)
211f4a2713aSLionel Sambuc
212f4a2713aSLionel SambucWhen running this tool over a small code snippet it will output all
213f4a2713aSLionel Sambucdeclarations of a class n::m::C it found:
214f4a2713aSLionel Sambuc
215f4a2713aSLionel Sambuc::
216f4a2713aSLionel Sambuc
217f4a2713aSLionel Sambuc      $ ./bin/find-class-decls "namespace n { namespace m { class C {}; } }"
218f4a2713aSLionel Sambuc      Found declaration at 1:29
219f4a2713aSLionel Sambuc
220