KSPはKotlinコードをどのようにモデル化するか
KSP GitHubリポジトリでAPI定義を確認できます。 以下の図は、KotlinがKSPでどのようにモデル化されているかの概要を示しています。
型と解決
解決(resolution)は、基盤となるAPI実装のコストの大部分を占めます。そのため、型参照は、(いくつかの例外を除き)プロセッサによって明示的に解決されるように設計されています。KSFunctionDeclaration.returnType
やKSAnnotation.annotationType
のような_型_が参照される場合、それは常にKSTypeReference
であり、これはアノテーションと修飾子を持つKSReferenceElement
です。
interface KSFunctionDeclaration : ... {
val returnType: KSTypeReference?
// ...
}
interface KSTypeReference : KSAnnotated, KSModifierListOwner {
val type: KSReferenceElement
}
KSTypeReference
はKSType
に解決(resolve)でき、これはKotlinの型システムにおける型を参照します。
KSTypeReference
はKSReferenceElement
を持っており、これはKotlinのプログラム構造、すなわち参照がどのように記述されているかをモデル化します。これはKotlinの文法におけるtype
要素に対応します。
KSReferenceElement
はKSClassifierReference
またはKSCallableReference
になることができ、これらは解決を必要とせずに多くの有用な情報を含んでいます。例えば、KSClassifierReference
はreferencedName
を持ち、KSCallableReference
はreceiverType
、functionArguments
、およびreturnType
を持ちます。
KSTypeReference
によって参照される元の宣言が必要な場合、通常はKSType
に解決し、KSType.declaration
を通じてアクセスすることで見つけることができます。型が言及されている場所から、そのクラスが定義されている場所に移動する様子は次のようになります。
val ksType: KSType = ksTypeReference.resolve()
val ksDeclaration: KSDeclaration = ksType.declaration
型解決はコストがかかるため、明示的な形式をとります。解決から得られる情報の一部は、すでにKSReferenceElement
で利用可能です。例えば、KSClassifierReference.referencedName
は、関心のない多くの要素をフィルタリングできます。KSDeclaration
またはKSType
からの特定の情報が必要な場合にのみ、型を解決する必要があります。
関数型を指すKSTypeReference
は、その要素にほとんどの情報を持っています。
Function0
、Function1
などのファミリーに解決できますが、これらの解決はKSCallableReference
以上の情報をもたらしません。関数型参照を解決するユースケースの1つは、関数のプロトタイプのアイデンティティを扱うことです。