环境clang版本为8.0.0,Visual Studio 2019
参数解析
使用clang解析C++文件需要传入编译参数,llvm提供类CommonOptionsParser,可以添加自定义解析规则
1
| CommonOptionsParser parser(argc, argv, GeneralCategory);
|
ClangTool获得解析后的参数即可分析文件
1
| ClangTool tool(parser.getCompilations(), parser.getSourcePathList());
|
FrontendAction与ASTConsumer
FrontendAction创建一个ASTConsumer,编译过程触发的事件通过重写ASTConsumer的虚函数可以进行处理,其中HandleTranslationUnit在每一个单元编译完成后调用,HandleTranslationUnit函数参数为ASTContext(可以看作AST树),RecursiveASTVisitor可以遍历ASTContext,完成AST树的遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| class ExampleVisitor : public RecursiveASTVisitor<ExampleVisitor> { public: ExampleVisitor(SourceManager& pSM) : _source_manager(pSM) { } bool VisitCXXRecordDecl(CXXRecordDecl* pDecl) { if (_source_manager.isInMainFile(pDecl->getLocation())) { _class_name.emplace_back(pDecl->getName()); if (pDecl->isTemplateDecl()) std::cout << "template "; std::cout << pDecl->getNameAsString() << std::endl; } return true; } bool VisitCXXMethodDecl(CXXMethodDecl* pDecl) { if (_source_manager.isInMainFile(pDecl->getLocation())) std::cout << pDecl->getNameAsString() << std::endl; return true; } bool TraverseNamespaceDecl(NamespaceDecl* pDecl) { if (_source_manager.isInMainFile(pDecl->getLocation())) { std::cout << pDecl->getNameAsString() << " Start" << std::endl; RecursiveASTVisitor::TraverseNamespaceDecl(pDecl); std::cout << pDecl->getNameAsString() << " End" << std::endl; } return true; } std::vector<std::string> _class_name; SourceManager& _source_manager; };
class ExampleConsumer : public ASTConsumer { public: ExampleConsumer(SourceManager& pSM) : _visitor(pSM) { } void HandleTranslationUnit(ASTContext& pContext) override { _visitor.TraverseDecl(pContext.getTranslationUnitDecl()); } private: ExampleVisitor _visitor; };
class ExampleAction : public ASTFrontendAction { public: std::unique_ptr<ASTConsumer> CreateASTConsumer( CompilerInstance& pCompiler, StringRef pFile) override { return std::unique_ptr<ASTConsumer>(new ExampleConsumer(pCompiler.getSourceManager())); } };
|
RecursiveASTVisitor
VisitCXXMethodDecl在遍历到类的成员方法时调用,Visit后可以跟节点名称
TraverseNamespaceDecl遍历该节点时调用,Traverse后可以跟节点名称,可以跳过某些类型节点
SourceManager
可以找到节点对应源文件的位置
运行FrontendAction
1
| tool.run(newFrontendActionFactory<ExampleAction>().get());
|
MatchFinder
当只需要查询某些节点,可以使用clang提供的MatchFinder类,则不需要自己去创建ASTConsumer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Printer : public MatchFinder::MatchCallback { void run(const MatchFinder::MatchResult& pRes) { auto node = pRes.Nodes.getNodeAs<CXXRecordDecl>(""); if (node && pRes.SourceManager->isInMainFile(node->getLocation()) && !node->isImplicit()) { std::cout << node->getName().str() << std::endl; } } };
MatchFinder finder; Printer printer; finder.addMatcher(cxxRecordDecl().bind(""), &printer); tool.run(newFrontendActionFactory(&finder).get());
|
附录
查看AST树
1
| clang++ -Xclang -ast-dump main.cpp
|
ASTMatcher和AST结点文档
https://clang.llvm.org/docs/LibASTMatchersReference.html
引入
头文件
1 2 3 4 5 6 7 8 9 10 11
| #include <clang/Tooling/CommonOptionsParser.h> #include <clang/Tooling/Tooling.h> #include <clang/ASTMatchers/ASTMatchers.h> #include <clang/ASTMatchers/ASTMatchFinder.h> #include <clang/AST/RecursiveASTVisitor.h> #include <clang/Frontend/CompilerInstance.h> using namespace clang::tooling; using namespace clang; using namespace clang::ast_matchers; using namespace llvm; using namespace llvm::cl;
|
库文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
| clangAST.lib clangBasic.lib clangFrontend.lib clangIndex.lib clangLex.lib clangSema.lib clangSerialization.lib clangTooling.lib clangARCMigrate.lib LLVMAArch64CodeGen.lib LLVMAArch64AsmParser.lib LLVMAArch64AsmPrinter.lib LLVMAArch64Desc.lib LLVMAArch64Disassembler.lib LLVMAArch64Info.lib LLVMAArch64Utils.lib LLVMAMDGPUCodeGen.lib LLVMAMDGPUAsmParser.lib LLVMAMDGPUAsmPrinter.lib LLVMAMDGPUDesc.lib LLVMAMDGPUDisassembler.lib LLVMAMDGPUInfo.lib LLVMAMDGPUUtils.lib LLVMARMCodeGen.lib LLVMARMAsmParser.lib LLVMARMAsmPrinter.lib LLVMARMDesc.lib LLVMARMDisassembler.lib LLVMARMInfo.lib LLVMARMUtils.lib LLVMBPFCodeGen.lib LLVMBPFAsmParser.lib LLVMBPFAsmPrinter.lib LLVMBPFDesc.lib LLVMBPFDisassembler.lib LLVMBPFInfo.lib LLVMHexagonCodeGen.lib LLVMHexagonAsmParser.lib LLVMHexagonDesc.lib LLVMHexagonDisassembler.lib LLVMHexagonInfo.lib LLVMLanaiCodeGen.lib LLVMLanaiAsmParser.lib LLVMLanaiAsmPrinter.lib LLVMLanaiDesc.lib LLVMLanaiDisassembler.lib LLVMLanaiInfo.lib LLVMMipsCodeGen.lib LLVMMipsAsmParser.lib LLVMMipsAsmPrinter.lib LLVMMipsDesc.lib LLVMMipsDisassembler.lib LLVMMipsInfo.lib LLVMMSP430CodeGen.lib LLVMMSP430AsmParser.lib LLVMMSP430AsmPrinter.lib LLVMMSP430Desc.lib LLVMMSP430Disassembler.lib LLVMMSP430Info.lib LLVMNVPTXCodeGen.lib LLVMNVPTXAsmPrinter.lib LLVMNVPTXDesc.lib LLVMNVPTXInfo.lib LLVMPowerPCCodeGen.lib LLVMPowerPCAsmParser.lib LLVMPowerPCAsmPrinter.lib LLVMPowerPCDesc.lib LLVMPowerPCDisassembler.lib LLVMPowerPCInfo.lib LLVMSparcCodeGen.lib LLVMSparcAsmParser.lib LLVMSparcAsmPrinter.lib LLVMSparcDesc.lib LLVMSparcDisassembler.lib LLVMSparcInfo.lib LLVMSystemZCodeGen.lib LLVMSystemZAsmParser.lib LLVMSystemZAsmPrinter.lib LLVMSystemZDesc.lib LLVMSystemZDisassembler.lib LLVMSystemZInfo.lib LLVMWebAssemblyCodeGen.lib LLVMWebAssemblyAsmParser.lib LLVMWebAssemblyAsmPrinter.lib LLVMWebAssemblyDesc.lib LLVMWebAssemblyDisassembler.lib LLVMWebAssemblyInfo.lib LLVMX86CodeGen.lib LLVMX86AsmParser.lib LLVMX86AsmPrinter.lib LLVMX86Desc.lib LLVMX86Disassembler.lib LLVMX86Info.lib LLVMX86Utils.lib LLVMXCoreCodeGen.lib LLVMXCoreAsmPrinter.lib LLVMXCoreDesc.lib LLVMXCoreDisassembler.lib LLVMXCoreInfo.lib LLVMCore.lib LLVMSupport.lib clangStaticAnalyzerCheckers.lib clangStaticAnalyzerCore.lib clangCrossTU.lib clangDriver.lib version.lib clangParse.lib LLVMOption.lib clangEdit.lib clangAnalysis.lib clangASTMatchers.lib clangFormat.lib clangToolingInclusions.lib clangToolingCore.lib clangRewrite.lib LLVMipo.lib LLVMVectorize.lib LLVMIRReader.lib LLVMAsmParser.lib LLVMInstrumentation.lib LLVMLinker.lib LLVMGlobalISel.lib LLVMAsmPrinter.lib LLVMSelectionDAG.lib LLVMCodeGen.lib LLVMScalarOpts.lib LLVMAggressiveInstCombine.lib LLVMInstCombine.lib LLVMBitWriter.lib LLVMTarget.lib LLVMTransformUtils.lib LLVMAnalysis.lib LLVMProfileData.lib LLVMObject.lib LLVMBitReader.lib LLVMMCParser.lib LLVMMCDisassembler.lib LLVMMC.lib LLVMBinaryFormat.lib LLVMDebugInfoCodeView.lib LLVMDebugInfoMSF.lib psapi.lib uuid.lib advapi32.lib delayimp.lib LLVMDemangle.lib kernel32.lib user32.lib gdi32.lib winspool.lib oleaut32.lib comdlg32.lib
|