Kotlin Symbol Processing API
Kotlin Symbol Processing (KSP) — это API, которое можно использовать для разработки лёгких плагинов компилятора. KSP предоставляет упрощённый API плагинов компилятора, использующий мощь Kotlin, при этом минимизируя кривую обучения. По сравнению с kapt, обработчики аннотаций, использующие KSP, могут работать до в 2 раза быстрее.
Чтобы узнать больше о том, как KSP сравнивается с kapt, ознакомьтесь с Почему KSP. Чтобы начать писать процессор KSP, взгляните на Быстрый старт KSP.
Обзор
API KSP обрабатывает Kotlin-программы идиоматично. KSP понимает специфические для Kotlin функции, такие как расширяющие функции, вариативность в месте объявления и локальные функции. Он также явно моделирует типы и предоставляет базовую проверку типов, такую как эквивалентность и совместимость присваивания.
API моделирует структуру Kotlin-программ на уровне символов в соответствии с грамматикой Kotlin. При обработке исходных программ плагинами, основанными на KSP, конструкции, такие как классы, члены классов, функции и связанные параметры, доступны для процессоров, в то время как такие вещи, как if блоки и for циклы, нет.
Концептуально, KSP похож на KType в отражении Kotlin. API позволяет процессорам переходить от объявлений классов к соответствующим типам со специфическими аргументами типа и наоборот. Вы также можете подставлять аргументы типа, указывать вариации, применять проекции звёздочек и помечать обязательность типов.
Ещё один способ понять KSP — это как среда предварительной обработки Kotlin-программ. Рассматривая плагины на основе KSP как процессоры символов, или просто процессоры, поток данных в компиляции можно описать следующими шагами:
Процессоры читают и анализируют исходные программы и ресурсы.
Процессоры генерируют код или другие формы вывода.
Kotlin-компилятор компилирует исходные программы вместе с сгенерированным кодом.
В отличие от полноценного плагина компилятора, процессоры не могут изменять код. Плагин компилятора, который изменяет семантику языка, иногда может быть очень запутанным. KSP избегает этого, рассматривая исходные программы как неизменяемые.
Вы также можете получить общее представление о KSP в этом видео:
Как KSP рассматривает исходные файлы
Большинство процессоров перемещаются по различным структурам программы входного исходного кода. Прежде чем углубляться в использование API, давайте посмотрим, как файл может выглядеть с точки зрения KSP:
KSFile
packageName: KSName
fileName: String
annotations: List<KSAnnotation> (File annotations)
declarations: List<KSDeclaration>
KSClassDeclaration // class, interface, object
simpleName: KSName
qualifiedName: KSName
containingFile: String
typeParameters: KSTypeParameter
parentDeclaration: KSDeclaration
classKind: ClassKind
primaryConstructor: KSFunctionDeclaration
superTypes: List<KSTypeReference>
// contains inner classes, member functions, properties, etc.
declarations: List<KSDeclaration>
KSFunctionDeclaration // top level function
simpleName: KSName
qualifiedName: KSName
containingFile: String
typeParameters: KSTypeParameter
parentDeclaration: KSDeclaration
functionKind: FunctionKind
extensionReceiver: KSTypeReference?
returnType: KSTypeReference
parameters: List<KSValueParameter>
// contains local classes, local functions, local variables, etc.
declarations: List<KSDeclaration>
KSPropertyDeclaration // global variable
simpleName: KSName
qualifiedName: KSName
containingFile: String
typeParameters: KSTypeParameter
parentDeclaration: KSDeclaration
extensionReceiver: KSTypeReference?
type: KSTypeReference
getter: KSPropertyGetter
returnType: KSTypeReference
setter: KSPropertySetter
parameter: KSValueParameter
Этот вид перечисляет общие вещи, которые объявлены в файле: классы, функции, свойства и так далее.
SymbolProcessorProvider: точка входа
KSP ожидает реализацию интерфейса SymbolProcessorProvider для создания SymbolProcessor.
interface SymbolProcessorProvider {
fun create(environment: SymbolProcessorEnvironment): SymbolProcessor
}
В то время как SymbolProcessor определено как:
interface SymbolProcessor {
fun process(resolver: Resolver): List<KSAnnotated> // Let's focus on this
fun finish() {}
fun onError() {}
}
A Resolver предоставляет SymbolProcessor доступ к деталям компилятора, таким как символы. Процессор, который находит все функции верхнего уровня и функции, не являющиеся локальными, в классах верхнего уровня, может выглядеть примерно так:
class HelloFunctionFinderProcessor : SymbolProcessor() {
// ...
val functions = mutableListOf<KSClassDeclaration>()
val visitor = FindFunctionsVisitor()
override fun process(resolver: Resolver) {
resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
}
inner class FindFunctionsVisitor : KSVisitorVoid() {
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
classDeclaration.getDeclaredFunctions().forEach { it.accept(this, Unit) }
}
override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
functions.add(function)
}
override fun visitFile(file: KSFile, data: Unit) {
file.declarations.forEach { it.accept(this, Unit) }
}
}
// ...
class Provider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = TODO()
}
}
Ресурсы
Поддерживаемые библиотеки
В таблице ниже представлен список популярных библиотек для Android и различные стадии их поддержки KSP.
Библиотека |
Статус |
Задача отслеживания для KSP |
|---|---|---|
Room |
||
Moshi |
||
RxHttp |
||
Kotshi |
||
Lyricist |
||
Lich SavedState |
||
gRPC Dekorator |
||
EasyAdapter |
||
Koin Annotations |
||
Auto Factory |
Пока не поддерживается |
|
Dagger |
Пока не поддерживается |
|
Hilt |
Пока не поддерживается |
|
Glide |
||
DeeplinkDispatch |
||
Micronaut |
В процессе |
|
Epoxy |
||
Paris |
||
Auto Dagger |
||
SealedX |
||
© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/ksp-overview.html