[messages] Parse type from messages.yaml.

Changes the logic for parsing analyzer-style `messages.yaml` files so
that an optional `type:` entry is accepted. When present, the type
will be checked against the type inferred from the diagnostic code's
class (`CompileTimeErrorCode` has type `compileTimeError`,
`StaticWarningCode` has type `staticWarning`, etc).

In a follow-up CL I will add these `type:` entries, and change the
code generation logic to use them instead of inferring the type from
the diagnostic code's class. This will pave the way for removing the
notion of diagnostic code class entirely.

Change-Id: I6a6a6964d58f06ea6573702f9afcc61b5370eda8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/464242
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Paul Berry
2025-11-25 09:40:03 -08:00
committed by Commit Queue
parent d8d61dee31
commit 5f569bf333
2 changed files with 45 additions and 2 deletions
@@ -15,7 +15,8 @@ import 'package:analyzer_utilities/located_error.dart';
import 'package:analyzer_utilities/messages.dart';
import 'package:analyzer_utilities/tools.dart';
import 'package:path/path.dart';
import 'package:yaml/yaml.dart' show YamlMap, YamlScalar, loadYamlNode;
import 'package:yaml/yaml.dart'
show YamlMap, YamlScalar, loadYamlNode, YamlNode;
/// Base diagnostic classes used for analyzer messages.
const analyzerBaseClasses = DiagnosticBaseClasses(
@@ -386,6 +387,10 @@ enum AnalyzerDiagnosticType {
syntacticError,
todo;
static final Map<String, AnalyzerDiagnosticType> _stringToValue = {
for (var value in values) value.name: value,
};
/// Base classes used for messages of this type.
final DiagnosticBaseClasses baseClasses;
@@ -393,6 +398,8 @@ enum AnalyzerDiagnosticType {
/// The representation of this type in analyzer source code.
String get code => 'DiagnosticType.${name.toSnakeCase().toUpperCase()}';
static AnalyzerDiagnosticType? fromString(String s) => _stringToValue[s];
}
/// In-memory representation of diagnostic information obtained from the
@@ -407,6 +414,9 @@ class AnalyzerMessage extends Message with MessageWithAnalyzerCode {
@override
final AnalyzerDiagnosticPackage package;
@override
final AnalyzerDiagnosticType? type;
factory AnalyzerMessage(
MessageYaml messageYaml, {
required AnalyzerCode analyzerCode,
@@ -437,6 +447,11 @@ class AnalyzerMessage extends Message with MessageWithAnalyzerCode {
required bool allowLinterKeys,
required this.package,
}) : hasPublishedDocs = messageYaml.getBool('hasPublishedDocs'),
type = messageYaml.get(
'type',
decode: MessageWithAnalyzerCode.decodeType,
ifAbsent: () => null,
),
super(messageYaml) {
// Ignore extra keys related to analyzer example-based tests.
messageYaml.allowExtraKeys({'experiment'});
@@ -580,6 +595,10 @@ mixin MessageWithAnalyzerCode on Message {
/// The package into which this error code will be generated.
AnalyzerDiagnosticPackage get package;
/// The type of this diagnostic, if present in `messages.yaml`. Otherwise
/// `null`.
AnalyzerDiagnosticType? get type;
void outputConstantHeader(StringSink out) {
out.write(toAnalyzerComments(indent: ' '));
if (deprecatedMessage != null) {
@@ -712,4 +731,11 @@ LocatableDiagnostic $withArgumentsName({$withArgumentsParams}) {
// But we also need to escape `$`.
return jsonEncoded.replaceAll(r'$', r'\$');
}
static AnalyzerDiagnosticType decodeType(YamlNode node) => switch (node) {
YamlScalar(:String value) =>
AnalyzerDiagnosticType.fromString(value) ??
(throw 'Unknown analyzer diagnostic type'),
_ => throw 'Must be a bool',
};
}
+18 -1
View File
@@ -450,6 +450,15 @@ class DiagnosticTables {
[])
.add(message);
var package = message.package;
var type = message.type;
if (type != null && analyzerCode.diagnosticClass.type != type) {
throw LocatedError(
'Diagnostic type is ${type.name}, but its diagnostic class '
'(${analyzerCode.diagnosticClass.name}) implies a type of '
'${analyzerCode.diagnosticClass.type.name}',
span: message.keySpan,
);
}
if (!message.isRemoved && message is! AliasMessage) {
(activeMessagesByPackage[package] ??= []).add(message);
}
@@ -925,12 +934,20 @@ class SharedMessage extends CfeStyleMessage with MessageWithAnalyzerCode {
@override
final bool hasPublishedDocs;
@override
final AnalyzerDiagnosticType? type;
SharedMessage(super.messageYaml)
: analyzerCode = messageYaml.get(
'analyzerCode',
decode: _decodeAnalyzerCode,
),
hasPublishedDocs = messageYaml.getBool('hasPublishedDocs');
hasPublishedDocs = messageYaml.getBool('hasPublishedDocs'),
type = messageYaml.get(
'type',
decode: MessageWithAnalyzerCode.decodeType,
ifAbsent: () => null,
);
@override
AnalyzerDiagnosticPackage get package => AnalyzerDiagnosticPackage.analyzer;