Skip to content

KSPがKotlinコードをどのようにモデル化するか

APIの定義はKSPのGitHubリポジトリで確認できます。 以下の図は、KSPでKotlinがどのようにモデル化されているかの概要を示しています。

class diagram

型と解決

解決(resolution)は、基盤となるAPI実装のコストの大部分を占めます。そのため、型参照は(いくつかの例外を除いて)プロセッサによって明示的に解決されるように設計されています。_type_KSFunctionDeclaration.returnTypeKSAnnotation.annotationTypeなど)が参照される場合、それは常にKSTypeReferenceであり、これはアノテーションと修飾子を持つKSReferenceElementです。

kotlin
interface KSFunctionDeclaration : ... {
  val returnType: KSTypeReference?
  // ...
}

interface KSTypeReference : KSAnnotated, KSModifierListOwner {
  val type: KSReferenceElement
}

KSTypeReferenceKSTypeに解決することができ、これはKotlinの型システムにおける型を参照します。

KSTypeReferenceにはKSReferenceElementがあり、これはKotlinのプログラム構造、つまり参照がどのように書かれているかをモデル化します。これはKotlinの文法におけるtype要素に対応します。

KSReferenceElementKSClassifierReferenceまたはKSCallableReferenceであることができ、これらは解決の必要なく多くの有用な情報を含んでいます。例えば、KSClassifierReferencereferencedNameを持ち、KSCallableReferencereceiverTypefunctionArgumentsreturnTypeを持っています。

KSTypeReferenceによって参照される元の宣言が必要な場合、通常はKSTypeに解決し、KSType.declarationを介してアクセスすることで見つけることができます。型が言及されている箇所から、そのクラスが定義されている箇所へ移動する例は次のようになります。

kotlin
val ksType: KSType = ksTypeReference.resolve()
val ksDeclaration: KSDeclaration = ksType.declaration

型解決はコストがかかるため、明示的な形式をとります。解決によって得られる情報の一部は、KSReferenceElementで既に利用可能です。例えば、KSClassifierReference.referencedNameを使用すると、多くの不要な要素をフィルタリングできます。KSDeclarationまたはKSTypeから特定の情報が必要な場合にのみ、型を解決すべきです。

関数型を指すKSTypeReferenceは、その要素にほとんどの情報を持っています。Function0Function1などのファミリーに解決することはできますが、これらの解決はKSCallableReference以上の情報をもたらしません。関数型参照を解決する1つのユースケースは、関数のプロトタイプの同一性(identity)を扱う場合です。