├── LibToolingExample ├── run_example.sh ├── test.c ├── readme.md ├── Makefile └── Example.cpp ├── PluginExample ├── run_example.sh ├── test.c ├── readme.md ├── Makefile └── PluginExample.cpp ├── LibExample ├── test.c ├── readme.md ├── Makefile └── test1.cpp └── readme.md /LibToolingExample/run_example.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./Example test.c -- 4 | -------------------------------------------------------------------------------- /PluginExample/run_example.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clang -Xclang -load \ 3 | -Xclang /home/workspace/MyProject_test/PluginExample/PluginExample.so \ 4 | -Xclang -plugin -Xclang -example-plugin \ 5 | -Wall -c test.c 6 | -------------------------------------------------------------------------------- /PluginExample/test.c: -------------------------------------------------------------------------------- 1 | //The header is commented because handling header needs additional effort. 2 | //#include 3 | 4 | void do_math(int *x) { 5 | *x += 5; 6 | } 7 | 8 | int main(void) { 9 | int result = -1, val = 4; 10 | do_math(&val); 11 | return result; 12 | } 13 | -------------------------------------------------------------------------------- /LibToolingExample/test.c: -------------------------------------------------------------------------------- 1 | //The header is commented because handling header needs additional effort. 2 | //#include 3 | 4 | void do_math(int *x) { 5 | *x += 5; 6 | } 7 | 8 | int main(void) { 9 | int result = -1, val = 4; 10 | do_math(&val); 11 | return result; 12 | } 13 | -------------------------------------------------------------------------------- /LibExample/test.c: -------------------------------------------------------------------------------- 1 | //The header is commented because handling header needs additional effort. 2 | //#include 3 | 4 | int global; 5 | 6 | void myPrint(int param) { 7 | if (param == 1) 8 | printf("param is 1"); 9 | 10 | for (int i = 0 ; i < 10 ; i++ ) { 11 | global += i; 12 | } 13 | } 14 | 15 | int main(int argc, char *argv[]) { 16 | int param = 1; 17 | myPrint(param); 18 | return 0; 19 | } -------------------------------------------------------------------------------- /LibToolingExample/readme.md: -------------------------------------------------------------------------------- 1 | # Clang LibTooling Usage 2 | This file gives a brief introduction of LibTooling usage. 3 | 4 | ##Source 5 | The source file origins from [Clang LibTooling Example](http://kevinaboos.blogspot.com/2013/07/clang-tutorial-part-ii-libtooling.html). However, due to the rapid change of Clang API, I have modified some code to support the newest Clang 3.8 and compeletly changed the makefile. 6 | 7 | ##Function of the source file 8 | Rewrite some part of the program. 9 | 10 | ##Usage 11 | ``` 12 | $ make 13 | $ ./run_example.sh 14 | ``` 15 | 16 | Make sure the permission of execution. 17 | -------------------------------------------------------------------------------- /PluginExample/readme.md: -------------------------------------------------------------------------------- 1 | # Clang Plugin Example 2 | This file gives a brief introduction of Clang Plugin usage. 3 | 4 | ##Source 5 | The source file origins from [Clang Plugin Example](http://kevinaboos.blogspot.com/2013/07/clang-tutorial-part-iii-plugin-example.html). However, due to the rapid change of Clang API, I have modified some code to support the newest Clang 3.8 and compeletly changed the makefile. 6 | 7 | ##Function of the source file 8 | Rewrite some part of the program. 9 | 10 | ##Usage 11 | ``` 12 | $ make 13 | $ ./run_example.sh 14 | ``` 15 | 16 | Make sure the permission of execution. 17 | 18 | -------------------------------------------------------------------------------- /LibExample/readme.md: -------------------------------------------------------------------------------- 1 | #LibClang usage 2 | This file contains a brief introduction about the given test1.cpp file and LibClang usage. 3 | 4 | ##Source 5 | Actually, this file comes from [this tutorial](http://swtv.kaist.ac.kr/courses/cs453-fall13/Clang%20tutorial%20v4.pdf). 6 | Due to the rapid change of Clang API, I have made some changes to ensure it can work under the newest Clang 3.8. 7 | BTW, this tutorial gives a nice introduction of basic Clang concepts, even though a little outdated. 8 | 9 | ##Function of the source file 10 | The source file test1.cpp can walk through the program test.c's AST, print all the function declarations and statement class name(a little ugly). 11 | 12 | ##Usage(comand) 13 | ``` 14 | $ make 15 | $ ./test1 test.c 16 | ``` 17 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | #Clang basic usage 2 | This repository follow my [blog](http://jszhujun2010.farbox.com), which gives an introduction of Clang basics which includes Clang library(LibClang), LibTooling and Plugin(namely corresponding to folder LibExample, LibToolingExample and PluginExample). It is inspired by [this blog](https://kevinaboos.wordpress.com/2013/07/23/clang-tutorial-part-i-introduction/), and I have modified some codes to be suitable for the newest Clang 3.8. 3 | 4 | ##What changes most? 5 | Smart pointer in C++11 is becoming more and more popular because of its safety, and Clang seems to have changed all possible raw pointers to smart pointers since Clang 3.4. So, I make some changes in pointer types. Also, due to the rapid change of Clang API, I have changed some other codes. Finally, makefile has been modified for general purpose use. 6 | 7 | ##Usage 8 | See details in readme.md in each subdirectory. 9 | -------------------------------------------------------------------------------- /LibExample/Makefile: -------------------------------------------------------------------------------- 1 | # This works for both binary installed and source installed 2 | # It seems that clang++ has some problem, so g++ is used. 3 | # Note that I add -std=c++11 option here to support smart pointer 4 | CXX := g++ 5 | CXXFLAGS := -fno-rtti -O0 -g -std=c++11 6 | 7 | # Your own LLVM build path 8 | LLVM_DIR := /home/workspace/Tools/build 9 | 10 | # LLVM C++ options and LLVM link options 11 | LLVM_CXXFLAGS := `${LLVM_DIR}/bin/llvm-config --cxxflags` 12 | LLVMLDFLAGS := `${LLVM_DIR}/bin/llvm-config --ldflags --libs --system-libs` 13 | 14 | SOURCES = test1.cpp 15 | 16 | OBJECTS = $(SOURCES:.cpp=.o) 17 | EXES = $(OBJECTS:.o=) 18 | CLANGLIBS = \ 19 | -lclangTooling\ 20 | -lclangFrontendTool\ 21 | -lclangFrontend\ 22 | -lclangDriver\ 23 | -lclangSerialization\ 24 | -lclangCodeGen\ 25 | -lclangParse\ 26 | -lclangSema\ 27 | -lclangStaticAnalyzerFrontend\ 28 | -lclangStaticAnalyzerCheckers\ 29 | -lclangStaticAnalyzerCore\ 30 | -lclangAnalysis\ 31 | -lclangARCMigrate\ 32 | -lclangRewriteFrontend\ 33 | -lclangRewrite\ 34 | -lclangEdit\ 35 | -lclangAST\ 36 | -lclangLex\ 37 | -lclangBasic\ 38 | $(shell $(LLVMCONFIG) --libs)\ 39 | $(shell $(LLVMCONFIG) --system-libs)\ 40 | -lcurses 41 | 42 | all: $(OBJECTS) $(EXES) 43 | 44 | #Not obvious, see my blog 45 | %: %.o 46 | $(CXX) -o $@ $< $(CLANGLIBS) $(LLVMLDFLAGS) 47 | 48 | #make clean manually 49 | clean: 50 | -rm -f $(EXES) $(OBJECTS) *~ 51 | -------------------------------------------------------------------------------- /LibToolingExample/Makefile: -------------------------------------------------------------------------------- 1 | # This works for both binary installed and source installed 2 | # It seems that clang++ has some problem, so g++ is used. 3 | # Note that I add -std=c++11 option here to support smart pointer 4 | CXX := g++ 5 | CXXFLAGS := -fno-rtti -O0 -g -std=c++11 6 | 7 | # Your own LLVM build path 8 | LLVM_DIR := /home/workspace/Tools/build 9 | 10 | # LLVM C++ options and LLVM link options 11 | LLVM_CXXFLAGS := `${LLVM_DIR}/bin/llvm-config --cxxflags` 12 | LLVMLDFLAGS := `${LLVM_DIR}/bin/llvm-config --ldflags --libs --system-libs` 13 | 14 | 15 | SOURCES = Example.cpp 16 | 17 | OBJECTS = $(SOURCES:.cpp=.o) 18 | EXES = $(OBJECTS:.o=) 19 | CLANGLIBS = \ 20 | -lclangTooling\ 21 | -lclangFrontendTool\ 22 | -lclangFrontend\ 23 | -lclangDriver\ 24 | -lclangSerialization\ 25 | -lclangCodeGen\ 26 | -lclangParse\ 27 | -lclangSema\ 28 | -lclangStaticAnalyzerFrontend\ 29 | -lclangStaticAnalyzerCheckers\ 30 | -lclangStaticAnalyzerCore\ 31 | -lclangAnalysis\ 32 | -lclangARCMigrate\ 33 | -lclangRewriteFrontend\ 34 | -lclangRewrite\ 35 | -lclangEdit\ 36 | -lclangAST\ 37 | -lclangLex\ 38 | -lclangBasic\ 39 | $(shell $(LLVMCONFIG) --libs)\ 40 | $(shell $(LLVMCONFIG) --system-libs)\ 41 | -lcurses 42 | 43 | all: $(OBJECTS) $(EXES) 44 | 45 | #Not obvious, see my blog 46 | %: %.o 47 | $(CXX) -o $@ $< $(CLANGLIBS) $(LLVMLDFLAGS) 48 | 49 | .PHONY: all clean 50 | 51 | #make clean manually 52 | clean: 53 | rm -f $(OBJECTS) $(EXES) *.o 54 | -------------------------------------------------------------------------------- /PluginExample/Makefile: -------------------------------------------------------------------------------- 1 | # This works for only for source installed only. 2 | # It seems that clang++ has some problem, so g++ is used. 3 | # Note that I add -std=c++11 option here to support smart pointer. 4 | CXX := g++ 5 | CXXFLAGS := -fno-rtti -O0 -g -std=c++11 6 | PLUGIN_CXXFLAGS := -fpic 7 | 8 | # Your LLVM source directory and build directory 9 | LLVM_SRC_DIR := /home/workspace/Tools/llvm 10 | LLVM_DIR := /home/workspace/Tools/build 11 | 12 | # This is why we need source installed LLVM 13 | CLANG_INCLUDES := \ 14 | -I$(LLVM_SRC_DIR)/tools/clang/include \ 15 | -I$(LLVM_DIR)/tools/clang/include 16 | 17 | # LLVM C++ options and LLVM link options 18 | LLVM_CXXFLAGS := `${LLVM_DIR}/bin/llvm-config --cxxflags` 19 | LLVMLDFLAGS := `${LLVM_DIR}/bin/llvm-config --ldflags --libs --system-libs` 20 | 21 | # Plugins shouldn't link LLVM and Clang libs statically, because they are 22 | # already linked into the main executable (opt or clang). LLVM doesn't like its 23 | # libs to be linked more than once because it uses globals for configuration 24 | # and plugin registration, and these trample over each other. 25 | LLVMLDFLAGS_NOLIBS := `${LLVM_DIR}/bin/llvm-config --ldflags` 26 | PLUGIN_LDFLAGS := -shared 27 | 28 | 29 | SOURCES = PluginExample.cpp 30 | 31 | SOLIB = $(SOURCES:.cpp=.so) 32 | 33 | 34 | CLANGLIBS = \ 35 | -lclangTooling\ 36 | -lclangFrontendTool\ 37 | -lclangFrontend\ 38 | -lclangDriver\ 39 | -lclangSerialization\ 40 | -lclangCodeGen\ 41 | -lclangParse\ 42 | -lclangSema\ 43 | -lclangStaticAnalyzerFrontend\ 44 | -lclangStaticAnalyzerCheckers\ 45 | -lclangStaticAnalyzerCore\ 46 | -lclangAnalysis\ 47 | -lclangARCMigrate\ 48 | -lclangRewriteFrontend\ 49 | -lclangRewrite\ 50 | -lclangEdit\ 51 | -lclangAST\ 52 | -lclangLex\ 53 | -lclangBasic\ 54 | $(shell $(LLVMCONFIG) --libs)\ 55 | $(shell $(LLVMCONFIG) --system-libs)\ 56 | -lcurses 57 | 58 | 59 | .PHONY: all 60 | all: $(SOLIB) 61 | 62 | # $@ stands for object file, $< is the first dependence source file(.cpp) 63 | %.so: %.cpp 64 | $(CXX) $(PLUGIN_CXXFLAGS) $(CXXFLAGS) $(LLVM_CXXFLAGS) -o $@ $< $(PLUGIN_LDFLAGS) $(LLVMLDFLAGS_NOLIBS) 65 | 66 | # make clean manually 67 | .PHONY: clean 68 | clean: 69 | -rm -f *.so 70 | -------------------------------------------------------------------------------- /PluginExample/PluginExample.cpp: -------------------------------------------------------------------------------- 1 | #include "clang/Driver/Options.h" 2 | #include "clang/AST/AST.h" 3 | #include "clang/AST/ASTContext.h" 4 | #include "clang/AST/ASTConsumer.h" 5 | #include "clang/AST/RecursiveASTVisitor.h" 6 | #include "clang/Frontend/ASTConsumers.h" 7 | #include "clang/Frontend/FrontendActions.h" 8 | #include "clang/Frontend/CompilerInstance.h" 9 | #include "clang/Frontend/FrontendPluginRegistry.h" 10 | #include "clang/Rewrite/Core/Rewriter.h" 11 | 12 | using namespace std; 13 | using namespace clang; 14 | using namespace llvm; 15 | 16 | Rewriter rewriter; 17 | int numFunctions = 0; 18 | 19 | 20 | class ExampleVisitor : public RecursiveASTVisitor { 21 | private: 22 | ASTContext *astContext; // used for getting additional AST info 23 | 24 | public: 25 | explicit ExampleVisitor(CompilerInstance *CI) 26 | : astContext(&(CI->getASTContext())) // initialize private members 27 | { 28 | rewriter.setSourceMgr(astContext->getSourceManager(), astContext->getLangOpts()); 29 | } 30 | 31 | virtual bool VisitFunctionDecl(FunctionDecl *func) { 32 | numFunctions++; 33 | string funcName = func->getNameInfo().getName().getAsString(); 34 | if (funcName == "do_math") { 35 | rewriter.ReplaceText(func->getLocation(), funcName.length(), "add5"); 36 | errs() << "** Rewrote function def: " << funcName << "\n"; 37 | } 38 | return true; 39 | } 40 | 41 | virtual bool VisitStmt(Stmt *st) { 42 | if (ReturnStmt *ret = dyn_cast(st)) { 43 | rewriter.ReplaceText(ret->getRetValue()->getLocStart(), 6, "val"); 44 | errs() << "** Rewrote ReturnStmt\n"; 45 | } 46 | if (CallExpr *call = dyn_cast(st)) { 47 | rewriter.ReplaceText(call->getLocStart(), 7, "add5"); 48 | errs() << "** Rewrote function call\n"; 49 | } 50 | return true; 51 | } 52 | }; 53 | 54 | 55 | 56 | class ExampleASTConsumer : public ASTConsumer { 57 | private: 58 | ExampleVisitor *visitor; // doesn't have to be private 59 | 60 | public: 61 | // override the constructor in order to pass CI 62 | explicit ExampleASTConsumer(CompilerInstance *CI): 63 | visitor(new ExampleVisitor(CI)) { } // initialize the visitor 64 | 65 | // override this to call our ExampleVisitor on the entire source file 66 | virtual void HandleTranslationUnit(ASTContext &Context) { 67 | /* we can use ASTContext to get the TranslationUnitDecl, which is 68 | a single Decl that collectively represents the entire source file */ 69 | visitor->TraverseDecl(Context.getTranslationUnitDecl()); 70 | } 71 | }; 72 | 73 | class PluginExampleAction : public PluginASTAction { 74 | protected: 75 | // this gets called by Clang when it invokes our Plugin 76 | // Note that unique pointer is used here. 77 | std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef file) { 78 | return llvm::make_unique(&CI); 79 | } 80 | 81 | // implement this function if you want to parse custom cmd-line args 82 | bool ParseArgs(const CompilerInstance &CI, const vector &args) { 83 | return true; 84 | } 85 | }; 86 | 87 | 88 | static FrontendPluginRegistry::Add X("-example-plugin", "simple Plugin example"); 89 | -------------------------------------------------------------------------------- /LibToolingExample/Example.cpp: -------------------------------------------------------------------------------- 1 | #include "clang/Driver/Options.h" 2 | #include "clang/AST/AST.h" 3 | #include "clang/AST/ASTContext.h" 4 | #include "clang/AST/ASTConsumer.h" 5 | #include "clang/AST/RecursiveASTVisitor.h" 6 | #include "clang/Frontend/ASTConsumers.h" 7 | #include "clang/Frontend/FrontendActions.h" 8 | #include "clang/Frontend/CompilerInstance.h" 9 | #include "clang/Tooling/CommonOptionsParser.h" 10 | #include "clang/Tooling/Tooling.h" 11 | #include "clang/Rewrite/Core/Rewriter.h" 12 | 13 | using namespace std; 14 | using namespace clang; 15 | using namespace clang::driver; 16 | using namespace clang::tooling; 17 | using namespace llvm; 18 | 19 | Rewriter rewriter; 20 | int numFunctions = 0; 21 | 22 | static llvm::cl::OptionCategory StatSampleCategory("Stat Sample"); 23 | 24 | class ExampleVisitor : public RecursiveASTVisitor { 25 | private: 26 | ASTContext *astContext; // used for getting additional AST info 27 | 28 | public: 29 | explicit ExampleVisitor(CompilerInstance *CI): astContext(&(CI->getASTContext())) { // initialize private members 30 | rewriter.setSourceMgr(astContext->getSourceManager(), astContext->getLangOpts()); 31 | } 32 | 33 | virtual bool VisitFunctionDecl(FunctionDecl *func) { 34 | numFunctions++; 35 | string funcName = func->getNameInfo().getName().getAsString(); 36 | if (funcName == "do_math") { 37 | rewriter.ReplaceText(func->getLocation(), funcName.length(), "add5"); 38 | errs() << "** Rewrote function def: " << funcName << "\n"; 39 | } 40 | return true; 41 | } 42 | 43 | virtual bool VisitStmt(Stmt *st) { 44 | if (ReturnStmt *ret = dyn_cast(st)) { 45 | rewriter.ReplaceText(ret->getRetValue()->getLocStart(), 6, "val"); 46 | errs() << "** Rewrote ReturnStmt\n"; 47 | } 48 | if (CallExpr *call = dyn_cast(st)) { 49 | rewriter.ReplaceText(call->getLocStart(), 7, "add5"); 50 | errs() << "** Rewrote function call\n"; 51 | } 52 | return true; 53 | } 54 | }; 55 | 56 | 57 | 58 | class ExampleASTConsumer : public ASTConsumer { 59 | private: 60 | ExampleVisitor *visitor; // doesn't have to be private 61 | 62 | public: 63 | // override the constructor in order to pass CI 64 | explicit ExampleASTConsumer(CompilerInstance *CI): visitor(new ExampleVisitor(CI)) {}// initialize the visitor 65 | 66 | // override this to call our ExampleVisitor on the entire source file 67 | virtual void HandleTranslationUnit(ASTContext &Context) { 68 | /* we can use ASTContext to get the TranslationUnitDecl, which is 69 | a single Decl that collectively represents the entire source file */ 70 | visitor->TraverseDecl(Context.getTranslationUnitDecl()); 71 | } 72 | }; 73 | 74 | 75 | 76 | class ExampleFrontendAction : public ASTFrontendAction { 77 | public: 78 | ExampleFrontendAction() {} 79 | 80 | //Note that unique pointer is used. 81 | virtual std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef file) { 82 | return llvm::make_unique(&CI); // pass CI pointer to ASTConsumer 83 | } 84 | }; 85 | 86 | 87 | 88 | int main(int argc, const char **argv) { 89 | // parse the command-line args passed to your code 90 | CommonOptionsParser op(argc, argv, StatSampleCategory); 91 | // create a new Clang Tool instance (a LibTooling environment) 92 | ClangTool Tool(op.getCompilations(), op.getSourcePathList()); 93 | 94 | // run the Clang Tool, creating a new FrontendAction (explained below) 95 | int result = Tool.run(newFrontendActionFactory().get()); 96 | 97 | errs() << "\nFound " << numFunctions << " functions.\n\n"; 98 | // print out the rewritten source code ("rewriter" is a global var.) 99 | rewriter.getEditBuffer(rewriter.getSourceMgr().getMainFileID()).write(errs()); 100 | return result; 101 | } -------------------------------------------------------------------------------- /LibExample/test1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | using namespace std; 26 | using namespace clang; 27 | 28 | class MyASTVisitor: public RecursiveASTVisitor { 29 | public: 30 | virtual bool VisitStmt(Stmt *s) { 31 | std::cout << s->getStmtClassName() << "\n"; 32 | return true; 33 | } 34 | 35 | virtual bool VisitFunctionDecl(FunctionDecl *f) { 36 | //std::cout << f->getName() << "\n"; 37 | cout << f->getNameInfo().getName().getAsString() << "\n"; 38 | return true; 39 | } 40 | }; 41 | 42 | class MyASTConsumer: public ASTConsumer { 43 | public: 44 | MyASTConsumer(): Visitor() {} 45 | 46 | virtual bool HandleTopLevelDecl(DeclGroupRef DR) { 47 | for(DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) { 48 | Visitor.TraverseDecl(*b); 49 | } 50 | return true; 51 | } 52 | 53 | private: 54 | MyASTVisitor Visitor; 55 | }; 56 | 57 | 58 | int main(int argc, char *argv[]) { 59 | if (argc != 2) { 60 | llvm::errs() << "Usage: PrintFunctions \n"; 61 | return 1; 62 | } 63 | 64 | // CompileInstance will hold the instance of Clang compiler for us, 65 | // managing the various objects needed to run the compiler. 66 | CompilerInstance Inst; 67 | 68 | // Diagnostics manage problems and issues in compile 69 | Inst.createDiagnostics(NULL, false); 70 | 71 | // TargetOptions *TO = new TargetOptions(); 72 | // Note that shared pointer is used here. 73 | // Set target paltform options, initi target info with default triple for our platform. 74 | std::shared_ptr TO = std::make_shared(); 75 | TO->Triple = llvm::sys::getDefaultTargetTriple(); 76 | TargetInfo *TI = TargetInfo::CreateTargetInfo(Inst.getDiagnostics(), TO); 77 | Inst.setTarget(TI); 78 | 79 | // FileManager supports for file system lookup, caching and directory search management. 80 | Inst.createFileManager(); 81 | FileManager &FileMgr = Inst.getFileManager(); 82 | 83 | // SourceManager handles loading and caching of source files into memory. 84 | Inst.createSourceManager(FileMgr); 85 | SourceManager &SourceMgr = Inst.getSourceManager(); 86 | 87 | // Preprocessor runs within a single file. 88 | Inst.createPreprocessor(clang::TU_Complete); 89 | 90 | // ASTContext holds long-lived AST nodes (such as types and decls) 91 | Inst.createASTContext(); 92 | 93 | // A Rewriter helps us manage the code rewriting task. 94 | Rewriter TheRewriter; 95 | 96 | TheRewriter.setSourceMgr(SourceMgr, Inst.getLangOpts()); 97 | 98 | // Set the main file handled by the source manager to the input file. 99 | const FileEntry *FileIn = FileMgr.getFile(argv[1]); 100 | // New API is used. 101 | SourceMgr.setMainFileID(SourceMgr.createFileID(FileIn, clang::SourceLocation(), clang::SrcMgr::C_User)); 102 | 103 | // Inform Diagnostics that processing of a source file is begining. 104 | Inst.getDiagnosticClient().BeginSourceFile(Inst.getLangOpts(), &Inst.getPreprocessor()); 105 | 106 | // Create an AST consumer instance which is gong to be called by ParseAST. 107 | MyASTConsumer TheConsumer; 108 | 109 | // Parse the file to AST, registering our consumer as the ASTConsumer. 110 | ParseAST(Inst.getPreprocessor(), &TheConsumer, Inst.getASTContext()); 111 | 112 | return 0; 113 | } 114 | --------------------------------------------------------------------------------