0
# Plugin System and Extensions
1
2
Extension framework for compiler plugins, custom compilation phases, and code generation hooks. The plugin system allows extending the Kotlin compiler with custom functionality for code analysis, transformation, and generation.
3
4
## Capabilities
5
6
### CompilerPluginRegistrar
7
8
Modern plugin registration interface for K2 compiler supporting extension-based architecture.
9
10
```kotlin { .api }
11
/**
12
* Modern plugin registration interface for K2 compiler
13
* Replaces ComponentRegistrar for new plugin development
14
*/
15
interface CompilerPluginRegistrar {
16
/** Extension storage for registering compiler extensions */
17
val supportsK2: Boolean get() = false
18
19
/** Register extensions in the compiler's extension storage */
20
fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration): Unit
21
22
companion object {
23
/** Create registrar instance from configuration */
24
fun create(configuration: CompilerConfiguration): CompilerPluginRegistrar?
25
}
26
}
27
```
28
29
### ComponentRegistrar (Legacy)
30
31
Legacy plugin registration interface for K1 compiler, being phased out in favor of CompilerPluginRegistrar.
32
33
```kotlin { .api }
34
/**
35
* Legacy plugin registration interface for K1 compiler
36
* Being replaced by CompilerPluginRegistrar for K2
37
*/
38
@Deprecated("Use CompilerPluginRegistrar for K2 compatibility")
39
interface ComponentRegistrar {
40
/** Register project components with the compiler */
41
fun registerProjectComponents(
42
project: MockProject,
43
configuration: CompilerConfiguration
44
): Unit
45
46
/** Whether this registrar supports K2 compiler */
47
val supportsK2: Boolean get() = false
48
}
49
```
50
51
### CommandLineProcessor
52
53
Interface for processing plugin-specific command-line arguments.
54
55
```kotlin { .api }
56
/**
57
* Interface for processing plugin-specific command-line arguments
58
* Allows plugins to define and parse their own CLI options
59
*/
60
abstract class CommandLineProcessor {
61
/** Unique plugin identifier */
62
abstract val pluginId: String
63
64
/** Plugin options that can be specified on command line */
65
abstract val pluginOptions: Collection<CliOption>
66
67
/** Process plugin options and update configuration */
68
abstract fun processOption(
69
option: AbstractCliOption,
70
value: String,
71
configuration: CompilerConfiguration
72
): Unit
73
74
companion object {
75
/** Create processor instance */
76
fun createInstance(): CommandLineProcessor?
77
}
78
}
79
80
/**
81
* Definition of a command-line option for plugins
82
*/
83
data class CliOption(
84
/** Option name (without dashes) */
85
val optionName: String,
86
87
/** Value description for help text */
88
val valueDescription: String,
89
90
/** Help description */
91
val description: String,
92
93
/** Whether option is required */
94
val required: Boolean = false,
95
96
/** Whether option allows multiple values */
97
val allowMultipleOccurrences: Boolean = false
98
)
99
```
100
101
**Plugin Development Examples:**
102
103
```kotlin
104
// Modern K2 plugin using CompilerPluginRegistrar
105
class MyCompilerPlugin : CompilerPluginRegistrar {
106
override val supportsK2: Boolean = true
107
108
override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) {
109
// Register FIR extensions for K2
110
FirExtensionRegistrarAdapter.registerExtension(MyFirExtensionRegistrar())
111
112
// Register backend extensions
113
IrGenerationExtension.registerExtension(MyIrGenerationExtension())
114
115
// Register additional extensions
116
registerExtension(MyAnalysisHandlerExtension())
117
}
118
}
119
120
// Command line processor for plugin options
121
class MyPluginCommandLineProcessor : CommandLineProcessor() {
122
override val pluginId: String = "my-plugin"
123
124
override val pluginOptions: Collection<CliOption> = listOf(
125
CliOption(
126
optionName = "enable-feature",
127
valueDescription = "true|false",
128
description = "Enable the special feature"
129
),
130
CliOption(
131
optionName = "output-dir",
132
valueDescription = "path",
133
description = "Output directory for generated files",
134
required = true
135
)
136
)
137
138
override fun processOption(
139
option: AbstractCliOption,
140
value: String,
141
configuration: CompilerConfiguration
142
) {
143
when (option.optionName) {
144
"enable-feature" -> {
145
configuration.put(MyPluginConfigurationKeys.ENABLE_FEATURE, value.toBoolean())
146
}
147
"output-dir" -> {
148
configuration.put(MyPluginConfigurationKeys.OUTPUT_DIR, File(value))
149
}
150
}
151
}
152
}
153
154
// Plugin configuration keys
155
object MyPluginConfigurationKeys {
156
val ENABLE_FEATURE = CompilerConfigurationKey.create<Boolean>("enable feature")
157
val OUTPUT_DIR = CompilerConfigurationKey.create<File>("output directory")
158
}
159
```
160
161
### Extension Points
162
163
Core extension interfaces for hooking into different compilation phases.
164
165
```kotlin { .api }
166
/**
167
* Extension for analysis phase - called during semantic analysis
168
*/
169
interface AnalysisHandlerExtension {
170
/** Perform analysis after resolution is complete */
171
fun analysisCompleted(
172
project: Project,
173
module: ModuleDescriptor,
174
bindingTrace: BindingTrace,
175
files: Collection<KtFile>
176
): AnalysisResult?
177
178
/** Check if extension should be applied to given files */
179
fun doAnalysis(
180
project: Project,
181
module: ModuleDescriptor,
182
projectContext: ProjectContext,
183
files: Collection<KtFile>,
184
bindingTrace: BindingTrace,
185
componentProvider: ComponentProvider
186
): AnalysisResult?
187
}
188
189
/**
190
* Extension for IR generation phase - transform intermediate representation
191
*/
192
interface IrGenerationExtension {
193
/** Generate or transform IR after initial generation */
194
fun generate(
195
moduleFragment: IrModuleFragment,
196
pluginContext: IrPluginContext
197
): Unit
198
199
companion object {
200
/** Register extension instance */
201
fun registerExtension(extension: IrGenerationExtension): Unit
202
}
203
}
204
205
/**
206
* Extension for class generation phase - modify generated JVM bytecode
207
*/
208
interface ClassGeneratorExtension {
209
/** Called for each generated class */
210
fun generateClass(
211
codegen: ImplementationBodyCodegen,
212
classDescriptor: ClassDescriptor
213
): Unit
214
215
/** Called when generating class file factory */
216
fun createClassFileFactory(
217
project: Project,
218
bindingContext: BindingContext,
219
classFileFactory: ClassFileFactory
220
): ClassFileFactory
221
}
222
223
/**
224
* Extension for synthetic symbol resolution
225
*/
226
interface SyntheticResolveExtension {
227
/** Generate synthetic members for classes */
228
fun generateSyntheticMethods(
229
thisDescriptor: ClassDescriptor,
230
result: MutableList<FunctionDescriptor>
231
): Unit
232
233
/** Generate synthetic properties for classes */
234
fun generateSyntheticProperties(
235
thisDescriptor: ClassDescriptor,
236
result: MutableList<PropertyDescriptor>
237
): Unit
238
}
239
```
240
241
### FIR Extensions (K2 Compiler)
242
243
Extensions for the new K2 compiler frontend (FIR - Frontend Intermediate Representation).
244
245
```kotlin { .api }
246
/**
247
* Registrar for FIR extensions in K2 compiler
248
*/
249
interface FirExtensionRegistrar {
250
/** Register FIR extensions */
251
fun ExtensionRegistrarContext.configurePlugin(): Unit
252
}
253
254
/**
255
* Context for registering FIR extensions
256
*/
257
interface ExtensionRegistrarContext {
258
/** Register declaration generation extension */
259
fun <T : FirDeclaration> registerDeclarationGenerators(
260
vararg generators: FirDeclarationGenerationExtension<T>
261
): Unit
262
263
/** Register additional checkers */
264
fun registerAdditionalCheckers(checkers: AdditionalCheckers): Unit
265
266
/** Register status transformer */
267
fun registerStatusTransformer(transformer: FirStatusTransformer): Unit
268
}
269
270
/**
271
* Extension for generating additional FIR declarations
272
*/
273
interface FirDeclarationGenerationExtension<T : FirDeclaration> {
274
/** Generate additional declarations */
275
fun generateDeclarations(
276
callableId: CallableId,
277
context: DeclarationGenerationContext
278
): List<T>
279
280
/** Check if extension applies to symbol */
281
fun matches(callableId: CallableId): Boolean
282
}
283
```
284
285
### Script Extensions
286
287
Extensions for Kotlin script compilation and evaluation.
288
289
```kotlin { .api }
290
/**
291
* Extension for script evaluation
292
*/
293
interface ScriptEvaluationExtension {
294
/** Evaluate compiled script */
295
fun eval(
296
script: KtScript,
297
scriptCompilationConfiguration: ScriptCompilationConfiguration,
298
evaluationConfiguration: ScriptEvaluationConfiguration
299
): ResultWithDiagnostics<EvaluationResult>
300
301
/** Check if extension can evaluate the script */
302
fun canEvaluate(script: KtScript): Boolean
303
}
304
305
/**
306
* Extension for shell interaction (REPL)
307
*/
308
interface ShellExtension {
309
/** Execute shell command */
310
fun execute(
311
command: String,
312
context: ShellExecutionContext
313
): ShellExecutionResult
314
315
/** Get completion suggestions */
316
fun getCompletions(
317
code: String,
318
cursor: Int
319
): List<CompletionSuggestion>
320
}
321
```
322
323
**Advanced Plugin Examples:**
324
325
```kotlin
326
// Code generation plugin
327
class CodeGenerationPlugin : CompilerPluginRegistrar {
328
override val supportsK2: Boolean = true
329
330
override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) {
331
val outputDir = configuration.get(MyPluginConfigurationKeys.OUTPUT_DIR)
332
333
IrGenerationExtension.registerExtension(object : IrGenerationExtension {
334
override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) {
335
// Transform IR to generate additional code
336
moduleFragment.transform(MyIrTransformer(pluginContext, outputDir), null)
337
}
338
})
339
340
ClassGeneratorExtension.registerExtension(object : ClassGeneratorExtension {
341
override fun generateClass(
342
codegen: ImplementationBodyCodegen,
343
classDescriptor: ClassDescriptor
344
) {
345
// Generate additional methods or modify bytecode
346
if (classDescriptor.hasAnnotation("GenerateToString")) {
347
generateToStringMethod(codegen, classDescriptor)
348
}
349
}
350
})
351
}
352
}
353
354
// Analysis plugin for code inspection
355
class AnalysisPlugin : CompilerPluginRegistrar {
356
override val supportsK2: Boolean = true
357
358
override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) {
359
AnalysisHandlerExtension.registerExtension(object : AnalysisHandlerExtension {
360
override fun analysisCompleted(
361
project: Project,
362
module: ModuleDescriptor,
363
bindingTrace: BindingTrace,
364
files: Collection<KtFile>
365
): AnalysisResult? {
366
// Perform custom analysis
367
files.forEach { file ->
368
analyzeFile(file, bindingTrace)
369
}
370
return null
371
}
372
})
373
}
374
375
private fun analyzeFile(file: KtFile, bindingTrace: BindingTrace) {
376
file.accept(object : KtVisitorVoid() {
377
override fun visitClass(klass: KtClass) {
378
super.visitClass(klass)
379
// Check for specific patterns
380
if (hasDeprecatedPattern(klass)) {
381
bindingTrace.report(Errors.DEPRECATED_USAGE.on(klass))
382
}
383
}
384
})
385
}
386
}
387
388
// FIR-based plugin for K2
389
class FirPlugin : FirExtensionRegistrar {
390
override fun ExtensionRegistrarContext.configurePlugin() {
391
registerDeclarationGenerators(MyDeclarationGenerator())
392
registerAdditionalCheckers(MyAdditionalCheckers())
393
registerStatusTransformer(MyStatusTransformer())
394
}
395
}
396
```
397
398
### Plugin Loading and Registration
399
400
Utilities for plugin discovery and registration.
401
402
```kotlin { .api }
403
/**
404
* Plugin loading utilities
405
*/
406
object PluginCliParser {
407
/** Parse plugin options from command line arguments */
408
fun parsePluginOptions(
409
pluginClasspaths: List<String>,
410
pluginOptions: List<String>,
411
configuration: CompilerConfiguration,
412
messageCollector: MessageCollector
413
): ExitCode
414
415
/** Load plugin from classpath */
416
fun loadPluginFromClasspath(
417
classpath: String,
418
configuration: CompilerConfiguration
419
): CompilerPluginRegistrar?
420
}
421
422
/**
423
* Plugin registry for managing loaded plugins
424
*/
425
interface CompilerPluginRegistry {
426
/** Register plugin instance */
427
fun registerPlugin(plugin: CompilerPluginRegistrar): Unit
428
429
/** Get all registered plugins */
430
fun getAllPlugins(): List<CompilerPluginRegistrar>
431
432
/** Find plugin by ID */
433
fun findPlugin(pluginId: String): CompilerPluginRegistrar?
434
}
435
```
436
437
## Plugin Packaging and Distribution
438
439
```kotlin
440
// Plugin descriptor for service loading
441
// META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
442
class MyPlugin : CompilerPluginRegistrar {
443
override val supportsK2: Boolean = true
444
445
override fun ExtensionStorage.registerExtensions(configuration: CompilerConfiguration) {
446
// Plugin implementation
447
}
448
}
449
450
// Gradle plugin for easy distribution
451
class MyKotlinCompilerPlugin : KotlinCompilerPluginSupportPlugin {
452
override fun apply(target: Project) {
453
target.extensions.create("myPlugin", MyPluginExtension::class.java)
454
}
455
456
override fun getCompilerPluginId(): String = "my-plugin"
457
458
override fun getPluginArtifact(): SubpluginArtifact {
459
return SubpluginArtifact(
460
groupId = "com.example",
461
artifactId = "my-kotlin-plugin",
462
version = "1.0.0"
463
)
464
}
465
466
override fun applyToCompilation(kotlinCompilation: KotlinCompilation<*>): Provider<List<SubpluginOption>> {
467
val extension = kotlinCompilation.target.project.extensions.getByType<MyPluginExtension>()
468
return kotlinCompilation.target.project.provider {
469
listOf(
470
SubpluginOption("enable-feature", extension.enableFeature.toString()),
471
SubpluginOption("output-dir", extension.outputDir.absolutePath)
472
)
473
}
474
}
475
}
476
```