背景
由于项目需要,需要解析cpp代码,经调查llvm,clang前端有这样的库可以使用,找到libtooling,功能强大,有完善的文档,于是写一系列的文章介绍libtooling库的使用,
安装llvm
欢迎关注专栏
前置知识
AST是什么:
LLVM Clang AST是指Clang编译器前端生成的抽象语法树(Abstract Syntax Tree)
解析的代码,被表示成树状结构,libtooling从抽象语法树解析
使用clang命令输出AST
clang -Xclang -ast-dump -fsyntax-only test.cc
test.cc内容
#include <stdio.h>
void test(int a, int b) {
int c = a + b -3
}
clang输出
`-FunctionDecl 0x7fc46e075608 <line:2:1, line:4:1> line:2:6 test 'void (int, int)'
|-ParmVarDecl 0x7fc46e075488 <col:11, col:15> col:15 used a 'int'
|-ParmVarDecl 0x7fc46e075508 <col:18, col:22> col:22 used b 'int'
`-CompoundStmt 0x7fc46e075880 <col:25, line:4:1>
`-DeclStmt 0x7fc46e075868 <line:3:3, col:19>
`-VarDecl 0x7fc46e075730 <col:3, col:18> col:7 c 'int' cinit
`-BinaryOperator 0x7fc46e075848 <col:11, col:18> 'int' '-'
|-BinaryOperator 0x7fc46e075808 <col:11, col:15> 'int' '+'
| |-ImplicitCastExpr 0x7fc46e0757d8 <col:11> 'int' <LValueToRValue>
| | `-DeclRefExpr 0x7fc46e075798 <col:11> 'int' lvalue ParmVar 0x7fc46e075488 'a' 'int'
| `-ImplicitCastExpr 0x7fc46e0757f0 <col:15> 'int' <LValueToRValue>
| `-DeclRefExpr 0x7fc46e0757b8 <col:15> 'int' lvalue ParmVar 0x7fc46e075508 'b' 'int'
`-IntegerLiteral 0x7fc46e075828 <col:18> 'int' 3
其中FunctionDecl就是函数节点,VarDecl是变量节点
其它:关于FrontendAction、ASTConsumer、RecursiveASTVisitor的介绍在这里
https://blog.csdn.net/weixin_43837016/article/details/140134391
代码
以下代码使用libtooling 遍历变量,函数,类等
#include <clang/AST/AST.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/ASTMatchers/ASTMatchFinder.h>
#include <clang/Tooling/Tooling.h>
#include <iostream>
using namespace clang;
using namespace clang::tooling;
using namespace clang::ast_matchers;
using namespace llvm;
using namespace std;
const char *toolOverview = "demo";
static cl::OptionCategory optCat("demo Options");
bool checkIfSystem(const Decl *D)
{
if (!D) {
return true;
}
ASTContext & context = D->getASTContext();
SourceManager &srcMgr = context.getSourceManager();
SourceLocation srcLoc = D->getLocation();
SourceLocation beginSrcLoc = D->getBeginLoc();
SourceLocation expansionLoc = srcMgr.getExpansionLoc(beginSrcLoc);
if (srcMgr.isInSystemHeader(expansionLoc)) {
return true;
}
if (srcMgr.getFileCharacteristic(srcLoc) == SrcMgr::C_System) {
return true;
}
if (srcMgr.getFileCharacteristic(srcLoc) == SrcMgr::C_ExternCSystem) {
return true;
}
return false;
}
class MyVisitor : public RecursiveASTVisitor<MyVisitor> {
public:
explicit MyVisitor() {}
bool VisitVarDecl(VarDecl *VD) {
if (checkIfSystem(VD)) {
return true;
}
std::cout << "Variable name: " << VD->getName().str() << std::endl;
return true;
}
bool VisitFunctionDecl(const FunctionDecl * FD) {
if (checkIfSystem(FD)) {
return true;
}
std::cout << "FunctionDecl name: " << FD->getName().str() << std::endl;
return true;
}
bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD) {
if (checkIfSystem(CXXRD)) {
return true;
}
std::cout << "CXXRecordDecl name: " << CXXRD->getName().str() << std::endl;
return true;
}
};
class MyConsumer : public ASTConsumer {
public:
explicit MyConsumer(ASTContext *Context) : Context(Context) {}
void HandleTranslationUnit(ASTContext &Context) override {
MyVisitor visitor;
visitor.TraverseDecl(Context.getTranslationUnitDecl());
}
private:
ASTContext *Context;
};
class MyAction : public ASTFrontendAction {
public:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef) override {
return std::make_unique<MyConsumer>(&CI.getASTContext());
}
};
int main(int argc, const char *argv[])
{
auto OptionsParserExpected = CommonOptionsParser::create(argc, argv, optCat, cl::OneOrMore, toolOverview);
if (!OptionsParserExpected) {
llvm::errs() << "Failed to parse options: " << toString(OptionsParserExpected.takeError()) << "\n";
return 1;
}
CommonOptionsParser &OptionsParser = *OptionsParserExpected;
ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());
Tool.run(newFrontendActionFactory<MyAction>().get());
return 0;
}
cmake文件:
cmake_minimum_required(VERSION 3.4.3)
project(demo2)
set(CMAKE_CXX_COMPILER "clang++")
find_package(Clang REQUIRED)
include_directories(${Clang_INCLUDE_DIRS} ${LLVM_MAIN_INCLUDE_DIR})
add_executable(demo2
demo2.cpp
)
target_link_libraries(demo2
PUBLIC
clangAST
clangASTMatchers
clangBasic
clangFrontend
clangSerialization
clangTooling
)
被解析的cpp代码:
#include <string>
#include <iostream>
using namespace std;
class Test {
public:
void p() {};
};
int main(int argc, const char *argv[]){
string s = "abc";
return 0;
}
打印结果:
CXXRecordDecl name: Test
FunctionDecl name: p
FunctionDecl name: main
Variable name: argc
Variable name: argv
Variable name: s
引用: