From d48e7dc6200d44899dd4d810c4721b76bf5e21e3 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Tue, 25 Nov 2025 14:16:01 -0800 Subject: [PATCH] [messages] Consume types from messages.yaml files. Now that all diagnostic codes in analyzer-style `messages.yaml` files have a `type:` entry, it can safely be used to determine the diagnostic's type. This replaces the old logic that inferred diagnostic types from the diagnostic's class name (diagnostics under the heading `CompileTimeErrorCode` have type `compileTimeError`, those under `StaticWarningCode` have type `staticWarning`, etc). This paves the way for removing the notion of diagnostic code class entirely. Change-Id: I6a6a69646fdcaccaef6f8c32a1ebf303a54548d8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/464283 Reviewed-by: Konstantin Shcheglov --- .../test/verify_diagnostics_test.dart | 4 +-- .../lib/analyzer_messages.dart | 27 +++++++++++++------ pkg/analyzer_utilities/lib/messages.dart | 12 ++++++--- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/pkg/analyzer/test/verify_diagnostics_test.dart b/pkg/analyzer/test/verify_diagnostics_test.dart index b27d7918c0e..febe03e6a08 100644 --- a/pkg/analyzer/test/verify_diagnostics_test.dart +++ b/pkg/analyzer/test/verify_diagnostics_test.dart @@ -371,7 +371,7 @@ class DocumentationValidator { } for (int i = 0; i < exampleSnippets.length; i++) { _SnippetData snippet = exampleSnippets[i]; - if (message.analyzerCode.diagnosticClass == linterLintCodeInfo) { + if (message.type == AnalyzerDiagnosticType.lint) { snippet.lintCode = codeName; } await _validateSnippet('example', i, snippet); @@ -386,7 +386,7 @@ class DocumentationValidator { if (firstExample != null) { snippet.auxiliaryFiles.addAll(firstExample.auxiliaryFiles); } - if (message.analyzerCode.diagnosticClass == linterLintCodeInfo) { + if (message.type == AnalyzerDiagnosticType.lint) { snippet.lintCode = codeName; } await _validateSnippet('fixes', i, snippet); diff --git a/pkg/analyzer_utilities/lib/analyzer_messages.dart b/pkg/analyzer_utilities/lib/analyzer_messages.dart index eb5704ca5b2..aec3fc04b0f 100644 --- a/pkg/analyzer_utilities/lib/analyzer_messages.dart +++ b/pkg/analyzer_utilities/lib/analyzer_messages.dart @@ -311,15 +311,24 @@ enum AnalyzerDiagnosticPackage { analyzer( diagnosticPathPart: 'src/diagnostic/diagnostic', dirName: 'analyzer', + permittedTypes: { + .compileTimeError, + .hint, + .staticWarning, + .syntacticError, + .todo, + }, ), analysisServer( diagnosticPathPart: 'src/diagnostic', dirName: 'analysis_server', + permittedTypes: {.compileTimeError}, shouldIgnorePreferSingleQuotes: true, ), linter( diagnosticPathPart: 'src/diagnostic', dirName: 'linter', + permittedTypes: {.lint}, shouldIgnorePreferExpressionFunctionBodies: true, shouldIgnorePreferSingleQuotes: true, ); @@ -335,6 +344,9 @@ enum AnalyzerDiagnosticPackage { /// file will be `pkg/linter/lib/src/diagnostic/diagnostic.g.dart`. final String diagnosticPathPart; + /// The set of [AnalyzerDiagnosticType]s that may be used in this package. + final Set permittedTypes; + /// Whether code generated in this package needs an "ignore" comment to ignore /// the `prefer_expression_function_bodies` lint. final bool shouldIgnorePreferExpressionFunctionBodies; @@ -346,6 +358,7 @@ enum AnalyzerDiagnosticPackage { const AnalyzerDiagnosticPackage({ required this.diagnosticPathPart, required this.dirName, + required this.permittedTypes, this.shouldIgnorePreferExpressionFunctionBodies = false, this.shouldIgnorePreferSingleQuotes = false, }); @@ -415,7 +428,7 @@ class AnalyzerMessage extends Message with MessageWithAnalyzerCode { final AnalyzerDiagnosticPackage package; @override - final AnalyzerDiagnosticType? type; + final AnalyzerDiagnosticType type; factory AnalyzerMessage( MessageYaml messageYaml, { @@ -450,7 +463,6 @@ class AnalyzerMessage extends Message with MessageWithAnalyzerCode { type = messageYaml.get( 'type', decode: MessageWithAnalyzerCode.decodeType, - ifAbsent: () => null, ), super(messageYaml) { // Ignore extra keys related to analyzer example-based tests. @@ -545,7 +557,7 @@ mixin MessageWithAnalyzerCode on Message { (value) => value != null && value.any((part) => part is TemplateParameterPart), ); - var baseClasses = analyzerCode.diagnosticClass.type.baseClasses; + var baseClasses = type.baseClasses; if (parameters.isNotEmpty && !usesParameters) { throw 'Error code declares parameters using a `parameters` entry, but ' "doesn't use them"; @@ -595,9 +607,8 @@ 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; + /// The type of this diagnostic. + AnalyzerDiagnosticType get type; void outputConstantHeader(StringSink out) { out.write(toAnalyzerComments(indent: ' ')); @@ -617,7 +628,7 @@ mixin MessageWithAnalyzerCode on Message { var diagnosticCode = analyzerCode.snakeCaseName; var correctionMessage = this.correctionMessage; String? withArgumentsName; - var baseClasses = analyzerCode.diagnosticClass.type.baseClasses; + var baseClasses = type.baseClasses; var ConstantStyle(:concreteClassName, :staticType) = constantStyle; if (constantStyle case WithArgumentsConstantStyle( :var withArgumentsParams, @@ -662,7 +673,7 @@ LocatableDiagnostic $withArgumentsName({$withArgumentsParams}) { constant.writeln('isUnresolvedIdentifier:true,'); } if (baseClasses.requiresTypeArgument) { - constant.writeln('type: ${diagnosticClassInfo.type.code},'); + constant.writeln('type: ${type.code},'); } String uniqueName = analyzerCode.toString().replaceFirst( 'LinterLintCode.', diff --git a/pkg/analyzer_utilities/lib/messages.dart b/pkg/analyzer_utilities/lib/messages.dart index f94cb1c5c54..8dff063dec3 100644 --- a/pkg/analyzer_utilities/lib/messages.dart +++ b/pkg/analyzer_utilities/lib/messages.dart @@ -451,7 +451,7 @@ class DiagnosticTables { .add(message); var package = message.package; var type = message.type; - if (type != null && analyzerCode.diagnosticClass.type != type) { + if (analyzerCode.diagnosticClass.type != type) { throw LocatedError( 'Diagnostic type is ${type.name}, but its diagnostic class ' '(${analyzerCode.diagnosticClass.name}) implies a type of ' @@ -459,6 +459,13 @@ class DiagnosticTables { span: message.keySpan, ); } + if (!package.permittedTypes.contains(type)) { + throw LocatedError( + 'Diagnostic type is ${type.name}, which may not be used in ' + 'package:${package.dirName}', + span: message.keySpan, + ); + } if (!message.isRemoved && message is! AliasMessage) { (activeMessagesByPackage[package] ??= []).add(message); } @@ -935,7 +942,7 @@ class SharedMessage extends CfeStyleMessage with MessageWithAnalyzerCode { final bool hasPublishedDocs; @override - final AnalyzerDiagnosticType? type; + final AnalyzerDiagnosticType type; SharedMessage(super.messageYaml) : analyzerCode = messageYaml.get( @@ -946,7 +953,6 @@ class SharedMessage extends CfeStyleMessage with MessageWithAnalyzerCode { type = messageYaml.get( 'type', decode: MessageWithAnalyzerCode.decodeType, - ifAbsent: () => null, ); @override