美文网首页iOS底层探究
Clang之二 : AST节点解析

Clang之二 : AST节点解析

作者: 好雨知时节浩宇 | 来源:发表于2020-06-14 09:29 被阅读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时,获取每个节点。
    同仁写的一篇文章

    相关文章

      网友评论

        本文标题:Clang之二 : AST节点解析

        本文链接:https://www.haomeiwen.com/subject/euyjzhtx.html