KSPがKotlinコードをどのようにモデル化するか
APIの定義はKSPのGitHubリポジトリで確認できます。 以下の図は、KSPでKotlinがどのようにモデル化されているかの概要を示しています。
NOTE
型と解決
解決(resolution)は、基盤となるAPI実装のコストの大部分を占めます。そのため、型参照は(いくつかの例外を除いて)プロセッサによって明示的に解決されるように設計されています。_type_
(KSFunctionDeclaration.returnType
やKSAnnotation.annotationType
など)が参照される場合、それは常にKSTypeReference
であり、これはアノテーションと修飾子を持つKSReferenceElement
です。
interface KSFunctionDeclaration : ... {
val returnType: KSTypeReference?
// ...
}
interface KSTypeReference : KSAnnotated, KSModifierListOwner {
val type: KSReferenceElement
}
KSTypeReference
はKSType
に解決することができ、これは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つのユースケースは、関数のプロトタイプの同一性(identity)を扱う場合です。