KSP 如何为 Kotlin 代码建模
You can find the API definition in the KSP GitHub repository. The diagram shows an overview of how Kotlin is modeled in KSP:
{thumbnail="true" width="800" thumbnail-same-file="true"}
Type and resolution
The resolution takes most of the cost of the underlying API implementation. So type references are designed to be
resolved by processors explicitly (with a few exceptions). When a type (such as KSFunctionDeclaration.returnType
or KSAnnotation.annotationType) is referenced, 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:
val ksType: KSType = ksTypeReference.resolve()
val ksDeclaration: KSDeclaration = ksType.declaration
Type resolution is costly and therefore has explicit form. 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.
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.