Kotlin 语言参考文档 中文版 Help

Kotlin 符号处理(Kotlin Symbol Processing) API

Kotlin 符号处理(Kotlin Symbol Processing, KSP) 是一组 API, 你可以使用它开发轻量的编译器插件. KSP 提供一组简化的编译器插件 API, 利用 Kotlin 的能力, 同时保持最小的学习曲线. 与 kapt 相比, 使用 KSP 的注解处理器运行速度可以快 2 倍.

概述

KSP API 按照语言习惯来处理 Kotlin 程序. KSP 理解 Kotlin 专有的功能特性, 比如扩展函数, 声明处类型变异(declaration-site variance), 以及局部函数. 它还明确的对类型建立模型, 并提供基本类型检查, 比如相等性, 以及赋值兼容性.

API 根据 Kotlin 语法, 在符号层面对 Kotlin 程序结构建立模型. 当基于 KSP 的插件处理源程序时, 处理器可以访问各种结构, 比如类, 类成员, 函数, 以及关联的参数, 而 if 代码段和 for 循环之类则不可以访问.

概念上来讲, KSP 类似于 Kotlin 反射中的 KType. API 允许处理器从类的声明查找到相应的带特定类型参数的类型, 或者反过来. 你也可以替换类型参数, 特定的变体, 应用星号投射(Star Projection), 以及标注类型可否为空.

看待 KSP 的另一种方式是当作 Kotlin 程序的一个预处理器框架. 将基于 KSP 的插件看作 符号处理器, 或者简称 处理器, 编译过程中的数据流可以描述为以下步骤:

  1. 处理器读取并分析源程序和资源.

  2. 处理器生成代码或其他形式的输出.

  3. 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<KSClassDeclaration>() 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

官方支持

DeeplinkDispatch

通过 airbnb/DeepLinkDispatch#323 支持

Dagger

Alpha

Motif

Alpha

Hilt

开发中

Auto Factory

目前不支持

最终更新: 2024/10/17