Clang之二 : AST节点解析
前言:为了基于clang对我们的代码做一些分析,我们最常用的就是去分析AST(抽象语法树),为了能达到分析AST的目的,我们首先需要做的是能看懂AST,因此本篇博客的目的是带大家学习一下AST中的常用节点以及其所对应的语法点 (这里只匹配OC语法)
一、AST节点含义解析
1、TranslationUnitDecl:
顶层节点
2、TypedefDecl:
3、ObjCInterfaceDecl
这个就是oc接口的声明
ex:
@interface Foo
@end
4、ObjCCategoryDecl
这个就是oc category的声明
ex:
@interface Foo (Additions)
@end
5、ObjCImplementationDecl
这个就是oc implementation的声明
@implementation Foo
@end
6、ObjCMethodDecl
这个节点表示:函数的声明和实现。这个节点是最重要的,也是最常见的一个节点!
ex:
@interface Foo
- (void)method;
@end
@implementation Foo - (void)method {} @end
这种类型的节点,内部肯定会会有子节点。如:ImplicitParamDecl(oc中任何函数都有这个节点,因为必备这个参数)CompoundStmt (函数体)、VarDecl(局部变量)。
例如:我们看一下setUpHaoyuView 这个函数的AST结构如下:
ObjCMethodDecl //消息发送调用的函数
- ImplicitParamDecl //隐式参数 self
- ImplicitParamDecl //隐式参数 _cmd
- CompoundStmt //函数体
- CallExpr //调用c或者c++函数
- ImplicitCastExpr //隐式类型转换
- DeclRefExpr //表达式变量
具体的实际代码以及转换后的AST如下:
- (void)setUpHaoyuView { //原始代码
NSString *ahaoyuHaha = [[NSString alloc] initWithString:@"Hello"];
[self setupGTestFunc:ahaoyuHaha];
}
AST: //转化后AST
|-ObjCMethodDecl 0x7f9ffcb3ac30 <line:28:1, line:31:1> line:28:1 - setUpHaoyuView 'void'
| | |-ImplicitParamDecl 0x7f9ffe013648 <<invalid sloc>> <invalid sloc> implicit used self 'UIViewController *const __strong'
| | |-ImplicitParamDecl 0x7f9ffe0136a8 <<invalid sloc>> <invalid sloc> implicit _cmd 'SEL':'SEL *'
| | |-VarDecl 0x7f9ffe013720 <line:29:5, col:69> col:15 used ahaoyuHaha 'NSString *__strong' cinit //局部变量声明,每一个方法的AST都是,先罗列代码中所有的局部变量,然后列出方法体。
| | | `-ExprWithCleanups 0x7f9ffe013a60 <col:28, col:69> 'NSString *'
| | | `-ImplicitCastExpr 0x7f9ffe013a48 <col:28, col:69> 'NSString *' <ARCConsumeObject>
| | | `-ObjCMessageExpr 0x7f9ffe013a10 <col:28, col:69> 'NSString *' selector=initWithString:
| | | |-ImplicitCastExpr 0x7f9ffe0137c0 <col:29, col:44> 'NSString *' <ARCConsumeObject>
| | | | `-ObjCMessageExpr 0x7f9ffe013790 <col:29, col:44> 'NSString *' selector=alloc class='NSString'
| | | `-ObjCStringLiteral 0x7f9ffe013838 <col:61, col:62> 'NSString *'
| | | `-StringLiteral 0x7f9ffe013818 <col:62> 'char [6]' lvalue "Hello"
| | `-CompoundStmt 0x7f9ffe013b68 <line:28:24, line:31:1> //方法体{ }
| | |-DeclStmt 0x7f9ffe013a78 <line:29:5, col:70>
| | | `-VarDecl 0x7f9ffe013720 <col:5, col:69> col:15 used ahaoyuHaha 'NSString *__strong' cinit
| | | `-ExprWithCleanups 0x7f9ffe013a60 <col:28, col:69> 'NSString *'
| | | `-ImplicitCastExpr 0x7f9ffe013a48 <col:28, col:69> 'NSString *' <ARCConsumeObject>
| | | `-ObjCMessageExpr 0x7f9ffe013a10 <col:28, col:69> 'NSString *' selector=initWithString:
| | | |-ImplicitCastExpr 0x7f9ffe0137c0 <col:29, col:44> 'NSString *' <ARCConsumeObject>
| | | | `-ObjCMessageExpr 0x7f9ffe013790 <col:29, col:44> 'NSString *' selector=alloc class='NSString'
| | | `-ObjCStringLiteral 0x7f9ffe013838 <col:61, col:62> 'NSString *'
| | | `-StringLiteral 0x7f9ffe013818 <col:62> 'char [6]' lvalue "Hello"
| | `-ObjCMessageExpr 0x7f9ffe013b30 <line:30:5, col:36> 'void' selector=setupGTestFunc:
| | |-ImplicitCastExpr 0x7f9ffe013b00 <col:6> 'UIViewController *' <LValueToRValue>
| | | `-DeclRefExpr 0x7f9ffe013a90 <col:6> 'UIViewController *const __strong' lvalue ImplicitParam 0x7f9ffe013648 'self' 'UIViewController *const __strong'
| | `-ImplicitCastExpr 0x7f9ffe013b18 <col:26> 'NSString *' <LValueToRValue>
| | `-DeclRefExpr 0x7f9ffe013ac8 <col:26> 'NSString *__strong' lvalue Var 0x7f9ffe013720 'ahaoyuHaha' 'NSString *__strong'
7、ObjCPropertyDecl
这个节点表示:我们程序中定义的oc属性
@interface Foo
@property BOOL enabled;
@end
8、ObjCIvarDecl
表示:实例变量(私有变量)
ex:
@implementation Foo
{
BOOL _enabled;
}
@end
9、VarDecl
这个节点:只代表局部变量,不能代表成员变量。
函数体内的局部变量
10、ObjCPropertyImplDecl
代表属性在类或者分类的implementation部分的实现声明,@synthesize prop1 = ivar1;
11、ImplicitParamDecl:
继承自VarDecl,代表各种类型的隐式参数。
例如:c++中的this、virtual table pointers、以及captured context
或者oc中的:self, _cmd。每个oc函数默认会有这两个参数
12、ParmVarDecl:
该节点表示:参数声明
OC属性在AST中常见的两种变现形式:
1)声明属性的同时,使用了synthesize关键字。
@property (nonatomic, strong) NSString *haoyuString;
@synthesize haoyuString = _haoyuString;
生成的AST如下:
ObjCIvarDecl :指出属性的实例变量 即:_haoyuString
ObjCPropertyImplDecl:指出haoyuString的synthesize
- ObjCProperty:这不是节点了:DeclNodes.inc文件中的 一个宏,代表对应的属性
- ObjCIvar:同上 ,代表实例变量。理解为叶子!!
|-ObjCIvarDecl 0x7ff2a6a68d88 <line:21:27> col:27 referenced _haoyuString 'NSString *__strong' synthesize private
| |-ObjCPropertyImplDecl 0x7ff2a6a68de0 <col:1, col:27> col:13 haoyuString synthesize
| | |-ObjCProperty 0x7ff2a6a33e00 'haoyuString'
| | `-ObjCIvar 0x7ff2a6a68d88 '_haoyuString' 'NSString *__strong'
2)不使用synthesize关键字
@property (nonatomic, strong) NSString *haoyuString;
生成的AST如下:
ObjCPropertyDecl 0x7f96f693a400 <line:13:1, col:41> col:41 haoyuString 'NSString *' readwrite nonatomic strong
| |-ObjCMethodDecl 0x7f96f693a478 <col:41> col:41 implicit - haoyuString 'NSString *'
| |-ObjCMethodDecl 0x7f96f693a4f8 <col:41> col:41 implicit - setHaoyuString: 'void'
| | `-ParmVarDecl 0x7f96f693a578 <col:41> col:41 haoyuString 'NSString *'
3)使用dynamic关键字,不会创建setter和getter函数
ObjCPropertyImplDecl 0x7fee7e02f788 <line:21:1, col:10> col:10 haoyuString dynamic
| | `-ObjCProperty 0x7fee7eb72000 'haoyuString'
//可以看到这时没有ObjCMethodDecl节点出现。
以上的
常见的数据类型
1、ObjCStringLiteral:
该节点对应:oc中NSString 类型
2、StringLiteral:
char[]类型的字符表示。oc中字符串用char类型来表示。
来看一个例子,字符串声明在AST中表示:
NSString *str = @"hahahah"; //oc中赋值代码
AST中的表示为:
VarDecl 0x7fd06cc91ae8 <line:24:5, col:22> col:15 str 'NSString *__strong' cinit //声明局部变量
| | | `-ObjCStringLiteral 0x7fd06cc91ba8 <col:21, col:22> 'NSString *' //声明变量类型
| | | `-StringLiteral 0x7fd06cc91b88 <col:22> 'char [8]' lvalue "hahahah" //右边的字符串有char类型表示
3、IntegerLiteral:
对应:整型变量,如NSInteger、int
NSInteger haoyuA = 10;
AST:
|-VarDecl 0x7ffe6db8c0a0 <line:26:5, col:24> col:15 haoyuA 'NSInteger':'long' cinit
| | | `-ImplicitCastExpr 0x7ffe6db8c120 <col:24> 'NSInteger':'long' <IntegralCast>
| | | `-IntegerLiteral 0x7ffe6db8c100 <col:24> 'int' 10
4、FloatingLiteral:
对应:浮点数
CGFloat haoFloat = 2.3f;
AST:
-VarDecl 0x7ffe6db8c160 <line:27:5, col:24> col:13 haoFloat 'CGFloat':'double' cinit
| | | `-ImplicitCastExpr 0x7ffe6db8c1e0 <col:24> 'CGFloat':'double' <FloatingCast>
| | | `-FloatingLiteral 0x7ffe6db8c1c0 <col:24> 'float' 2.300000e+00
5、ObjCArrayLiteral
数组
NSArray *arr = @["sss",];
AST表示如下:
|-VarDecl 0x7fec3c1cf050 <line:28:5, col:32> col:14 arr 'NSArray *__strong' cinit
| | | `-ExprWithCleanups 0x7fec3c1c8b68 <col:20, col:32> 'NSArray *'//这里可以看到,arr这个局部变量被自动添加了autoRelease。
| | | `-ImplicitCastExpr 0x7fec3c1c8b50 <col:20, col:32> 'NSArray *' <ARCReclaimReturnedObject>
| | | `-ObjCArrayLiteral 0x7fec3c1c8b18 <col:20, col:32> 'NSArray *' //数组类型
| | | |-ImplicitCastExpr 0x7fec3c1c8ae8 <col:22> 'ObjectType _Nonnull':'id' <BitCast>
| | | | `-ObjCStringLiteral 0x7fec3c1c8ac8 <col:22> 'NSString *' //代表数组中第一个字符串元素
| | | | `-StringLiteral 0x7fec3c1cf108 <col:22> 'char [4]' lvalue "sss"
| | | `-ImplicitCastExpr 0x7fec3c1c8b00 <col:28, col:31> 'ObjectType _Nonnull':'id' <BitCast>
| | | `-ImplicitCastExpr 0x7fec3c1c8638 <col:28, col:31> 'NSNumber *' <ARCReclaimReturnedObject>
| | | `-ObjCBoxedExpr 0x7fec3c1c8610 <col:28, col:31> 'NSNumber *' selector=numberWithInt: //代表数组中第2个元素:@(1)
| | | `-ParenExpr 0x7fec3c1cf148 <col:29, col:31> 'int'
| | | `-IntegerLiteral 0x7fec3c1cf128 <col:30> 'int' 1
6、ObjCDictionaryLiteral
对应:字典类型
NSDictionary *dic = @{@"key11":@"value11"};
AST:
|-VarDecl 0x7fec3c1c8be0 <line:29:5, col:46> col:19 dic 'NSDictionary *__strong' cinit
| | | `-ExprWithCleanups 0x7fec3c1c9510 <col:25, col:46> 'NSDictionary *'
| | | `-ImplicitCastExpr 0x7fec3c1c94f8 <col:25, col:46> 'NSDictionary *' <ARCReclaimReturnedObject>
| | | `-ObjCDictionaryLiteral 0x7fec3c1c94c0 <col:25, col:46> 'NSDictionary *' //表示代码中的字典NSDictionary
| | | |-ImplicitCastExpr 0x7fec3c1c9490 <col:27, col:28> 'id<NSCopying> _Nonnull':'id<NSCopying>' <BitCast> //字典中声明的key,按照字符串类型来解析。
| | | | `-ObjCStringLiteral 0x7fec3c1c8cb8 <col:27, col:28> 'NSString *'
| | | | `-StringLiteral 0x7fec3c1c8c98 <col:28> 'char [6]' lvalue "key11"
| | | `-ImplicitCastExpr 0x7fec3c1c94a8 <col:36, col:37> 'ObjectType _Nonnull':'id' <BitCast>
| | | `-ObjCStringLiteral 0x7fec3c1c8cf8 <col:36, col:37> 'NSString *' //字典中声明的value,同样按照字符串类型来解析
| | | `-StringLiteral 0x7fec3c1c8cd8 <col:37> 'char [8]' lvalue "value11"
Type 类型:
1、TypedefDecl:
对应typedef
2、BlockPointerType:
block的指针类型声明
3、ParenType:
block的函数原型
4、FunctionProtoType:
函数协议类型
5、TypedefType:(注意同TypedefDecl区别)
参数类型或者是返回值类型,包含Typedef类型以及BuiltinType编译原类型
语法
1、CompoundStmt:
该节点代表:代表了像{ stmt stmt } 这样的statement的集合。实际上就是用'{}' and '{{}}' 包裹的代码块。
例如:函数{} 或者 for循环 for (;;) {{}} 这些形式的代码中,的{} 或者 {{}}。
其内部会包含很多子节点。
2、DeclStmt:
适配器类,用于混合声明与语句和表达式。
例如,CompoundStmt混合了语句、表达式和声明(变量、类型)。另一个例子是ForStmt,其中第一个语句可以是表达式或声明。
文档上写的很抽象,有些博客上写的是:变量声明
,这里感觉不恰当,应该是语句声明。常出现在局部变量的声明语句解析出来的AST中。如:
NSString *str = @"hahahah";
在AST中对应的表示为:
|-DeclStmt 0x7f9ffc07b1c8 <line:22:5, col:31> //语句声明
| | | `-VarDecl 0x7f9ffc07b0e8 <col:5, col:22> col:15 str 'NSString *__strong' cinit //局部变量声明
| | | `-ObjCStringLiteral 0x7f9ffc07b1a8 <col:21, col:22> 'NSString *'
| | | `-StringLiteral 0x7f9ffc07b188 <col:22> 'char [8]' lvalue "hahahah"
3、 DeclRefExpr:
该节点对应的是:表达式中使用到的变量。例如:
if(x)
\bool x
\if(x) { }
表达式中,x就是DeclRefExpr。常见的结构组合如下:ObjCMessageExpr ImplicitCastExpr DeclRefExpr:表达式的变量声明 (同DeclStmt区别,后者是变量声明,前者是在表>达式中出现的变量)
DeclStmt 同DeclRefExpr区别:
//以下面的代码为例。
NSString *ahaoyuHaha = [[NSString alloc] initWithString:@"Hello"];
[self setupGTestFunc];
//在AST中:
ahaoyuHaha :在AST中就是DeclStmt.
self:在AST中就是DeclRefExpr.
4、ObjCAutoreleasePoolStmt
该节点:Matches an Objective-C autorelease pool statement.
Given
@autoreleasepool {
int x = 0;
}
autoreleasePoolStmt(stmt()) matches the declaration of "x"
inside the autorelease pool.
5、ReturnStmt:
return的表达式,多个return出口有多个,这就是为啥编译也会变慢的原因
6、IfStmt:
if表达语句
7、ObjCAtSynchronizedStmt:
对应@Synchronized。注意不是
synthesize
!!
8、ObjCAtTryStmt:
对应@try
9、ForStmt:
对应for
10、UnaryOperator:
对应i++
11、ObjCAtCatchStmt:
对应@catch
常用表达式:
1、ExprWithCleanups
表示一个表达式(通常是一个完整的表达式),该表达式引入要在子表达式求值结束时运行的清理。
表达式引入的清理最常见的来源是c++中的临时对象,但是其他几种表达式可以创建清理,包括在ARC中返回一个Objective-C指针的每个调用。
此表达式还跟踪子表达式是否包含潜在计算的block。block的生命周期是封闭范围的范围。
出现场景:函数体内出现的局部变量等。
NSString *haoyu = [NSString alloc] initwithString:@"xxx"];
std::string str = std::string();
通俗一些理解就是:ARC下带上了autorelease的变量。
2、PseudoObjectExpr:
OC属性get方法的返回类型。
这里暂且也先这样理解,6.7经常组合出现
3、OpaqueValueExpr:
文档写的太抽象了,没看懂。
暂且理解为:关键字表达式。self.
4、ObjCPropertyRefExpr:
属性表达式。例如:self.haoyuString = @"xxxx";
5、ObjCIvarRefExpr:
私有变量参与的表达式,比如:_aaa=@“xxx”
6、ImplicitCastExpr:
隐式转换,<IntegralCast>代表数字类型的转换,'int64_t':'long long' <LValueToRValue>代表int64_t转成longlong,<BitCast>代表位转换, <ARCReclaimReturnedObject>代表ARC模式下的返回值,可以假设带上了autorelease,
7、CallExpr:
调用C/C++函数方法。例如: x.y() 或 y() 或 X x 或 x.y() 或 y()
8、 BlockExpr:
该节点表示block的实现
例如: "^{ }" 或 void f() { ^{}(); }
9、ObjCBoxedExpr:
通常对应 @() 用法。
例如: BOOL isTest = @(1); 会被解析成:
ObjCBoxedExpr 0x7fa48d188710 <col:19, col:22> 'NSNumber *' selector=numberWithInt: //将int转换成number
10、ParenExpr:
表示括号表达式,常跟上面的一起出现。
11、CStyleCastExpr:
c语言类型的转换
12、ObjCSubscriptRefExpr:
NSDictionary[]对应的方法调用
13、ObjCMessageExpr:
表示oc中消息发送的节点.
例如: [[NSString alloc] initWithString:@"Hello"]; 这里会产生2个ObjCMessageExpr节点。
我们看一下block
在AST
中表示:
源代码如下:
//特意把行号也标注上了,因为在AST中会标注每个节点在原文件中的位置!
29 - (void)setUpHaoyuView {
30 NSString *ahaoyuHaha = [[NSString alloc] initWithString:@"Hello"];
31 // [self setupGTestFunc:ahaoyuHaha];
32 // self.haoyuString = @"aaaa";
33 // BOOL isTest = @(1);
34 void (^haoyuTestBlcok)(void) = ^{
35 [self setupGTestFunc:ahaoyuHaha];
36 };
37 }
|-ObjCMethodDecl 0x7f96f696f230 <line:29:1, line:37:1> line:29:1 - setUpHaoyuView 'void'
| | |-ImplicitParamDecl 0x7f96f693c7b0 <<invalid sloc>> <invalid sloc> implicit used self 'UIViewController *const __strong'
| | |-ImplicitParamDecl 0x7f96f693c810 <<invalid sloc>> <invalid sloc> implicit _cmd 'SEL':'SEL *'
| | |-VarDecl 0x7f96f693c888 <line:30:5, col:69> col:15 used ahaoyuHaha 'NSString *__strong' cinit
| | | `-ExprWithCleanups 0x7f96f693cbc0 <col:28, col:69> 'NSString *'
| | | `-ImplicitCastExpr 0x7f96f693cba8 <col:28, col:69> 'NSString *' <ARCConsumeObject>
| | | `-ObjCMessageExpr 0x7f96f693cb70 <col:28, col:69> 'NSString *' selector=initWithString:
| | | |-ImplicitCastExpr 0x7f96f693c928 <col:29, col:44> 'NSString *' <ARCConsumeObject>
| | | | `-ObjCMessageExpr 0x7f96f693c8f8 <col:29, col:44> 'NSString *' selector=alloc class='NSString'
| | | `-ObjCStringLiteral 0x7f96f693c998 <col:61, col:62> 'NSString *'
| | | `-StringLiteral 0x7f96f693c978 <col:62> 'char [6]' lvalue "Hello"
| | |-VarDecl 0x7f96f693cc90 <line:34:5, line:36:5> line:34:12 haoyuTestBlcok 'void (^__strong)(void)' cinit
| | | `-ExprWithCleanups 0x7f96f693cee0 <col:36, line:36:5> 'void (^)(void)'
| | | |-cleanup Block 0x7f96f693ccf0
| | | `-BlockExpr 0x7f96f693cec8 <line:34:36, line:36:5> 'void (^)(void)'
| | | `-BlockDecl 0x7f96f693ccf0 <line:34:36, line:36:5> line:34:36
| | | |-capture ImplicitParam 0x7f96f693c7b0 'self' 'UIViewController *const __strong'
| | | |-capture Var 0x7f96f693c888 'ahaoyuHaha' 'NSString *__strong'
| | | `-CompoundStmt 0x7f96f693ce90 <col:37, line:36:5>
| | | `-ObjCMessageExpr 0x7f96f693ce58 <line:35:9, col:40> 'void' selector=setupGTestFunc:
| | | |-ImplicitCastExpr 0x7f96f693ce28 <col:10> 'UIViewController *' <LValueToRValue>
| | | | `-DeclRefExpr 0x7f96f693cdb8 <col:10> 'UIViewController *const __strong' lvalue ImplicitParam 0x7f96f693c7b0 'self' 'UIViewController *const __strong'
| | | `-ImplicitCastExpr 0x7f96f693ce40 <col:30> 'NSString *' <LValueToRValue>
| | | `-DeclRefExpr 0x7f96f693cdf0 <col:30> 'NSString *const __strong' lvalue Var 0x7f96f693c888 'ahaoyuHaha' 'NSString *__strong'
| | |-BlockDecl 0x7f96f693ccf0 <line:34:36, line:36:5> line:34:36
| | | |-capture ImplicitParam 0x7f96f693c7b0 'self' 'UIViewController *const __strong'
| | | |-capture Var 0x7f96f693c888 'ahaoyuHaha' 'NSString *__strong'
| | | `-CompoundStmt 0x7f96f693ce90 <col:37, line:36:5>
| | | `-ObjCMessageExpr 0x7f96f693ce58 <line:35:9, col:40> 'void' selector=setupGTestFunc:
| | | |-ImplicitCastExpr 0x7f96f693ce28 <col:10> 'UIViewController *' <LValueToRValue>
| | | | `-DeclRefExpr 0x7f96f693cdb8 <col:10> 'UIViewController *const __strong' lvalue ImplicitParam 0x7f96f693c7b0 'self' 'UIViewController *const __strong'
| | | `-ImplicitCastExpr 0x7f96f693ce40 <col:30> 'NSString *' <LValueToRValue>
| | | `-DeclRefExpr 0x7f96f693cdf0 <col:30> 'NSString *const __strong' lvalue Var 0x7f96f693c888 'ahaoyuHaha' 'NSString *__strong'
| | `-CompoundStmt 0x7f96f693cf18 <line:29:24, line:37:1>
| | |-DeclStmt 0x7f96f693cbd8 <line:30:5, col:70>
| | | `-VarDecl 0x7f96f693c888 <col:5, col:69> col:15 used ahaoyuHaha 'NSString *__strong' cinit
| | | `-ExprWithCleanups 0x7f96f693cbc0 <col:28, col:69> 'NSString *'
| | | `-ImplicitCastExpr 0x7f96f693cba8 <col:28, col:69> 'NSString *' <ARCConsumeObject>
| | | `-ObjCMessageExpr 0x7f96f693cb70 <col:28, col:69> 'NSString *' selector=initWithString:
| | | |-ImplicitCastExpr 0x7f96f693c928 <col:29, col:44> 'NSString *' <ARCConsumeObject>
| | | | `-ObjCMessageExpr 0x7f96f693c8f8 <col:29, col:44> 'NSString *' selector=alloc class='NSString'
| | | `-ObjCStringLiteral 0x7f96f693c998 <col:61, col:62> 'NSString *'
| | | `-StringLiteral 0x7f96f693c978 <col:62> 'char [6]' lvalue "Hello"
| | `-DeclStmt 0x7f96f693cf00 <line:34:5, line:36:6>
| | `-VarDecl 0x7f96f693cc90 <line:34:5, line:36:5> line:34:12 haoyuTestBlcok 'void (^__strong)(void)' cinit
| | `-ExprWithCleanups 0x7f96f693cee0 <col:36, line:36:5> 'void (^)(void)'
| | |-cleanup Block 0x7f96f693ccf0
| | `-BlockExpr 0x7f96f693cec8 <line:34:36, line:36:5> 'void (^)(void)'
| | `-BlockDecl 0x7f96f693ccf0 <line:34:36, line:36:5> line:34:36
| | |-capture ImplicitParam 0x7f96f693c7b0 'self' 'UIViewController *const __strong'
| | |-capture Var 0x7f96f693c888 'ahaoyuHaha' 'NSString *__strong'
| | `-CompoundStmt 0x7f96f693ce90 <col:37, line:36:5>
| | `-ObjCMessageExpr 0x7f96f693ce58 <line:35:9, col:40> 'void' selector=setupGTestFunc:
| | |-ImplicitCastExpr 0x7f96f693ce28 <col:10> 'UIViewController *' <LValueToRValue>
| | | `-DeclRefExpr 0x7f96f693cdb8 <col:10> 'UIViewController *const __strong' lvalue ImplicitParam 0x7f96f693c7b0 'self' 'UIViewController *const __strong'
| | `-ImplicitCastExpr 0x7f96f693ce40 <col:30> 'NSString *' <LValueToRValue>
| | `-DeclRefExpr 0x7f96f693cdf0 <col:30> 'NSString *const __strong' lvalue Var 0x7f96f693c888 'ahaoyuHaha' 'NSString *__strong'
分析一下:
因为我们在函数中定义了一个block
类型的临时变量haoyuTestBlcok
,并且为其赋值了一个block
。
所以我们看到结构是这样的:
ObjCMethodDecl:
- ImplicitParamDecl
- ImplicitParamDecl
- VarDecl
- VarDecl: 这个变量声明节点表示的是:我们定义的haoyuTestBlcok 这个变量,因为给它赋的值就是一个block。所有他下面挂有一个BlockDecl节点。
- ExprWithCleanups
- BlockExpr
-BlockDecl:
- capture:这里代表的是捕获的self变量
- capture:这里则是捕获的 ahaoyuHaha 变量
- CompoundStmt:这里代表的是{ }体重的内容。
- ObjCMessageExpr :这里是标识block体内的函数调用。对应:我们在block中执行了 [self setupGTestFunc:ahaoyuHaha]; 函数调用。
- BlockDecl: 这里的block声明对应的 “=” 右边定义的block,它跟上面的BlockDecl实质上一个。我们可以看其内存地址,都为0x7f96f693ccf0。
- CompoundStmt: 这里则代表函数体。我们可以看到他的代码范围是:<line:29:24, line:37:1> 即:29行到37行。
(同样,它里面也会包含一个BlockDecl节点,该节点跟上面的仍然是同一个节点)
//从上面的AST中也可以看出,BlockDecl有多种途径可以到达。 所以我们遍历查找某个节点时也会可以有多种方式。
二、AST结构分析
有了上面的基础后,我们在来看一个相对完整的AST,分析下它的结构。以下面的代码为例,我们分析一下其转化为AST后的内容。
@interface UIViewController ()
@property (nonatomic, strong) NSString *haoyuString;
@property (nonatomic, strong) UIView *haoyuView;
@property (nonatomic, copy) void (^haoyuTestBlcok)(void);
@end
@implementation UIViewController
- (void)viewDidLoad {
NSString *str = @"hahahah";
[self setUpHaoyuView];
}
- (void)setUpHaoyuView {
NSString *ahaoyuHaha = [[NSString alloc] initWithString:@"Hello"];
void (^haoyuTestBlcok)(void) = ^{
[self setupGTestFunc:ahaoyuHaha];
};
}
- (void)setupGTestFunc:(NSString *)stringA {
NSLog(@"=====字符串:%@",stringA);
}
@end
经过clang转换后得到的AST如下:
TranslationUnitDecl 0x7ffc9982de08 <<invalid sloc>> <invalid sloc>
|-TypedefDecl 0x7ffc9982e6a0 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128'
| `-BuiltinType 0x7ffc9982e3a0 '__int128'
|-TypedefDecl 0x7ffc9982e708 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128'
| `-BuiltinType 0x7ffc9982e3c0 'unsigned __int128'
|-TypedefDecl 0x7ffc9982e7a0 <<invalid sloc>> <invalid sloc> implicit SEL 'SEL *'
| `-PointerType 0x7ffc9982e760 'SEL *' imported
| `-BuiltinType 0x7ffc9982e600 'SEL'
|-TypedefDecl 0x7ffc9982e878 <<invalid sloc>> <invalid sloc> implicit id 'id'
| `-ObjCObjectPointerType 0x7ffc9982e820 'id' imported
| `-ObjCObjectType 0x7ffc9982e7f0 'id' imported
|-TypedefDecl 0x7ffc9982e958 <<invalid sloc>> <invalid sloc> implicit Class 'Class'
| `-ObjCObjectPointerType 0x7ffc9982e900 'Class' imported
| `-ObjCObjectType 0x7ffc9982e8d0 'Class' imported
|-ObjCInterfaceDecl 0x7ffc9982e9a8 <<invalid sloc>> <invalid sloc> implicit Protocol
|-TypedefDecl 0x7ffc9982ece8 <<invalid sloc>> <invalid sloc> implicit __NSConstantString 'struct __NSConstantString_tag'
| `-RecordType 0x7ffc9982eb00 'struct __NSConstantString_tag'
| `-Record 0x7ffc9982ea70 '__NSConstantString_tag'
|-TypedefDecl 0x7ffc9982ed80 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *'
| `-PointerType 0x7ffc9982ed40 'char *'
| `-BuiltinType 0x7ffc9982dea0 'char'
|-TypedefDecl 0x7ffc9986b868 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list 'struct __va_list_tag [1]'
| `-ConstantArrayType 0x7ffc9986b810 'struct __va_list_tag [1]' 1
| `-RecordType 0x7ffc9986b690 'struct __va_list_tag'
| `-Record 0x7ffc9986b600 '__va_list_tag'
|-ImportDecl 0x7ffc9986c548 <HaoyuViewController.m:9:1> col:1 implicit UIKit
|-ObjCCategoryDecl 0x7ffc9c0b5748 <line:11:1, line:17:2> line:11:12
| |-ObjCInterface 0x7ffc9c09bd80 'UIViewController'
| |-ObjCPropertyDecl 0x7ffc9c0af400 <line:13:1, col:41> col:41 haoyuString 'NSString *' readwrite nonatomic strong
| |-ObjCMethodDecl 0x7ffc9c0af478 <col:41> col:41 implicit - haoyuString 'NSString *'
| |-ObjCMethodDecl 0x7ffc9c0af4f8 <col:41> col:41 implicit - setHaoyuString: 'void'
| | `-ParmVarDecl 0x7ffc9c0af578 <col:41> col:41 haoyuString 'NSString *'
| |-ObjCPropertyDecl 0x7ffc9c0c5e30 <line:14:1, col:39> col:39 haoyuView 'UIView *' readwrite nonatomic strong
| |-ObjCMethodDecl 0x7ffc9c0c5ea8 <col:39> col:39 implicit - haoyuView 'UIView *'
| |-ObjCMethodDecl 0x7ffc9c0c5f28 <col:39> col:39 implicit - setHaoyuView: 'void'
| | `-ParmVarDecl 0x7ffc9c0c5fa8 <col:39> col:39 haoyuView 'UIView *'
| |-ObjCPropertyDecl 0x7ffc9c0c6168 <line:15:1, col:36> col:36 haoyuTestBlcok 'void (^)(void)' readwrite copy nonatomic
| |-ObjCMethodDecl 0x7ffc9c0d2a00 <col:36> col:36 implicit - haoyuTestBlcok 'void (^)(void)'
| `-ObjCMethodDecl 0x7ffc9c0d2a80 <col:36> col:36 implicit - setHaoyuTestBlcok: 'void'
| `-ParmVarDecl 0x7ffc9c0d2b00 <col:36> col:36 haoyuTestBlcok 'void (^)(void)'
|-ObjCImplementationDecl 0x7ffc9c0e3d08 <line:19:1, line:38:1> line:19:17 UIViewController
| |-ObjCInterface 0x7ffc9c09bd80 'UIViewController'
| |-ObjCMethodDecl 0x7ffc9c0e3d98 <line:21:1, line:24:1> line:21:1 - viewDidLoad 'void'
| | |-ImplicitParamDecl 0x7ffc9c11a610 <<invalid sloc>> <invalid sloc> implicit used self 'UIViewController *const __strong'
| | |-ImplicitParamDecl 0x7ffc9c11a670 <<invalid sloc>> <invalid sloc> implicit _cmd 'SEL':'SEL *'
| | |-VarDecl 0x7ffc9c11a6e8 <line:22:5, col:22> col:15 str 'NSString *__strong' cinit
| | | `-ObjCStringLiteral 0x7ffc9c11a7a8 <col:21, col:22> 'NSString *'
| | | `-StringLiteral 0x7ffc9c11a788 <col:22> 'char [8]' lvalue "hahahah"
| | `-CompoundStmt 0x7ffc9c0b0ff8 <line:21:21, line:24:1>
| | |-DeclStmt 0x7ffc9c11a7c8 <line:22:5, col:31>
| | | `-VarDecl 0x7ffc9c11a6e8 <col:5, col:22> col:15 str 'NSString *__strong' cinit
| | | `-ObjCStringLiteral 0x7ffc9c11a7a8 <col:21, col:22> 'NSString *'
| | | `-StringLiteral 0x7ffc9c11a788 <col:22> 'char [8]' lvalue "hahahah"
| | `-ObjCMessageExpr 0x7ffc9c123030 <line:23:5, col:25> 'void' selector=setUpHaoyuView
| | `-ImplicitCastExpr 0x7ffc9c123018 <col:6> 'UIViewController *' <LValueToRValue>
| | `-DeclRefExpr 0x7ffc9c11a7e0 <col:6> 'UIViewController *const __strong' lvalue ImplicitParam 0x7ffc9c11a610 'self' 'UIViewController *const __strong'
| |-ObjCMethodDecl 0x7ffc9c0e3e30 <line:28:1, line:33:1> line:28:1 - setUpHaoyuView 'void'
| | |-ImplicitParamDecl 0x7ffc9c0b1048 <<invalid sloc>> <invalid sloc> implicit used self 'UIViewController *const __strong'
| | |-ImplicitParamDecl 0x7ffc9c0b10a8 <<invalid sloc>> <invalid sloc> implicit _cmd 'SEL':'SEL *'
| | |-VarDecl 0x7ffc9c0b1120 <line:29:5, col:69> col:15 used ahaoyuHaha 'NSString *__strong' cinit
| | | `-ExprWithCleanups 0x7ffc9c0b1460 <col:28, col:69> 'NSString *'
| | | `-ImplicitCastExpr 0x7ffc9c0b1448 <col:28, col:69> 'NSString *' <ARCConsumeObject>
| | | `-ObjCMessageExpr 0x7ffc9c0b1410 <col:28, col:69> 'NSString *' selector=initWithString:
| | | |-ImplicitCastExpr 0x7ffc9c0b11c0 <col:29, col:44> 'NSString *' <ARCConsumeObject>
| | | | `-ObjCMessageExpr 0x7ffc9c0b1190 <col:29, col:44> 'NSString *' selector=alloc class='NSString'
| | | `-ObjCStringLiteral 0x7ffc9c0b1238 <col:61, col:62> 'NSString *'
| | | `-StringLiteral 0x7ffc9c0b1218 <col:62> 'char [6]' lvalue "Hello"
| | |-VarDecl 0x7ffc9c0b1530 <line:30:5, line:32:5> line:30:12 haoyuTestBlcok 'void (^__strong)(void)' cinit
| | | `-ExprWithCleanups 0x7ffc9c0b1780 <col:36, line:32:5> 'void (^)(void)'
| | | |-cleanup Block 0x7ffc9c0b1590
| | | `-BlockExpr 0x7ffc9c0b1768 <line:30:36, line:32:5> 'void (^)(void)'
| | | `-BlockDecl 0x7ffc9c0b1590 <line:30:36, line:32:5> line:30:36
| | | |-capture ImplicitParam 0x7ffc9c0b1048 'self' 'UIViewController *const __strong'
| | | |-capture Var 0x7ffc9c0b1120 'ahaoyuHaha' 'NSString *__strong'
| | | `-CompoundStmt 0x7ffc9c0b1730 <col:37, line:32:5>
| | | `-ObjCMessageExpr 0x7ffc9c0b16f8 <line:31:9, col:40> 'void' selector=setupGTestFunc:
| | | |-ImplicitCastExpr 0x7ffc9c0b16c8 <col:10> 'UIViewController *' <LValueToRValue>
| | | | `-DeclRefExpr 0x7ffc9c0b1658 <col:10> 'UIViewController *const __strong' lvalue ImplicitParam 0x7ffc9c0b1048 'self' 'UIViewController *const __strong'
| | | `-ImplicitCastExpr 0x7ffc9c0b16e0 <col:30> 'NSString *' <LValueToRValue>
| | | `-DeclRefExpr 0x7ffc9c0b1690 <col:30> 'NSString *const __strong' lvalue Var 0x7ffc9c0b1120 'ahaoyuHaha' 'NSString *__strong'
| | |-BlockDecl 0x7ffc9c0b1590 <line:30:36, line:32:5> line:30:36
| | | |-capture ImplicitParam 0x7ffc9c0b1048 'self' 'UIViewController *const __strong'
| | | |-capture Var 0x7ffc9c0b1120 'ahaoyuHaha' 'NSString *__strong'
| | | `-CompoundStmt 0x7ffc9c0b1730 <col:37, line:32:5>
| | | `-ObjCMessageExpr 0x7ffc9c0b16f8 <line:31:9, col:40> 'void' selector=setupGTestFunc:
| | | |-ImplicitCastExpr 0x7ffc9c0b16c8 <col:10> 'UIViewController *' <LValueToRValue>
| | | | `-DeclRefExpr 0x7ffc9c0b1658 <col:10> 'UIViewController *const __strong' lvalue ImplicitParam 0x7ffc9c0b1048 'self' 'UIViewController *const __strong'
| | | `-ImplicitCastExpr 0x7ffc9c0b16e0 <col:30> 'NSString *' <LValueToRValue>
| | | `-DeclRefExpr 0x7ffc9c0b1690 <col:30> 'NSString *const __strong' lvalue Var 0x7ffc9c0b1120 'ahaoyuHaha' 'NSString *__strong'
| | `-CompoundStmt 0x7ffc9c0b17b8 <line:28:24, line:33:1>
| | |-DeclStmt 0x7ffc9c0b1478 <line:29:5, col:70>
| | | `-VarDecl 0x7ffc9c0b1120 <col:5, col:69> col:15 used ahaoyuHaha 'NSString *__strong' cinit
| | | `-ExprWithCleanups 0x7ffc9c0b1460 <col:28, col:69> 'NSString *'
| | | `-ImplicitCastExpr 0x7ffc9c0b1448 <col:28, col:69> 'NSString *' <ARCConsumeObject>
| | | `-ObjCMessageExpr 0x7ffc9c0b1410 <col:28, col:69> 'NSString *' selector=initWithString:
| | | |-ImplicitCastExpr 0x7ffc9c0b11c0 <col:29, col:44> 'NSString *' <ARCConsumeObject>
| | | | `-ObjCMessageExpr 0x7ffc9c0b1190 <col:29, col:44> 'NSString *' selector=alloc class='NSString'
| | | `-ObjCStringLiteral 0x7ffc9c0b1238 <col:61, col:62> 'NSString *'
| | | `-StringLiteral 0x7ffc9c0b1218 <col:62> 'char [6]' lvalue "Hello"
| | `-DeclStmt 0x7ffc9c0b17a0 <line:30:5, line:32:6>
| | `-VarDecl 0x7ffc9c0b1530 <line:30:5, line:32:5> line:30:12 haoyuTestBlcok 'void (^__strong)(void)' cinit
| | `-ExprWithCleanups 0x7ffc9c0b1780 <col:36, line:32:5> 'void (^)(void)'
| | |-cleanup Block 0x7ffc9c0b1590
| | `-BlockExpr 0x7ffc9c0b1768 <line:30:36, line:32:5> 'void (^)(void)'
| | `-BlockDecl 0x7ffc9c0b1590 <line:30:36, line:32:5> line:30:36
| | |-capture ImplicitParam 0x7ffc9c0b1048 'self' 'UIViewController *const __strong'
| | |-capture Var 0x7ffc9c0b1120 'ahaoyuHaha' 'NSString *__strong'
| | `-CompoundStmt 0x7ffc9c0b1730 <col:37, line:32:5>
| | `-ObjCMessageExpr 0x7ffc9c0b16f8 <line:31:9, col:40> 'void' selector=setupGTestFunc:
| | |-ImplicitCastExpr 0x7ffc9c0b16c8 <col:10> 'UIViewController *' <LValueToRValue>
| | | `-DeclRefExpr 0x7ffc9c0b1658 <col:10> 'UIViewController *const __strong' lvalue ImplicitParam 0x7ffc9c0b1048 'self' 'UIViewController *const __strong'
| | `-ImplicitCastExpr 0x7ffc9c0b16e0 <col:30> 'NSString *' <LValueToRValue>
| | `-DeclRefExpr 0x7ffc9c0b1690 <col:30> 'NSString *const __strong' lvalue Var 0x7ffc9c0b1120 'ahaoyuHaha' 'NSString *__strong'
| |-ObjCMethodDecl 0x7ffc9c0e3ee0 <line:34:1, line:36:1> line:34:1 - setupGTestFunc: 'void'
| | |-ImplicitParamDecl 0x7ffc9c0b1808 <<invalid sloc>> <invalid sloc> implicit self 'UIViewController *const __strong'
| | |-ImplicitParamDecl 0x7ffc9c0b1868 <<invalid sloc>> <invalid sloc> implicit _cmd 'SEL':'SEL *'
| | |-ParmVarDecl 0x7ffc9c0e3f60 <col:25, col:36> col:36 used stringA 'NSString *__strong'
| | `-CompoundStmt 0x7ffc9c0b1a70 <col:44, line:36:1>
| | `-CallExpr 0x7ffc9c0b1a10 <line:35:5, col:39> 'void'
| | |-ImplicitCastExpr 0x7ffc9c0b19f8 <col:5> 'void (*)(id, ...)' <FunctionToPointerDecay>
| | | `-DeclRefExpr 0x7ffc9c0b18c8 <col:5> 'void (id, ...)' Function 0x7ffc9c0e3fe8 'NSLog' 'void (id, ...)'
| | |-ImplicitCastExpr 0x7ffc9c0b1a40 <col:11, col:12> 'id':'id' <BitCast>
| | | `-ObjCStringLiteral 0x7ffc9c0b1958 <col:11, col:12> 'NSString *'
| | | `-StringLiteral 0x7ffc9c0b1928 <col:12> 'char [18]' lvalue "=====\345\255\227\347\254\246\344\270\262:%@"
| | `-ImplicitCastExpr 0x7ffc9c0b1a58 <col:32> 'NSString *' <LValueToRValue>
| | `-DeclRefExpr 0x7ffc9c0b1978 <col:32> 'NSString *__strong' lvalue ParmVar 0x7ffc9c0e3f60 'stringA' 'NSString *__strong'
| |-ObjCIvarDecl 0x7ffc9c115630 </Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIViewController.h:110:54> col:54 implicit _view 'UIView * _Null_unspecified __strong':'UIView *__strong' synthesize private
| |-ObjCPropertyImplDecl 0x7ffc9c115688 <<invalid sloc>, col:54> <invalid sloc> view synthesize
| | |-ObjCProperty 0x7ffc9c0d3560 'view'
| | `-ObjCIvar 0x7ffc9c115630 '_view' 'UIView * _Null_unspecified __strong':'UIView *__strong'
| |-ObjCIvarDecl 0x7ffc9c115880 <line:113:58> col:58 implicit _viewIfLoaded 'UIView * _Nullable __strong':'UIView *__strong' synthesize private
| |-ObjCPropertyImplDecl 0x7ffc9c1158d8 <<invalid sloc>, col:58> <invalid sloc> viewIfLoaded synthesize
实在太长了,我做了一下删减,把从UIViewController中继承的一些方法属性和方法给省略。
最顶层的节点是TranslationUnitDecl。接下来是两大部分ObjCCategoryDecl、ObjCImplementationDecl。然后在各自的节点下又有子节点。了解所有节点后。整体还是很简单的。
TranslationUnitDecl
-ObjCCategoryDecl
-ObjCInterface
-ObjCPropertyDecl //声明property属性
-ObjCMethodDecl //属性对应的getter。这里参考一个method解析转换即可。
-ObjCMethodDecl //setter方法
-ParmVarDecl ///setter方法中用到的参数
......
-ObjCImplementationDecl //对应我们的implemention实现,下面都是各种方法的声明。
-ObjCInterface
-ObjCMethodDecl
-ImplicitParamDecl //这里会一直都都有这两个默认参数
-ImplicitParamDecl //同上
-VarDecl //函数中定义的局部变量
...
-CompoundStmt //每个函数的方法体
...
-ObjCMethodDecl
.......
综上就是整个AST的结构,我们可以参照这个结构来理解AST内容。
大家可以结合上面讲到的各节点的含义来具体理解一下我们得出的AST内容。先参考这个结构,有问题可以给我发信息。
参考:
这里提供一个比较不错的参考:官方提供的ASTMatcher 文档,用来在遍历AST时,获取每个节点。
同仁写的一篇文章