From 5f569bf333438dcc246f5494743be2feca475484 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Tue, 25 Nov 2025 09:40:03 -0800 Subject: [PATCH] [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 --- .../lib/analyzer_messages.dart | 28 ++++++++++++++++++- pkg/analyzer_utilities/lib/messages.dart | 19 ++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/pkg/analyzer_utilities/lib/analyzer_messages.dart b/pkg/analyzer_utilities/lib/analyzer_messages.dart index 527c5313a47..eb5704ca5b2 100644 --- a/pkg/analyzer_utilities/lib/analyzer_messages.dart +++ b/pkg/analyzer_utilities/lib/analyzer_messages.dart @@ -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 _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', + }; } diff --git a/pkg/analyzer_utilities/lib/messages.dart b/pkg/analyzer_utilities/lib/messages.dart index 966d3e12b9c..f94cb1c5c54 100644 --- a/pkg/analyzer_utilities/lib/messages.dart +++ b/pkg/analyzer_utilities/lib/messages.dart @@ -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;