Clang RecursiveASTVisitor & ASTFrontendActions based on it
RecursiveASTVisitor Basics
类声明
template<typename Derived>
class clang::RecursiveASTVisitor<Derived>;
以前序或后序深度优先的方式遍历整个 Clang AST 并访问每个节点的一个类。其执行三种不同的操作:
- 遍历整个 AST(即访问每个节点)
- 对于给定的一个节点,沿着其类继承关系向前(Derived->Base方向)游历,直至到达一个顶层类(如 Stmt,Decl,Type)
- 对于一个给定的 (node, class) 组合,调用一个可由用户重写(user-overridable)的函数来访问该节点,其中 class 是 node 的动态类型的某个基类
这些操作由三组类方法来完成,分别是:
- TraverseDecl(Decl *x) 执行任务1,是遍历以x为根的 AST 的入口函数。该函数只是简单地将任务分派(dispatchs, i.e. forwards)给 TraverseFoo(Foo *x),继而调用 WalkUpFromFoo(x),然后递归地访问x的子节点。TraverseFoo 中的 Foo 是 *x 的动态类型。TraverseDecl(Decl *x) 和 TraverseType(QualType x) 执行的操作类似
- WalkUpFromFoo(Foo *x) 执行任务2。该函数首先调用 WalkUpFromBar(x),然后调用 VisitFoo(x)。其中 Bar 是 Foo 的直接父类(direct parent)
- VisitFoo(Foo *x) 执行任务3
这三组方法具有下列层次关系:Traverse* > WalkUpFrom* > Visit*。某一层次的方法可以调用相同层次的另一个方法以及较低层次的方法,但不能调用层次比它高的方法。
由于 WalkUpFromFoo() 在调用 VisitFoo() 之前先调用 WalkUpFromBar(Bar是Foo的超类),因此最终结果是对于一个给定的节点将以自顶向下的顺序依次调用其 Visit*() 方法(如,对于 NamespaceDecl 类型的节点,调用顺序依次为 VisitDecl(),VisitNamedDecl(),VisitNamespaceDecl())。这种机制保证相同类型 AST 节点的 Visit*() 方法调用被组合在一起,而不会与不同类型节点的 Visit*() 方法搅和在一起。
要使用该 visitor,首先要进行子类化(将其自身作为模板参数,采用奇异递归模板模式(curiously recurring template pattern)),然后为声明、类型、语句、表达式以及其他所有需要自定义行为的 AST 节点重写(override)Traverse*、WalkUpFrom* 和 Visit* 方法。大多数用户只需要重写 Visit* 方法即可,也可以重写前两种方法以实现更加高级的操作。在遍历的过程中,如果这些重写函数中的任意一个返回了 false,则整个遍历过程将终止。
默认情况下该 visitor 尝试访问显式源代码(explicit source code)的每一部分而且只访问一次。针对模板的讨论详参原文档。
默认情况下该 visitor 以前序的形式遍历AST,如果需要后序遍历,需要重写 shouldTraversePostOrder 方法并返回 true。
源码简析
TraverseDecl 方法
1 template <typename Derived>
2 bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
3 if (!D)
4 return true;
5
6 // As a syntax visitor, by default we want to ignore declarations for
7 // implicit declarations (ones not typed explicitly by the user).
8 if (!getDerived().shouldVisitImplicitCode() && D->isImplicit())
9 return true;
10
11 switch (D->getKind()) {
12 #define ABSTRACT_DECL(DECL)
13 #define DECL(CLASS, BASE) \
14 case Decl::CLASS: \
15 if (!getDerived().Traverse##CLASS##Decl(static_cast<CLASS##Decl *>(D))) \
16 return false; \
17 break;
18 #include "clang/AST/DeclNodes.inc"
19 }
20
21 // Visit any attributes attached to this declaration.
22 for (auto *I : D->attrs()) {
23 if (!getDerived().TraverseAttr(I))
24 return false;
25 }
26 return true;
27 }
行11到行19便是整个分派过程。getDerived() 方法返回派生子类的引用,
基于 RecursiveASTVisitor 的 ASTFrontendAction
关于 FrontendAction 的知识见另一篇 blog:Clang FrontendActions。此处给出的例子只是简单地打印出程序中所有的 witch-case 语句的两部分信息:switch 条件表达式和 case 语句。
ClangTool 的 run 方法接受一个 FrontendAction (wrapped with newFrontendActionFactory),因此首先创建一个 FrontendAction 类:
1 class SwitchAction : public ASTFrontendAction {
2 public:
3 virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
4 StringRef InFile) {
5 return std::unique_ptr<ASTConsumer>(
6 new SwitchConsumer(&CI.getASTContext()));
7 }
8 };
编译器在对源文件进行 parsing 时执行传进来的 FrontendAction(Act),在 Act 的准备阶段调用 CreateASTConsumer 方法,在生成完 AST 后,会调用 ASTConsumer 的 HandleTranslationUnit(ASTContext &Ctx) 方法。下面创建一个 ASTConsumer 类:
1 class SwitchConsumer : public ASTConsumer {
2 public:
3 explicit SwitchConsumer(ASTContext *Context) : Visitor(Context) {}
4 virtual void HandleTranslationUnit(ASTContext &Context) {
5 Visitor.TraverseDecl(Context.getTranslationUnitDecl());
6 }
7
8 private:
9 SwitchVisitor Visitor;
10 };
在 ASTConsumer 的 HandleTranslationUnit 中调用 Visitor 的 TraverseDecl 方法来遍历 AST。此时 AST 已经创建完毕,我们将其根 TranslationUnitDecl 传递给 TraverseDecl 方法。
Refenences:
Clang RecursiveASTVisitor & ASTFrontendActions based on it的更多相关文章
- YOCVM
一.热补丁的本质 对于线上紧急的bug,重新提审AppStore的时间过长.因此,能够下发一段补丁代码到线上运行,并结合Runtime,实时改变App原有的行为,就显得极为重要.补丁代码的形式可以有很 ...
- 微信团队分享:极致优化,iOS版微信编译速度3倍提升的实践总结
1.引言 岁月真是个养猪场,这几年,人胖了,微信代码也翻了. 记得 14 年转岗来微信时,用自己笔记本编译微信工程才十来分钟.如今用公司配的 17 年款 27-inch iMac 编译要接近半小时:偶 ...
- c++ binding code generator based on clang
google it http://www.swig.org/Doc3.0/CSharp.html http://samanbarghi.com/blog/2016/12/06/generate-c-i ...
- “Clang” CFE Internals Manual---中文版---"Clang"C语言前端内部手册
原文地址:http://clang.llvm.org/docs/InternalsManual.html 译者:史宁宁(snsn1984) "Clang"C语言前端内部手册 简介 ...
- 基于Clang的Source to Source源代码转换(一)
Clang中包含了非常多的关于抽象语法树(AST)的访问和操作的类和接口.我们程序开发人员可以直接通过继承其中的某些类,重写其中的关键成员方法,从而形成我们自己的对抽象语法树的操作. 那么,首先我们简 ...
- clang format 官方文档自定义参数介绍(中英文)
官方文档:http://clang.llvm.org/docs/ClangFormatStyleOptions.html 中文 在代码中配置样式 当使用 clang::format::reformat ...
- 打造基于Clang LibTooling的iOS自动打点系统CLAS(二)
1. 配置LLVM和Clang 在这篇文章里,我们会基于上一篇所述的方案进行展开,详细讲解如何从0开始创建一个基于Clang LibTooling的编译器前端工具.在开始之前,我们假设你已经基本了解何 ...
- Clang之语法抽象语法树AST
语法分析器的任务是确定某个单词流是否能够与源语言的语法适配,即设定一个称之为上下文无关语言(context-free language)的语言集合,语法分析器建立一颗与(词法分析出的)输入单词流对应的 ...
- clang 编译 OC
clang -fobjc-arc -framework Foundation helloworld.m -o helloworld.out OVERVIEW: clang LLVM compiler ...
- iOS编程 手动忽略clang编译器警告
在iOS开发过程中, 我们可能会碰到一些系统方法弃用, weak.循环引用.不能运行之类的警告. 有代码洁癖的孩子们非常想消除他们, 今天就让我们来一次Fuck 警告.! 首先学会主要的语句 #pra ...
随机推荐
- Codeforces Round #824 (Div. 2) A-E
比赛链接 A 题解 知识点:贪心,数学. 注意到三段工作时间一共 \(n-3\) 天,且天数实际上可以随意分配到任意一段,每段至少有一天,现在目的就是最大化段差最小值. 不妨设 \(l_1<l_ ...
- webgl 系列
webgl 背景 工作所需... 目录 初识 WebGL 绘制一个点 三角形 变换矩阵和动画 渐变三角形 绘制猫 着色器语言
- Java编程思想第四版(完整中文高清版)pdf
这是一本有独到.深入的见解的Java语言,以通俗易懂及小而直接的示例解释了一个个晦涩抽象的概念.本书共22章,包括操作符.控制执行流程.访问权限控制.复用类.多态.接口.通过异常处理错误.字符串.泛 ...
- Ubuntu下使用PlatformIO开发STC89/STC12/Arduino
安装VSCode 从 https://code.visualstudio.com/Download 下载最新的 deb 版, 通过命令行安装 sudo apt install ./code_1.59. ...
- STM32F103C8T6与W5500的运行示例
模块说明 W5500的厂商是韩国WIZnet, 特性如下 全硬件TCP/IP协议栈: TCP,UDP,ICMP,IPv4,ARP,IGMP,PPPoE -- 注意只有IPv4 支持SPI模式0,3, ...
- 核心MySQL主库优化总结
公司核心主库,在我来公司时是1主5从库(腾讯云RDS),外加7个自建级联从库. 从2020年2月到2021年8月优化总结: 1, 7个自建多级从库,从以前的中转同步改成从一级从库同步,废弃了5个从库 ...
- elasticsearch should实现or功能,设置minimum_should_match
elasticsearch实现传统数据库中的or功能,需要使用bool下面的should关键字,对于A or B的情况,应该至少返回A和B中的一个,但是如下语句,不仅返回A和B中的至少一个,也返回了没 ...
- nginx添加站点
1.修改配置文件 vim /usr/local/nginx/conf/nginx.conf 添加一个server节点: server { listen 81; ...
- Java Socket设置timeout几种常用方式总结
原文链接:https://my.oschina.net/shipley/blog/715196 最近碰到读取第三方提供socket接口需要设置超时时间问题,特此记录一下.原文中有几处拼写错误顺便改掉了 ...
- Excelize 开源基础发布 2.8.1 版本,2024 年首个更新
Excelize 是 Go 语言编写的用于操作电子表格办公文档的开源基础库,基于 ISO/IEC 29500.ECMA-376 国际标准.可以使用它来读取.写入由 Microsoft Excel.WP ...