Skip to content

多輪處理

KSP 支援 多輪處理,或稱為跨多個回合處理檔案。這表示後續回合會使用前一個回合的輸出作為額外輸入。

對處理器的變更

要使用多輪處理,SymbolProcessor.process() 函數需要針對無效符號傳回一個延遲符號清單 (List<KSAnnotated>)。請使用 KSAnnotated.validate() 來過濾無效符號,以便將其延遲到下一個回合。

以下範例程式碼展示了如何透過使用驗證檢查來延遲無效符號:

kotlin
override fun process(resolver: Resolver): List<KSAnnotated> {
    val symbols = resolver.getSymbolsWithAnnotation("com.example.annotation.Builder")
    val result = symbols.filter { !it.validate() }
    symbols
        .filter { it is KSClassDeclaration && it.validate() }
        .map { it.accept(BuilderVisitor(), Unit) }
    return result
}

多輪行為

將符號延遲到下一個回合

處理器可以將某些符號的處理延遲到下一個回合。當符號被延遲時,處理器正在等待其他處理器提供額外資訊。它可以根據需求延遲符號任意多個回合。一旦其他處理器提供了所需資訊,處理器就可以處理該延遲符號。處理器應只延遲那些缺少必要資訊的無效符號。因此,處理器不應延遲來自 classpath 的符號,KSP 也會過濾掉任何不是來自原始碼的延遲符號。

例如,一個為帶有註解的類別建立建構器(builder)的處理器可能要求其建構函數的所有參數類型都是有效的(解析為具體類型)。在第一個回合中,其中一個參數類型無法解析。然後在第二個回合中,由於第一個回合生成的檔案,它變得可解析。

驗證符號

判斷符號是否應被延遲的一個方便方法是透過驗證。處理器應知道哪些資訊對於正確處理符號是必要的。 請注意,驗證通常需要解析,這可能耗時,因此我們建議只檢查所需的內容。 沿用前述範例,對於建構器處理器而言,一個理想的驗證只檢查帶有註解的符號的建構函數所有已解析參數類型是否包含 isError == false

KSP 提供了一個預設的驗證工具。更多資訊請參閱 進階 章節。

終止條件

當一個完整的處理回合沒有生成新的檔案時,多輪處理就會終止。如果終止條件達成時仍存在未處理的延遲符號,KSP 會為每個帶有未處理延遲符號的處理器記錄一條錯誤訊息。

每個回合可存取的檔案

新生成的檔案和現有檔案都可以透過 Resolver 存取。KSP 提供了兩個用於存取檔案的 API:Resolver.getAllFiles()Resolver.getNewFiles()getAllFiles() 會傳回現有檔案和新生成檔案的組合清單,而 getNewFiles() 只傳回新生成的檔案。

getSymbolsAnnotatedWith() 的變更

為避免不必要的符號重複處理,getSymbolsAnnotatedWith() 只傳回在新生成的檔案中找到的符號,以及來自上一個回合的延遲符號。

處理器實例化

處理器實例只會建立一次,這表示您可以將資訊儲存在處理器物件中,以供後續回合使用。

跨回合資訊的一致性

所有 KSP 符號都無法跨多個回合重複使用,因為解析結果可能會根據前一個回合生成的內容而改變。然而,由於 KSP 不允許修改現有程式碼,某些資訊(例如符號名稱的字串值)應該仍然可以重複使用。 總之,處理器可以儲存來自前一個回合的資訊,但需要記住這些資訊在未來回合中可能會無效。

錯誤與例外處理

當發生錯誤(由處理器呼叫 KSPLogger.error() 所定義)或例外時,當前回合完成後處理會停止。所有處理器都將呼叫 onError() 方法,並且不會呼叫 finish() 方法。

請注意,即使發生錯誤,其他處理器也會在該回合中繼續正常處理。這意味著錯誤處理發生在該回合處理完成之後。

遇到例外時,KSP 將嘗試區分來自 KSP 的例外和來自處理器的例外。例外將導致處理立即終止,並在 KSPLogger 中記錄為錯誤。來自 KSP 的例外應回報給 KSP 開發者以供進一步調查。在發生例外或錯誤的回合結束時,所有處理器都將呼叫 onError() 函數來執行各自的錯誤處理。

KSP 為 onError() 提供了一個預設的無操作(no-op)實作,作為 SymbolProcessor 介面的一部分。您可以覆寫此方法來提供您自己的錯誤處理邏輯。

進階

驗證的預設行為

KSP 提供的預設驗證邏輯會驗證正在驗證的符號之封裝範圍內所有直接可達的符號。 預設驗證會檢查封裝範圍中的參考是否可解析為具體類型,但不會遞迴地深入參考類型以執行驗證。

編寫您自己的驗證邏輯

預設的驗證行為可能不適用於所有情況。您可以參考 KSValidateVisitor 並透過提供一個自訂的 predicate lambda 來編寫您自己的驗證邏輯,該 lambda 隨後會由 KSValidateVisitor 用來過濾出需要檢查的符號。