[analyzer] Stop using Diagnostic.data and deprecate it. The only two uses of `Diagnostic.data` have been replaced with expandos keyed off the `Diagnostic` object. To make this possible, the `at...` methods of `DiagnosticReporter` have been changed to return the `Diagnostic` object they create. This paves the way for a future CL series, in which I plan to change the API for reporting errors to a more literate API in which the caller will have access to the `Diagnostic` object. Change-Id: I40820387abcd53daf934974c93106803d706fe07 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/444461 Commit-Queue: Paul Berry <paulberry@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com> Reviewed-by: Samuel Rawlins <srawlins@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_missing_switch_cases.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_missing_switch_cases.dart index 0f29e15..378bcfa 100644 --- a/pkg/analysis_server/lib/src/services/correction/dart/add_missing_switch_cases.dart +++ b/pkg/analysis_server/lib/src/services/correction/dart/add_missing_switch_cases.dart
@@ -32,8 +32,8 @@ return; } - var patternPartsList = diagnostic.data; - if (patternPartsList is! List<List<MissingPatternPart>>) { + var patternPartsList = MissingPatternPart.byDiagnostic[diagnostic]; + if (patternPartsList == null) { return; }
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart b/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart index d1efa20..42c9399 100644 --- a/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart +++ b/pkg/analysis_server/lib/src/services/correction/fix/pubspec/fix_generator.dart
@@ -154,7 +154,7 @@ defaultEol: endOfLine, ); - var data = diagnostic.data as MissingDependencyData; + var data = MissingDependencyData.byDiagnostic[diagnostic]!; var addDeps = data.addDeps; var addDevDeps = data.addDevDeps; var removeDevDeps = data.removeDevDeps;
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md index 8dfdd7f..6d50b0a 100644 --- a/pkg/analyzer/CHANGELOG.md +++ b/pkg/analyzer/CHANGELOG.md
@@ -22,6 +22,8 @@ * Deprecate `ClassElement.isImplementableIn`; use `isImplementableOutside` instead. * Deprecate `ClassElement.isMixableIn`; use `isMixableOutside` instead. * Deprecate `MixinElement.isImplementableIn`; use `isImplementableOutside` instead. +* Deprecate `Diagnostic.data`. Instead, please use an expando to attach data to + the `Diagnostic` object. ## 8.0.0 * Remove deprecated element model V1.
diff --git a/pkg/analyzer/api.txt b/pkg/analyzer/api.txt index f353dc3..0491cba 100644 --- a/pkg/analyzer/api.txt +++ b/pkg/analyzer/api.txt
@@ -4763,8 +4763,8 @@ buildSdkSummary (function: Future<Uint8List> Function({String? embedderYamlPath, required ResourceProvider resourceProvider, required String sdkPath})) package:analyzer/diagnostic/diagnostic.dart: Diagnostic (class extends Object): - forValues (constructor: Diagnostic Function({List<DiagnosticMessage> contextMessages, String? correctionMessage, Object? data, DiagnosticCode? diagnosticCode, deprecated DiagnosticCode? errorCode, required int length, required String message, required int offset, required Source source})) - tmp (constructor: Diagnostic Function({List<Object?> arguments, List<DiagnosticMessage> contextMessages, Object? data, DiagnosticCode? diagnosticCode, deprecated DiagnosticCode? errorCode, required int length, required int offset, required Source source})) + forValues (constructor: Diagnostic Function({List<DiagnosticMessage> contextMessages, String? correctionMessage, deprecated Object? data, DiagnosticCode? diagnosticCode, deprecated DiagnosticCode? errorCode, required int length, required String message, required int offset, required Source source})) + tmp (constructor: Diagnostic Function({List<Object?> arguments, List<DiagnosticMessage> contextMessages, deprecated Object? data, DiagnosticCode? diagnosticCode, deprecated DiagnosticCode? errorCode, required int length, required int offset, required Source source})) contextMessages (getter: List<DiagnosticMessage>) correction (getter: String?, deprecated) correctionMessage (getter: String?) @@ -4874,13 +4874,13 @@ lockLevel (getter: int) lockLevel= (setter: int) source (getter: Source) - atConstructorDeclaration (method: void Function(ConstructorDeclaration, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, Object? data})) - atElement2 (method: void Function(Element, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, Object? data}), experimental) - atEntity (method: void Function(SyntacticEntity, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, Object? data})) - atNode (method: void Function(AstNode, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, Object? data})) - atOffset (method: void Function({List<Object>? arguments, List<DiagnosticMessage>? contextMessages, Object? data, DiagnosticCode? diagnosticCode, deprecated DiagnosticCode? errorCode, required int length, required int offset})) - atSourceSpan (method: void Function(SourceSpan, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, Object? data})) - atToken (method: void Function(Token, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, Object? data})) + atConstructorDeclaration (method: Diagnostic Function(ConstructorDeclaration, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, deprecated Object? data})) + atElement2 (method: Diagnostic Function(Element, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, deprecated Object? data}), experimental) + atEntity (method: Diagnostic Function(SyntacticEntity, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, deprecated Object? data})) + atNode (method: Diagnostic Function(AstNode, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, deprecated Object? data})) + atOffset (method: Diagnostic Function({List<Object>? arguments, List<DiagnosticMessage>? contextMessages, deprecated Object? data, DiagnosticCode? diagnosticCode, deprecated DiagnosticCode? errorCode, required int length, required int offset})) + atSourceSpan (method: Diagnostic Function(SourceSpan, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, deprecated Object? data})) + atToken (method: Diagnostic Function(Token, DiagnosticCode, {List<Object>? arguments, List<DiagnosticMessage>? contextMessages, deprecated Object? data})) reportError (method: void Function(Diagnostic)) RecordingDiagnosticListener (class extends Object implements AnalysisErrorListener, DiagnosticListener): new (constructor: RecordingDiagnosticListener Function())
diff --git a/pkg/analyzer/lib/diagnostic/diagnostic.dart b/pkg/analyzer/lib/diagnostic/diagnostic.dart index 723fd43..682b0d3 100644 --- a/pkg/analyzer/lib/diagnostic/diagnostic.dart +++ b/pkg/analyzer/lib/diagnostic/diagnostic.dart
@@ -24,6 +24,7 @@ final List<DiagnosticMessage> contextMessages; /// Data associated with this diagnostic, specific for [diagnosticCode]. + @Deprecated('Use an expando instead') final Object? data; /// A description of how to fix the problem, or `null` if there is no such @@ -46,7 +47,7 @@ required String message, this.correctionMessage, this.contextMessages = const [], - this.data, + @Deprecated('Use an expando instead') this.data, }) : diagnosticCode = _useNonNullCodeBetween(diagnosticCode, errorCode), problemMessage = DiagnosticMessageImpl( filePath: source.fullName, @@ -72,7 +73,7 @@ DiagnosticCode? errorCode, List<Object?> arguments = const [], List<DiagnosticMessage> contextMessages = const [], - Object? data, + @Deprecated('Use an expando instead') Object? data, }) { var code = _useNonNullCodeBetween(diagnosticCode, errorCode); assert( @@ -98,6 +99,7 @@ message: message, correctionMessage: correctionMessage, contextMessages: contextMessages, + // ignore: deprecated_member_use_from_same_package data: data, ); }
diff --git a/pkg/analyzer/lib/error/listener.dart b/pkg/analyzer/lib/error/listener.dart index c2440ca..2efdae8 100644 --- a/pkg/analyzer/lib/error/listener.dart +++ b/pkg/analyzer/lib/error/listener.dart
@@ -96,47 +96,54 @@ /// Reports a diagnostic with the given [diagnosticCode] and [arguments]. /// /// The location of the diagnostic will be the name of the [node]. - void atConstructorDeclaration( + /// + /// The reported [Diagnostic] is returned so that the caller may attach + /// additional information to it (for example, using an expando). + Diagnostic atConstructorDeclaration( ConstructorDeclaration node, DiagnosticCode diagnosticCode, { List<Object>? arguments, List<DiagnosticMessage>? contextMessages, - Object? data, + @Deprecated('Use an expando instead') Object? data, }) { // TODO(brianwilkerson): Consider extending this method to take any // declaration and compute the correct range for the name of that // declaration. This might make it easier to be consistent. if (node.name case var nameToken?) { var offset = node.returnType.offset; - atOffset( + return atOffset( offset: offset, length: nameToken.end - offset, diagnosticCode: diagnosticCode, arguments: arguments, ); } else { - atNode(node.returnType, diagnosticCode, arguments: arguments); + return atNode(node.returnType, diagnosticCode, arguments: arguments); } } /// Reports a diagnostic with the given [diagnosticCode] and [arguments]. /// /// The [element] is used to compute the location of the diagnostic. + /// + /// The reported [Diagnostic] is returned so that the caller may attach + /// additional information to it (for example, using an expando). @experimental - void atElement2( + Diagnostic atElement2( Element element, DiagnosticCode diagnosticCode, { List<Object>? arguments, List<DiagnosticMessage>? contextMessages, - Object? data, + @Deprecated('Use an expando instead') Object? data, }) { var nonSynthetic = element.nonSynthetic; - atOffset( + return atOffset( diagnosticCode: diagnosticCode, offset: nonSynthetic.firstFragment.nameOffset ?? -1, length: nonSynthetic.name?.length ?? 0, arguments: arguments, contextMessages: contextMessages, + // ignore: deprecated_member_use_from_same_package data: data, ); } @@ -144,19 +151,23 @@ /// Reports a diagnostic with the given [diagnosticCode] and [arguments]. /// /// The [entity] is used to compute the location of the diagnostic. - void atEntity( + /// + /// The reported [Diagnostic] is returned so that the caller may attach + /// additional information to it (for example, using an expando). + Diagnostic atEntity( SyntacticEntity entity, DiagnosticCode diagnosticCode, { List<Object>? arguments, List<DiagnosticMessage>? contextMessages, - Object? data, + @Deprecated('Use an expando instead') Object? data, }) { - atOffset( + return atOffset( diagnosticCode: diagnosticCode, offset: entity.offset, length: entity.length, arguments: arguments, contextMessages: contextMessages, + // ignore: deprecated_member_use_from_same_package data: data, ); } @@ -164,19 +175,23 @@ /// Reports a diagnostic with the given [diagnosticCode] and [arguments]. /// /// The [node] is used to compute the location of the diagnostic. - void atNode( + /// + /// The reported [Diagnostic] is returned so that the caller may attach + /// additional information to it (for example, using an expando). + Diagnostic atNode( AstNode node, DiagnosticCode diagnosticCode, { List<Object>? arguments, List<DiagnosticMessage>? contextMessages, - Object? data, + @Deprecated('Use an expando instead') Object? data, }) { - atOffset( + return atOffset( diagnosticCode: diagnosticCode, offset: node.offset, length: node.length, arguments: arguments, contextMessages: contextMessages, + // ignore: deprecated_member_use_from_same_package data: data, ); } @@ -186,18 +201,18 @@ /// /// The location of the diagnostic is specified by the given [offset] and /// [length]. - void atOffset({ + /// + /// The reported [Diagnostic] is returned so that the caller may attach + /// additional information to it (for example, using an expando). + Diagnostic atOffset({ required int offset, required int length, @Deprecated("Use 'diagnosticCode' instead") DiagnosticCode? errorCode, DiagnosticCode? diagnosticCode, List<Object>? arguments, List<DiagnosticMessage>? contextMessages, - Object? data, + @Deprecated('Use an expando instead') Object? data, }) { - if (lockLevel != 0) { - return; - } if ((errorCode == null && diagnosticCode == null) || (errorCode != null && diagnosticCode != null)) { throw ArgumentError( @@ -225,35 +240,40 @@ contextMessages ??= []; contextMessages.addAll(convertTypeNames(arguments)); - _diagnosticListener.onDiagnostic( - Diagnostic.tmp( - source: _source, - offset: offset, - length: length, - diagnosticCode: diagnosticCode, - arguments: arguments ?? const [], - contextMessages: contextMessages, - data: data, - ), + var diagnostic = Diagnostic.tmp( + source: _source, + offset: offset, + length: length, + diagnosticCode: diagnosticCode, + arguments: arguments ?? const [], + contextMessages: contextMessages, + // ignore: deprecated_member_use_from_same_package + data: data, ); + reportError(diagnostic); + return diagnostic; } /// Reports a diagnostic with the given [diagnosticCode] and [arguments]. /// /// The [span] is used to compute the location of the diagnostic. - void atSourceSpan( + /// + /// The reported [Diagnostic] is returned so that the caller may attach + /// additional information to it (for example, using an expando). + Diagnostic atSourceSpan( SourceSpan span, DiagnosticCode diagnosticCode, { List<Object>? arguments, List<DiagnosticMessage>? contextMessages, - Object? data, + @Deprecated('Use an expando instead') Object? data, }) { - atOffset( + return atOffset( diagnosticCode: diagnosticCode, offset: span.start.offset, length: span.length, arguments: arguments, contextMessages: contextMessages, + // ignore: deprecated_member_use_from_same_package data: data, ); } @@ -261,25 +281,32 @@ /// Reports a diagnostic with the given [diagnosticCode] and [arguments]. /// /// The [token] is used to compute the location of the diagnostic. - void atToken( + /// + /// The reported [Diagnostic] is returned so that the caller may attach + /// additional information to it (for example, using an expando). + Diagnostic atToken( Token token, DiagnosticCode diagnosticCode, { List<Object>? arguments, List<DiagnosticMessage>? contextMessages, - Object? data, + @Deprecated('Use an expando instead') Object? data, }) { - atOffset( + return atOffset( diagnosticCode: diagnosticCode, offset: token.offset, length: token.length, arguments: arguments, contextMessages: contextMessages, + // ignore: deprecated_member_use_from_same_package data: data, ); } /// Report the given [diagnostic]. void reportError(Diagnostic diagnostic) { + if (lockLevel != 0) { + return; + } _diagnosticListener.onDiagnostic(diagnostic); } }
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart index 3dc919d..c6c0937 100644 --- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart +++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -1115,7 +1115,7 @@ correctionData.add(correctionDataBuffer.parts); } } - _diagnosticReporter.atToken( + var diagnostic = _diagnosticReporter.atToken( switchKeyword, isSwitchExpression ? CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_EXPRESSION @@ -1125,8 +1125,10 @@ errorBuffer.toString(), correctionTextBuffer.toString(), ], - data: correctionData.isNotEmpty ? correctionData : null, ); + if (correctionData.isNotEmpty) { + MissingPatternPart.byDiagnostic[diagnostic] = correctionData; + } } } else { if (defaultNode != null && mustBeExhaustive) {
diff --git a/pkg/analyzer/lib/src/error/literal_element_verifier.dart b/pkg/analyzer/lib/src/error/literal_element_verifier.dart index 59ba9a2..02bb419 100644 --- a/pkg/analyzer/lib/src/error/literal_element_verifier.dart +++ b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
@@ -257,10 +257,11 @@ ); if (iterableType == null) { - return _diagnosticReporter.atNode( + _diagnosticReporter.atNode( expression, CompileTimeErrorCode.NOT_ITERABLE_SPREAD, ); + return; } var iterableElementType = iterableType.typeArguments[0]; @@ -357,10 +358,11 @@ var mapType = expressionType.asInstanceOf(typeProvider.mapElement); if (mapType == null) { - return _diagnosticReporter.atNode( + _diagnosticReporter.atNode( expression, CompileTimeErrorCode.NOT_MAP_SPREAD, ); + return; } var keyType = mapType.typeArguments[0];
diff --git a/pkg/analyzer/lib/src/generated/exhaustiveness.dart b/pkg/analyzer/lib/src/generated/exhaustiveness.dart index a42374d..46edd65 100644 --- a/pkg/analyzer/lib/src/generated/exhaustiveness.dart +++ b/pkg/analyzer/lib/src/generated/exhaustiveness.dart
@@ -476,7 +476,14 @@ String toString() => value2.name!; } -abstract class MissingPatternPart {} +abstract class MissingPatternPart { + /// Expando associating each + /// [CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_EXPRESSION] or + /// [CompileTimeErrorCode.NON_EXHAUSTIVE_SWITCH_STATEMENT] diagnostic with a + /// list of missing patterns; this data is used by the analysis server to add + /// missing switch cases. + static final byDiagnostic = Expando<List<List<MissingPatternPart>>>(); +} class MissingPatternTextPart extends MissingPatternPart { final String text;
diff --git a/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart b/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart index d55bedb..dca0eb1 100644 --- a/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart +++ b/pkg/analyzer/lib/src/pubspec/pubspec_validator.dart
@@ -165,7 +165,6 @@ DiagnosticCode diagnosticCode, [ List<Object>? arguments, List<DiagnosticMessage>? messages, - Object? data, ]) { var span = node.span; reporter.atOffset( @@ -174,7 +173,6 @@ diagnosticCode: diagnosticCode, arguments: arguments, contextMessages: messages, - data: data, ); } }
diff --git a/pkg/analyzer/lib/src/pubspec/validators/missing_dependency_validator.dart b/pkg/analyzer/lib/src/pubspec/validators/missing_dependency_validator.dart index 9f3ff29..66a6337 100644 --- a/pkg/analyzer/lib/src/pubspec/validators/missing_dependency_validator.dart +++ b/pkg/analyzer/lib/src/pubspec/validators/missing_dependency_validator.dart
@@ -12,6 +12,12 @@ import 'package:yaml/yaml.dart'; class MissingDependencyData { + /// Expando associating each [PubspecWarningCode.MISSING_DEPENDENCY] with + /// missing dependency information; this information is used by the analysis + /// server to list of missing patterns; this data is used by the analysis + /// server to compute fixes. + static final byDiagnostic = Expando<MissingDependencyData>(); + final List<String> addDeps; final List<String> addDevDeps; final List<String> removeDevDeps; @@ -127,33 +133,37 @@ "$message ${addDevDeps.map((s) => "'$s'").join(',')} in 'dev_dependencies'"; } if (addDeps.isNotEmpty || addDevDeps.isNotEmpty) { - _reportErrorForNode( + var diagnostic = _reportErrorForNode( contents.nodes.values.first, PubspecWarningCode.MISSING_DEPENDENCY, [message], [], - MissingDependencyData(addDeps, addDevDeps, removeDevDeps), + ); + MissingDependencyData.byDiagnostic[diagnostic] = MissingDependencyData( + addDeps, + addDevDeps, + removeDevDeps, ); } return recorder.diagnostics; } /// Report an error for the given node. - void _reportErrorForNode( + /// + /// The reported [Diagnostic] is returned. + Diagnostic _reportErrorForNode( YamlNode node, DiagnosticCode diagnosticCode, [ List<Object>? arguments, List<DiagnosticMessage>? messages, - Object? data, ]) { var span = node.span; - reporter.atOffset( + return reporter.atOffset( offset: span.start.offset, length: span.length, diagnosticCode: diagnosticCode, arguments: arguments, contextMessages: messages, - data: data, ); } }
diff --git a/pkg/analyzer/test/src/pubspec/diagnostics/missing_dependency_test.dart b/pkg/analyzer/test/src/pubspec/diagnostics/missing_dependency_test.dart index 70113f3..acae8a9 100644 --- a/pkg/analyzer/test/src/pubspec/diagnostics/missing_dependency_test.dart +++ b/pkg/analyzer/test/src/pubspec/diagnostics/missing_dependency_test.dart
@@ -34,7 +34,7 @@ List<String> removeDevDeps = const [], }) { var error = _runValidator(content, usedDeps, usedDevDeps).first; - var data = error.data as MissingDependencyData; + var data = MissingDependencyData.byDiagnostic[error]!; expect(error.diagnosticCode, PubspecWarningCode.MISSING_DEPENDENCY); expect(data.addDeps, addDeps); expect(data.addDevDeps, addDevDeps);