API обработки символов Kotlin
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 позволяет обработчикам перемещаться от объявлений классов к соответствующим типам со специфическими аргументами типов и наоборот. Также можно подставлять аргументы типов, указывать вариативность, применять проекции звёзд и отмечать возможность null для типов.
Ещё один способ понять 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() {}
}
Обработчик Resolver предоставляет SymbolProcessor доступ к данным компилятора, таким как символы. Обработчик, который находит все функции верхнего уровня и нелокальные функции в классах верхнего уровня, может выглядеть примерно так:
class HelloFunctionFinderProcessor : SymbolProcessor() {
// ...
val functions = mutableListOf<String>()
val visitor = FindFunctionsVisitor()
override fun process(resolver: Resolver) {
resolver.getAllFiles().map { it.accept(visitor, Unit) }
}
inner class FindFunctionsVisitor : KSVisitorVoid() {
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
classDeclaration.getDeclaredFunctions().map { it.accept(this, Unit) }
}
override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) {
functions.add(function)
}
override fun visitFile(file: KSFile, data: Unit) {
file.declarations.map { it.accept(this, Unit) }
}
}
// ...
class Provider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = TODO()
}
}
Ресурсы
Поддерживаемые библиотеки
В таблице ниже представлен список популярных библиотек для Android и различные стадии их поддержки для KSP.
Библиотека |
Статус |
Проблема отслеживания для KSP |
|---|---|---|
Room |
||
Moshi |
||
RxHttp |
||
Kotshi |
© 2010–2022 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/ksp-overview.html