Пользовательские плагины компилятора
Плагины компилятора подключаются к процессу компиляции, чтобы анализировать или изменять код во время компиляции, не изменяя сам компилятор. Например, они могут добавлять к коду аннотации или генерировать новый код, чтобы обеспечить совместимость с другими фреймворками или API.
Прежде чем создавать собственный плагин компилятора, ознакомьтесь со списком доступных плагинов компилятора, чтобы проверить, нет ли уже подходящего для вашего случая.
Также проверьте, можно ли достичь ваших целей с помощью API Kotlin Symbol Processing (KSP) или внешнего линтера, например Android lint.
Если вы всё ещё не нашли то, что вам нужно, можно создать пользовательский плагин компилятора. Имейте в виду, что API плагинов компилятора Kotlin нестабилен. Для его поддержки потребуются значительные постоянные усилия, поскольку каждый новый выпуск компилятора содержит несовместимые изменения.
Компилятор Kotlin и плагины компилятора
-
-
Компилятор Kotlin:
Анализирует исходный код и преобразует его в структурированное синтаксическое дерево.
Анализирует и разрешает код: определяет его смысл, разрешает имена, проверяет типы и применяет правила видимости.
Создаёт промежуточное представление (IR) — структуру данных, служащую связующим звеном между исходным кодом и машинным кодом.
Последовательно понижает уровень IR, преобразуя его в более простые формы.
Преобразует пониженный IR в целевой код, например байт-код JVM, JavaScript или машинный код для конкретной платформы.
Плагины могут влиять на начальные этапы работы компилятора через API фронтенда, изменяя способ разрешения кода компилятором. Например, плагин может добавлять аннотации или новые методы без тел, а также изменять модификаторы видимости. Эти изменения видны в IDE.
Плагины также могут влиять на более поздние этапы через API бэкенда, изменяя поведение объявлений. Эти изменения проявляются в двоичных файлах, создаваемых по завершении компиляции.
На практике плагины компилятора влияют на этапы от анализа и разрешения кода до генерации кода, охватывая фронтенд и бэкенд. Например, часть фронтенда генерирует объявления, а часть бэкенда добавляет к ним тела.
Плагин сериализации Kotlin — хороший пример. Часть фронтенда плагина добавляет объект-компаньон и функцию сериализатора, а также проверки, предотвращающие конфликты имён. Часть бэкенда реализует требуемое поведение сериализации с помощью объектов KSerializer.
Шаблон плагина компилятора Kotlin
Чтобы приступить к созданию пользовательского плагина компилятора, воспользуйтесь шаблоном плагина компилятора Kotlin. Затем зарегистрируйте точки расширения из API плагинов фронтенда и бэкенда.
API плагинов фронтенда
API плагинов фронтенда, также известное как промежуточное представление фронтенда (FIR), предоставляет следующие специализированные точки расширения для настройки разрешения кода:
Название расширения |
Описание |
|---|---|
Добавляет пользовательские средства проверки компилятора. |
|
Генерирует новые объявления. |
|
Регистрирует пользовательские компоненты в |
|
Определяет новые семейства функциональных типов. |
|
Читает и записывает сведения в метаданные объявлений. |
|
Изменяет атрибуты состояния объявления, например видимость или модальность. |
|
Добавляет новые суперклассы и супертипы существующему классу. |
|
Добавляет специальные атрибуты к определённым типам на основе их аннотаций типов. |
Интеграция с IDE
Изменения в разрешении кода влияют на работу IDE, например на подсветку кода и подсказки, поэтому важно обеспечить совместимость плагина с IDE. Каждая версия IntelliJ IDEA и Android Studio включает версию компилятора Kotlin, предназначенную для разработки. Эта версия специфична для IDE и не имеет двоичной совместимости с выпущенным компилятором Kotlin. Поэтому при обновлении IDE необходимо также обновить плагин компилятора, чтобы он продолжал работать. По этой причине плагины сообщества по умолчанию не загружаются.
Чтобы пользовательский плагин компилятора работал с разными версиями IDE, проверяйте его в каждой версии IDE и устраняйте обнаруженные проблемы.
Поддерживать несколько версий IDE может стать проще, если появится devkit для плагинов компилятора Kotlin. Если вас интересует эта возможность, оставьте отзыв в нашем трекере задач.
API плагинов бэкенда
API плагинов бэкенда, также известное как IR, имеет единственную точку расширения: IrGenerationExtension. Используйте эту точку расширения и переопределите функцию generate(), чтобы добавлять тела к объявлениям, уже сгенерированным фронтендом, или изменять тела существующих объявлений.
Изменения, внесённые через эту точку расширения, не проверяются компилятором. Вы должны убедиться, что эти изменения не нарушают ожидания компилятора на данном этапе. Например, можно случайно ввести недопустимый тип, неверную ссылку на функцию или ссылку за пределами нужной области видимости.
Изучите код плагина бэкенда
Чтобы увидеть, как на практике выглядит код плагина бэкенда компилятора, изучите код плагина сериализации Kotlin. Например, SerializableCompanionIrGenerator.kt заполняет отсутствующие тела ключевых членов сериализатора. Например, функция generateChildSerializersGetter() собирает список выражений KSerializer и возвращает их в массиве.
Проверьте код плагина бэкенда на наличие проблем
Проверить код плагина бэкенда на наличие проблем можно тремя способами:
-
Проверьте IR
Соберите дерево IR и включите параметр компилятора
Xverify-ir. Этот параметр снижает скорость компиляции, поэтому используйте его только во время тестирования. -
Сохраните дамп IR и сравните результаты
Создайте файл дампа после этапа понижения IR при компиляции, указав параметр компилятора
-Xphases-to-dump-before=ExternalPackageParentPatcherLowering. Для бэкенда JVM задайте каталог для дампов с помощью параметра компилятора-Xdump-directory=<your-file-directory>. Напишите ожидаемый код вручную, создайте ещё один файл дампа и сравните их, чтобы найти различия. -
Отладьте код компилятора
Добавьте точки останова в функцию
convertToIrAndActualize()в файлеconvertToIr.ktи запустите компилятор в режиме отладки, чтобы получить более подробную информацию во время компиляции.
Протестируйте плагин
После реализации плагина тщательно его протестируйте. Шаблон плагина компилятора Kotlin уже настроен для использования среды тестирования компилятора Kotlin. Тесты можно добавить в следующие каталоги:
compiler-plugin/testDatacompiler-plugin/testData/box— для тестов генерации кодаcompiler-plugin/testData/diagnostics— для диагностических тестов
При запуске теста среда:
Анализирует исходный файл теста. Например,
anotherBoxTest.ktСтроит FIR и IR для каждого файла.
Записывает их в виде текстовых файлов дампа. Например,
anotherBoxTest.fir.txtиanotherBoxTest.fir.ir.txt.Сравнивает эти файлы с ранее созданными, если они есть.
Используйте эти файлы, чтобы проверить, не появились ли в сгенерированной разнице непреднамеренные изменения. Если проблем нет, новые файлы дампа становятся вашими актуальными эталонными файлами — утверждённым и надёжным источником для сравнения будущих изменений.
Получите помощь
Если при разработке пользовательского плагина компилятора у вас возникли проблемы, обратитесь в Kotlin Slack, в канал #compiler. Мы не можем гарантировать решение, но постараемся помочь, если сможем.
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/custom-compiler-plugins.html