or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

compiler-entry-points.mdconfiguration-system.mdhigh-level-api.mdincremental-compilation.mdindex.mdmessage-collection.mdplugin-system.md

plugin-system.mddocs/

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

```