12.4.1 Kotlin Symbol Processing API

原文链接: https://kotlinlang.org/docs/ksp-overview.html

12.4.1 Kotlin Symbol Processing API

Kotlin Symbol Processing(KSP)是一个针对 Kotlin 的源码生成框架。借助 KSP API,你可以创建处理器,根据源码中的注解生成代码。

KSP 的目标是简化轻量级编译器插件的创建。它定义良好的 API 隐藏了编译器的变化,因此你无需花太多精力维护处理器。不过,这种方式也有取舍。例如,基于 KSP 的处理器无法检查表达式或语句,也无法修改源代码。

基于 KSP 的插件典型用例包括:

要了解如何创建你的第一个基于 KSP 的处理器,请参阅 KSP 快速入门。

概览

KSP API 以符合 Kotlin 习惯的方式处理 Kotlin 程序。KSP 理解 Kotlin 特有的特性,例如扩展函数、声明处型变和局部函数。它还显式地为类型建模,并提供基本的类型检查,例如等价性和可赋值兼容性。

该 API 依据 Kotlin 语法在符号级别为 Kotlin 程序结构建模。当基于 KSP 的插件处理源程序时,类、类成员、函数及相关参数等构造对处理器是可访问的,而 if 块和 for 循环之类的内容则不可访问。

从概念上讲,KSP 类似于 Kotlin 反射中的 KType。该 API 允许处理器从类声明导航到带特定类型实参的对应类型,反之亦然。你还可以替换类型实参、指定型变、应用星投影,并标记类型的可空性。

另一种理解 KSP 的方式是把它看作 Kotlin 程序的预处理器框架。如果把基于 KSP 的插件视为_符号处理器_(或简称_处理器_),那么一次编译中的数据流可以用以下步骤描述:

  1. 处理器读取并分析源程序和资源。
  2. 处理器生成代码或其他形式的输出。
  3. Kotlin 编译器把源程序与生成的代码一起编译。

与功能完备的编译器插件不同,处理器不能修改代码。改变语言语义的编译器插件有时会非常令人困惑。KSP 把源程序视为只读,从而避免了这一点。

你也可以通过这个视频了解 KSP 概览:

视频:Kotlin Symbol Processing (KSP)

KSP 如何看待源文件

大多数处理器都会遍历输入源码的各种程序结构。在深入了解 API 的用法之前,我们先看看从 KSP 的视角来看一个文件可能是什么样子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
KSFile
  packageName: KSName
  fileName: String
  annotations: List<KSAnnotation>  (File annotations)
  declarations: List<KSDeclaration>
    KSClassDeclaration // 类、接口、对象
      simpleName: KSName
      qualifiedName: KSName
      containingFile: String
      typeParameters: KSTypeParameter
      parentDeclaration: KSDeclaration
      classKind: ClassKind
      primaryConstructor: KSFunctionDeclaration
      superTypes: List<KSTypeReference>
      // 包含内部类、成员函数、属性等
      declarations: List<KSDeclaration>
    KSFunctionDeclaration // 顶层函数
      simpleName: KSName
      qualifiedName: KSName
      containingFile: String
      typeParameters: KSTypeParameter
      parentDeclaration: KSDeclaration
      functionKind: FunctionKind
      extensionReceiver: KSTypeReference?
      returnType: KSTypeReference
      parameters: List<KSValueParameter>
      // 包含局部类、局部函数、局部变量等
      declarations: List<KSDeclaration>
    KSPropertyDeclaration // 全局变量
      simpleName: KSName
      qualifiedName: KSName
      containingFile: String
      typeParameters: KSTypeParameter
      parentDeclaration: KSDeclaration
      extensionReceiver: KSTypeReference?
      type: KSTypeReference
      getter: KSPropertyGetter
        returnType: KSTypeReference
      setter: KSPropertySetter
        parameter: KSValueParameter

这个视图列出了文件中常见的声明内容:类、函数、属性等等。

SymbolProcessorProvider:入口点

KSP 期望通过 SymbolProcessorProvider 接口的实现来实例化 SymbolProcessor:

1
2
3
interface SymbolProcessorProvider {
    fun create(environment: SymbolProcessorEnvironment): SymbolProcessor
}

而 SymbolProcessor 的定义是:

1
2
3
4
5
interface SymbolProcessor {
    fun process(resolver: Resolver): List<KSAnnotated> // 我们重点关注这个方法
    fun finish() {}
    fun onError() {}
}

Resolver 为 SymbolProcessor 提供对编译器细节(例如符号)的访问。一个查找所有顶层函数和顶层类中非局部函数的处理器大致如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class HelloFunctionFinderProcessor : SymbolProcessor() {
    // ...
    val functions = mutableListOf<KSFunctionDeclaration>()
    val visitor = FindFunctionsVisitor()

    override fun process(resolver: Resolver) {
        resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
    }

    inner class FindFunctionsVisitor : KSVisitorVoid() {
        override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
            classDeclaration.getDeclaredFunctions().forEach { it.accept(this, Unit) }
        }

        override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
            functions.add(function)
        }

        override fun visitFile(file: KSFile, data: Unit) {
            file.declarations.forEach { it.accept(this, Unit) }
        }
    }
    // ...

    class Provider : SymbolProcessorProvider {
        override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = TODO()
    }
}

资源

受支持的库

下表列出了 Android 上一些流行的库以及它们对 KSP 支持的不同阶段:

| 库 | 状态 |

| Room | 官方支持 | | Moshi | 官方支持 | | RxHttp | 官方支持 | | Kotshi | 官方支持 | | Lyricist | 官方支持 | | Lich SavedState | 官方支持 | | gRPC Dekorator | 官方支持 | | EasyAdapter | 官方支持 | | Koin Annotations | 官方支持 | | Glide | 官方支持 | | Micronaut | 官方支持 | | Epoxy | 官方支持 | | Paris | 官方支持 | | Auto Dagger | 官方支持 | | SealedX | 官方支持 | | Ktorfit | 官方支持 | | Mockative | 官方支持 | | Kotest | 官方支持 | | DeeplinkDispatch | 通过 airbnb/DeepLinkDispatch#323 支持 | | Dagger | Alpha | | Motif | Alpha | | Hilt | 进行中 | | Auto Factory | 尚不支持 |