The API definition can be found here. The diagram below is an overview of how Kotlin is modeled in KSP:
In KSP, references to types are designed to be resolved by processors explicitly (with a few exceptions) because most of the cost of the underlying API implementation is in resolution. When a type is referenced, such as KSFunctionDeclaration.returnType
or KSAnnotation.annotationType
, it is always a KSTypeReference
, which is a KSReferenceElement
with annotations and modifiers.
interface KSFunctionDeclaration : ... { val returnType: KSTypeReference? ... } interface KSTypeReference : KSAnnotated, KSModifierListOwner { val type: KSReferenceElement }
A KSTypeReference
can be resolved to a KSType
, which refers to a type in Kotlin's type system.
A KSTypeReference
has a KSReferenceElement
, which models Kotlin‘s program structure: namely, how the reference is written. It corresponds to the type
element in Kotlin's grammar.
A KSReferenceElement
can be a KSClassifierReference
or KSCallableReference
, which contains a lot of useful information without the need for resolution. For example, KSClassifierReference
has referencedName
, while KSCallableReference
has receiverType
, functionArguments
, and returnType
.
If the original declaration referenced by a KSTypeReference
is needed, it can usually be found by resolving to KSType
and accessing through KSType.declaration
. Moving from where a type is mentioned to where its class is defined looks like this:
KSTypeReference -> .resolve() -> KSType -> .declaration -> KSDeclaration
Type resolution is costly and is therefore made explicit. Some of the information obtained from resolution is already available in KSReferenceElement
. For example, KSClassifierReference.referencedName
can filter out a lot of elements that are not interesting. You should resolve type only if you need specific information from KSDeclaration
or KSType
.
Note that a KSTypeReference
pointing to a function type has most of its information in its element. Although it can be resolved to the family of Function0
, Function1
, and so on, these resolutions don‘t bring any more information than KSCallableReference
. One use case for resolving function type references is dealing with the identity of the function's prototype.