菜单

诊断系统

相关源文件

目的与范围

Kotlin 诊断系统负责在程序编译期间检测、创建和报告错误及警告。它为开发者提供关于代码问题的具体、可操作性的反馈。本文档涵盖了 Kotlin 编译器中诊断系统的架构和实现、诊断的定义、渲染和测试方式,以及它们如何与语言版本设置进行交互。

有关语言版本设置的详细信息,请参阅 语言版本设置

架构概述

诊断系统与 Kotlin 编译器前端紧密集成,特别是与 FIR(前端 IR)系统。诊断在编译的各个阶段生成,并提供反馈,帮助开发者理解和修复其代码中的问题。

来源:compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt

诊断类别和类型

Kotlin 编译器中的诊断被组织成几个类别。每个诊断都有一个特定的类型、严重级别(错误、警告或信息),并且可能包含提供上下文特定信息的参数。

来源:compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt

诊断的创建和表示

诊断的创建和表示过程涉及多个协同工作的组件。

来源:analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnostics.kt analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KaFirDiagnosticsImpl.kt

诊断定义

诊断在编译器中使用类似 DSL 的方法进行定义。每个诊断都定义了其严重级别(错误、警告或信息)、适用的 PSI 元素类型以及所需的任何参数。

例如,在 FirDiagnosticsList.kt 中,诊断的定义如下:

来源:compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt

错误消息渲染

每个诊断在 FirErrorsDefaultMessages.kt 中都有相应的消息模板。

消息模板中的占位符在渲染诊断时会被实际的参数值替换。

来源:compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt

语言版本集成

诊断系统与语言版本设置紧密集成,后者决定了特定 Kotlin 版本中可用的语言功能。不同的语言版本可能在什么构成错误或警告方面有不同的规则。

来源:compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt

抑制机制

某些诊断可以使用 @Suppress 注解进行抑制,允许开发者在特定情况下静默警告或错误。但是,某些关键错误无法被抑制,如 FirNonSuppressibleErrorNames.kt 中所定义的。这确保了基本错误始终会被报告。

类别不可抑制错误的示例
元错误UNSUPPORTEDUNSUPPORTED_FEATURENEW_INFERENCE_ERROR
语法ILLEGAL_CONST_EXPRESSIONEXPRESSION_EXPECTED
类型系统CREATING_AN_INSTANCE_OF_ABSTRACT_CLASSNO_CONSTRUCTOR
名称解析INVISIBLE_REFERENCEUNRESOLVED_REFERENCE

来源:compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirNonSuppressibleErrorNames.kt

测试基础设施

Kotlin 编译器包含一套详尽的诊断测试,以确保它们得到正确报告。这些测试组织在 DiagnosticTestGenerated.javaFirLightTreeOldFrontendDiagnosticsWithLatestLanguageVersionTestGenerated.java 等文件中。

诊断测试通常包括:

  1. 一个包含应触发特定诊断的代码的测试文件。
  2. 文件中指示应在何处报告诊断的注释。
  3. 编译该文件并验证诊断的测试工具。

来源:compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLightTreeOldFrontendDiagnosticsWithLatestLanguageVersionTestGenerated.java compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/PhasedJvmDiagnosticPsiTestGenerated.java

平台特定诊断

Kotlin 编译器为 JVM、JavaScript 和 Native 目标提供了特定于平台的诊断系统。这些诊断解决了每个平台特有的问题。

例如,特定于 JVM 的诊断包括:

  • JVM_STATIC_NOT_IN_OBJECT_OR_CLASS_COMPANION
  • JVM_STATIC_ON_NON_PUBLIC_MEMBER
  • JVM_FIELD_IN_INTERFACE

来源:compiler/fir/checkers/checkers.jvm/src/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrorsDefaultMessages.kt compiler/fir/checkers/checkers.jvm/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/jvm/FirJvmErrors.kt

实际示例

让我们看一个简单的诊断报告示例。考虑以下 Kotlin 代码:

诊断过程如下:

  1. FIR 检查器检测到 Int(文字 42)和 String(声明的类型)之间的类型不匹配。
  2. 创建了 TYPE_MISMATCH 诊断,并带有期望类型和实际类型的参数。
  3. 诊断渲染器格式化消息:“Type mismatch: inferred type is Int but String was expected”(类型不匹配:推断类型为 Int 但期望 String)。
  4. 诊断被报告给编译器输出或 IDE。

此诊断无法被抑制,因为类型不匹配被认为是必须修复的基本错误。

总结

Kotlin 诊断系统是编译器的一个复杂组件,用于检测和报告代码中的问题。它与语言版本设置紧密集成,确保诊断适用于指定的 Kotlin 版本。该系统为开发者提供清晰、可操作的反馈,帮助他们编写正确且符合习惯的 Kotlin 代码。

来源:compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt