iOS底层探究

Clang之二 : AST节点解析

2020-06-14  本文已影响0人  好雨知时节浩宇

前言:为了基于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节点。

我们看一下blockAST中表示:
源代码如下:

//特意把行号也标注上了,因为在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时,获取每个节点。
同仁写的一篇文章

上一篇下一篇

猜你喜欢

热点阅读