一起养成写作习惯!这是我参与「日新计划 4 月更文挑战」的第7天,点击查看活动详情。
分析OC
代码
搭建App
项目,打开ViewController字符是什么.m
文件,写入以下代码:
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic, strong) NSString* name;
@property(nonatomic, strong) NSArray* arrs;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
@end
生成AST
代码,找到属性的声明
- 在
ObjCPropertyDecl
节点中,可以找到属APP性的声明,包含属性的类型和修饰符
AST
节点的过滤
系统API
提供MatchFinder
,用于AST
语法树节点的查找
其中addMatcher函数,可以查找指定节点
void addMatcher(const DeclarationMatcher &NodeMatch,
MatchCallback *Action);
-
参数1
:设置指定节点 -
参数2
:执行xcode是什么软件回字符调,此处并非使用回调函数,而是一个回调类。需要继承MatchCallback
系统类,实现自己的子测试用例类
添加MatchFinder所在命名空间
using namespace clang::ast_matchers;
实现HKMatchHandler
回调类,继承自MatchCallback
class HKMatchHandler:public MatchFinder::MatchCallback{
public:
void run(const MatchFinder::MatchResult &Result) {
const ObjCPropertyDecl *propertyDecl = Result.Nodes.getNodeAs<ObjCPropertyDecl>("objcPropertyDecl");
if(propertyDecl){
string typeStr = propertyDecl->getType().getAsString();
cout<<"------拿到了:"<<typeStr<<endl;
}
}
};
- 必须实现
run
函数,它就是真正的回调函数 - 通xcode是什么软件过
Result
结果,获取节点对象 - 通过节点对象的
getType().getAsString()
,以字符串的形式返回属性类型
在HKxcode是什么意思Cons测试用例umer
类中,定义私有MatchFinder
和H测试仪KMatchHandler
,重写构造方法,添加AST
节点过滤器
class HKConsumer:public ASTConsumer{
private:
MatchFinder matcher;
HKMatchHandler handler;
public:
HKConsumer(){
matcher.addMatcher(objcPropertyDecl().bind("objcPropertyDecl"), &handler);
}
};
- 解析语法树,查找
objcPropertyDecl
节点
在文件解析完成的回调函数中,调用matcher
的matchAST
函数,将文件的语法树传入过滤器
void HandleTranslationUnit(ASTContext &Ctx) {
cout<<"文件解析完成..."<<endl;
matcher.matchAST(Ctx);
}
测试插件
- 通过语法树分析,可以找到属性的声明,包含属性的类型和修饰符
- 但也存在一些问题,在预处理阶段,头文件会被展开,测试抑郁程度的问卷我们可能会获Xcode取到系统头文件中的属性,所以我们要想办法过滤掉系统文件中的代码
过滤系统文件
可以通过文件路径判断系统文件,因为系统文件都存在于/Applicappointmentations/Xcode.app/
开头的目录中
在PluginASTAction
类中,存在CompilerInstance
类型的CI
参数
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override = 0;
-
CI
为编译器实例对象,可以通过它获取到文件路径,以及警告的提示
重写HKConsumer
的构造函数,增加CI
参数
HKConsumer(CompilerInstance &CI){
matcher.addMatcher(objcPropertyDecl().bind("objcPropertyDecl"), &handler);
}
在HKASxcode修改项目名TAction
类中,创建ASTConsumer
时,将CI
传入
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
return unique_ptr<HKConsumer> (new HKConsumer(CI));
}
重写HKMatchHandler
的xcode汽车报价构造函数,增加CI
参数。定义私有CompilerInstance
,通过构造函数对其赋值
class HKMatchHandler:public MatchFinder::MatchCallback{
private:
CompilerInstance &CI;
public:
HKMatchHandler(CompilerInstance &CI):CI(CI){
}
};
在HKConsumer
的构造函数中,对HKMatchHandler
中的C字符串逆序输出I
进行传递
HKConsumer(CompilerInstance &CI):handler(CI){
matcher.addMatcher(objcPropertyDecl().bind("objcPropertyDecl"), &handler);
}
在HKMatchHaxcode是什么软件ndxcode是什么软件ler使用CI,获取文件路径并进行过滤
class HKMatchHandler:public MatchFinder::MatchCallback{
private:
CompilerInstance &CI;
bool isUserSourceCode(const string fileName){
if(fileName.empty()){
return false;
}
if(fileName.find("/Applications/Xcode.app/")==0){
return false;
}
return true;
}
public:
HKMatchHandler(CompilerInstance &CI):CI(CI){
}
void run(const MatchFinder::MatchResult &Result) {
const ObjCPropertyDecl *propertyDecl = Result.Nodes.getNodeAs<ObjCPropertyDecl>("objcPropertyDecl");
string fileName = CI.getSourceManager().getFilename(propertyDecl->getSourceRange().getBegin()).str();
if(propertyDecl && isUserSourceCode(fileName)){
string typeStr = propertyDecl->getType().getAsString();
cout<<"------拿到了:"<<typeStr<<endl;
}
}
};
- 通过
CI.getSourceManager().getFilename
获取文件名称,包含文件路径 - 需要传入
SourceLocation
,可以通过节点的propertyDecl测试你的自卑程度->getSourceRange().getBegin()
获得 - 实现
isUserSourceCode
函数,判断路径非空,并且非/Applications/Xcode.app/
目录开头,视为自定义文件
测试插件
文件解析完成...
------拿到了:NSString *
------拿到了:NSArray *
- 成功过滤系统文件,获取到自定义文件中的两个属性