| # Compiler Plugins |
| |
| **WARNING:** The Compiler Plugin API is very unstable and low-level. |
| Please consider other options whenever possible. Many use cases for compiler plugins can be addressed by tools like [KSP](https://kotlinlang.org/docs/ksp-overview.html) or external linters. |
| |
| The compiler provides several extension points that can modify its behavior. |
| |
| Currently, no stable API for compiler plugins is available. This means there is no guarantee that a compiler plugin built against one version of the compiler will work with another version. |
| You need to either build the compiler plugin within your project or publish versions built specifically for all the compiler versions you need as dependencies. |
| |
| ## Types of Extension Points |
| |
| There are two types of extension points: |
| |
| 1. **Frontend extension points** – Required for working with declarations that need to be visible during resolution. |
| 2. **Backend extension points** – Required for working with declaration bodies and private declarations. |
| |
| ## Frontend Part |
| |
| This part is specific to the version of the frontend being used. |
| If you need to work with language versions below 1.9, you must use the K1 Compiler Plugin API. |
| |
| The frontend part of Compiler Plugin API allows you to: |
| |
| - Declare new publicly visible declarations. |
| - Modify some properties of existing declarations. |
| - Provide additional compiler warnings and errors relevant to your plugin. |
| |
| For new plugins, you should work with the [K2 Compiler Plugin API](../fir/fir-plugins.md). |
| |
| ## Backend Part |
| |
| The backend part enables you to generate bodies of declarations created in frontend part and modify bodies of preexisting declarations. |
| This is achieved by changing the compiler's intermediate representation (IR), which is generated by compiler. |
| |
| The primary entry point for this is the `org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension::generate` method. |
| |
| Unfortunately, there is no comprehensive documentation on what specific IR represents or how it corresponds to Kotlin code. |
| The best way to understand which IR needs to be generated for your use case is as follows: |
| |
| 1. Write the code that you want to generate manually. |
| 2. Observe the IR generated by the compiler for that code. |
| 3. Mimic the generated IR as closely as possible. |
| |
| Here are some useful utilities for working with IR: |
| |
| - The `IrElement.dump()` extension function allows you to inspect IR by logging it or checking it in a debugger within your `generate` method. |
| - You can dump IR to text files by passing the following options to the compiler: |
| - `-Xphases-to-dump-before=<phase-name>` |
| - `-Xdump-directory=<path>` |
| |
| You can check the name of the first backend compiler phase to dump IR for the JVM backend [here](../../compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/JvmLoweringPhases.kt), and |
| in similar places for other backends. Currently, for the JVM backend, the name of the first phase is `ExternalPackageParentPatcherLowering`. |
| |
| ## Examples |
| |
| There are several plugins in the Kotlin repository, located in the [plugins](../../plugins) directory. |
| Also, there is a toy [sandbox plugin](../../plugins/plugin-sandbox) which tests all existing extension points, and can be used as example for simple cases. |