Skip to content

Kotlin 符號處理 API

Kotlin 符號處理 (Symbol Processing) (KSP) 是一個可用於開發輕量級編譯器外掛程式 (compiler plugins) 的 API。KSP 提供一個簡化的編譯器外掛程式 API,它利用 Kotlin 的強大功能,同時將學習曲線保持在最低限度。相較於 kapt,使用 KSP 的註解處理器 (annotation processors) 執行速度可提高兩倍。

概述

KSP API 以慣用的方式處理 Kotlin 程式。KSP 理解 Kotlin 特有的功能,例如擴充函數 (extension functions)、宣告點變異 (declaration-site variance) 和局部函數 (local functions)。它還明確地建模類型,並提供基本的類型檢查,例如等價 (equivalence) 和賦值相容性 (assign-compatibility)。

該 API 根據 Kotlin 文法 在符號層級建模 Kotlin 程式結構。當基於 KSP 的外掛程式處理原始程式時,類別、類別成員、函數和相關參數等構造對於處理器而言是可存取的,而 if 區塊和 for 迴圈等則不可存取。

從概念上講,KSP 與 Kotlin 反射 (reflection) 中的 KType 相似。該 API 允許處理器從類別宣告導航到具有特定類型參數 (type arguments) 的相應類型,反之亦然。您還可以替換類型參數、指定變異 (variances)、應用星形投影 (star projections) 和標記類型的可空性 (nullabilities)。

另一種看待 KSP 的方式是將其視為 Kotlin 程式的前處理器框架 (preprocessor framework)。將基於 KSP 的外掛程式視為 符號處理器,或簡稱為 處理器,編譯中的資料流可以透過以下步驟描述:

  1. 處理器讀取並分析原始程式和資源。
  2. 處理器產生程式碼或其他形式的輸出。
  3. Kotlin 編譯器將原始程式與產生的程式碼一起編譯。

不同於一個功能齊全的編譯器外掛程式,處理器無法修改程式碼。改變語言語義 (semantics) 的編譯器外掛程式有時會非常令人困惑。KSP 透過將原始程式視為唯讀 (read-only) 來避免這種情況。

您也可以透過此影片瞭解 KSP 概述:

KSP 如何看待原始碼檔案

大多數處理器會遍歷輸入原始碼的各種程式結構。在深入探討 API 的使用之前,讓我們看看 KSP 如何看待一個檔案:

text
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

kotlin
interface SymbolProcessorProvider {
    fun create(environment: SymbolProcessorEnvironment): SymbolProcessor
}

SymbolProcessor 則定義為:

kotlin
interface SymbolProcessor {
    fun process(resolver: Resolver): List<KSAnnotated> // 讓我們專注於此
    fun finish() {}
    fun onError() {}
}

Resolver 提供 SymbolProcessor 存取編譯器詳細資訊,例如符號。尋找所有頂層函數和頂層類別中非局部函數的處理器可能看起來像以下這樣:

kotlin
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官方支援
Ktorfit官方支援
Mockative官方支援
DeeplinkDispatch透過 airbnb/DeepLinkDispatch#323 支援
DaggerAlpha
MotifAlpha
Hilt進行中
Auto Factory尚未支援