目 录 Contents
前言
第一部分 元编程的基础知识
第1章 元编程概述2
1.1 元编程的需求背景2
1.2 元编程的基本概念4
1.2.1 元编程的定义5
1.2.2 元编程的分类5
1.3 元编程的学习方法6
1.3.1 培养兴趣6
1.3.2 付诸行动6
1.3.3 善用工具7
1.3.4 多读源代码8
1.4 常用项目的调试环境配置8
1.4.1 Java编译器8
1.4.2 Kotlin编译器11
1.4.3 IntelliJ社区版13
1.4.4 Jetpack Compose编译器插件19
1.5 本章小结21
第2章 元数据概述22
2.1 基本概念22
2.1.1 语法结构23
2.1.2 编译产物23
2.2 注释23
2.2.1 注释的结构化23
2.2.2 文档生成24
2.3 注解25
2.3.1 注解的概念25
2.3.2 源代码可见的注解26
2.3.3 二进制可见的注解27
2.3.4 运行时可见的注解30
2.4 Kotlin的元数据31
2.4.1 Kotlin JVM中的@Metadata
注解31
2.4.2 Kotlin JVM模块中的元数据35
2.4.3 klib中的元数据37
2.5 Kotlin的语法树39
2.5.1 Kotlin的语法定义40
2.5.2 基于IntelliJ平台接口的抽象语
法树41
2.5.3 新一代语法树FIR42
2.5.4 连接前后端编译器的IR43
2.5.5 Java和Kotlin的符号树45
2.6 Kotlin的编译产物47
2.6.1 JVM47
2.6.2 JavaScript48
2.6.3 Native48
2.7 本章小结49
第二部分 元编程的技术实践
第3章 运行时的反射52
3.1 Java反射52
3.1.1 基本功能52
3.1.2 解除访问限制53
3.1.3 动态代理54
3.1.4 对注解的支持55
3.1.5 对方法参数名的支持56
3.1.6 访问Kotlin代码57
3.2 Kotlin反射58
3.2.1 基本功能59
3.2.2 类引用的获取61
3.2.3 属性引用和函数引用65
3.2.4 typeOf67
3.2.5 dynamic类型69
3.2.6 属性委托70
3.3 案例:Retrofit的接口实现72
3.3.1 Retrofit基本用法72
3.3.2 GitHubService实例的创建73
3.3.3 函数参数与请求参数的
对应关系74
3.3.4 泛型类型的反序列化74
3.3.5 案例小结75
3.4 案例:使用反射实现DeepCopy75
3.4.1 案例背景75
3.4.2 需求分析76
3.4.3 案例实现78
3.4.4 小试牛刀79
3.4.5 案例小结79
3.5 案例:使用dynamic类型为
Kotlin JS实现DeepCopy80
3.5.1 案例背景80
3.5.2 需求分析80
3.5.3 案例实现83
3.5.4 案例小结83
3.6 本章小结84
第4章 源代码生成85
4.1 直接输出目标代码85
4.1.1 一个简单的例子85
4.1.2 标准库的代码生成87
4.2 案例:为Kotlin添加Tuple类型88
4.2.1 案例背景88
4.2.2 需求分析90
4.2.3 案例实现91
4.3 使用模板引擎生成目标代码93
4.3.1 Anko中的代码生成93
4.3.2 使用模板引擎渲染目标代码95
4.4 案例:为Java静态方法生成
Kotlin扩展函数(模板引擎)96
4.4.1 案例背景96
4.4.2 需求分析96
4.4.3 案例实现98
4.4.4 代码优化101
4.5 使用代码生成框架生成目标代码104
4.5.1 JavaPoet104
4.5.2 KotlinPoet109
4.6 案例:为Java静态方法生成
Kotlin扩展函数(KotlinPoet)114
4.6.1 类型的映射114
4.6.2 实现代码生成116
4.6.3 泛型参数的支持118
4.7 本章小结121
第5章 编译时的符号处理122
5.1 符号的基本概念122
5.1.1 Java的符号122
5.1.2 Kotlin的符号124
5.1.3 符号与语法树节点的关系和
区别125
5.2 处理器的基本结构125
5.2.1 APT的基本结构125
5.2.2 KSP的基本结构130
5.2.3 APT与KSP的结构差异131
5.2.4 处理器的配置文件132
5.3 深入理解符号和类型132
5.3.1 获取修饰符133
5.3.2 通过名称获取符号133
5.3.3 获取符号的类型134
5.3.4 通过类型获取符号138
5.3.5 判断类型之间的关系139
5.3.6 获取注解及其参数值141
5.4 案例:基于源代码生成模块的
符号文件144
5.4.1 案例背景144
5.4.2 案例实现:APT版本145
5.4.3 案例实现:KSP版本147
5.5 深入理解符号处理器148
5.5.1 如何使用APT处理Kotlin
符号148
5.5.2 符号的有效性验证150
5.5.3 处理器的轮次和符号的延迟
处理150
5.5.4 处理器对增量编译的支持151
5.5.5 多模块的符号处理154
5.6 案例:使用符号处理器实现
DeepCopy156
5.6.1 案例背景156
5.6.2 需求分析156
5.6.3 案例实现:APT版本157
5.6.4 案例实现:KSP版本160
5.6.5 案例小结163
5.7 本章小结163
第6章 程序静态分析164
6.1 案例:检查项目中的数据类164
6.1.1 案例背景164
6.1.2 需求分析166
6.1.3 案例实现:使用正则表达式
匹配167
6.1.4 案例小结169
6.2 Kotlin程序的语法分析169
6.2.1 需求扩展169
6.2.2 案例实现:使用Antlr实现
语法树解析170
6.2.3 案例小结173
6.3 Kotlin程序的语义分析173
6.3.1 需求扩展173
6.3.2 案例实现:使用Kotlin编译器
进行语义分析174
6.3.3 案例小结176
6.4 使用detekt进行静态扫描176
6.4.1 基于detekt实现数据类扫描177
6.4.2 使用detekt的IntelliJ插件178
6.5 基于IntelliJ IDEA进行语法检查180
6.5.1 IntelliJ IDEA中的代码检查180
6.5.2 实现对数据类的检查181
6.5.3 实现快捷修复操作182
6.6 本章小结184
第7章 编译器插件185
7.1 编译器插件概述185
7.1.1 什么是编译器插件185
7.1.2 编译器插件能做什么186
7.2 编译器插件项目的基本结构187
7.2.1 编译器插件模块187
7.2.2 编译工具链插件模块190
7.2.3 集成开发环境插件模块191
7.3 案例:trimIndent函数的编译时
实现195
7.3.1 案例背景195
7.3.2 需求分析196
7.3.3 案例实现197
7.3.4 插件的发布202
7.3.5 案例小结205
7.4 案例:使用编译器插件实现
DeepCopy205
7.4.1 案例背景205
7.4.2 需求分析205
7.4.3 案例实现206
7.4.4 案例小结212
7.5 符号处理器的实现原理212
7.5.1 Java存根的生成212
7.5.2 Java编译器的调用213
7.5.3 增量编译的支持214
7.5.4 多轮次符号处理215
7.5.5 注解实例的构造216
7.5.6 延伸:依赖关系分析217
7.6 本章小结217
第8章 元程序的开发和调试218
8.1 使用kotlin-compile-testing编写
单元测试218
8.1.1 编译器的调用和调试218
8.1.2 检查KAPT的输出221
8.1.3 添加对KSP的支持222
8.1.4 运行编译后的程序223
8.1.5 打印变换之后的IR225
8.1.6 多模块编译227
8.2 使用kotlin-compile-testing-extensions
简化单元测试228
8.2.1 测试数据的组织形式228
8.2.2 测试数据的加载230
8.2.3 编译运行并检查结果231
8.2.4 检查IR和运行时输出232
8.3 在实际项目中集成233
8.3.1 工程的组织形式234
8.3.2 单步调试Kotlin编译器235
8.3.3 Kotlin编译器的日志输出237
8.4 本章小结238
第三部分 综合案例
第9章 Jetpack Compose的编译
时处理240
9.1 Jetpack Compose简介240
9.2 静态检查243
9.2.1 错误信息243
9.2.2 声明检查245
9.2.3 调用检查251
9.2.4 目标检查260
9.3 案例:为DeepCopy添加代码检查261
9.3.1 案例背景261
9.3.2 需求分析261
9.3.3 案例实现262
9.3.4 案例效果265
9.4 代码提示266
9.4.1 Composable函数的命名266
9.4.2 Composable函数调用的颜色270
9.5 Composable函数的变换272
9.5.1 $composer参数272
9.5.2 参数默认值277
9.5.3 参数的变化状态与重组的
跳过机制284
9.6 本章小结299
第10章 AtomicFU的编译产物
处理300
10.1 AtomicFU的由来300
10.2 Kotlin JVM平台的编译产物
处理304
10.2.1 需求背景分析304
10.2.2 技术选型分析305
10.2.3 方案实现分析305
10.3 Kotlin JS平台的编译产物处理315
10.3.1 需求背景分析316
10.3.2 技术选型分析317
10.3.3 方案实现分析317
10.4 本章小结324