Kotlin 符号处理(Kotlin Symbol Processing) API
Kotlin 符号处理(Kotlin Symbol Processing, KSP) 是一个针对 Kotlin 的源代码生成框架. 通过 KSP API, 你可以创建处理器, 根据源代码中的 注解 生成代码.
KSP 的目的是简化轻量级编译器 plugin 的开发工作. 它拥有定义良好的 API, 隐藏了编译器的变更, 因此你不需要耗费大量精力来维护你的处理器. 但是, 这种方案也有一些代价. 例如, 基于 KSP 的处理器不能分析表达式或语句, 也不能修改源代码.
基于 KSP 的 plugin 的典型使用场景包括:
关于如何创建你的第一个基于 KSP 的处理器, 请参见 KSP 快速入门.
概述
KSP API 按照语言习惯来处理 Kotlin 程序. KSP 理解 Kotlin 专有的功能特性, 比如扩展函数, 声明处类型变异(declaration-site variance), 以及局部函数. 它还明确的对类型建立模型, 并提供基本类型检查, 比如相等性, 以及赋值兼容性.
API 根据 Kotlin 语法, 在符号层面对 Kotlin 程序结构建立模型. 当基于 KSP 的插件处理源程序时, 处理器可以访问各种结构, 比如类, 类成员, 函数, 以及关联的参数, 而 if 代码段和 for 循环之类则不可以访问.
概念上来讲, KSP 类似于 Kotlin 反射中的 KType. API 允许处理器从类的声明查找到相应的带特定类型参数的类型, 或者反过来. 你也可以替换类型参数, 特定的变体, 应用星号投射(Star Projection), 以及标注类型可否为空.
看待 KSP 的另一种方式是当作 Kotlin 程序的一个预处理器框架. 将基于 KSP 的插件看作 符号处理器, 或者简称 处理器, 编译过程中的数据流可以描述为以下步骤:
处理器读取并分析源程序和资源.
处理器生成代码或其他形式的输出.
Kotlin 编译器将源程序和生成的代码一起编译.
与功能完全的编译器插件不同, 处理器不能修改代码. 修改程序语义的编译器插件有时可能会非常令人困惑. KSP 将源程序当作只读, 避免这种情况.
你也可以观看这个视频, 大致了解 KSP:
KSP 如何看待源代码文件
大多数处理器会浏览输入的源代码的各种程序结构. 在介绍 API 的使用方法之前, 我们来看一下从 KSP 的观点如何看待文件:
KSFile
packageName: KSName
fileName: String
annotations: List<KSAnnotation> // 源代码文件注解
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 实例:
interface SymbolProcessorProvider {
fun create(environment: SymbolProcessorEnvironment): SymbolProcessor
}
其中 SymbolProcessor 定义如下:
interface SymbolProcessor {
fun process(resolver: Resolver): List<KSAnnotated> // 我们集中看这里
fun finish() {}
fun onError() {}
}
SymbolProcessor 使用 Resolver 来访问编译器细节, 比如符号. 如果一个处理器要查找所有的顶层函数和顶层类中的非局部函数, 大概实现如下:
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 的支持情况:
2026/07/03