0
# Message Handling and Diagnostics
1
2
Comprehensive diagnostic and message reporting system providing multiple output formats, severity levels, and source location tracking. The message handling system supports integration with IDEs, build tools, and command-line interfaces through customizable renderers and collectors.
3
4
## Capabilities
5
6
### MessageCollector
7
8
Core interface for collecting compilation messages and diagnostics with severity-based filtering.
9
10
```kotlin { .api }
11
/**
12
* Interface for collecting compilation messages and diagnostics
13
* Provides extensible message handling with severity levels
14
*/
15
interface MessageCollector {
16
/**
17
* Report a compilation message
18
*
19
* @param severity Message severity level
20
* @param message Message text content
21
* @param location Optional source location information
22
*/
23
fun report(
24
severity: CompilerMessageSeverity,
25
message: String,
26
location: CompilerMessageSourceLocation? = null
27
)
28
29
/**
30
* Check if message collector has reported errors
31
*
32
* @return true if any error messages have been reported
33
*/
34
fun hasErrors(): Boolean
35
36
/**
37
* Clear all collected messages
38
* Resets error state and clears message history
39
*/
40
fun clear()
41
42
companion object {
43
/** No-op message collector that discards all messages */
44
val NONE: MessageCollector
45
}
46
}
47
```
48
49
### Message Severity Levels
50
51
Hierarchical severity levels for categorizing compilation messages.
52
53
```kotlin { .api }
54
/**
55
* Compilation message severity levels
56
* Hierarchical system from logging to errors
57
*/
58
enum class CompilerMessageSeverity(val presentableName: String) {
59
/** Detailed logging information */
60
LOGGING("logging"),
61
62
/** General information messages */
63
INFO("info"),
64
65
/** General warnings */
66
WARNING("warning"),
67
68
/** Important warnings that should not be ignored */
69
STRONG_WARNING("strong warning"),
70
71
/** Compilation errors */
72
ERROR("error"),
73
74
/** Fatal compiler errors */
75
EXCEPTION("exception");
76
77
companion object {
78
/** Verbose output including all severity levels */
79
val VERBOSE: Set<CompilerMessageSeverity>
80
81
/**
82
* Check if severity level is error or higher
83
*
84
* @param severity Severity to check
85
* @return true if error level or higher
86
*/
87
fun isError(severity: CompilerMessageSeverity): Boolean
88
89
/**
90
* Check if severity level is warning or higher
91
*
92
* @param severity Severity to check
93
* @return true if warning level or higher
94
*/
95
fun isWarning(severity: CompilerMessageSeverity): Boolean
96
}
97
}
98
```
99
100
### Source Location Information
101
102
Source file location information for precise error reporting.
103
104
```kotlin { .api }
105
/**
106
* Source location information for diagnostic messages
107
* Provides file path and position information
108
*/
109
interface CompilerMessageSourceLocation {
110
/** Source file path */
111
val path: String
112
113
/** Line number (1-based) */
114
val line: Int
115
116
/** Column number (1-based) */
117
val column: Int
118
119
/** Line content for context */
120
val lineContent: String?
121
122
companion object {
123
/**
124
* Create source location
125
*
126
* @param path File path
127
* @param line Line number (1-based)
128
* @param column Column number (1-based)
129
* @param lineContent Optional line content
130
* @return Source location instance
131
*/
132
fun create(
133
path: String,
134
line: Int,
135
column: Int,
136
lineContent: String?
137
): CompilerMessageSourceLocation
138
}
139
}
140
```
141
142
### Message Renderers
143
144
Pluggable message rendering system for different output formats and tools.
145
146
```kotlin { .api }
147
/**
148
* Interface for rendering diagnostic messages
149
* Supports different output formats for various tools
150
*/
151
interface MessageRenderer {
152
/**
153
* Render diagnostic message to string
154
*
155
* @param severity Message severity level
156
* @param message Message content
157
* @param location Source location information
158
* @return Formatted message string
159
*/
160
fun render(
161
severity: CompilerMessageSeverity,
162
message: String,
163
location: CompilerMessageSourceLocation?
164
): String
165
166
/**
167
* Get path representation
168
* Controls how file paths are displayed
169
*
170
* @param location Source location
171
* @return Formatted path string
172
*/
173
fun getPath(location: CompilerMessageSourceLocation): String
174
175
companion object {
176
/** Plain text renderer with full file paths */
177
val PLAIN_FULL_PATHS: MessageRenderer
178
179
/** Plain text renderer with relative file paths */
180
val PLAIN_RELATIVE_PATHS: MessageRenderer
181
182
/** Plain text renderer without file paths */
183
val PLAIN_WITHOUT_PATHS: MessageRenderer
184
}
185
}
186
```
187
188
### Specialized Message Renderers
189
190
Pre-built renderers for common IDE and build tool integration.
191
192
```kotlin { .api }
193
/**
194
* Plain text message renderer
195
* Standard text output for command-line tools
196
*/
197
class PlainTextMessageRenderer(
198
private val withPaths: Boolean = true
199
) : MessageRenderer {
200
override fun render(
201
severity: CompilerMessageSeverity,
202
message: String,
203
location: CompilerMessageSourceLocation?
204
): String
205
}
206
207
/**
208
* Xcode-compatible message renderer
209
* Formats messages for Xcode IDE integration
210
*/
211
class XcodeStyleMessageRenderer : MessageRenderer {
212
override fun render(
213
severity: CompilerMessageSeverity,
214
message: String,
215
location: CompilerMessageSourceLocation?
216
): String
217
}
218
219
/**
220
* Gradle-compatible message renderer
221
* Formats messages for Gradle build tool integration
222
*/
223
class GradleStyleMessageRenderer : MessageRenderer {
224
override fun render(
225
severity: CompilerMessageSeverity,
226
message: String,
227
location: CompilerMessageSourceLocation?
228
): String
229
}
230
```
231
232
### Printing Message Collector
233
234
Concrete message collector that prints messages to output streams.
235
236
```kotlin { .api }
237
/**
238
* Message collector that prints to output streams
239
* Supports custom renderers and severity filtering
240
*/
241
class PrintingMessageCollector(
242
private val stream: PrintStream,
243
private val messageRenderer: MessageRenderer,
244
private val verbose: Boolean
245
) : MessageCollector {
246
247
/**
248
* Create printing message collector
249
*
250
* @param stream Output stream for messages
251
* @param messageRenderer Message rendering strategy
252
* @param verbose Enable verbose output (all severity levels)
253
*/
254
constructor(
255
stream: PrintStream,
256
messageRenderer: MessageRenderer,
257
verbose: Boolean
258
)
259
260
override fun report(
261
severity: CompilerMessageSeverity,
262
message: String,
263
location: CompilerMessageSourceLocation?
264
) {
265
if (verbose || severity != CompilerMessageSeverity.LOGGING) {
266
val renderedMessage = messageRenderer.render(severity, message, location)
267
stream.println(renderedMessage)
268
}
269
}
270
271
override fun hasErrors(): Boolean
272
override fun clear()
273
}
274
```
275
276
### Grouping Message Collector
277
278
Message collector that groups related messages together.
279
280
```kotlin { .api }
281
/**
282
* Message collector that groups related messages
283
* Useful for organizing diagnostic output by file or module
284
*/
285
class GroupingMessageCollector(
286
private val delegate: MessageCollector
287
) : MessageCollector {
288
289
/**
290
* Start new message group
291
*
292
* @param groupName Name for the message group
293
*/
294
fun startGroup(groupName: String)
295
296
/**
297
* End current message group
298
*/
299
fun endGroup()
300
301
override fun report(
302
severity: CompilerMessageSeverity,
303
message: String,
304
location: CompilerMessageSourceLocation?
305
)
306
307
override fun hasErrors(): Boolean
308
override fun clear()
309
}
310
```
311
312
### Analysis and Diagnostic Reporting
313
314
Advanced diagnostic reporting with analysis integration.
315
316
```kotlin { .api }
317
/**
318
* Analyzer with integrated compiler reporting
319
* Combines frontend analysis with diagnostic collection
320
*/
321
class AnalyzerWithCompilerReport(
322
private val messageCollector: MessageCollector,
323
private val languageVersionSettings: LanguageVersionSettings
324
) {
325
/**
326
* Check for compilation errors
327
*
328
* @return true if compilation should stop due to errors
329
*/
330
fun hasErrors(): Boolean
331
332
/**
333
* Report analysis result
334
*
335
* @param result Analysis result to report
336
* @param files Source files analyzed
337
*/
338
fun reportAnalysisResult(
339
result: AnalysisResult,
340
files: Collection<KtFile>
341
)
342
343
/**
344
* Render diagnostic with context
345
*
346
* @param diagnostic Diagnostic to render
347
* @return Formatted diagnostic message
348
*/
349
fun renderDiagnostic(diagnostic: Diagnostic): String
350
}
351
352
/**
353
* Default diagnostic reporter implementation
354
* Standard diagnostic message formatting and reporting
355
*/
356
class DefaultDiagnosticReporter(
357
private val messageCollector: MessageCollector
358
) : DiagnosticReporter {
359
360
override fun report(
361
diagnostic: Diagnostic,
362
bindingContext: BindingContext
363
) {
364
val severity = diagnostic.severity.toCompilerMessageSeverity()
365
val message = renderDiagnosticMessage(diagnostic)
366
val location = diagnostic.psiElement?.let {
367
getLocationFromPsiElement(it)
368
}
369
370
messageCollector.report(severity, message, location)
371
}
372
}
373
```
374
375
### Diagnostic Message Reporter
376
377
High-level diagnostic message reporting with rich formatting.
378
379
```kotlin { .api }
380
/**
381
* Rich diagnostic message reporter
382
* Provides detailed diagnostic information with context
383
*/
384
class DiagnosticMessageReporter(
385
private val messageCollector: MessageCollector,
386
private val messageRenderer: MessageRenderer = MessageRenderer.PLAIN_FULL_PATHS
387
) {
388
/**
389
* Report diagnostic with full context
390
*
391
* @param diagnostic Diagnostic information
392
* @param file Source file context
393
* @param context Binding context for resolution
394
*/
395
fun reportDiagnostic(
396
diagnostic: Diagnostic,
397
file: KtFile,
398
context: BindingContext
399
)
400
401
/**
402
* Report multiple diagnostics from analysis
403
*
404
* @param diagnostics Collection of diagnostics
405
* @param context Binding context
406
*/
407
fun reportDiagnostics(
408
diagnostics: Collection<Diagnostic>,
409
context: BindingContext
410
)
411
412
/**
413
* Report exception as diagnostic
414
*
415
* @param exception Exception to report
416
* @param location Optional source location
417
*/
418
fun reportException(
419
exception: Throwable,
420
location: CompilerMessageSourceLocation? = null
421
)
422
}
423
```
424
425
## Usage Examples
426
427
### Basic Message Collection
428
429
```kotlin
430
import org.jetbrains.kotlin.cli.common.messages.*
431
import java.io.PrintStream
432
433
// Create message collector with plain text renderer
434
val messageCollector = PrintingMessageCollector(
435
stream = System.err,
436
messageRenderer = MessageRenderer.PLAIN_FULL_PATHS,
437
verbose = true
438
)
439
440
// Report messages with different severity levels
441
messageCollector.report(
442
CompilerMessageSeverity.INFO,
443
"Starting compilation of module 'my-app'"
444
)
445
446
messageCollector.report(
447
CompilerMessageSeverity.WARNING,
448
"Unused import: kotlin.collections.List",
449
CompilerMessageSourceLocation.create(
450
path = "src/main/kotlin/Main.kt",
451
line = 3,
452
column = 1,
453
lineContent = "import kotlin.collections.List"
454
)
455
)
456
457
messageCollector.report(
458
CompilerMessageSeverity.ERROR,
459
"Unresolved reference: unknownFunction",
460
CompilerMessageSourceLocation.create(
461
path = "src/main/kotlin/Main.kt",
462
line = 10,
463
column = 5,
464
lineContent = " unknownFunction()"
465
)
466
)
467
468
// Check for errors
469
if (messageCollector.hasErrors()) {
470
println("Compilation failed due to errors")
471
}
472
```
473
474
### Custom Message Renderer
475
476
```kotlin
477
// Custom JSON message renderer
478
class JsonMessageRenderer : MessageRenderer {
479
override fun render(
480
severity: CompilerMessageSeverity,
481
message: String,
482
location: CompilerMessageSourceLocation?
483
): String {
484
val json = buildJsonObject {
485
put("severity", severity.presentableName)
486
put("message", message)
487
put("timestamp", System.currentTimeMillis())
488
489
location?.let { loc ->
490
putJsonObject("location") {
491
put("path", loc.path)
492
put("line", loc.line)
493
put("column", loc.column)
494
put("lineContent", loc.lineContent)
495
}
496
}
497
}
498
return json.toString()
499
}
500
501
override fun getPath(location: CompilerMessageSourceLocation): String {
502
return location.path
503
}
504
}
505
506
// Use custom renderer
507
val jsonCollector = PrintingMessageCollector(
508
stream = System.out,
509
messageRenderer = JsonMessageRenderer(),
510
verbose = false
511
)
512
```
513
514
### IDE Integration
515
516
```kotlin
517
// Xcode integration
518
val xcodeCollector = PrintingMessageCollector(
519
stream = System.err,
520
messageRenderer = XcodeStyleMessageRenderer(),
521
verbose = false
522
)
523
524
// Gradle integration
525
val gradleCollector = PrintingMessageCollector(
526
stream = System.err,
527
messageRenderer = GradleStyleMessageRenderer(),
528
verbose = true
529
)
530
531
// Configure in compiler configuration
532
val configuration = CompilerConfiguration().apply {
533
put(CommonConfigurationKeys.MESSAGE_COLLECTOR_KEY, gradleCollector)
534
}
535
```
536
537
### Grouped Message Collection
538
539
```kotlin
540
val baseCollector = PrintingMessageCollector(
541
System.err,
542
MessageRenderer.PLAIN_FULL_PATHS,
543
true
544
)
545
546
val groupingCollector = GroupingMessageCollector(baseCollector)
547
548
// Group messages by module
549
groupingCollector.startGroup("Module: core")
550
groupingCollector.report(
551
CompilerMessageSeverity.INFO,
552
"Compiling core module"
553
)
554
groupingCollector.report(
555
CompilerMessageSeverity.ERROR,
556
"Missing dependency in core module"
557
)
558
groupingCollector.endGroup()
559
560
groupingCollector.startGroup("Module: api")
561
groupingCollector.report(
562
CompilerMessageSeverity.INFO,
563
"Compiling api module"
564
)
565
groupingCollector.endGroup()
566
```
567
568
### Filtering Message Collector
569
570
```kotlin
571
// Custom filtering message collector
572
class FilteringMessageCollector(
573
private val delegate: MessageCollector,
574
private val minSeverity: CompilerMessageSeverity
575
) : MessageCollector {
576
577
override fun report(
578
severity: CompilerMessageSeverity,
579
message: String,
580
location: CompilerMessageSourceLocation?
581
) {
582
if (severity.ordinal >= minSeverity.ordinal) {
583
delegate.report(severity, message, location)
584
}
585
}
586
587
override fun hasErrors(): Boolean = delegate.hasErrors()
588
override fun clear() = delegate.clear()
589
}
590
591
// Only show warnings and errors
592
val filteringCollector = FilteringMessageCollector(
593
delegate = PrintingMessageCollector(
594
System.err,
595
MessageRenderer.PLAIN_FULL_PATHS,
596
true
597
),
598
minSeverity = CompilerMessageSeverity.WARNING
599
)
600
```
601
602
### Diagnostic Integration
603
604
```kotlin
605
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
606
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
607
608
// Create analyzer with reporting
609
val analyzerWithReport = AnalyzerWithCompilerReport(
610
messageCollector = messageCollector,
611
languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT
612
)
613
614
// Analyze and report
615
val analysisResult = analyzeFiles(sourceFiles, environment)
616
analyzerWithReport.reportAnalysisResult(analysisResult, sourceFiles)
617
618
if (analyzerWithReport.hasErrors()) {
619
return ExitCode.COMPILATION_ERROR
620
}
621
```
622
623
### Exception Reporting
624
625
```kotlin
626
// Enhanced message collector with exception handling
627
class ExceptionHandlingMessageCollector(
628
private val delegate: MessageCollector
629
) : MessageCollector by delegate {
630
631
fun reportException(
632
exception: Throwable,
633
context: String? = null,
634
location: CompilerMessageSourceLocation? = null
635
) {
636
val message = buildString {
637
context?.let { append("$it: ") }
638
append(exception.message ?: exception.javaClass.simpleName)
639
640
// Add stack trace for debugging
641
if (exception.stackTrace.isNotEmpty()) {
642
append("\n")
643
exception.stackTrace.take(5).forEach { frame ->
644
append(" at ${frame}\n")
645
}
646
}
647
}
648
649
delegate.report(
650
CompilerMessageSeverity.EXCEPTION,
651
message,
652
location
653
)
654
}
655
}
656
657
// Usage
658
val exceptionCollector = ExceptionHandlingMessageCollector(messageCollector)
659
660
try {
661
// Compilation code
662
} catch (e: Exception) {
663
exceptionCollector.reportException(
664
e,
665
"Compilation failed",
666
CompilerMessageSourceLocation.create("build.gradle.kts", 1, 1, null)
667
)
668
}
669
```
670
671
### Performance Monitoring Integration
672
673
```kotlin
674
// Message collector with performance monitoring
675
class PerformanceMonitoringCollector(
676
private val delegate: MessageCollector
677
) : MessageCollector by delegate {
678
679
private var messageCount = 0
680
private var errorCount = 0
681
private var warningCount = 0
682
private val startTime = System.currentTimeMillis()
683
684
override fun report(
685
severity: CompilerMessageSeverity,
686
message: String,
687
location: CompilerMessageSourceLocation?
688
) {
689
messageCount++
690
when (severity) {
691
CompilerMessageSeverity.ERROR,
692
CompilerMessageSeverity.EXCEPTION -> errorCount++
693
CompilerMessageSeverity.WARNING,
694
CompilerMessageSeverity.STRONG_WARNING -> warningCount++
695
else -> {}
696
}
697
698
delegate.report(severity, message, location)
699
}
700
701
fun printStatistics() {
702
val duration = System.currentTimeMillis() - startTime
703
delegate.report(
704
CompilerMessageSeverity.INFO,
705
"Compilation completed in ${duration}ms: " +
706
"$messageCount messages ($errorCount errors, $warningCount warnings)"
707
)
708
}
709
}
710
711
// Usage
712
val performanceCollector = PerformanceMonitoringCollector(baseCollector)
713
// ... perform compilation ...
714
performanceCollector.printStatistics()
715
```
716
717
### Multi-Output Message Collection
718
719
```kotlin
720
// Broadcast messages to multiple collectors
721
class BroadcastMessageCollector(
722
private val collectors: List<MessageCollector>
723
) : MessageCollector {
724
725
override fun report(
726
severity: CompilerMessageSeverity,
727
message: String,
728
location: CompilerMessageSourceLocation?
729
) {
730
collectors.forEach { collector ->
731
collector.report(severity, message, location)
732
}
733
}
734
735
override fun hasErrors(): Boolean {
736
return collectors.any { it.hasErrors() }
737
}
738
739
override fun clear() {
740
collectors.forEach { it.clear() }
741
}
742
}
743
744
// Send messages to both console and log file
745
val consoleCollector = PrintingMessageCollector(
746
System.err,
747
MessageRenderer.PLAIN_FULL_PATHS,
748
false
749
)
750
751
val fileCollector = PrintingMessageCollector(
752
PrintStream(File("compilation.log")),
753
JsonMessageRenderer(),
754
true
755
)
756
757
val broadcastCollector = BroadcastMessageCollector(
758
listOf(consoleCollector, fileCollector)
759
)
760
```
761
762
## Error Handling
763
764
```kotlin { .api }
765
class MessageCollectionException(message: String, cause: Throwable? = null) : Exception(message, cause)
766
767
class InvalidMessageRendererException(message: String) : MessageCollectionException(message)
768
769
class MessageRenderingException(message: String, cause: Throwable) : MessageCollectionException(message, cause)
770
```
771
772
Common message handling scenarios:
773
- **INVALID_SEVERITY_LEVEL**: Unknown or invalid severity level
774
- **RENDERING_ERROR**: Error during message formatting or rendering
775
- **OUTPUT_STREAM_ERROR**: Problems writing to output stream
776
- **SOURCE_LOCATION_ERROR**: Invalid or inaccessible source location information