一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
编写插件代码
文件和顶级节点的解析
导入插件使用的头文件和命名空间
#include <iostream>
#include "clang/AST/AST.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
using namespace clang;
using namespace std;
using namespace llvm;
定义命名空间、定义HKASTAction类,继承自系统的PluginASTAction类
namespace HKPlugin {
class HKASTAction:public PluginASTAction{
};
}
注册插件
static FrontendPluginRegistry::Add<HKPlugin::HKASTAction> X("HKPlugin","this is the description");
参数1:插件名称参数2:插件描述 现有的需求分为三个步骤:- 【第一步】读取代码
- 【第二步】找到目标类型定义的属性和修饰符
- 【第三步】不符合标准,提示警告
实现需求的第一步读取代码,需要用到AST语法树,然后对AST节点进行解析
我们可以使用以下两个函数
CreateASTConsumerParseArgs在HKASTAction类中,重写CreateASTConsumer和ParseArgs函数
namespace HKPlugin {
class HKASTAction:public PluginASTAction{
public:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return unique_ptr<ASTConsumer> (new ASTConsumer);
}
bool ParseArgs(const CompilerInstance &CI, const std::vector<std::string> &arg) {
return true;
}
};
}
ASTConsumer是系统提供的基类,作为基类,它的作用大多有两种
- 抽取代码
- 由开发者继承,实现它的子类,对其进行扩展
所以,我们不能直接使用ASTConsumer,需要对其进行继承,实现自定义子类
namespace HKPlugin {
class HKConsumer:public ASTConsumer{
public:
bool HandleTopLevelDecl(DeclGroupRef D) {
cout<<"正在解析..."<<endl;
return true;
}
void HandleTranslationUnit(ASTContext &Ctx) {
cout<<"文件解析完成..."<<endl;
}
};
class HKASTAction:public PluginASTAction{
public:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return unique_ptr<HKConsumer> (new HKConsumer);
}
bool ParseArgs(const CompilerInstance &CI, const std::vector<std::string> &arg) {
return true;
}
};
}
重写HandleTopLevelDecl和HandleTranslationUnit函数
HandleTopLevelDecl:顶级节点解析回调函数,顶级节点,例如:全局变量、函数定义、属性
HandleTranslationUnit:整个文件解析完成后的回调
编译HKPlugin项目,在项目的Products目录下,找到编译出的clang可执行文件
同样在
Products目录下,找到HKPlugin.dylib
使用插件,测试文件和顶级节点的解析
创建hello.m文件,写入以下代码:
int sum(int a);
int a;
int sum(int a){
int b = 10;
return 10 + b;
}
int sum2(int a,int b){
int c = 10;
return a + b + c;
}
使用以下命令,测试插件
//自己编译的clang路径 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.5.sdk/ -Xclang -load -Xclang 插件(.dylib)路径 -Xclang -add-plugin -Xclang 插件名称 -c 源码路径
/Volumes/study/Source/llvm-hk/build_xcode/Debug/bin/clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator14.5.sdk/ -Xclang -load -Xclang /Volumes/study/Source/llvm-hk/build_xcode/Debug/lib/HKPlugin.dylib -Xclang -add-plugin -Xclang HKPlugin -c hello.m
-------------------------
//输出以下内容:
正在解析...
正在解析...
正在解析...
正在解析...
文件解析完成...
- 共解析出四个顶级节点